diff --git a/.gitignore b/.gitignore index b7fb466ca4bf..8faa686c0ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ *.lo *.in *.[ch]e +*.log +*.rule +*.rules +*.yaml Makefile .deps/ .libs/ @@ -31,6 +35,10 @@ libhtp/stamp-h1 libhtp/test/TAGS libtool ltmain.sh +src/*.diff +src/*.patch +src/*.rej +src/*.orig src/TAGS src/suricata stamp-h1 diff --git a/.travis.yml b/.travis.yml index 297b6133b026..0194a079211b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,169 @@ +sudo: false language: c -compiler: - - gcc - - clang -# Change this to your needs -script: sh autogen.sh && ./configure --enable-nfqueue --enable-unittests && make && make check + +addons: + apt: + # Define the required packages without libjansson so we can do a + # build without libjansson. + packages-without-jansson: &packages-without-jansson + - libpcre3 + - libpcre3-dbg + - libpcre3-dev + - build-essential + - autoconf + - automake + - libtool + - libpcap-dev + - libnet1-dev + - libyaml-0-2 + - libyaml-dev + - zlib1g + - zlib1g-dev + - libcap-ng-dev + - libcap-ng0 + - make + - libmagic-dev + - libnetfilter-queue-dev + - libnetfilter-queue1 + - libnfnetlink-dev + - libnfnetlink0 + - libhiredis-dev + - libjansson-dev + # Now define the default set of packages which is those above, and + # libjansson. + packages: &packages + - *packages-without-jansson + - libjansson-dev + +# Define the default CFLAGS used by all builds as a YAML anchor. +default-cflags: &default-cflags + CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" + +matrix: + include: + # Linux, gcc, coccinelle. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,cocci" + - *default-cflags + addons: + apt: + sources: + - sourceline: ppa:npalix/coccinelle + packages: + - *packages + - coccinelle + # Linux, gcc, -DNDEBUG. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,ndebug" + - *default-cflags + - EXTRA_CFLAGS="-DNDEBUG" + # Linux, clang. For this build we'll also enable -Wshadow. + - os: linux + compiler: clang + env: + - NAME="linux,clang" + - *default-cflags + - EXTRA_CFLAGS="-Wshadow" + # Linux, gcc, profiling. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,profiling" + - *default-cflags + - ARGS="--enable-profiling" + # Linux, gcc, debug. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,debug" + - *default-cflags + - ARGS="--enable-debug" + - ENABLE_DEBUG="yes" + # Linux, gcc, no jansson. + - os: linux + compiler: gcc + env: + - NAME="linux,gcc,no-json" + - *default-cflags + addons: + apt: + packages: + - *packages-without-jansson + # OSX 10.12, XCode 8.1 + - os: osx + compiler: gcc + osx_image: xcode8.1 + sudo: true + env: + - NAME="osx,gcc" + - *default-cflags + +script: + - sh ./autogen.sh + - | + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}" + ./configure --enable-nfqueue --enable-unittests --enable-hiredis ${ARGS} + fi + - | + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}" + ./configure --enable-unittests --enable-hiredis --enable-ipfw \ + --enable-lua --with-libpcre-includes=/usr/local/include \ + --with-libpcre-includes=/usr/local/include \ + --with-libpcre-libraries=/usr/local/lib \ + --with-libnss-includes=/usr/local/opt/nss/include/nss \ + --with-libnss-libraries=/usr/local/opt/nss/lib \ + --with-libnspr-includes=/usr/local/opt/nspr/include/nspr \ + --with-libnspr-libraries=/usr/local/opt/nspr/lib + fi + # With debug enabled too much output is generated for Travis, so + # redirect stderr to a file. + - | + # Linux container builds have 2 cores, make use of them. + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + j="-j 2" + fi + if [[ "$ENABLE_DEBUG" == "yes" ]]; then + make ${j} check 2> stderr.log + else + make ${j} check + fi + before_install: - - sudo add-apt-repository -y ppa:npalix/coccinelle - - sudo apt-get update -qq - - sudo apt-get install -y libpcre3 libpcre3-dbg libpcre3-dev build-essential autoconf automake libtool libpcap-dev libnet1-dev libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 make libmagic-dev libnetfilter-queue-dev libnetfilter-queue1 libnfnetlink-dev libnfnetlink0 coccinelle - - ./qa/travis-libhtp.sh + - | + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update + + # Unlink and install each dependency to avoid errors where a + # formula might already be installed but is not the current + # version. + packages="" + packages="$packages pkg-config" + packages="$packages libmagic" + packages="$packages libyaml" + packages="$packages nss" + packages="$packages nspr" + packages="$packages jansson" + packages="$packages libnet" + packages="$packages lua" + packages="$packages pcre" + packages="$packages hiredis" + for package in $packages; do + if brew ls $package --versions > /dev/null; then + brew unlink $package + fi + done + # Now install. + brew install $packages + + # Now relink, becuase if a newer version of a package wasn't + # installed above, it will remain unlinked. + brew link $packages + fi + - ./qa/travis-libhtp.sh diff --git a/COPYING b/COPYING index 5b6e7c66c276..d159169d1050 100644 --- a/COPYING +++ b/COPYING @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -303,10 +303,9 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + 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. Also add information on how to contact you by electronic and paper mail. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/ChangeLog b/ChangeLog index 8e3cb6766f34..9401b1579f4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,388 @@ +3.2.1 -- 2017-02-15 + +Feature #1951: Allow building without libmagic/file +Feature #1972: SURICATA ICMPv6 unknown type 143 for MLDv2 report +Feature #2010: Suricata should confirm SSSE3 presence at runtime when built with Hyperscan support +Bug #467: compilation with unittests & debug validation +Bug #1780: VLAN tags not forwarded in afpacket inline mode +Bug #1827: Mpm AC fails to alloc memory +Bug #1843: Mpm Ac: int overflow during init +Bug #1887: pcap-log sets snaplen to -1 +Bug #1946: can't get response info in some situation +Bug #1973: suricata fails to start because of unix socket +Bug #1975: hostbits/xbits memory leak +Bug #1982: tls: invalid record event triggers on valid traffic +Bug #1984: http: protocol detection issue if both sides are malformed +Bug #1985: pcap-log: minor memory leaks +Bug #1987: log-pcap: pcap files created with invalid snaplen +Bug #1988: tls_cert_subject bug +Bug #1989: SMTP protocol detection is case sensitive +Bug #1991: Suricata cannot parse ports: "![1234, 1235]" +Bug #1997: tls-store: bug that cause Suricata to crash +Bug #2001: Handling of unsolicited DNS responses. +Bug #2003: BUG_ON body sometimes contains side-effectual code +Bug #2004: Invalid file hash computation when force-hash is used +Bug #2005: Incoherent sizes between request, capture and http length +Bug #2007: smb: protocol detection just checks toserver +Bug #2008: Suricata 3.2, pcap-log no longer works due to timestamp_pattern PCRE +Bug #2009: Suricata is unable to get offloading settings when run under non-root +Bug #2012: dns.log does not log unanswered queries +Bug #2017: EVE Log Missing Fields +Bug #2019: IPv4 defrag evasion issue +Bug #2022: dns: out of bound memory read + +3.2 -- 2016-12-01 + +Bug #1117: PCAP file count does not persist +Bug #1577: luajit scripts load error +Bug #1924: Windows dynamic DNS updates trigger 'DNS malformed request data' alerts +Bug #1938: suricata: log handling issues +Bug #1955: luajit script init failed +Bug #1960: Error while parsing rule with PCRE keyword with semicolon +Bug #1961: No error on missing semicolon between depth and classtype +Bug #1965: dnp3/enip/cip keywords naming convention +Bug #1966: af-packet fanout detection broken on Debian Jessie (master) + +3.2RC1 -- 2016-11-01 + +Feature #1906: doc: install man page and ship pdf +Feature #1916: lua: add an SCPacketTimestamp function +Feature #1867: rule compatibility: flow:not_established not supported. +Bug #1525: Use pkg-config for libnetfilter_queue +Bug #1690: app-layer-proto negation issue +Bug #1909: libhtp 0.5.23 +Bug #1914: file log always shows stored: no even if file is stored +Bug #1917: nfq: bypass SEGV +Bug #1919: filemd5: md5-list does not allow comments any more +Bug #1923: dns - back to back requests results in loss of response +Bug #1928: flow bypass leads to memory errors +Bug #1931: multi-tenancy fails to start +Bug #1932: make install-full does not install tls-events.rules +Bug #1935: Check redis reply in non pipeline mode +Bug #1936: Can't set fast_pattern on tls_sni content + +3.2beta1 -- 2016-10-03 + +Feature #509: add SHA1 and SHA256 checksum support for files +Feature #1231: ssl_state negation support +Feature #1345: OOBE -3- disable NIC offloading by default +Feature #1373: Allow different reassembly depth for filestore rules +Feature #1495: EtherNet/IP and CIP support +Feature #1583: tls: validity fields (notBefore and notAfter) +Feature #1657: Per application layer stats +Feature #1896: Reimplement tls.subject and tls.isserdn +Feature #1903: tls: tls_cert_valid and tls_cert_expired keywords +Feature #1907: http_request_line and http_response_line +Optimization #1044: TLS buffers evaluated by fast_pattern matcher. +Optimization #1277: Trigger second live rule-reload while first one is in progress +Bug #312: incorrect parsing of rules with missing semi-colon for keywords +Bug #712: wildcard matches on tls.subject +Bug #1353: unix-command socket created with last character missing +Bug #1486: invalid rule: parser err msg not descriptive enough +Bug #1525: Use pkg-config for libnetfilter_queue +Bug #1893: tls: src_ip and dest_ip reversed in TLS events for IPS vs IDS mode. +Bug #1898: Inspection does not always stop when stream depth is reached + +3.1.2 -- 2016-09-06 + +Feature #1830: support 'tag' in eve log +Feature #1870: make logged flow_id more unique +Feature #1874: support Cisco Fabric Path / DCE +Feature #1885: eve: add option to log all dropped packets +Bug #1849: ICMPv6 incorrect checksum alert if Ethernet FCS is present +Bug #1853: suricata is matching everything on dce_stub_data buffer +Bug #1854: unified2: logging of tagged packets not working +Bug #1856: PCAP mode device not found +Bug #1858: Lots of TCP 'duplicated option/DNS malformed request data' after upgrading from 3.0.1 to 3.1.1 +Bug #1878: dns: crash while logging sshfp records +Bug #1880: icmpv4 error packets can lead to missed detection in tcp/udp +Bug #1884: libhtp 0.5.22 + +3.1.1 -- 2016-07-13 + +Feature #1775: Lua: SMTP-support +Bug #1419: DNS transaction handling issues +Bug #1515: Problem with Threshold.config when using more than one IP +Bug #1664: Unreplied DNS queries not logged when flow is aged out +Bug #1808: Can't set thread priority after dropping privileges. +Bug #1821: Suricata 3.1 fails to start on CentOS6 +Bug #1839: suricata 3.1 configure.ac says >=libhtp-0.5.5, but >=libhtp-0.5.20 required +Bug #1840: --list-keywords and --list-app-layer-protos not working +Bug #1841: libhtp 0.5.21 +Bug #1844: netmap: IPS mode doesn't set 2nd iface in promisc mode +Bug #1845: Crash on disabling a app-layer protocol when it's logger is still enabled +Optimization #1846: af-packet: improve thread calculation logic +Optimization #1847: rules: don't warn on empty files + +3.1 -- 2016-06-20 + +Bug #1589: Cannot run nfq in workers mode +Bug #1804: yaml: legacy detect-engine parsing custom values broken + +3.1RC1 -- 2016-06-07 + +Feature #681: Implement TPACKET_V3 support in AF_PACKET +Feature #1134: tls: server name rule keyword +Feature #1343: OOBE -1- increasing the default stream.memcap and stream.reassembly.memcap values +Feature #1344: OOBE -2- decreasing the default flow-timeouts (at least for TCP) +Feature #1563: dns: log sshfp records +Feature #1760: Unit tests: Don't register return value, use 1 for success, 0 for failure. +Feature #1761: Unit tests: Provide macros for clean test failures. +Feature #1762: default to AF_PACKET for -i if available +Feature #1785: hyperscan spm integration +Feature #1789: hyperscan mpm: enable by default +Feature #1797: netmap: implement 'threads: auto' +Feature #1798: netmap: warn about NIC offloading on FreeBSD +Feature #1800: update bundled libhtp to 0.5.20 +Feature #1801: reduce info level verbosity +Feature #1802: yaml: improve default layout +Feature #1803: reimplement rule grouping +Bug #1078: 'Not" operator (!) in Variable causes extremely slow loading of Suricata +Bug #1202: detect-engine profile medium consumes more memory than detect-engine profile high +Bug #1289: MPM b2gm matcher has questionable code +Bug #1487: Configuration parser depends on key ordering +Bug #1524: Potential Thread Name issues due to RHEL7 Interface Naming Contentions +Bug #1584: Rule keywords conflict will cause Suricata restart itself in loop +Bug #1606: [ERRCODE: SC_ERR_SYSCALL(50)] - Failure when trying to get MTU via ioctl: 6 +Bug #1665: Default maximum packet size is insufficient when VLAN tags are present (and not stripped) +Bug #1714: Kernel panic on application exit with netmap Suricata 3.0 stable +Bug #1746: deadlock with autofp and --disable-detection +Bug #1764: app-layer-modbus: AddressSanitizer error (segmentation fault) +Bug #1768: packet processing threads doubled +Bug #1771: tls store memory leak +Bug #1773: smtp: not all attachments inspected in all cases +Bug #1786: spm crash on rule reload +Bug #1792: dns-json-log produces no output +Bug #1795: Remove unused CPU affinity settings from suricata.yaml +Optimization #563: pmq optimization -- remove patter_id_array +Optimization #1037: Optimize TCP Option storage +Optimization #1418: lockless flow handling during capture (autofp) +Optimization #1784: reduce storage size of IPv4 options and IPv6 ext hdrs + +3.0.1 -- 2016-04-04 + +Feature #1704: hyperscan mpm integration +Feature #1661: Improved support for xbits/hostbits (in particular ip_pair) when running with multiple threads +Bug #1697: byte_extract incompatibility with Snort. +Bug #1737: Stats not reset between PCAPs when Suricata runs in socket mode + +3.0.1RC1 -- 2016-03-23 + +Feature #1535: Expose the certificate itself in TLS-lua +Feature #1696: improve logged flow_id +Feature #1700: enable "relro" and "now" in compile options for 3.0 +Feature #1734: gre: support transparent ethernet bridge decoding +Feature #1740: Create counters for decode-events errors +Bug #873: suricata.yaml: .mgc is NOT actually added to value for magic file +Bug #1166: tls: CID 1197759: Resource leak (RESOURCE_LEAK) +Bug #1268: suricata and macos/darwin: [ERRCODE: SC_ERR_MAGIC_LOAD(197)] - magic_load failed: File 5.19 supports only version 12 magic files. `/usr/share/file/magic.mgc' is version 7 +Bug #1359: memory leak +Bug #1411: Suricata generates huge load when nfq_create_queue failed +Bug #1570: stream.inline defaults to IDS mode if missing +Bug #1591: afpacket: unsupported datalink type 65534 on tun device +Bug #1619: Per-Thread Delta Stats Broken +Bug #1638: rule parsing issues: rev +Bug #1641: Suricata won't build with --disable-unix-socket when libjansson is enabled +Bug #1646: smtp: fix inspected tracker values +Bug #1660: segv when using --set on a list +Bug #1669: Suricate 3.0RC3 segfault after 10 hours +Bug #1670: Modbus compiler warnings on Fedora 23 +Bug #1671: Cygwin Windows compilation with libjansson from source +Bug #1674: Cannot use 'tag:session' after base64_data keyword +Bug #1676: gentoo build error +Bug #1679: sensor-name configuration parameter specified in wrong place in default suricata.yaml +Bug #1680: Output sensor name in json +Bug #1684: eve: stream payload has wrong direction in IPS mode +Bug #1686: Conflicting "no" for "totals" and "threads" in stats output +Bug #1689: Stack overflow in case of variables misconfiguration +Bug #1693: Crash on Debian with libpcre 8.35 +Bug #1695: Unix Socket missing dump-counters mode +Bug #1698: Segmentation Fault at detect-engine-content-inspection.c:438 (master) +Bug #1699: CUDA build broken +Bug #1701: memory leaks +Bug #1702: TLS SNI parsing issue +Bug #1703: extreme slow down in HTTP multipart parsing +Bug #1706: smtp memory leaks +Bug #1707: malformed json if message is too big +Bug #1708: dcerpc memory leak +Bug #1709: http memory leak +Bug #1715: nfq: broken time stamps with recent Linux kernel 4.4 +Bug #1717: Memory leak on Suricata 3.0 with Netmap +Bug #1719: fileinfo output wrong in eve in http +Bug #1720: flowbit memleak +Bug #1724: alert-debuglog: non-decoder events won't trigger rotation. +Bug #1725: smtp logging memleak +Bug #1727: unix socket runmode per pcap memory leak +Bug #1728: unix manager command channel memory leaks +Bug #1729: PCRE jit is disabled/blacklisted when it should not +Bug #1731: detect-tls memory leak +Bug #1735: cppcheck: Shifting a negative value is undefined behaviour +Bug #1736: tls-sni: memory leaks on malformed traffic +Bug #1742: vlan use-for-tracking including Priority in hashing +Bug #1743: compilation with musl c library fails +Bug #1744: tls: out of bounds memory read on malformed traffic +Optimization #1642: Add --disable-python option + +3.0 -- 2016-01-27 + +Bug #1673: smtp: crash during mime parsing + +3.0RC3 -- 2015-12-21 + +Bug #1632: Fail to download large file with browser +Bug #1634: Fix non thread safeness of Prelude analyzer +Bug #1640: drop log crashes +Bug #1645: Race condition in unix manager +Bug #1647: FlowGetKey flow-hash.c:240 segmentation fault (master) +Bug #1650: DER parsing issue (master) + +3.0RC2 -- 2015-12-08 + +Bug #1551: --enable-profiling-locks broken +Bug #1602: eve-log prefix field feature broken +Bug #1614: app_proto key missing from EVE file events +Bug #1615: disable modbus by default +Bug #1616: TCP reassembly bug +Bug #1617: DNS over TCP parsing issue +Bug #1618: SMTP parsing issue +Feature #1635: unified2 output: disable by default + +3.0RC1 -- 2015-11-25 + +Bug #1150: TLS store disabled by TLS EVE logging +Bug #1210: global counters in stats.log +Bug #1423: Unix domain log file writer should automatically reconnect if receiving program is restarted. +Bug #1466: Rule reload - Rules won't reload if rule files are listed in an included file. +Bug #1467: Specifying an IPv6 entry before an IPv4 entry in host-os-policy causes ASAN heap-buffer-overflow. +Bug #1472: Should 'goodsigs' be 'goodtotal' when checking if signatures were loaded in detect.c? +Bug #1475: app-layer-modbus: AddressSanitizer error (heap-buffer-overflow) +Bug #1481: Leading whitespace in flowbits variable names +Bug #1482: suricata 2.1 beta4: StoreStateTxFileOnly crashes +Bug #1485: hostbits - leading and trailing spaces are treated as part of the name and direction. +Bug #1488: stream_size <= and >= modifiers function as < and > (equality is not functional) +Bug #1491: pf_ring is not able to capture packets when running under non-root account +Bug #1493: config test (-T) doesn't fail on missing files +Bug #1494: off by one on rulefile count +Bug #1500: suricata.log +Bug #1508: address var parsing issue +Bug #1517: Order dependent, ambiguous YAML in multi-detect. +Bug #1518: multitenancy - selector vlan - vlan id range +Bug #1521: multitenancy - global vlan tracking relation to selector +Bug #1523: Decoded base64 payload short by 16 characters +Bug #1530: multitenant mapping relation +Bug #1531: multitenancy - confusing tenant id and vlan id output +Bug #1556: MTU setting on NIC interface not considered by af-packet +Bug #1557: stream: retransmission not detected +Bug #1565: defrag: evasion issue +Bug #1597: dns parser issue (master) +Bug #1601: tls: server name logging +Feature #1116: ips packet stats in stats.log +Feature #1137: Support IP lists in threshold.config +Feature #1228: Suricata stats.log in JSON format +Feature #1265: Replace response on Suricata dns decoder when dns error please +Feature #1281: long snort ruleset support for "SC_ERR_NOT_SUPPORTED(225): content length greater than 255 unsupported" +Feature #1282: support for base64_decode from snort's ruleset +Feature #1342: Support Cisco erspan traffic +Feature #1374: Write pre-aggregated counters for all threads +Feature #1408: multi tenancy for detection +Feature #1440: Load rules file from a folder or with a star pattern rather then adding them manually to suricata.yaml +Feature #1454: Proposal to add Lumberjack/CEE formatting option to EVE JSON syslog output for compatibility with rsyslog parsing +Feature #1492: Add HUP coverage to output json-log +Feature #1498: color output +Feature #1499: json output for engine messages +Feature #1502: Expose tls fields to lua +Feature #1514: SSH softwareversion regex should allow colon +Feature #1527: Add ability to compile as a Position-Independent Executable (PIE) +Feature #1568: TLS lua output support +Feature #1569: SSH lua support +Feature #1582: Redis output support +Feature #1586: Add flow memcap counter +Feature #1599: rule profiling: json output +Optimization #1269: Convert SM List from linked list to array + +2.1beta4 -- 2015-05-08 + +Bug #1314: http-events performance issues +Bug #1340: null ptr dereference in Suricata v2.1beta2 (output-json.c:347) +Bug #1352: file list is not cleaned up +Bug #1358: Gradual memory leak using reload (kill -USR2 $pid) +Bug #1366: Crash if default_packet_size is below 32 bytes +Bug #1378: stats api doesn't call thread deinit funcs +Bug #1384: tcp midstream window issue (master) +Bug #1388: pcap-file hangs on systems w/o atomics support (master) +Bug #1392: http uri parsing issue (master) +Bug #1393: CentOS 5.11 build failures +Bug #1398: DCERPC traffic parsing issue (master) +Bug #1401: inverted matching on incomplete session +Bug #1402: When re-opening files on HUP (rotation) always use the append flag. +Bug #1417: no rules loaded - latest git - rev e250040 +Bug #1425: dead lock in de_state vs flowints/flowvars +Bug #1426: Files prematurely truncated by detection engine even though force-md5 is enabled +Bug #1429: stream: last_ack update issue leading to stream gaps +Bug #1435: EVE-Log alert payload option loses data +Bug #1441: Local timestamps in json events +Bug #1446: Unit ID check in Modbus packet error +Bug #1449: smtp parsing issue +Bug #1451: Fix list-keywords regressions +Bug #1463: modbus parsing issue +Feature #336: Add support for NETMAP to Suricata. +Feature #885: smtp file_data support +Feature #1394: Improve TCP reuse support +Feature #1410: add alerts to EVE's drop logs +Feature #1445: Suricata does not work on pfSense/FreeBSD interfaces using PPPoE +Feature #1447: Ability to reject ICMP traffic +Feature #1448: xbits +Optimization #1014: app layer reassembly fast-path +Optimization #1377: flow manager: reduce (try)locking +Optimization #1403: autofp packet pool performance problems +Optimization #1409: http pipeline support for stateful detection + +2.1beta3 -- 2015-01-29 + +Bug #977: WARNING on empty rules file is fatal (should not be) +Bug #1184: pfring: cppcheck warnings +Bug #1321: Flow memuse bookkeeping error +Bug #1327: pcre pkt/flowvar capture broken for non-relative matches (master) +Bug #1332: cppcheck: ioctl +Bug #1336: modbus: CID 1257762: Logically dead code (DEADCODE) +Bug #1351: output-json: duplicate logging (2.1.x) +Bug #1354: coredumps on quitting on OpenBSD +Bug #1355: Bus error when reading pcap-file on OpenBSD +Bug #1363: Suricata does not compile on OS X/Clang due to redefinition of string functions (2.1.x) +Bug #1365: evasion issues (2.1.x) +Feature #1261: Request for Additional Lua Capabilities +Feature #1309: Lua support for Stats output +Feature #1310: Modbus parsing and matching +Feature #1317: Lua: Indicator for end of flow +Feature #1333: unix-socket: allow (easier) non-root usage +Optimization #1339: flow timeout optimization +Optimization #1339: flow timeout optimization +Optimization #1371: mpm optimization + +2.1beta2 -- 2014-11-06 + +Feature #549: Extract file attachments from emails +Feature #1312: Lua output support +Feature #899: MPLS over Ethernet support +Feature #707: ip reputation files - network range inclusion availability (cidr) +Feature #383: Stream logging +Feature #1263: Lua: Access to Stream Payloads +Feature #1264: Lua: access to TCP quad / Flow Tuple +Bug #1048: PF_RING/DNA config - suricata.yaml +Bug #1230: byte_extract, within combination not working +Bug #1257: Flow switch is missing from the eve-log section in suricata.yaml +Bug #1259: AF_PACKET IPS is broken in 2.1beta1 +Bug #1260: flow logging at shutdown broken +Bug #1279: BUG: NULL pointer dereference when suricata was debug mode. +Bug #1280: BUG: IPv6 address vars issue +Bug #1285: Lua - http.request_line not working (2.1) +Bug #1287: Lua Output has dependency on eve-log:http +Bug #1288: Filestore keyword in wrong place will cause entire rule not to trigger +Bug #1294: Configure doesn't use --with-libpcap-libraries when testing PF_RING library +Bug #1301: suricata yaml - PF_RING load balance per hash option +Bug #1308: http_header keyword not matching when SYN|ACK and ACK missing (master) +Bug #1311: EVE output Unix domain socket not working (2.1) + 2.1beta1 -- 2014-08-12 Feature #1155: Log packet payloads in eve alerts diff --git a/LICENSE b/LICENSE index d511905c1647..d159169d1050 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - GNU GENERAL PUBLIC LICENSE + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS - How to Apply These Terms to Your New Programs + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it diff --git a/Makefile.am b/Makefile.am index 5e534ee07bc7..d33150fff3b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,40 +12,47 @@ CLEANFILES = stamp-h[0-9]* install-data-am: @echo "Run 'make install-conf' if you want to install initial configuration files. Or 'make install-full' to install configuration and rules"; -install-full: install install-conf install-rules +install-full: + $(MAKE) install + $(MAKE) install-conf + $(MAKE) install-rules install-conf: - install -d "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/suricata.yaml" || install -m 600 "$(top_srcdir)/suricata.yaml" "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/classification.config" || install -m 600 "$(top_srcdir)/classification.config" "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/reference.config" || install -m 600 "$(top_srcdir)/reference.config" "$(e_sysconfdir)" - @test -e "$(e_sysconfdir)/threshold.config" || install -m 600 "$(top_srcdir)/threshold.config" "$(e_sysconfdir)" - install -d "$(e_logfilesdir)" - install -d "$(e_logcertsdir)" - install -d "$(e_rundir)" - install -m 770 -d "$(e_localstatedir)" + install -d "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/suricata.yaml" || install -m 600 "$(top_srcdir)/suricata.yaml" "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/classification.config" || install -m 600 "$(top_srcdir)/classification.config" "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/reference.config" || install -m 600 "$(top_srcdir)/reference.config" "$(DESTDIR)$(e_sysconfdir)" + @test -e "$(DESTDIR)$(e_sysconfdir)/threshold.config" || install -m 600 "$(top_srcdir)/threshold.config" "$(DESTDIR)$(e_sysconfdir)" + install -d "$(DESTDIR)$(e_logfilesdir)" + install -d "$(DESTDIR)$(e_logcertsdir)" + install -d "$(DESTDIR)$(e_rundir)" + install -m 770 -d "$(DESTDIR)$(e_localstatedir)" install-rules: - install -d "$(e_sysconfrulesdir)" + install -d "$(DESTDIR)$(e_sysconfrulesdir)" if HAVE_FETCH_COMMAND if HAVE_WGET_COMMAND - $(HAVE_WGET) -qO - http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(e_sysconfdir)" -f - + $(HAVE_WGET) -qO - https://rules.emergingthreats.net/open/suricata-3.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - else - $(HAVE_CURL) -s http://rules.emergingthreats.net/open/suricata-2.0/emerging.rules.tar.gz | tar -x -z -C "$(e_sysconfdir)" -f - + $(HAVE_CURL) -s https://rules.emergingthreats.net/open/suricata-3.0/emerging.rules.tar.gz | tar -x -z -C "$(DESTDIR)$(e_sysconfdir)" -f - endif else @echo "UNABLE to load ruleset wget or curl are not installed on system." endif - @test -e "$(e_sysconfrulesdir)decoder-events.rules" || install -m 600 "$(top_srcdir)/rules/decoder-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)stream-events.rules" || install -m 600 "$(top_srcdir)/rules/stream-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(e_sysconfrulesdir)" - @test -e "$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)decoder-events.rules" || install -m 600 "$(top_srcdir)/rules/decoder-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)stream-events.rules" || install -m 600 "$(top_srcdir)/rules/stream-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)smtp-events.rules" || install -m 600 "$(top_srcdir)/rules/smtp-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)http-events.rules" || install -m 600 "$(top_srcdir)/rules/http-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)dns-events.rules" || install -m 600 "$(top_srcdir)/rules/dns-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)tls-events.rules" || install -m 600 "$(top_srcdir)/rules/tls-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)modbus-events.rules" || install -m 600 "$(top_srcdir)/rules/modbus-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)app-layer-events.rules" || install -m 600 "$(top_srcdir)/rules/app-layer-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" + @test -e "$(DESTDIR)$(e_sysconfrulesdir)dnp3-events.rules" || install -m 600 "$(top_srcdir)/rules/dnp3-events.rules" "$(DESTDIR)$(e_sysconfrulesdir)" @echo "" - @echo "You can now start suricata by running as root something like '$(bindir)/suricata -c $(e_sysconfdir)/suricata.yaml -i eth0'." + @echo "You can now start suricata by running as root something like '$(DESTDIR)$(bindir)/suricata -c $(DESTDIR)$(e_sysconfdir)/suricata.yaml -i eth0'." @echo "" @echo "If a library like libhtp.so is not found, you can run suricata with:" - @echo "'LD_LIBRARY_PATH="$(prefix)/lib" "$(bindir)/suricata" -c "$(e_sysconfdir)/suricata.yaml" -i eth0'." + @echo "'LD_LIBRARY_PATH="$(DESTDIR)$(prefix)/lib" "$(DESTDIR)$(bindir)/suricata" -c "$(DESTDIR)$(e_sysconfdir)/suricata.yaml" -i eth0'." @echo "" @echo "While rules are installed now, it's highly recommended to use a rule manager for maintaining rules." @echo "The two most common are Oinkmaster and Pulledpork. For a guide see:" diff --git a/README.md b/README.md new file mode 100644 index 000000000000..9fc5d03a2256 --- /dev/null +++ b/README.md @@ -0,0 +1,114 @@ +Suricata +======== + +Introduction +------------ + +Suricata is a network IDS, IPS and NSM engine. + + +Installation +------------ + +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Installation + +User Guide +---------- + +You can follow the [Suricata user guide](http://suricata.readthedocs.io/en/latest/) to get started. + +Our deprecated (but still useful) user guide is also [available](https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_User_Guide). + + +Contributing +------------ + +We're happily taking patches and other contributions. Please see https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Contributing for how to get started. + +Suricata is a complex piece of software dealing with mostly untrusted input. Mishandling this input will have serious consequences: + +* in IPS mode a crash may knock a network offline; +* in passive mode a compromise of the IDS may lead to loss of critical and confidential data; +* missed detection may lead to undetected compromise of the network. + +In other words, we think the stakes are pretty high, especially since in many common cases the IDS/IPS will be directly reachable by an attacker. + +For this reason, we have developed a QA process that is quite extensive. A consequence is that contributing to Suricata can be a somewhat lengthy process. + +On a high level, the steps are: + +1. Travis-CI based build & unit testing. This runs automatically when a pull request is made. + +2. Review by devs from the team and community + +3. QA runs + + + +### Overview of Suricata's QA steps + +Trusted devs and core team members are able to submit builds to our (semi) public Buildbot instance. It will run a series of build tests and a regression suite to confirm no existing features break. + +The final QA run takes a few hours minimally, and is started by Victor. It currently runs: + +- extensive build tests on different OS', compilers, optimization levels, configure features +- static code analysis using cppcheck, scan-build +- runtime code analysis using valgrind, DrMemory, AddressSanitizer, LeakSanitizer +- regression tests for past bugs +- output validation of logging +- unix socket testing +- pcap based fuzz testing using ASAN and LSAN + +Next to these tests, based on the type of code change further tests can be run manually: + +- traffic replay testing (multi-gigabit) +- large pcap collection processing (multi-terabytes) +- AFL based fuzz testing (might take multiple days or even weeks) +- pcap based performance testing +- live performance testing +- various other manual tests based on evaluation of the proposed changes + + +It's important to realize that almost all of the tests above are used as acceptance tests. If something fails, it's up to you to address this in your code. + + +One step of the QA is currently run post-merge. We submit builds to the Coverity Scan program. Due to limitations of this (free) service, we can submit once a day max. +Of course it can happen that after the merge the community will find issues. For both cases we request you to help address the issues as they may come up. + + + + +### FAQ + +__Q: Will you accept my PR?__ + +A: That depends on a number of things, including the code quality. With new features it also depends on whether the team and/or the community think the feature is useful, how much it affects other code and features, the risk of performance regressions, etc. + + +__Q: When will my PR be merged?__ + +A: It depends, if it's a major feature or considered a high risk change, it will probably go into the next major version. + + +__Q: Why was my PR closed?__ + +A: As documented in the Suricata Github workflow here https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Github_work_flow, we expect a new pull request for every change. + +Normally, the team (or community) will give feedback on a pull request after which it is expected to be replaced by an improved PR. So look at the comments. If you disagree with the comments we can still discuss them in the closed PR. + +If the PR was closed without comments it's likely due to QA failure. If the Travis-CI check failed, the PR should be fixed right away. No need for a discussion about it, unless you believe the QA failure is incorrect. + + +__Q: the compiler/code analyser/tool is wrong, what now?__ + +A: to assist in the automation of the QA, we're not accepting warnings or errors to stay. In some cases this could mean that we add a suppression if the tool supports that (e.g. valgrind, DrMemory). Some warnings can be disabled. In some exceptional cases the only 'solution' is to refactor the code to work around a static code checker limitation false positive. While frusterating, we prefer this over leaving warnings in the output. Warnings tend to get ignored and then increase risk of hiding other warnings. + + +__Q: I think your QA test is wrong__ + +A: If you really think it is, we can discuss how to improve it. But don't come to this conclusion to quickly, moreoften it's the code that turns out to be wrong. + + +__Q: do you require signing of a contributor license agreement?__ + +A: Yes, we do this to keep the ownership of Suricata in one hand: the Open Information Security Foundation. See http://suricata-ids.org/about/open-source/ and http://suricata-ids.org/about/contribution-agreement/ diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000000..3419d1c98e09 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,61 @@ +# Based on https://github.com/redis/hiredis/blob/master/appveyor.yml +# and https://github.com/dokan-dev/dokany/pull/336/files +# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) +environment: + matrix: +# - CYG_ROOT: C:\cygwin64 +# CYG_SETUP: setup-x86_64.exe +# CYG_MIRROR: http://cygwin.mirror.constant.com +# CYG_CACHE: C:\cygwin64\var\cache\setup +# CYG_BASH: C:\cygwin64\bin\bash +# CC: gcc + - CYG_ROOT: C:\cygwin + CYG_SETUP: setup-x86.exe + CYG_MIRROR: http://cygwin.mirror.constant.com + CYG_CACHE: C:\cygwin\var\cache\setup + CYG_BASH: C:\cygwin\bin\bash + CC: gcc + CFLAGS: -Wall -Wextra -Werror -Wshadow -Wno-unused-parameter -Wno-unused-function + +# Cache Cygwin files to speed up build +cache: + - '%CYG_CACHE%' +clone_depth: 1 + +# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail +init: + - git config --global core.autocrlf input +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + +# Install needed build dependencies. First update cygwin to avoid weird dll issues. +install: + - ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"' + - '%CYG_SETUP% -gqnNdO --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" > NUL 2>&1' + - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm,libpcre-devel,file-devel,wget,zlib-devel,libnss-devel,libnspr-devel,libGeoIP-devel,libyaml-devel,luajit-devel,unzip,libiconv,libiconv-devel > NUL 2>&1' + - '%CYG_BASH% -lc "cygcheck -dc cygwin"' + - '%CYG_BASH% -lc "wget https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip && ls && unzip WpdPack_4_1_2.zip"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/libpacket.a /usr/lib/"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/libwpcap.a /usr/lib/libpcap.a"' # so -lpcap works +# - '%CYG_BASH% -lc "cp WpdPack/Lib/libwpcap.a /usr/lib/libwpcap.a"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/Packet.lib /usr/lib/"' + - '%CYG_BASH% -lc "cp WpdPack/Lib/wpcap.lib /usr/lib/"' + - '%CYG_BASH% -lc "mkdir -p /usr/include/pcap"' + - '%CYG_BASH% -lc "cp -r WpdPack/Include/* /usr/include/"' + - choco install winpcap # userspace + +build_script: + - 'echo building...' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; bash ./qa/travis-libhtp.sh"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; ./configure --enable-unittests --disable-shared --disable-gccmarch-native --enable-luajit --enable-geoip"' + - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0], + PKG_PROG_PKG_CONFIG(0.21) # 0.21 is the CentOS 5.11 version + + dnl Taken from https://llvm.org/svn/llvm-project/llvm/trunk/autoconf/configure.ac + dnl check if we compile using clang or gcc. On some systems the gcc binary is + dnl is actually clang, so do a compile test. + AC_MSG_CHECKING([whether GCC or Clang is our compiler]) + AC_LANG_PUSH([C]) + compiler=unknown + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if ! __clang__ + #error + #endif + ]])], + compiler=clang, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if ! __GNUC__ + #error + #endif + ]])], + compiler=gcc, [])]) + AC_LANG_POP([C]) + AC_MSG_RESULT([${compiler}]) + + case "$compiler" in + clang) + CLANG_CFLAGS="-Wextra -Werror-implicit-function-declaration -Wno-error=unused-command-line-argument" + AC_MSG_CHECKING([clang __sync_bool_compare_and_swap support]) + AC_TRY_COMPILE([#include ], [ unsigned int i = 0; (void)__sync_bool_compare_and_swap(&i, 1, 1);], [ AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1], [1], [Fake GCC atomic support]) @@ -50,29 +43,32 @@ AC_DEFINE([__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8], [1], [Fake GCC atomic support]) AC_MSG_RESULT([yes]) ], [AC_MSG_RESULT([no])]) - fi - if test `basename $CC` = "gcc"; then - dnl get gcc version - AC_MSG_CHECKING([gcc version]) - gccver=$($CC -dumpversion) - gccvermajor=$(echo $gccver | cut -d . -f1) - gccverminor=$(echo $gccver | cut -d . -f2) - gccvernum=$(expr $gccvermajor "*" 100 + $gccverminor) - AC_MSG_RESULT($gccver) - - if test "$gccvernum" -ge "400"; then + AC_SUBST(CLANG_CFLAGS) + ;; + gcc) + dnl get gcc version + AC_MSG_CHECKING([gcc version]) + gccver=$($CC -dumpversion) + gccvermajor=$(echo $gccver | cut -d . -f1) + gccverminor=$(echo $gccver | cut -d . -f2) + gccvernum=$(expr $gccvermajor "*" 100 + $gccverminor) + AC_MSG_RESULT($gccver) + + if test "$gccvernum" -ge "400"; then dnl gcc 4.0 or later - CFLAGS="$CFLAGS -Wextra -Werror-implicit-function-declaration" + GCC_CFLAGS="-Wextra -Werror-implicit-function-declaration" # remove optimization options that break our code # VJ 2010/06/27: no-tree-pre added. It breaks ringbuffers code. - CFLAGS="$CFLAGS -fno-tree-pre" - else - CFLAGS="$CFLAGS -W" - fi - fi - CFLAGS="$CFLAGS -Wall" - CFLAGS="$CFLAGS -Wno-unused-parameter" - CFLAGS="$CFLAGS -std=gnu99" + GCC_CFLAGS="$GCC_CFLAGS -fno-tree-pre" + else + GCC_CFLAGS="-W" + fi + AC_SUBST(GCC_CFLAGS) + ;; + *) + AC_MSG_WARN([unsupported/untested compiler, this may or may not work]) + ;; + esac # Checks for programs. AC_PROG_AWK @@ -92,17 +88,24 @@ exit 1 fi + AC_ARG_ENABLE(python, + AS_HELP_STRING([--enable-python], [Enable python]),,[enable_python=yes]) AC_PATH_PROG(HAVE_PYTHON_CONFIG, python, "no") + if test "x$enable_python" = "xno" ; then + echo + echo " Warning! python disabled, you will not be " + echo " able to install suricatasc unix socket client " + echo + enable_python="no" + fi if test "$HAVE_PYTHON_CONFIG" = "no"; then echo echo " Warning! python not found, you will not be " - echo " able to install surictasc unix socket client " + echo " able to install suricatasc unix socket client " echo enable_python="no" - else - enable_python="yes" fi - AM_CONDITIONAL([HAVE_PYTHON], [test "$HAVE_PYTHON_CONFIG" != "no"]) + AM_CONDITIONAL([HAVE_PYTHON], [test "x$enable_python" = "xyes"]) AC_PATH_PROG(HAVE_WGET, wget, "no") if test "$HAVE_WGET" = "no"; then @@ -119,14 +122,18 @@ # Checks for libraries. # Checks for header files. + AC_CHECK_HEADERS([stddef.h]) AC_CHECK_HEADERS([arpa/inet.h assert.h ctype.h errno.h fcntl.h inttypes.h]) AC_CHECK_HEADERS([getopt.h]) AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h poll.h sched.h signal.h]) - AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h string.h sys/ioctl.h]) + AC_CHECK_HEADERS([stdarg.h stdint.h stdio.h stdlib.h stdbool.h string.h strings.h sys/ioctl.h]) AC_CHECK_HEADERS([syslog.h sys/prctl.h sys/socket.h sys/stat.h sys/syscall.h]) AC_CHECK_HEADERS([sys/time.h time.h unistd.h]) AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) AC_CHECK_HEADERS([linux/ethtool.h linux/sockios.h]) + AC_CHECK_HEADER(glob.h,,[AC_ERROR(glob.h not found ...)]) + AC_CHECK_HEADERS([dirent.h fnmatch.h]) + AC_CHECK_HEADERS([sys/resource.h]) AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [], [[#ifdef HAVE_SYS_SOCKET_H @@ -165,6 +172,11 @@ AC_FUNC_REALLOC AC_CHECK_FUNCS([gettimeofday memset strcasecmp strchr strdup strerror strncasecmp strtol strtoul memchr memrchr]) + OCFLAGS=$CFLAGS + CFLAGS="" + AC_CHECK_FUNCS([strlcpy strlcat]) + CFLAGS=$OCFLAGS + # Add large file support AC_SYS_LARGEFILE @@ -181,7 +193,8 @@ fi echo -n "installation for $host OS... " - e_magic_file="/usr/share/file/magic" + e_magic_file="" + e_magic_file_comment="#" case "$host" in *-*-*freebsd*) LUA_PC_NAME="lua-5.1" @@ -189,14 +202,12 @@ CFLAGS="${CFLAGS} -DOS_FREEBSD" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet11" LDFLAGS="${LDFLAGS} -L/usr/local/lib -L/usr/local/lib/libnet11" - e_magic_file="/usr/share/misc/magic" ;; *-*-openbsd*) LUA_PC_NAME="lua51" CFLAGS="${CFLAGS} -D__OpenBSD__" CPPFLAGS="${CPPFLAGS} -I/usr/local/include -I/usr/local/include/libnet-1.1" LDFLAGS="${LDFLAGS} -L/usr/local/lib -I/usr/local/lib/libnet-1.1" - e_magic_file="/usr/local/share/misc/magic.mgc" ;; *darwin*|*Darwin*) LUA_PC_NAME="lua-5.1" @@ -218,19 +229,52 @@ LUA_LIB_NAME="lua" WINDOWS_PATH="yes" ;; + *-*-solaris*) + AC_MSG_WARN([support for Solaris/Illumos/SunOS is experimental]) + LDFLAGS="${LDFLAGS} -lsocket -lnsl" + ;; *) AC_MSG_WARN([unsupported OS this may or may not work]) ;; esac AC_MSG_RESULT(ok) - # check if our target supports thread local storage - AC_MSG_CHECKING(for thread local storage __thread support) - AC_TRY_COMPILE([#include ], - [ static __thread int i; i = 1; i++; ], - [AC_DEFINE([TLS], [1], [Thread local storage]) - AC_MSG_RESULT([yes]) ], - [AC_MSG_RESULT([no])]) + # enable modifications for AFL fuzzing + AC_ARG_ENABLE(afl, + AS_HELP_STRING([--enable-afl], Enable AFL fuzzing logic[])], [enable_afl="$enableval"],[enable_afl=no]) + + AS_IF([test "x$enable_afl" = "xyes"], [ + AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions]) + AC_DEFINE([AFLFUZZ_DISABLE_MGTTHREADS], [1], [Disable all management threads]) + AC_DEFINE([AFLFUZZ_PCAP_RUNMODE], [1], [Enable special AFL 'single' runmode]) + AC_DEFINE([AFLFUZZ_CONF_TEST], [1], [Enable special --afl-parse-rules commandline option]) + AC_DEFINE([AFLFUZZ_APPLAYER], [1], [Enable --afl-$proto-request commandline option]) + AC_DEFINE([AFLFUZZ_MIME], [1], [Enable --afl-mime commandline option]) + AC_DEFINE([AFLFUZZ_DECODER], [1], [Enable --afl-decoder-$proto commandline option]) + AC_DEFINE([AFLFUZZ_DER], [1], [Enable --afl-der commandline option]) + AC_DEFINE([AFLFUZZ_RULES], [1], [Enable --afl-rules commandline option]) + + # test for AFL PERSISTANT_MODE support + CFLAGS_ORIG=$CFLAGS + CFLAGS="-Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[while (__AFL_LOOP(1000))]])], + [AC_DEFINE([AFLFUZZ_PERSISTANT_MODE], [1], [Enable AFL PERSISTANT_MODE])], + []) + CFLAGS=$CFLAGS_ORIG + ]) + + # disable TLS on user request + AC_ARG_ENABLE(threading-tls, + AS_HELP_STRING([--disable-threading-tls], [Disable TLS (thread local storage)]), [enable_tls="$enableval"],[enable_tls=yes]) + AS_IF([test "x$enable_tls" = "xyes"], [ + # check if our target supports thread local storage + AC_MSG_CHECKING(for thread local storage __thread support) + AC_TRY_COMPILE([#include ], + [ static __thread int i; i = 1; i++; ], + [AC_DEFINE([TLS], [1], [Thread local storage]) + AC_MSG_RESULT([yes]) ], + [AC_MSG_RESULT([no])]) + ]) #Enable support for gcc compile time security options. There is no great way to do detection of valid cflags that I have found #AX_CFLAGS_GCC_OPTION don't seem to do a better job than the code below and are a pain because of extra m4 files etc. @@ -244,9 +288,9 @@ AC_MSG_CHECKING(for -fstack-protector) TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -fstack-protector" - AC_TRY_LINK(,,SECCFLAGS="${SECCFLAGS} -fstack-protector" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_TRY_LINK(,,SECCFLAGS="-fstack-protector" + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #compile-time best-practices errors for certain libc functions, provides checks of buffer lengths and memory regions @@ -254,8 +298,8 @@ TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -D_FORTIFY_SOURCE=2" AC_TRY_COMPILE(,,SECCFLAGS="${SECCFLAGS} -D_FORTIFY_SOURCE=2" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #compile-time warnings about misuse of format strings @@ -263,8 +307,8 @@ TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wformat -Wformat-security" AC_TRY_COMPILE(,,SECCFLAGS="${SECCFLAGS} -Wformat -Wformat-security" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) CFLAGS="${TMPCFLAGS}" #provides a read-only relocation table area in the final ELF @@ -272,8 +316,8 @@ TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z relro" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z relro" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" #forces all relocations to be resolved at run-time @@ -281,12 +325,12 @@ TMPLDFLAGS="${LDFLAGS}" LDFLAGS="${LDFLAGS} -z now" AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z now" - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) LDFLAGS="${TMPLDFLAGS}" - CFLAGS="${CFLAGS} ${SECCFLAGS}" - LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" + AC_SUBST(SECCFLAGS) + AC_SUBST(SECLDFLAGS) ]) #enable profile generation @@ -300,13 +344,18 @@ AC_ARG_ENABLE(gccmarch_native, AS_HELP_STRING([--enable-gccmarch-native], [Enable gcc march=native gcc 4.2 and later only]),,[enable_gccmarch_native=yes]) AS_IF([test "x$enable_gccmarch_native" = "xyes"], [ + case "$host" in + *powerpc*) + ;; + *) OFLAGS="$CFLAGS" CFLAGS="$CFLAGS -march=native" AC_MSG_CHECKING([checking if $CC supports -march=native]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]])], [ AC_MSG_RESULT([yes]) - CFLAGS="$OFLAGS -march=native" + OPTIMIZATION_CFLAGS="-march=native" + AC_SUBST(OPTIMIZATION_CFLAGS) ], [ AC_MSG_RESULT([no]) @@ -314,6 +363,8 @@ enable_gccmarch_native=no ] ) + ;; + esac ]) # options @@ -322,71 +373,70 @@ AC_ARG_ENABLE(unittests, AS_HELP_STRING([--enable-unittests], [Enable compilation of the unit tests]),,[enable_unittests=no]) AS_IF([test "x$enable_unittests" = "xyes"], [ - UT_ENABLED="yes" - CFLAGS="${CFLAGS} -DUNITTESTS" + AC_DEFINE([UNITTESTS],[1],[Enable built-in unittests]) ]) - AM_CONDITIONAL([BUILD_UNITTESTS], [test "x$enable_unittests" = "xyes"]) # enable workaround for old barnyard2 for unified alert output AC_ARG_ENABLE(old-barnyard2, AS_HELP_STRING([--enable-old-barnyard2], [Use workaround for old barnyard2 in unified2 output]),,[enable_old_barnyard2=no]) AS_IF([test "x$enable_old_barnyard2" = "xyes"], [ - CFLAGS="${CFLAGS} -DHAVE_OLD_BARNYARD2" + AC_DEFINE([HAVE_OLD_BARNYARD2],[1],[Use workaround for old barnyard2 in unified2 output]) ]) # enable debug output AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [Enable debug output]),,[enable_debug=no]) AS_IF([test "x$enable_debug" = "xyes"], [ - CFLAGS="${CFLAGS} -DDEBUG" + AC_DEFINE([DEBUG],[1],[Enable debug output]) ]) + AM_CONDITIONAL([DEBUG], [test "x$enable_debug" = "xyes"]) # enable debug validation functions & macro's output AC_ARG_ENABLE(debug-validation, AS_HELP_STRING([--enable-debug-validation], [Enable (debug) validation code output]),,[enable_debug_validation=no]) AS_IF([test "x$enable_debug_validation" = "xyes"], [ - CFLAGS="${CFLAGS} -DDEBUG_VALIDATION" + if test "$enable_unittests" = "yes"; then + AC_MSG_ERROR([debug_validation can't be enabled with enabled unittests!]) + else + AC_DEFINE([DEBUG_VALIDATION],[1],[Enable (debug) validation code output]) + fi ]) # profiling support AC_ARG_ENABLE(profiling, AS_HELP_STRING([--enable-profiling], [Enable performance profiling]),,[enable_profiling=no]) AS_IF([test "x$enable_profiling" = "xyes"], [ - - case "$host" in - *-*-openbsd*) - AC_MSG_ERROR([profiling is not supported on OpenBSD]) - ;; - *) - CFLAGS="${CFLAGS} -DPROFILING" - ;; - esac + case "$host" in + *-*-openbsd*) + AC_MSG_ERROR([profiling is not supported on OpenBSD]) + ;; + *) + AC_DEFINE([PROFILING],[1],[Enable performance profiling]) + ;; + esac ]) # profiling support, locking AC_ARG_ENABLE(profiling-locks, AS_HELP_STRING([--enable-profiling-locks], [Enable performance profiling for locks]),,[enable_profiling_locks=no]) AS_IF([test "x$enable_profiling_locks" = "xyes"], [ - CFLAGS="${CFLAGS} -DPROFILING -DPROFILE_LOCKING" + AC_DEFINE([PROFILING],[1],[Enable performance profiling]) + AC_DEFINE([PROFILE_LOCKING],[1],[Enable performance profiling for locks]) ]) # enable support for IPFW AC_ARG_ENABLE(ipfw, AS_HELP_STRING([--enable-ipfw], [Enable FreeBSD IPFW support for inline IDP]),,[enable_ipfw=no]) AS_IF([test "x$enable_ipfw" = "xyes"], [ - CFLAGS="$CFLAGS -DIPFW" + AC_DEFINE([IPFW],[1],[Enable FreeBSD IPFW support for inline IDP]) ]) AC_ARG_ENABLE(coccinelle, - AS_HELP_STRING([--disable-coccinelle], [Disable coccinelle QA steps during make check])],[enable_coccinelle="$enableval"],[enable_coccinelle=yes]) + AS_HELP_STRING([--disable-coccinelle], [Disable coccinelle QA steps during make check]),[enable_coccinelle="$enableval"],[enable_coccinelle=yes]) AS_IF([test "x$enable_coccinelle" = "xyes"], [ AC_PATH_PROG(HAVE_COCCINELLE_CONFIG, spatch, "no") if test "$HAVE_COCCINELLE_CONFIG" = "no"; then - echo " Warning! spatch not found, you will not be " - echo " able to run code checking with coccinelle " - echo " get it from http://coccinelle.lip6.fr " - echo " or install from your distribution " enable_coccinelle=no fi ]) @@ -394,11 +444,12 @@ # disable detection AC_ARG_ENABLE(detection, - AS_HELP_STRING([--disable-detection], [Disable Detection Modules])], [enable_detection="$enableval"],[enable_detection=yes]) + AS_HELP_STRING([--disable-detection], [Disable Detection Modules]), [enable_detection="$enableval"],[enable_detection=yes]) AS_IF([test "x$enable_detection" = "xno"], [ AC_DEFINE([HAVE_DETECT_DISABLED], [1], [Detection is disabled]) ]) + # Tilera PCIE logging AM_CONDITIONAL([BUILD_PCIE_LOGGING], [test ! -z "$TILERA_ROOT"]) # libraries @@ -427,10 +478,10 @@ AC_CHECK_HEADER(pcre.h,,[AC_ERROR(pcre.h not found ...)]) if test "$with_libpcre_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" + LDFLAGS="${LDFLAGS} -L${with_libpcre_libraries}" fi PCRE="" - AC_CHECK_LIB(pcre, pcre_get_substring,, PCRE="no",-lpthread) + AC_CHECK_LIB(pcre, pcre_get_substring,, PCRE="no") if test "$PCRE" = "no"; then echo echo " ERROR! pcre library not found, go get it" @@ -439,6 +490,22 @@ exit 1 fi + # libpcre 8.35 (especially on debian) has a known issue that results in segfaults + # see https://redmine.openinfosecfoundation.org/issues/1693 + if test "$with_libpcre_libraries" = "no"; then + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.35],[libpcre_buggy_found="yes"],[libprce_buggy_found="no"]) + if test "$libpcre_buggy_found" = "yes"; then + echo + echo " Warning! vulnerable libpcre version 8.35 found" + echo " This version has a known issue that could result in segfaults" + echo " please upgrade to a newer version of pcre which you can get from" + echo " www.pcre.org. For more information, see issue #1693" + echo + echo " Continuing for now with JIT disabled..." + echo + fi + fi + # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful PCRE="" @@ -459,13 +526,13 @@ [ pcre_match_limit_recursion_available=yes ], [:] ) if test "$pcre_match_limit_recursion_available" != "yes"; then - CFLAGS="${CFLAGS} -DNO_PCRE_MATCH_RLIMIT" echo echo " Warning! pcre extra opt PCRE_EXTRA_MATCH_LIMIT_RECURSION not found" echo " This could lead to potential DoS please upgrade to pcre >= 6.5" - echo " Continuing for now...." echo " from www.pcre.org." + echo " Continuing for now...." echo + AC_DEFINE([NO_PCRE_MATCH_RLIMIT],[1],[Pcre PCRE_EXTRA_MATCH_LIMIT_RECURSION not available]) fi TMPCFLAGS="${CFLAGS}" @@ -486,6 +553,25 @@ [ pcre_jit_available=yes ], [ pcre_jit_available=no ] ) + case $host in + *powerpc64*) + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.39],[libpcre_ppc64_buggy_found1="yes"],[libprce_ppc64_buggy_found1="no"]) + PKG_CHECK_MODULES(LIBPCREVERSION, [libpcre = 8.40],[libpcre_ppc64_buggy_found2="yes"],[libprce_ppc64_buggy_found2="no"]) + + if test "$libprce_ppc64_buggy_found1" = "yes" || test "$libprce_ppc64_buggy_found2"; then + # on powerpc64, both gcc and clang lead to SIGILL in + # unittests when jit is enabled. + pcre_jit_available="no, pcre 8.39/8.40 jit disabled for powerpc64" + fi + ;; + *) + # bug 1693, libpcre 8.35 is broken and debian jessie is still using that + if test "$libpcre_buggy_found" = "yes"; then + pcre_jit_available="no, libpcre 8.35 blacklisted" + fi + ;; + esac + if test "x$pcre_jit_available" = "xyes"; then AC_MSG_RESULT(yes) AC_DEFINE([PCRE_HAVE_JIT], [1], [Pcre with JIT compiler support enabled]) @@ -524,6 +610,45 @@ AC_MSG_RESULT(no) fi + # libhs + enable_hyperscan="no" + + # Try pkg-config first: + PKG_CHECK_MODULES([libhs], libhs,, [with_pkgconfig_libhs=no]) + if test "$with_pkgconfig_libhs" != "no"; then + CPPFLAGS="${CPPFLAGS} ${libhs_CFLAGS}" + LIBS="${LIBS} ${libhs_LIBS}" + fi + + AC_ARG_WITH(libhs_includes, + [ --with-libhs-includes=DIR libhs include directory], + [with_libhs_includes="$withval"],[with_libhs_includes=no]) + AC_ARG_WITH(libhs_libraries, + [ --with-libhs-libraries=DIR libhs library directory], + [with_libhs_libraries="$withval"],[with_libhs_libraries="no"]) + + if test "$with_libhs_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libhs_includes}" + fi + AC_CHECK_HEADER(hs.h,HYPERSCAN="yes",HYPERSCAN="no") + if test "$HYPERSCAN" = "yes"; then + if test "$with_libhs_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libhs_libraries}" + fi + + AC_CHECK_LIB(hs,hs_compile,,HYPERSCAN="no") + AC_CHECK_FUNCS(hs_valid_platform) + enable_hyperscan="yes" + if test "$HYPERSCAN" = "no"; then + echo + echo " Hyperscan headers are present, but link test failed." + echo " Check that you have a shared library and C++ linkage available." + echo + enable_hyperscan="no" + fi + fi + AS_IF([test "x$enable_hyperscan" = "xyes"], [AC_DEFINE([BUILD_HYPERSCAN], [1], [Intel Hyperscan support enabled])]) + # libyaml AC_ARG_WITH(libyaml_includes, [ --with-libyaml-includes=DIR libyaml include directory], @@ -539,7 +664,7 @@ AC_CHECK_HEADER(yaml.h,,LIBYAML="no") if test "$with_libyaml_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libyaml_libraries}" + LDFLAGS="${LDFLAGS} -L${with_libyaml_libraries}" fi LIBYAML="" @@ -585,6 +710,21 @@ exit 1 fi + # hpfeeds + + AC_CHECK_LIB(hpfeeds, hpf_msg_publish, LHPFEEDS="yes", LHPFEEDS="no") + + if test "$LHPFEEDS" != "no"; then + LIBS="${LIBS} -lhpfeeds" + else + echo + echo " ERROR! hpfeeds not found" + echo " Get it https://github.com/threatstream/hpfeeds" + echo + exit 1 + fi + + # libjansson enable_jansson="no" AC_ARG_WITH(libjansson_includes, @@ -618,7 +758,7 @@ echo " Go get it from your distribution or from:" echo " http://www.digip.org/jansson/" echo - if test "x$enable_unixsocket" = "xyes"; then + if test "x$enable_unixsocket" = "xyes"; then exit 1 fi enable_unixsocket="no" @@ -626,14 +766,14 @@ else case $host in *-*-mingw32*) - ;; + ;; *-*-cygwin) - ;; + ;; *) - if test "x$enable_unixsocket" = "xtest"; then - enable_unixsocket="yes" - fi - ;; + if test "x$enable_unixsocket" = "xtest"; then + enable_unixsocket="yes" + fi + ;; esac fi else @@ -649,47 +789,59 @@ fi AS_IF([test "x$enable_unixsocket" = "xyes"], [AC_DEFINE([BUILD_UNIX_SOCKET], [1], [Unix socket support enabled])]) + e_enable_evelog=$enable_jansson - # libnfnetlink - case $host in - *-*-mingw32*) - ;; - *) - AC_ARG_WITH(libnfnetlink_includes, - [ --with-libnfnetlink-includes=DIR libnfnetlink include directory], - [with_libnfnetlink_includes="$withval"],[with_libnfnetlink_includes=no]) - AC_ARG_WITH(libnfnetlink_libraries, - [ --with-libnfnetlink-libraries=DIR libnfnetlink library directory], - [with_libnfnetlink_libraries="$withval"],[with_libnfnetlink_libraries="no"]) + AC_ARG_ENABLE(nflog, + AS_HELP_STRING([--enable-nflog],[Enable libnetfilter_log support]), + [ enable_nflog="yes"], + [ enable_nflog="no"]) + AC_ARG_ENABLE(nfqueue, + AS_HELP_STRING([--enable-nfqueue], [Enable NFQUEUE support for inline IDP]),[enable_nfqueue=yes],[enable_nfqueue=no]) + if test "$enable_nfqueue" != "no"; then + PKG_CHECK_MODULES([libnetfilter_queue], [libnetfilter_queue], [enable_nfqueue=yes], [enable_nfqueue=no]) + CPPFLAGS="${CPPFLAGS} ${libnetfilter_queue_CFLAGS}" + fi - if test "$with_libnfnetlink_includes" != "no"; then - CPPFLAGS="${CPPFLAGS} -I${with_libnfnetlink_includes}" - fi + if test "x$enable_nflog" = "xyes" || test "x$enable_nfqueue" = "xyes"; then + # libnfnetlink + case $host in + *-*-mingw32*) + ;; + *) + AC_ARG_WITH(libnfnetlink_includes, + [ --with-libnfnetlink-includes=DIR libnfnetlink include directory], + [with_libnfnetlink_includes="$withval"],[with_libnfnetlink_includes=no]) + AC_ARG_WITH(libnfnetlink_libraries, + [ --with-libnfnetlink-libraries=DIR libnfnetlink library directory], + [with_libnfnetlink_libraries="$withval"],[with_libnfnetlink_libraries="no"]) + + if test "$with_libnfnetlink_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libnfnetlink_includes}" + fi - if test "$with_libnfnetlink_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libnfnetlink_libraries}" - fi + if test "$with_libnfnetlink_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libnfnetlink_libraries}" + fi - NFNL="" - AC_CHECK_LIB(nfnetlink, nfnl_fd,, NFNL="no") + NFNL="" + AC_CHECK_LIB(nfnetlink, nfnl_fd,, NFNL="no") - if test "$NFNL" = "no"; then - echo - echo " ERROR! nfnetlink library not found, go get it" - echo " from www.netfilter.org." - echo " we automatically append libnetfilter_queue/ when searching" - echo " for headers etc. when the --with-libnfnetlink-includes directive" - echo " is used" - echo - fi - ;; - esac + if test "$NFNL" = "no"; then + echo + echo " ERROR! nfnetlink library not found, go get it" + echo " from www.netfilter.org." + echo " we automatically append libnetfilter_queue/ when searching" + echo " for headers etc. when the --with-libnfnetlink-includes directive" + echo " is used" + echo + fi + ;; + esac + fi - #enable support for NFQUEUE - AC_ARG_ENABLE(nfqueue, - AS_HELP_STRING([--enable-nfqueue], [Enable NFQUEUE support for inline IDP]),,[enable_nfqueue=no]) + # enable support for NFQUEUE AS_IF([test "x$enable_nfqueue" = "xyes"], [ - CFLAGS="$CFLAGS -DNFQ" + AC_DEFINE_UNQUOTED([NFQ],[1],[Enable Linux Netfilter NFQUEUE support for inline IDP]) #libnetfilter_queue AC_ARG_WITH(libnetfilter_queue_includes, @@ -774,10 +926,6 @@ ]) # libnetfilter_log - AC_ARG_ENABLE(nflog, - AS_HELP_STRING([--enable-nflog],[Enable libnetfilter_log support]), - [ enable_nflog="yes"], - [ enable_nflog="no"]) AC_ARG_WITH(libnetfilter_log_includes, [ --with-libnetfilter_log-includes=DIR libnetfilter_log include directory], [with_libnetfilter_log_includes="$withval"],[with_libnetfilter_log_includes="no"]) @@ -865,12 +1013,13 @@ fi done + enable_libnet="no" AC_MSG_CHECKING(for libnet.h version 1.1.x) if test "$LIBNET_INC_DIR" != ""; then - if eval "grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep -v '1.[[12]]' >/dev/null"; then + LIBNET_VER=`grep LIBNET_VERSION $LIBNET_INC_DIR/libnet.h | grep '1.[[12]]' | sed 's/[[^"]]*"\([[^"]]*\).*/\1/'` + + if test -z "$LIBNET_VER" ; then AC_MSG_RESULT(no) - LIBNET_DETECT_FAIL="yes" - LIBNET_FAIL_WARN($libnet_dir) else AC_MSG_RESULT(yes) fi @@ -881,13 +1030,13 @@ LLIBNET="" AC_CHECK_LIB(net, libnet_write,, LLIBNET="no") if test "$LLIBNET" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_LIBNET11 -D_BSD_SOURCE -D__BSD_SOURCE -D__FAVOR_BSD -DHAVE_NET_ETHERNET_H" - else - #if we displayed a warning already no reason to do it again. - if test "$LIBNET_DETECT_FAIL" = "no"; then - LIBNET_DETECT_FAIL="yes" - LIBNET_FAIL_WARN($libnet_dir) - fi + AC_DEFINE([HAVE_LIBNET11],[1],(libnet 1.1 available)) + AC_DEFINE([_DEFAULT_SOURCE],[1],(default source)) + AC_DEFINE([_BSD_SOURCE],[1],(bsd source)) + AC_DEFINE([__BSD_SOURCE],[1],(bsd source)) + AC_DEFINE([__FAVOR_BSD],[1],(favor bsd)) + AC_DEFINE([HAVE_NET_ETHERNET_H],[1],(ethernet.h)) + enable_libnet="yes" fi # see if we have the patched libnet 1.1 @@ -895,19 +1044,55 @@ # # To prevent duping the lib link we reset LIBS after this check. Setting action-if-found to NULL doesn't seem to work # see: http://blog.flameeyes.eu/2008/04/29/i-consider-ac_check_lib-harmful - if test "$LIBNET_DETECT_FAIL" = "no"; then + if test "$enable_libnet" = "yes"; then LLIBNET="" TMPLIBS="${LIBS}" AC_CHECK_LIB(net, libnet_build_icmpv6_unreach,, LLIBNET="no") if test "$LLIBNET" != "no"; then - CFLAGS="$CFLAGS -DHAVE_LIBNET_ICMPV6_UNREACH" + AC_DEFINE([HAVE_LIBNET_ICMPV6_UNREACH],[1],(libnet_build_icmpv6_unreach available)) fi LIBS="${TMPLIBS}" fi + + # See if we have libnet 1.1.6 or newer - these versions handle capabilities correctly + # Some patched 1.1.4 versions are also good, but it's not guaranteed for all distros. + # + # Details: https://bugzilla.redhat.com/show_bug.cgi?id=589770 + AS_VERSION_COMPARE([LIBNET_VER], [1.1.6], + [], + [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))], + [AC_DEFINE([HAVE_LIBNET_CAPABILITIES],[1], (libnet_have_capabilities_patch))]) + + + # check if the argument to libnet_init is char* or const char* + AC_MSG_CHECKING([libnet_init dev type]) + STORECFLAGS="${CFLAGS}" + if test `basename $CC` = "clang"; then + CFLAGS="${CFLAGS} -Werror=incompatible-pointer-types" + else + CFLAGS="${CFLAGS} -Werror" + fi + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [ + #include + #include + ], + [[ + const char dev[32] = ""; + char ebuf[LIBNET_ERRBUF_SIZE]; + (void)libnet_init(LIBNET_LINK, dev, ebuf); + ]])], + [libnet_init_const="yes"], + [libnet_init_const="no"]) + AC_MSG_RESULT($libnet_init_const) + if test "x$libnet_init_const" = "xyes"; then + AC_DEFINE([HAVE_LIBNET_INIT_CONST], [1], [libnet_init takes const argument]) + fi + CFLAGS="${STORECFLAGS}" fi else - LIBNET_DETECT_FAIL="yes" - LIBNET_FAIL_WARN($libnet_dir) + AC_MSG_RESULT(no) fi # libpcap @@ -930,7 +1115,7 @@ AC_CHECK_HEADERS([pcap.h pcap/pcap.h pcap/bpf.h]) LIBPCAP="" - AC_CHECK_LIB(pcap, pcap_open_live,, LIBPCAP="no", [-lpthread]) + AC_CHECK_LIB(pcap, pcap_open_live,, LIBPCAP="no") if test "$LIBPCAP" = "no"; then echo echo " ERROR! libpcap library not found, go get it" @@ -950,13 +1135,15 @@ AC_CHECK_LIB(pcap, pcap_activate,, LPCAPVTEST="no") if test "$LPCAPVTEST" != "no"; then AC_PATH_PROG(HAVE_PCAP_CONFIG, pcap-config, "no") - if test "$HAVE_PCAP_CONFIG" = "no"; then - CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=1" + if test "$HAVE_PCAP_CONFIG" = "no" -o "$cross_compiling" = "yes"; then + AC_DEFINE([LIBPCAP_VERSION_MAJOR],[1],(libpcap version 1.0+)) else - CFLAGS="${CFLAGS} `pcap-config --defines` `pcap-config --cflags` -DLIBPCAP_VERSION_MAJOR=1" + PCAP_CFLAGS="$(pcap-config --defines) $(pcap-config --cflags)" + AC_SUBST(PCAP_CFLAGS) + AC_DEFINE([LIBPCAP_VERSION_MAJOR],[1],(libpcap version 1.0+)) fi else - CFLAGS="${CFLAGS} -DLIBPCAP_VERSION_MAJOR=0" + AC_DEFINE([LIBPCAP_VERSION_MAJOR],[0],(libpcap version 0.x)) fi LIBS="${TMPLIBS}" @@ -967,7 +1154,7 @@ TMPLIBS="${LIBS}" AC_CHECK_LIB(pcap, pcap_set_buffer_size,, LPCAPSBUFF="no") if test "$LPCAPSBUFF" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_PCAP_SET_BUFF" + AC_DEFINE([HAVE_PCAP_SET_BUFF],[1],(libpcap has pcap_set_buffer_size function)) fi LIBS="${TMPLIBS}" @@ -977,7 +1164,7 @@ AC_ARG_ENABLE(pfring, AS_HELP_STRING([--enable-pfring], [Enable Native PF_RING support]),,[enable_pfring=no]) AS_IF([test "x$enable_pfring" = "xyes"], [ - CFLAGS="$CFLAGS -DHAVE_PFRING" + AC_DEFINE([HAVE_PFRING],[1],(PF_RING support enabled)) #We have to set CFLAGS for AC_TRY_COMPILE as it doesn't pay attention to CPPFLAGS AC_ARG_WITH(libpfring_includes, @@ -1019,8 +1206,6 @@ echo exit 1 fi - else - LIBS="${LIBS} -lrt -lnuma" fi else if test "x$enable_pfring" = "xyes"; then @@ -1043,17 +1228,48 @@ [enable_af_packet="no"], [[#include #include ]]) - AC_CHECK_DECL([PACKET_FANOUT], - AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Packet fanout support is available]), + AC_CHECK_DECL([PACKET_FANOUT_QM], + AC_DEFINE([HAVE_PACKET_FANOUT],[1],[Recent packet fanout support is available]), [], [[#include ]]) + AC_CHECK_DECL([TPACKET_V3], + AC_DEFINE([HAVE_TPACKET_V3],[1],[AF_PACKET tpcket_v3 support is available]), + [], + [[#include + #include ]]) + AC_CHECK_DECL([SOF_TIMESTAMPING_RAW_HARDWARE], + AC_DEFINE([HAVE_HW_TIMESTAMPING],[1],[Hardware timestamping support is available]), + [], + [[#include ]]) ]) + # Netmap support + AC_ARG_ENABLE(netmap, + AS_HELP_STRING([--enable-netmap], [Enable Netmap support]),,[enable_netmap=no]) + AC_ARG_WITH(netmap_includes, + [ --with-netmap-includes=DIR netmap include directory], + [with_netmap_includes="$withval"],[with_netmap_includes=no]) + + AS_IF([test "x$enable_netmap" = "xyes"], [ + AC_DEFINE([HAVE_NETMAP],[1],(NETMAP support enabled)) + + if test "$with_netmap_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_netmap_includes}" + fi + + AC_CHECK_HEADER(net/netmap_user.h,,[AC_ERROR(net/netmap_user.h not found ...)],) + ]) # libhtp AC_ARG_ENABLE(non-bundled-htp, AS_HELP_STRING([--enable-non-bundled-htp], [Enable the use of an already installed version of htp]),,[enable_non_bundled_htp=no]) AS_IF([test "x$enable_non_bundled_htp" = "xyes"], [ + PKG_CHECK_MODULES([libhtp], htp,, [with_pkgconfig_htp=no]) + if test "$with_pkgconfig_htp" != "no"; then + CPPFLAGS="${CPPFLAGS} ${libhtp_CFLAGS}" + LIBS="${LIBS} ${libhtp_LIBS}" + fi + AC_ARG_WITH(libhtp_includes, [ --with-libhtp-includes=DIR libhtp include directory], [with_libhtp_includes="$withval"],[with_libhtp_includes=no]) @@ -1079,12 +1295,12 @@ echo exit 1 fi - PKG_CHECK_MODULES(LIBHTPMINVERSION, [htp >= 0.5.5],[libhtp_minver_found="yes"],[libhtp_minver_found="no"]) + PKG_CHECK_MODULES(LIBHTPMINVERSION, [htp >= 0.5.20],[libhtp_minver_found="yes"],[libhtp_minver_found="no"]) if test "$libhtp_minver_found" = "no"; then PKG_CHECK_MODULES(LIBHTPDEVVERSION, [htp = 0.5.X],[libhtp_devver_found="yes"],[libhtp_devver_found="no"]) if test "$libhtp_devver_found" = "no"; then echo - echo " ERROR! libhtp was found but it is neither >= 0.5.5, nor the dev 0.5.X" + echo " ERROR! libhtp was found but it is neither >= 0.5.20, nor the dev 0.5.X" echo exit 1 fi @@ -1094,6 +1310,7 @@ # check for htp_tx_get_response_headers_raw AC_CHECK_LIB([htp], [htp_tx_get_response_headers_raw],AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Found htp_tx_get_response_headers_raw in libhtp]) ,,[-lhtp]) AC_CHECK_LIB([htp], [htp_decode_query_inplace],AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Found htp_decode_query_inplace function in libhtp]) ,,[-lhtp]) + AC_CHECK_LIB([htp], [htp_config_set_response_decompression_layer_limit],AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT],[1],[Found htp_config_set_response_decompression_layer_limit function in libhtp]) ,,[-lhtp]) AC_EGREP_HEADER(htp_config_set_path_decode_u_encoding, htp/htp.h, AC_DEFINE_UNQUOTED([HAVE_HTP_SET_PATH_DECODE_U_ENCODING],[1],[Found usable htp_config_set_path_decode_u_encoding function in libhtp]) ) ]) @@ -1106,17 +1323,19 @@ HTP_LDADD="../libhtp/htp/libhtp.la" AC_SUBST(HTP_LDADD) # make sure libhtp is added to the includes - CPPFLAGS="-I${srcdir}/../libhtp/ ${CPPFLAGS}" + CPPFLAGS="-I\${srcdir}/../libhtp/ ${CPPFLAGS}" AC_CHECK_HEADER(iconv.h,,[AC_ERROR(iconv.h not found ...)]) AC_CHECK_LIB(iconv, libiconv_close) AC_DEFINE_UNQUOTED([HAVE_HTP_URI_NORMALIZE_HOOK],[1],[Assuming htp_config_register_request_uri_normalize function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_TX_GET_RESPONSE_HEADERS_RAW],[1],[Assuming htp_tx_get_response_headers_raw function in bundled libhtp]) AC_DEFINE_UNQUOTED([HAVE_HTP_DECODE_QUERY_INPLACE],[1],[Assuming htp_decode_query_inplace function in bundled libhtp]) + # enable when libhtp has been updated + AC_DEFINE_UNQUOTED([HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT],[1],[Assuming htp_config_set_response_decompression_layer_limit function in bundled libhtp]) else echo echo " ERROR: Libhtp is not bundled. Get libhtp by doing:" - echo " git clone https://github.com/ironbee/libhtp" + echo " git clone https://github.com/OISF/libhtp" echo " Then re-run Suricata's autogen.sh and configure script." echo " Or, if libhtp is installed in a different location," echo " pass --enable-non-bundled-htp to Suricata's configure script." @@ -1142,7 +1361,7 @@ [ --with-cuda-nvcc=DIR cuda nvcc compiler directory], [with_cuda_nvcc="$withval"],[with_cuda_nvcc=no]) - CFLAGS="${CFLAGS} -D__SC_CUDA_SUPPORT__" + AC_DEFINE([__SC_CUDA_SUPPORT__],[1],(CUDA support enabled)) if test "$with_cuda_includes" != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_cuda_includes}" @@ -1199,6 +1418,7 @@ fi ]) AM_CONDITIONAL([BUILD_CUDA], [test "x$enable_cuda" = "xyes"]) + AM_CONDITIONAL([__SC_CUDA_SUPPORT__], [test "x$enable_cuda" = "xyes"]) # Check for libcap-ng @@ -1226,7 +1446,7 @@ fi if test "$LIBCAP_NG" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_LIBCAP_NG" + AC_DEFINE([HAVE_LIBCAP_NG],[1],[Libpcap-ng support]) fi if test "$LIBCAP_NG" = "no"; then @@ -1269,11 +1489,7 @@ AC_CHECK_HEADER(dagapi.h,DAG="yes",DAG="no") if test "$DAG" != "no"; then DAG="" - AC_CHECK_LIB(dag,dag_open,,DAG="no",) - fi - - if test "$DAG" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_DAG" + AC_CHECK_LIB(dag,dag_open,,DAG="no",) fi if test "$DAG" = "no"; then @@ -1282,6 +1498,8 @@ echo exit 1 fi + + AC_DEFINE([HAVE_DAG],[1],(Endace DAG card support enabled)) fi # libnspr @@ -1371,35 +1589,43 @@ fi # libmagic - AC_ARG_WITH(libmagic_includes, - [ --with-libmagic-includes=DIR libmagic include directory], - [with_libmagic_includes="$withval"],[with_libmagic_includes=no]) - AC_ARG_WITH(libmagic_libraries, - [ --with-libmagic-libraries=DIR libmagic library directory], - [with_libmagic_libraries="$withval"],[with_libmagic_libraries="no"]) - - if test "$with_libmagic_includes" != "no"; then - CPPFLAGS="${CPPFLAGS} -I${with_libmagic_includes}" - fi - - AC_CHECK_HEADER(magic.h,,[AC_ERROR(magic.h not found ...)]) - - if test "$with_libmagic_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libmagic_libraries}" - fi + enable_magic="no" + AC_ARG_ENABLE(libmagic, + AS_HELP_STRING([--enable-libmagic], [Enable libmagic support [default=yes]]), + ,[enable_magic=yes]) + if test "$enable_magic" = "yes"; then + AC_ARG_WITH(libmagic_includes, + [ --with-libmagic-includes=DIR libmagic include directory], + [with_libmagic_includes="$withval"],[with_libmagic_includes=no]) + AC_ARG_WITH(libmagic_libraries, + [ --with-libmagic-libraries=DIR libmagic library directory], + [with_libmagic_libraries="$withval"],[with_libmagic_libraries="no"]) + + if test "$with_libmagic_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libmagic_includes}" + fi - MAGIC="" - AC_CHECK_LIB(magic, magic_open,, MAGIC="no") + AC_CHECK_HEADER(magic.h,,MAGIC="no") + if test "$MAGIC" != "no"; then + MAGIC="" + AC_CHECK_LIB(magic, magic_open,, MAGIC="no") + fi - if test "$MAGIC" = "no"; then - echo - echo " ERROR! magic library not found, go get it" - echo " from http://www.darwinsys.com/file/ or your distribution:" - echo - echo " Ubuntu: apt-get install libmagic-dev" - echo " Fedora: yum install file-devel" - echo - exit 1 + if test "x$MAGIC" != "xno"; then + if test "$with_libmagic_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libmagic_libraries}" + fi + AC_DEFINE([HAVE_MAGIC],[1],(Libmagic for file handling)) + else + echo + echo " WARNING! magic library not found, go get it" + echo " from http://www.darwinsys.com/file/ or your distribution:" + echo + echo " Ubuntu: apt-get install libmagic-dev" + echo " Fedora: yum install file-devel" + echo + enable_magic="no" + fi fi # Napatech - Using the 3GD API @@ -1423,16 +1649,14 @@ AC_CHECK_LIB(ntapi, NT_Init,NAPATECH="yes",NAPATECH="no") fi - if test "$NAPATECH" != "no"; then - CFLAGS="${CFLAGS} -DHAVE_NAPATECH" - fi - if test "$NAPATECH" = "no"; then echo echo " ERROR! libntapi library not found" echo exit 1 fi + + AC_DEFINE([HAVE_NAPATECH],[1],(Napatech capture card support)) fi # liblua @@ -1440,6 +1664,22 @@ AS_HELP_STRING([--enable-lua],[Enable Lua support]), [ enable_lua="yes"], [ enable_lua="no"]) + AC_ARG_ENABLE(luajit, + AS_HELP_STRING([--enable-luajit],[Enable Luajit support]), + [ enable_luajit="yes"], + [ enable_luajit="no"]) + if test "$enable_lua" = "yes"; then + if test "$enable_luajit" = "yes"; then + echo "ERROR: can't enable liblua and luajit at the same time." + echo "For LuaJIT, just use --enable-luajit. For liblua (no jit)" + echo "support, use just --enable-lua." + echo "Both options will enable the Lua scripting capabilities" + echo "in Suricata". + echo + exit 1 + fi + fi + AC_ARG_WITH(liblua_includes, [ --with-liblua-includes=DIR liblua include directory], [with_liblua_includes="$withval"],[with_liblua_includes="no"]) @@ -1474,7 +1714,7 @@ echo " ERROR! liblua library not found, go get it" echo " from http://lua.org/index.html or your distribution:" echo - echo " Ubuntu: apt-get install liblua-5.1-dev" + echo " Ubuntu: apt-get install liblua5.1-dev" echo " CentOS/Fedora: yum install lua-devel" echo echo " If you installed software in a non-standard prefix" @@ -1497,14 +1737,20 @@ LDFLAGS="${LDFLAGS} ${LUA_LIBS}" fi - AC_DEFINE([HAVE_LUA],[1],[liblua available]) - enable_lua="yes" + if test "$LUA" = "no"; then + AC_CHECK_LIB(lua, luaL_openlibs,, LUA="no") + fi + + if test "$LUA" = "yes"; then + AC_DEFINE([HAVE_LUA],[1],[liblua available]) + enable_lua="yes" + fi else echo echo " ERROR! liblua headers not found, go get them" echo " from http://lua.org/index.html or your distribution:" echo - echo " Ubuntu: apt-get install liblua-5.1-dev" + echo " Ubuntu: apt-get install liblua5.1-dev" echo " CentOS/Fedora: yum install lua-devel" echo echo " If you installed software in a non-standard prefix" @@ -1517,10 +1763,6 @@ fi # libluajit - AC_ARG_ENABLE(luajit, - AS_HELP_STRING([--enable-luajit],[Enable Luajit support]), - [ enable_luajit="yes"], - [ enable_luajit="no"]) AC_ARG_WITH(libluajit_includes, [ --with-libluajit-includes=DIR libluajit include directory], [with_libluajit_includes="$withval"],[with_libluajit_includes="no"]) @@ -1563,7 +1805,7 @@ AC_DEFINE([HAVE_LUA],[1],[lua support available]) AC_DEFINE([HAVE_LUAJIT],[1],[libluajit available]) - enable_lua="yes" + enable_lua="yes, through luajit" enable_luajit="yes" else echo @@ -1601,7 +1843,7 @@ AC_CHECK_HEADER(GeoIP.h,GEOIP="yes",GEOIP="no") if test "$GEOIP" = "yes"; then if test "$with_libgeoip_libraries" != "no"; then - LDFLAGS="${LDFLAGS} -L${with_libgeoip_libraries}" + LDFLAGS="${LDFLAGS} -L${with_libgeoip_libraries}" fi AC_CHECK_LIB(GeoIP, GeoIP_country_code_by_ipnum,, GEOIP="no") fi @@ -1615,9 +1857,59 @@ echo exit 1 fi - if test "$GEOIP" = "yes"; then - AC_DEFINE([HAVE_GEOIP],[1],[libgeoip available]) - enable_geoip="yes" + + AC_DEFINE([HAVE_GEOIP],[1],[libgeoip available]) + enable_geoip="yes" + fi + + # Position Independent Executable + AC_ARG_ENABLE(pie, + AS_HELP_STRING([--enable-pie],[Enable compiling as a position independent executable]), + [ enable_pie="yes"], + [ enable_pie="no"]) + if test "$enable_pie" = "yes"; then + CPPFLAGS="${CPPFLAGS} -fPIC" + LDFLAGS="${LDFLAGS} -pie" + fi + +# libhiredis + AC_ARG_ENABLE(hiredis, + AS_HELP_STRING([--enable-hiredis],[Enable Redis support]), + [ enable_hiredis="yes"], + [ enable_hiredis="no"]) + AC_ARG_WITH(libhiredis_includes, + [ --with-libhiredis-includes=DIR libhiredis include directory], + [with_libhiredis_includes="$withval"],[with_libhiredis_includes="no"]) + AC_ARG_WITH(libhiredis_libraries, + [ --with-libhiredis-libraries=DIR libhiredis library directory], + [with_libhiredis_libraries="$withval"],[with_libhiredis_libraries="no"]) + + if test "$enable_hiredis" = "yes"; then + if test "$with_libhiredis_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libhiredis_includes}" + fi + + AC_CHECK_HEADER("hiredis/hiredis.h",HIREDIS="yes",HIREDIS="no") + if test "$HIREDIS" = "yes"; then + if test "$with_libhiredis_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libhiredis_libraries}" + fi + AC_CHECK_LIB(hiredis, redisConnect,, HIREDIS="no") + fi + if test "$HIREDIS" = "no"; then + echo + echo " ERROR! libhiredis library not found, go get it" + echo " from https://github.com/redis/hiredis or your distribution:" + echo + echo " Ubuntu: apt-get install libhiredis-dev" + echo " Fedora: dnf install hiredis-devel" + echo " RHEL/CentOS: yum install hiredis-devel" + echo + exit 1 + fi + if test "$HIREDIS" = "yes"; then + AC_DEFINE([HAVE_LIBHIREDIS],[1],[libhiredis available]) + enable_hiredis="yes" fi fi @@ -1628,22 +1920,40 @@ if [test "$CLS" != "" && test "$CLS" != "0"]; then AC_DEFINE_UNQUOTED([CLS],[${CLS}],[L1 cache line size]) else - AC_DEFINE_UNQUOTED([CLS],[64],[L1 cache line size]) + AC_DEFINE([CLS],[64],[L1 cache line size]) fi else - AC_DEFINE_UNQUOTED([CLS],[64],[L1 cache line size]) + AC_DEFINE([CLS],[64],[L1 cache line size]) + fi + +# sphinx for documentation + AC_PATH_PROG(HAVE_SPHINXBUILD, sphinx-build, "no") + if test "$HAVE_SPHINXBUILD" = "no"; then + enable_sphinxbuild=no + if test -e "$srcdir/doc/userguide/suricata.1"; then + have_suricata_man=yes + fi + fi + AM_CONDITIONAL([HAVE_SPHINXBUILD], [test "x$enable_sphinxbuild" != "xno"]) + AM_CONDITIONAL([HAVE_SURICATA_MAN], [test "x$have_suricata_man" = "xyes"]) + +# pdflatex for the pdf version of the user manual + AC_PATH_PROG(HAVE_PDFLATEX, pdflatex, "no") + if test "$HAVE_PDFLATEX" = "no"; then + enable_pdflatex=no fi + AM_CONDITIONAL([HAVE_PDFLATEX], [test "x$enable_pdflatex" != "xno"]) # get revision if test -f ./revision; then REVISION=`cat ./revision` - CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" + AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision]) else AC_PATH_PROG(HAVE_GIT_CMD, git, "no") if test "$HAVE_GIT_CMD" != "no"; then if [ test -d .git ]; then REVISION=`git rev-parse --short HEAD` - CFLAGS="${CFLAGS} -DREVISION=\"${REVISION}\"" + AC_DEFINE_UNQUOTED([REVISION],[${REVISION}],[Git revision]) fi fi fi @@ -1702,8 +2012,17 @@ AC_SUBST(e_sysconfrulesdir) AC_SUBST(e_localstatedir) AC_DEFINE_UNQUOTED([CONFIG_DIR],["$e_sysconfdir"],[Our CONFIG_DIR]) AC_SUBST(e_magic_file) +AC_SUBST(e_magic_file_comment) +AC_SUBST(e_enable_evelog) -AC_OUTPUT(Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile contrib/tile_pcie_logd/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc) +EXPAND_VARIABLE(prefix, CONFIGURE_PREFIX) +EXPAND_VARIABLE(sysconfdir, CONFIGURE_SYSCONDIR) +EXPAND_VARIABLE(localstatedir, CONFIGURE_LOCALSTATEDIR) +AC_SUBST(CONFIGURE_PREFIX) +AC_SUBST(CONFIGURE_SYSCONDIR) +AC_SUBST(CONFIGURE_LOCALSTATEDIR) + +AC_OUTPUT(Makefile src/Makefile qa/Makefile qa/coccinelle/Makefile rules/Makefile doc/Makefile doc/userguide/Makefile contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile contrib/tile_pcie_logd/Makefile suricata.yaml scripts/Makefile scripts/suricatasc/Makefile scripts/suricatasc/suricatasc) SURICATA_BUILD_CONF="Suricata Configuration: AF_PACKET support: ${enable_af_packet} @@ -1711,14 +2030,18 @@ SURICATA_BUILD_CONF="Suricata Configuration: NFQueue support: ${enable_nfqueue} NFLOG support: ${enable_nflog} IPFW support: ${enable_ipfw} + Netmap support: ${enable_netmap} DAG enabled: ${enable_dag} Napatech enabled: ${enable_napatech} + Unix socket enabled: ${enable_unixsocket} Detection enabled: ${enable_detection} + Libmagic support: ${enable_magic} libnss support: ${enable_nss} libnspr support: ${enable_nspr} libjansson support: ${enable_jansson} + hiredis support: ${enable_hiredis} Prelude support: ${enable_prelude} PCRE jit: ${pcre_jit_available} LUA support: ${enable_lua} @@ -1727,26 +2050,38 @@ SURICATA_BUILD_CONF="Suricata Configuration: Non-bundled htp: ${enable_non_bundled_htp} Old barnyard2 support: ${enable_old_barnyard2} CUDA enabled: ${enable_cuda} + Hyperscan support: ${enable_hyperscan} + Libnet support: ${enable_libnet} Suricatasc install: ${enable_python} - Unit tests enabled: ${enable_unittests} - Debug output enabled: ${enable_debug} - Debug validation enabled: ${enable_debug_validation} Profiling enabled: ${enable_profiling} Profiling locks enabled: ${enable_profiling_locks} + +Development settings: Coccinelle / spatch: ${enable_coccinelle} + Unit tests enabled: ${enable_unittests} + Debug output enabled: ${enable_debug} + Debug validation enabled: ${enable_debug_validation} Generic build parameters: - Installation prefix (--prefix): ${prefix} - Configuration directory (--sysconfdir): ${e_sysconfdir} - Log directory (--localstatedir) : ${e_logdir} + Installation prefix: ${prefix} + Configuration directory: ${e_sysconfdir} + Log directory: ${e_logdir} + + --prefix ${CONFIGURE_PREFIX} + --sysconfdir ${CONFIGURE_SYSCONDIR} + --localstatedir ${CONFIGURE_LOCALSTATEDIR} Host: ${host} - GCC binary: ${CC} + Compiler: ${CC} (exec name) / ${compiler} (real) GCC Protect enabled: ${enable_gccprotect} GCC march native enabled: ${enable_gccmarch_native} - GCC Profile enabled: ${enable_gccprofile}" + GCC Profile enabled: ${enable_gccprofile} + Position Independent Executable enabled: ${enable_pie} + CFLAGS ${CFLAGS} + PCAP_CFLAGS ${PCAP_CFLAGS} + SECCFLAGS ${SECCFLAGS}" echo echo "$SURICATA_BUILD_CONF" diff --git a/contrib/suri-graphite b/contrib/suri-graphite index 7a71ecf2dd5f..beac0792b090 100755 --- a/contrib/suri-graphite +++ b/contrib/suri-graphite @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (C) 2013 Eric Leblond +# Copyright (C) 2013, 2015 Eric Leblond # # You can copy, redistribute or modify this Program under the terms of # the GNU General Public License version 3 as published by the Free @@ -20,32 +20,61 @@ import socket import time import argparse +have_daemon = True +try: + import daemon +except: + logging.warning("No daemon support available, install python-daemon if feature is needed") + have_daemon = False + parser = argparse.ArgumentParser(prog='suri-graphite', description='Export suricata stats to Graphite') parser.add_argument('-H', '--host', default='localhost', help='Host running Graphite') parser.add_argument('-P', '--port', default=2003, help='Port of Graphite data socket') parser.add_argument('-O', '--oneshot', action='store_const', const=True, help='Send one update and exit', default=False) parser.add_argument('-D', '--delay', default=10, help='Delay between data dump') parser.add_argument('-r', '--root', default='suricata.perf', help='Prefix of data name in Graphite') +parser.add_argument('-o', '--output', default=None, help='Output stats to a file instead of using Graphite') parser.add_argument('socket', help='suricata socket file to connect to', default="/usr/local/var/run/suricata/suricata-command.socket", nargs='?') parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output', default=False) +if have_daemon: + parser.add_argument('-d', '--daemon', default=False, action="store_true", help="Run as unix daemon") + args = parser.parse_args() -sc = suricatasc.SuricataSC(args.socket) -sc.connect() - -sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -sck.connect((args.host, args.port)) - -while 1: - res = sc.send_command("dump-counters") - res = res['message'] - tnow = int(time.time()) - for thread in res: - for counter in res[thread]: - sck.send("%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow)) - if args.verbose: - print "%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow) - if args.oneshot: - break - time.sleep(float(args.delay)) + +if args.output: + import json + +def main_task(args): + sc = suricatasc.SuricataSC(args.socket) + sc.connect() + + if args.output: + logfile = open(args.output, 'a') + else: + sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sck.connect((args.host, int(args.port))) + + while 1: + res = sc.send_command("dump-counters") + res = res['message'] + tnow = int(time.time()) + for thread in res: + for counter in res[thread]: + if args.output: + data = {"key": "%s.%s" % (thread , counter), "value": res[thread][counter], "time": tnow} + logfile.write(json.dumps(data) + '\n') + else: + sck.send("%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow)) + if args.verbose: + print "%s.%s.%s %s %d\n" % (args.root, thread , counter, res[thread][counter], tnow) + if args.oneshot: + break + time.sleep(float(args.delay)) + +if have_daemon and args.daemon: + with daemon.DaemonContext(): + main_task(args) +else: + main_task(args) diff --git a/doc/Makefile.am b/doc/Makefile.am index e507b07b0e25..4589a9fe1004 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = userguide + EXTRA_DIST = \ AUTHORS \ GITGUIDE \ @@ -30,5 +32,6 @@ Ubuntu_Installation.txt \ Ubuntu_Installation_from_GIT.txt \ Windows.txt +datarootdir=@datarootdir@ docdir = ${datarootdir}/doc/${PACKAGE} dist_doc_DATA = ${EXTRA_DIST} diff --git a/doc/userguide/.gitignore b/doc/userguide/.gitignore new file mode 100644 index 000000000000..e35d8850c968 --- /dev/null +++ b/doc/userguide/.gitignore @@ -0,0 +1 @@ +_build diff --git a/doc/userguide/Makefile.am b/doc/userguide/Makefile.am new file mode 100644 index 000000000000..3852a251dae9 --- /dev/null +++ b/doc/userguide/Makefile.am @@ -0,0 +1,84 @@ +EXTRA_DIST = \ + conf.py \ + index.rst \ + install.rst \ + acknowledgements.rst \ + rule-management \ + command-line-options.rst \ + initscripts.rst \ + public-data-sets.rst \ + what-is-suricata.rst \ + make-sense-alerts.rst \ + setting-up-ipsinline-for-linux.rst \ + unix-socket.rst \ + capture-hardware \ + configuration \ + file-extraction \ + licenses \ + manpages \ + output \ + performance \ + reputation \ + rules \ + setting-up-ipsinline-for-linux \ + partials + +if HAVE_SURICATA_MAN +man1_MANS = suricata.1 +endif + +if HAVE_SPHINXBUILD +man1_MANS = suricata.1 + +if HAVE_PDFLATEX +EXTRA_DIST += $(man1_MANS) userguide.pdf +endif + +SPHINX_BUILD = sphinx-build -q + +html: + sysconfdir=$(sysconfdir) \ + localstatedir=$(localstatedir) \ + version=$(PACKAGE_VERSION) \ + $(SPHINX_BUILD) -W -b html -d _build/doctrees \ + $(top_srcdir)/doc/userguide _build/html + +_build/latex/Suricata.pdf: + sysconfdir=$(sysconfdir) \ + localstatedir=$(localstatedir) \ + version=$(PACKAGE_VERSION) \ + $(SPHINX_BUILD) -W -b latex -d _build/doctrees \ + $(top_srcdir)/doc/userguide _build/latex +# The Sphinx generated Makefile is GNU Make specific, so just do what +# it does here - yes, multiple passes of pdflatex is required. + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && makeindex -s python.ist Suricata.idx + cd _build/latex && pdflatex Suricata.tex + cd _build/latex && pdflatex Suricata.tex + +userguide.pdf: _build/latex/Suricata.pdf + cp _build/latex/Suricata.pdf userguide.pdf + +pdf: userguide.pdf + +_build/man/suricata.1: + sysconfdir=$(sysconfdir) \ + localstatedir=$(localstatedir) \ + version=$(PACKAGE_VERSION) \ + $(SPHINX_BUILD) -b man -d _build/doctrees \ + $(top_srcdir)/doc/userguide _build/man + +suricata.1: _build/man/suricata.1 + cp _build/man/suricata.1 suricata.1 + +man: _build/man/suricata.1 + +# Remove build artifacts that aren't tracked by autotools. +clean-local: + rm -rf $(top_builddir)/doc/userguide/_build + rm -f $(top_builddir)/doc/userguide/suricata.1 + rm -f $(top_builddir)/doc/userguide/userguide.pdf + +endif # HAVE_SPHINXBUILD diff --git a/doc/userguide/Makefile.sphinx b/doc/userguide/Makefile.sphinx new file mode 100644 index 000000000000..12d28b7a11a4 --- /dev/null +++ b/doc/userguide/Makefile.sphinx @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Suricata.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Suricata.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Suricata" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Suricata" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/userguide/README.md b/doc/userguide/README.md new file mode 100644 index 000000000000..fe06acda5e22 --- /dev/null +++ b/doc/userguide/README.md @@ -0,0 +1,20 @@ +# Suricata User Guide + +This directory contains the Suricata Guide. The +[Sphinx Document Generate](http://sphinx-doc.org) is used to build the +documentation. For a primer os reStructuredText see the +[reStructuredText Primer](http://sphinx-doc.org/rest.html). + +## Development Server + +To help with writing documentation there is a development web server +with live reload. To get run the live server you will first need npm +installed then run the following: + + npm install + gulp serve + +Then point your browser at http://localhost:8000/_build/html/index.html + +Any edits to .rst files should trigger a "make html" and cause your +browser to refresh. diff --git a/doc/userguide/_static/.gitignore b/doc/userguide/_static/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/doc/userguide/acknowledgements.rst b/doc/userguide/acknowledgements.rst new file mode 100644 index 000000000000..add6bb565adc --- /dev/null +++ b/doc/userguide/acknowledgements.rst @@ -0,0 +1,38 @@ +Acknowledgements +================ + +Thank you to the following for their Wiki and documentation +contributions that have made this user guide possible: + +- Andreas Herz +- Andreas Moe +- Anne-Fleur Koolstra +- Christophe Vandeplas +- Darren Spruell +- David Cannings +- David Diallo +- David Wharton +- Eric Leblond +- god lol +- Haris Haq +- Ignacio Sanchez +- Jason Ish +- Jason Taylor +- Josh Smith +- Ken Steele +- Les Syv +- Mark Solaris +- Martin Holste +- Mats Klepsland +- Matt Jonkman +- Michael Bentley +- Michael Hrishenko +- Nathan Jimerson +- Nicolas Merle +- Peter Manev +- Philipp Buehler +- Rob MacGregor +- Russel Fulton +- Victor Julien +- Vincent Fang +- Zach Rasmor diff --git a/doc/userguide/capture-hardware/endace-dag.rst b/doc/userguide/capture-hardware/endace-dag.rst new file mode 100644 index 000000000000..72eb78f8f39a --- /dev/null +++ b/doc/userguide/capture-hardware/endace-dag.rst @@ -0,0 +1,46 @@ +Endace DAG +========== + +Suricata comes with native Endace DAG card support. This means Suricata can use the *libdag* interface directly, instead of a libpcap wrapper (which should also work). + +Steps: + +Configure with DAG support: + + +:: + + + ./configure --enable-dag --prefix=/usr --sysconfdir=/etc --localstatedir=/var + make + sudo make install + +Results in: + +:: + + + Suricata Configuration: + AF_PACKET support: no + PF_RING support: no + NFQueue support: no + IPFW support: no + DAG enabled: yes + Napatech enabled: no + +Start with: + + +:: + + + suricata -c suricata.yaml --dag 0:0 + +Started up! + + +:: + + + [5570] 10/7/2012 -- 13:52:30 - (source-erf-dag.c:262) (ReceiveErfDagThreadInit) -- Attached and started stream: 0 on DAG: /dev/dag0 + [5570] 10/7/2012 -- 13:52:30 - (source-erf-dag.c:288) (ReceiveErfDagThreadInit) -- Starting processing packets from stream: 0 on DAG: /dev/dag0 diff --git a/doc/userguide/capture-hardware/index.rst b/doc/userguide/capture-hardware/index.rst new file mode 100644 index 000000000000..a078541e36bb --- /dev/null +++ b/doc/userguide/capture-hardware/index.rst @@ -0,0 +1,8 @@ +Using Capture Hardware +====================== + +.. toctree:: + + endace-dag + napatech + myricom diff --git a/doc/userguide/capture-hardware/myricom.rst b/doc/userguide/capture-hardware/myricom.rst new file mode 100644 index 000000000000..680e2fb85ca2 --- /dev/null +++ b/doc/userguide/capture-hardware/myricom.rst @@ -0,0 +1,98 @@ +Myricom +======= + +From: http://blog.inliniac.net/2012/07/10/suricata-on-myricom-capture-cards/ + +In this guide I’ll describe using the Myricom libpcap support. I’m going to assume you installed the card properly, installed the Sniffer driver and made sure that all works. Make sure that in your dmesg you see that the card is in sniffer mode: + +:: + + + [ 2102.860241] myri_snf INFO: eth4: Link0 is UP + [ 2101.341965] myri_snf INFO: eth5: Link0 is UP + +I have installed the Myricom runtime and libraries in /opt/snf + +Compile Suricata against Myricom’s libpcap: + + +:: + + + ./configure --with-libpcap-includes=/opt/snf/include/ --with-libpcap-libraries=/opt/snf/lib/ --prefix=/usr --sysconfdir=/etc --localstatedir=/var + make + sudo make install + +Next, configure the amount of ringbuffers. I’m going to work with 8 here, as my quad core + hyper threading has 8 logical CPU’s. *See below* for additional information about the buffer-size parameter. + + +:: + + + pcap: + - interface: eth5 + threads: 8 + buffer-size: 512kb + checksum-checks: no + +The 8 threads setting makes Suricata create 8 reader threads for eth5. The Myricom driver makes sure each of those is attached to it’s own ringbuffer. + +Then start Suricata as follows: + +:: + + + SNF_NUM_RINGS=8 SNF_FLAGS=0x1 suricata -c suricata.yaml -i eth5 --runmode=workers + +If you want 16 ringbuffers, update the “threads” variable in your yaml to 16 and start Suricata: + +:: + + + SNF_NUM_RINGS=16 SNF_FLAGS=0x1 suricata -c suricata.yaml -i eth5 --runmode=workers + +Note that the pcap.buffer-size yaml setting shown above is currently ignored when using Myricom cards. The value is passed through to the pcap_set_buffer_size libpcap API within the Suricata source code. From Myricom support: + +:: + + + “The libpcap interface to Sniffer10G ignores the pcap_set_buffer_size() value. The call to snf_open() uses zero as the dataring_size which informs the Sniffer library to use a default value or the value from the SNF_DATARING_SIZE environment variable." + +The following pull request opened by Myricom in the libpcap project indicates that a future SNF software release could provide support for setting the SNF_DATARING_SIZE via the pcap.buffer-size yaml setting: + +* https://github.com/the-tcpdump-group/libpcap/pull/435 + +Until then, the data ring and descriptor ring values can be explicitly set using the SNF_DATARING_SIZE and SNF_DESCRING_SIZE environment variables, respectively. + +The SNF_DATARING_SIZE is the total amount of memory to be used for storing incoming packet data. This size is shared across all rings. +The SNF_DESCRING_SIZE is the total amount of memory to be used for storing meta information about the packets (packet lengths, offsets, timestamps). This size is also shared across all rings. + +Myricom recommends that the descriptor ring be 1/4 the size of the data ring, but the ratio can be modified based on your traffic profile. +If not set explicitly, Myricom uses the following default values: SNF_DATARING_SIZE = 256MB, and SNF_DESCRING_SIZE = 64MB + +Expanding on the 16 thread example above, you can start Suricata with a 16GB Data Ring and a 4GB Descriptor Ring using the following command: + +:: + + + SNF_NUM_RINGS=16 SNF_DATARING_SIZE=17179869184 SNF_DESCRING_SIZE=4294967296 SNF_FLAGS=0x1 suricata -c suricata.yaml -i eth5 --runmode=workers + +Debug Info +~~~~~~~~~~ + +Myricom also provides a means for obtaining debug information. This can be useful for verifying your configuration and gathering additional information. +Setting SNF_DEBUG_MASK=3 enables debug information, and optionally setting the SNF_DEBUG_FILENAME allows you to specify the location of the output file. + +Following through with the example: + +:: + + + SNF_NUM_RINGS=16 SNF_DATARING_SIZE=17179869184 SNF_DESCRING_SIZE=4294967296 SNF_FLAGS=0x1 SNF_DEBUG_MASK=3 SNF_DEBUG_FILENAME="/tmp/snf.out" suricata -c suricata.yaml -i eth5 --runmode=workers + +Additional Info +~~~~~~~~~~~~~~~ + +* http://www.40gbe.net/index_files/be59da7f2ab5bf0a299ab99ef441bb2e-28.html + +* http://o-www.emulex.com/blogs/implementers/2012/07/23/black-hat-usa-2012-emulex-faststack-sniffer10g-product-demo-emulex-booth/ diff --git a/doc/userguide/capture-hardware/napatech.rst b/doc/userguide/capture-hardware/napatech.rst new file mode 100644 index 000000000000..2ac4aa685f30 --- /dev/null +++ b/doc/userguide/capture-hardware/napatech.rst @@ -0,0 +1,211 @@ + + +Napatech Suricata Installation Guide +============================================================= + +Contents +-------- + + * Introduction + + * Package Installation + + * Basic Configuration + + * Advanced Multithreaded Configuration + +Introduction +------------ + +Napatech packet capture accelerator cards can greatly improve the performance of your Suricata deployment using these +hardware based features: + + * On board burst buffering (up to 12GB) + + * Zero-copy kernel bypass DMA + + * Non-blocking PCIe performance + + * Port merging + + * Load distribution to up 128 host buffers + + * Precise timestamping + + * Accurate time synchronization + +The Napatech Software Suite (driver package) comes in two varieties, NAC and OEM. +The NAC package distributes deb and rpm packages to ease the installation. +The OEM package uses a proprietary shell script to handle the installation process. +In either case, gcc, make and the kernel header files are required to compile the kernel module and +install the software. + + +Package Installation +-------------------- + +*Note that make, gcc, and the kernel headers are required for installation* + +*Root privileges are also required* + +Napatech NAC Package +^^^^^^^^^^^^^^^^^^^^ + +Red Hat Based Distros:: + + $ yum install kernel-devel-$(uname -r) gcc make ncurses-libs + $ yum install nac-pcap-.x86_64.rpm + +Some distributions will require you to use the --nogpgcheck option with yum for the NAC Software Suite package file:: + + $ yum --nogpgcheck install nac-pcap-.x86_64.rpm + +Debian Based Distros:: + + $ apt-get install linux-headers-$(uname .r) gcc make libncurses5 + $ dpkg .i nac-pcap__amd64.deb + +To complete installation for all distros stop ntservice:: + + $ /opt/napatech3/bin/ntstop.sh -m + +Remove these existing setup files:: + + $ cd /opt/napatech3/config + $ rm ntservice.ini setup.ini + +Restart ntservice (a new ntservice.ini configuration file will be generated automatically):: + + $ /opt/napatech3/bin/ntstart.sh -m + + +Napatech OEM Package +^^^^^^^^^^^^^^^^^^^^ + +*Note that you will be prompted to install the Napatech libpcap library. Answer "yes" if you would like to +use the Napatech card to capture packets in WIreshark, tcpdump, or another pcap based application. +Libpcap is not needed for Suricata as native Napatech API support is included* + +Red Hat Based Distros:: + + $ yum install kernel-devel-$(uname -r) gcc make + $ ./package_install_3gd.sh + +Debian Based Distros:: + + $ apt-get install linux-headers-$(uname .r) gcc make + $ ./package_install_3gd.sh + +To complete installation for all distros ntservice:: + + $ /opt/napatech3/bin/ntstart.sh -m + +Suricata Installation +--------------------- + +After downloading and extracting the Suricata tarball, you need to run configure to enable Napatech support and +prepare for compilation:: + + $ ./configure --enable-napatech --with-napatech-includes=/opt/napatech3/include --with-napatech-libraries=/opt/napatech3/lib + $ make + $ make install-full + +Now edit the suricata.yaml file to configure the maximum number of streams to use. If you plan on using the load distribution +(RSS - like) feature in the Napatech accelerator, then the list should contain the same number of streams as host buffers defined in +ntservice.ini:: + + Napatech: + # The Host Buffer Allowance for all streams + # (-1 = OFF, 1 - 100 = percentage of the host buffer that can be held back) + hba: -1 + + # use_all_streams set to "yes" will query the Napatech service for all configured + # streams and listen on all of them. When set to "no" the streams config array + # will be used. + use-all-streams: yes + + # The streams to listen on + streams: [0, 1, 2, 3, 4, 5, 6, 7] + + +Basic Configuration +------------------- + +For the basic installation we will setup the Napatech capture accelerator to merge all physical +ports into single stream that Suricata can read from. for this configuration, Suricata will +handle the packet distribution to multiple threads. + +Here are the lines that need changing in /opt/napatech3/bin/ntservice.ini for best single buffer performance:: + + TimeSyncReferencePriority = OSTime # Timestamp clock synchronized to the OS + HostBuffersRx = [1,16,0] # [number of host buffers, Size(MB), NUMA node] + +Stop and restart ntservice after making changes to ntservice:: + + $ /opt/napatech3/bin/ntstop.sh -m + $ /opt/napatech3/bin/ntstart.sh -m + +Now we need to execute a few NTPL (Napatech Programming Language) commands to complete the setup. Create +a file will the following commands:: + + Delete=All # Delete any existing filters + Setup[numaNode=0] = streamid==0 # Set stream ID 0 to NUMA 0 + Assign[priority=0; streamid=0]= all # Assign all phisical ports to stream ID 0 + +Next execute those command using the ntpl tool:: + + $ /opt/napatech3/bin/ntpl -f + +Now you are ready to start suricata:: + + $ suricata -c /usr/local/etc/suricata/suricata.yaml --napatech --runmode workers + +Advanced Multithreaded Configuration +------------------------------------ + +Now let's do a more advanced configuration where we will use the load distribution (RSS - like) capability in the +accelerator. We will create 8 streams and setup the accelerator to distribute the load based on a 5 tuple hash. +Increasing buffer size will minimize packet loss only if your CPU cores are fully saturated. Setting the minimum +buffer size (16MB) will gave the best performance (minimize L3 cache hits) if your CPU cores are keeping up. + +*Note that it is extremely important that the NUMA node the host buffers are define in is the same physical CPU +socket that the Napatech accelerator is plugged into* + +First let's modify the ntservice.ini file to increase the number and size of the host buffers:: + + HostBuffersRx = [8,256,0] # [number of host buffers, Size (MB), NUMA node] + +Stop and restart ntservice after making changes to ntservice:: + + $ /opt/napatech3/bin/ntstop.sh -m + $ /opt/napatech3/bin/ntstart.sh -m + +Now let's assign the streams to host buffers and configure the load distribution. The load distribution will be +setup to support both tunneled and non-tunneled traffic. Create a file that contains the ntpl commands below:: + + Delete=All # Delete any existing filters + Setup[numaNode=0] = streamid==0 + Setup[numaNode=0] = streamid==1 + Setup[numaNode=0] = streamid==2 + Setup[numaNode=0] = streamid==3 + Setup[numaNode=0] = streamid==4 + Setup[numaNode=0] = streamid==5 + Setup[numaNode=0] = streamid==6 + Setup[numaNode=0] = streamid==7 + HashMode[priority=4]=Hash5TupleSorted + Assign[priority=0; streamid=(0..7)]= all + +Next execute those command using the ntpl tool:: + + $ /opt/napatech3/bin/ntpl -f + +Now you are ready to start Suricata:: + + $ suricata -c /usr/local/etc/suricata/suricata.yaml --napatech --runmode workers + + +Support +------- + +Contact a support engineer at: ntsupport@napatech.com + diff --git a/doc/userguide/command-line-options.rst b/doc/userguide/command-line-options.rst new file mode 100644 index 000000000000..77f6a381a6fc --- /dev/null +++ b/doc/userguide/command-line-options.rst @@ -0,0 +1,19 @@ +Command Line Options +==================== + +.. toctree:: + +Suricata's command line options: + +.. include:: partials/options.rst + +Unit Tests +~~~~~~~~~~ + +Builtin unittests are only available if Suricata has been built with +--enable-unittests. + +Running unittests does not take a configuration file. Use -l to supply +an output directory. + +.. include:: partials/options-unittests.rst diff --git a/doc/userguide/conf.py b/doc/userguide/conf.py new file mode 100644 index 000000000000..f93222049a3f --- /dev/null +++ b/doc/userguide/conf.py @@ -0,0 +1,318 @@ +# -*- coding: utf-8 -*- +# +# Suricata documentation build configuration file, created by +# sphinx-quickstart on Fri Nov 6 10:12:25 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex +import re + +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Suricata' +copyright = u'2016, OISF' +author = u'OISF' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. + +# Attempt to extract the version configure.ac. +try: + version = os.environ.get('version', None) + if not version: + version = re.search( + "AC_INIT\(suricata,\s*(.*)?\)", + open("../../configure.ac").read()).groups()[0] + if not version: + version = "unknown" +except: + version = "unknown" +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + '_build', + + # Documents that are included, rather than in a TOC. + 'partials', +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +if not on_rtd: + # Attempt to use the read the docs theme. + try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + except: + html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'suricatadoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Suricata.tex', u'Suricata User Guide', + u'OISF', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + # (master_doc, 'suricata', u'Suricata Documentation', + # [author], 1) + ("manpages/suricata", "suricata", "Suricata", [], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Suricata', u'Suricata User Guide', + author, 'Suricata', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +rst_epilog = """ +.. |sysconfdir| replace:: %(sysconfdir)s +.. |localstatedir| replace:: %(localstatedir)s +""" % { + "sysconfdir": os.getenv("sysconfdir", "/etc"), + "localstatedir": os.getenv("localstatedir", "/var"), +} diff --git a/doc/userguide/configuration/dropping-privileges.rst b/doc/userguide/configuration/dropping-privileges.rst new file mode 100644 index 000000000000..937a3951a498 --- /dev/null +++ b/doc/userguide/configuration/dropping-privileges.rst @@ -0,0 +1,49 @@ +Dropping Privileges After Startup +================================= + +Currently, libcap-ng is needed for dropping privileges on Suricata +after startup. For libcap, see status of feature request number #276 +-- Libcap support for dropping privileges. + +Most distributions have ``libcap-ng`` in their repositories. + +To download the current version of libcap-ng from upstream, see also +http://people.redhat.com/sgrubb/libcap-ng/ChangeLog + +:: + + wget http://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.7.8.tar.gz + tar -xzvf libcap-ng-0.7.8.tar.gz + cd libcap-ng-0.7.8 + ./configure + make + make install + +Download, configure, compile and install Suricata for your particular setup. +See :doc:`../install`. Depending on your environment, you may need to add the +--with-libpcap_ng-libraries and --with-libpcap_ng-includes options +during the configure step. e.g: + +:: + + ./configure --with-libcap_ng-libraries=/usr/local/lib \ + --with-libcap_ng-includes=/usr/local/include + +Now, when you run Suricata, tell it what user and/or group you want it +to run as after startup with the --user and --group options. +e.g. (this assumes a 'suri' user and group): + +:: + + suricata -D -i eth0 --user=suri --group=suri + +You will also want to make sure your user/group permissions are set so +suricata can still write to its log files which are usually located in +/var/log/suricata. + +:: + + mkdir -p /var/log/suricata + chown -R root:suri /var/log/suricata + chmod -R 775 /var/log/suricata + diff --git a/doc/userguide/configuration/global-thresholds.rst b/doc/userguide/configuration/global-thresholds.rst new file mode 100644 index 000000000000..adb5cb8b47fe --- /dev/null +++ b/doc/userguide/configuration/global-thresholds.rst @@ -0,0 +1,203 @@ +Global-Thresholds +================= + +Thresholds can be configured in the rules themselves, see +:doc:`../rules/thresholding`. They are often set by rule writers based on +their intel for creating a rule combined with a judgement on how often +a rule will alert. + +Threshold Config +---------------- + +Next to rule thresholding more thresholding can be configured on the sensor +using the threshold.config. + +threshold/event_filter +~~~~~~~~~~~~~~~~~~~~~~ + +Syntax: + +:: + + threshold gen_id , sig_id , type , \ + track , count , seconds + +rate_filter +~~~~~~~~~~~ + +Rate filters allow changing of a rule action when a rule matches. + +Syntax:: + + rate_filter: rate_filter gen_id , sig_id , track , \ + count , seconds , new_action , timeout + +Example:: + + rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, \ + new_action alert, timeout 30 + +gen_id +^^^^^^ +Generator id. Normally 1, but if a rule uses the ``gid`` keyword to set +another value it has to be matched in the ``gen_id``. + +sig_id +^^^^^^ + +Rule/signature id as set by the rule ``sid`` keyword. + +track +^^^^^ + +Where to track the rule matches. When using by_src/by_dst the tracking is +done per IP-address. The Host table is used for storage. When using by_rule +it's done globally for the rule. + +count +^^^^^ + +Number of rule hits before the ``rate_filter`` is activated. + +seconds +^^^^^^^ + +Time period within which the ``count`` needs to be reached to activate +the ``rate_filter`` + +new_action +^^^^^^^^^^ + +New action that is applied to matching traffic when the ``rate_filter`` +is in place. + +Values:: + + + +Note: 'sdrop' and 'log' are supported by the parser but not implemented otherwise. + +timeout +^^^^^^^ + +Time in seconds during which the ``rate_filter`` will remain active. + +Example +^^^^^^^ + +Lets say we want to limit incoming connections to our SSH server. The rule +``888`` below simply alerts on SYN packets to the SSH port of our SSH server. +If an IP-address triggers this more than 10 or more with a minute, the +drop ``rate_filter`` is set with a timeout of 5 minutes. + +Rule:: + + alert tcp any any -> $MY_SSH_SERVER 22 (msg:"Connection to SSH server"; \ + flow:to_server; flags:S,12; sid:888;) + +Rate filter:: + + rate_filter gen_id 1, sig_id 888, track by_src, count 10, seconds 60, \ + new_action drop, timeout 300 + + +suppress +~~~~~~~~ + +Suppressions can be used to suppress alerts for a rule or a +host/network. Actions performed when a rule matches, such as setting a +flowbit, are still performed. + +Syntax: + +:: + + suppress gen_id , sig_id + suppress gen_id , sig_id , track , ip + +Examples: + +:: + + suppress gen_id 1, sig_id 2002087, track by_src, ip 209.132.180.67 + +This will make sure the signature 2002087 will never match for src +host 209.132.180.67. + +Other possibilities/examples:: + + suppress gen_id 1, sig_id 2003614, track by_src, ip 217.110.97.128/25 + suppress gen_id 1, sig_id 2003614, track by_src, ip [192.168.0.0/16,10.0.0.0/8,172.16.0.0/12] + suppress gen_id 1, sig_id 2003614, track by_src, ip $HOME_NET + +.. _global-thresholds-vs-rule-thresholds: + +Global thresholds vs rule thresholds +------------------------------------ + +**Note: this section applies to 1.4+ In 1.3 and before mixing rule and +global thresholds is not supported.** + +When a rule has a threshold/detection_filter set a rule can still be +affected by the global threshold file. + +The rule below will only fire if 10 or more emails are being +delivered/sent from a host within 60 seconds. + +:: + + alert tcp any any -> any 25 (msg:"ET POLICY Inbound Frequent Emails - Possible Spambot Inbound"; \ + flow:established; content:"mail from|3a|"; nocase; \ + threshold: type threshold, track by_src, count 10, seconds 60; \ + reference:url,doc.emergingthreats.net/2002087; classtype:misc-activity; sid:2002087; rev:10;) + +Next, we'll see how global settings affect this rule. + +Suppress +~~~~~~~~ + +Suppressions can be combined with rules with +thresholds/detection_filters with no exceptions. + +:: + + suppress gen_id 1, sig_id 2002087, track by_src, ip 209.132.180.67 + suppress gen_id 0, sig_id 0, track by_src, ip 209.132.180.67 + suppress gen_id 1, sig_id 0, track by_src, ip 209.132.180.67 + +Each of the rules above will make sure 2002087 doesn't alert when the +source of the emails is 209.132.180.67. It **will** alert for all other +hosts. + +:: + + suppress gen_id 1, sig_id 2002087 + +This suppression will simply convert the rule to "noalert", meaning it +will never alert in any case. If the rule sets a flowbit, that will +still happen. + +Threshold/event_filter +~~~~~~~~~~~~~~~~~~~~~~ + +When applied to a specific signature, thresholds and event_filters +(threshold from now on) will override the signature setting. This can +be useful for when the default in a signature doesn't suit your +evironment. + +:: + + threshold gen_id 1, sig_id 2002087, type both, track by_src, count 3, seconds 5 + threshold gen_id 1, sig_id 2002087, type threshold, track by_src, count 10, seconds 60 + threshold gen_id 1, sig_id 2002087, type limit, track by_src, count 1, seconds 15 + +Each of these will replace the threshold setting for 2002087 by the +new threshold setting. + +**Note:** overriding all gids or sids (by using gen_id 0 or sig_id 0) +is not supported. Bug #425. + +Rate_filter +~~~~~~~~~~~ + +TODO diff --git a/doc/userguide/configuration/index.rst b/doc/userguide/configuration/index.rst new file mode 100644 index 000000000000..f25591952c7d --- /dev/null +++ b/doc/userguide/configuration/index.rst @@ -0,0 +1,11 @@ +Configuration +============= + +.. toctree:: + + suricata-yaml + global-thresholds + snort-to-suricata + log-rotation + multi-tenant + dropping-privileges diff --git a/doc/userguide/configuration/log-rotation.rst b/doc/userguide/configuration/log-rotation.rst new file mode 100644 index 000000000000..85c4a63e75b8 --- /dev/null +++ b/doc/userguide/configuration/log-rotation.rst @@ -0,0 +1,24 @@ +Log Rotation +============ + +Suricata can generate lot of output, so it's important to manage the files +to avoid issues with disks filling up. + +A HUP signal sent to Suricata will force it to reopen the logfiles. + +Example logrotate file: + +:: + + /var/log/suricata/*.log /var/log/suricata/*.json + { + rotate 3 + missingok + nocompress + create + sharedscripts + postrotate + /bin/kill -HUP $(cat /var/run/suricata.pid) + endscript + } + diff --git a/doc/userguide/configuration/multi-tenant.rst b/doc/userguide/configuration/multi-tenant.rst new file mode 100644 index 000000000000..73abdae8556f --- /dev/null +++ b/doc/userguide/configuration/multi-tenant.rst @@ -0,0 +1,163 @@ +Multi Tenancy +============= + +Introduction +------------ + +Multi tenancy support allows for different rule sets with different +rule vars. + +YAML +---- + +In the main ("master") YAML, the suricata.yaml, a new section called +"multi-detect" should be added. + +Settings: + +* enabled: yes/no -> is multi-tenancy support enable +* default: yes/no -> is the normal detect config a default 'fall back' tenant? +* selector: direct (for unix socket pcap processing, see below) or vlan +* loaders: number of 'loader' threads, for parallel tenant loading at startup +* tenants: list of tenants + + * id: tenant id + * yaml: separate yaml file with the tenant specific settings + +* mappings: + + * vlan id + * tenant id: tenant to associate with the vlan id + +:: + + multi-detect: + enabled: yes + #selector: direct # direct or vlan + selector: vlan + loaders: 3 + + tenants: + - id: 1 + yaml: tenant-1.yaml + - id: 2 + yaml: tenant-2.yaml + - id: 3 + yaml: tenant-3.yaml + + mappings: + - vlan-id: 1000 + tenant-id: 1 + - vlan-id: 2000 + tenant-id: 2 + - vlan-id: 1112 + tenant-id: 3 + +The tenant-1.yaml, tenant-2.yaml, tenant-3.yaml each contain a partial +configuration: + +:: + + # Set the default rule path here to search for the files. + # if not set, it will look at the current working dir + default-rule-path: /etc/suricata/rules + rule-files: + - rules1 + + # You can specify a threshold config file by setting "threshold-file" + # to the path of the threshold config file: + # threshold-file: /etc/suricata/threshold.config + + classification-file: /etc/suricata/classification.config + reference-config-file: /etc/suricata/reference.config + + # Holds variables that would be used by the engine. + vars: + + # Holds the address group vars that would be passed in a Signature. + # These would be retrieved during the Signature address parsing stage. + address-groups: + + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + + EXTERNAL_NET: "!$HOME_NET" + + ... + + port-groups: + + HTTP_PORTS: "80" + + SHELLCODE_PORTS: "!80" + + ... + +Unix Socket +----------- + +Registration +~~~~~~~~~~~~ + +register-tenant + +Examples: + +:: + + register-tenant 1 tenant-1.yaml + register-tenant 2 tenant-2.yaml + register-tenant 3 tenant-3.yaml + register-tenant 5 tenant-5.yaml + register-tenant 7 tenant-7.yaml + +unregister-tenant + +:: + + unregister-tenant 2 + unregister-tenant 1 + +Unix socket runmode (pcap processing) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Unix Socket "pcap-file" command can be used to select the tenant +to inspect the pcap against: + +:: + + pcap-file traffic1.pcap /logs1/ 1 + pcap-file traffic2.pcap /logs2/ 2 + pcap-file traffic3.pcap /logs3/ 3 + pcap-file traffic4.pcap /logs5/ 5 + pcap-file traffic5.pcap /logs7/ 7 + +This runs the traffic1.pcap against tenant 1 and it logs into /logs1/, +traffic2.pcap against tenant 2 and logs to /logs2/ and so on. + +Live traffic mode +~~~~~~~~~~~~~~~~~ + +For live traffic currently only a vlan based multi-tenancy is supported. + +The master yaml needs to have the selector set to "vlan". + +Registration +~~~~~~~~~~~~ + +Tenants can be mapped to vlan id's. + +register-tenant-handler vlan + +:: + + register-tenant-handler 1 vlan 1000 + +unregister-tenant-handler vlan + +:: + + unregister-tenant-handler 4 vlan 1111 + unregister-tenant-handler 1 vlan 1000 + +The registration of tenant and tenant handlers can be done on a +running engine. diff --git a/doc/userguide/configuration/snort-to-suricata.rst b/doc/userguide/configuration/snort-to-suricata.rst new file mode 100644 index 000000000000..f9ea3b36e049 --- /dev/null +++ b/doc/userguide/configuration/snort-to-suricata.rst @@ -0,0 +1,276 @@ +Snort.conf to Suricata.yaml +=========================== + +This guide is meant for those who are familiar with Snort and the +snort.conf configuration format. This guide will provide a 1:1 mapping +between Snort and Suricata configuration wherever possible. + +Variables +--------- + +snort.conf + +:: + + ipvar HOME_NET any + ipvar EXTERNAL_NET any + ... + + portvar HTTP_PORTS [80,81,311,591,593,901,1220,1414,1741,1830,2301,2381,2809,3128,3702,4343,4848,5250,7001,7145,7510,7777,7779,8000,8008,8014,8028,8080,8088,8090,8118,8123,8180,8181,8243,8280,8800,8888,8899,9000,9080,9090,9091,9443,9999,11371,55555] + portvar SHELLCODE_PORTS !80 + ... + +suricata.yaml + +:: + + + vars: + address-groups: + + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + EXTERNAL_NET: "!$HOME_NET" + + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + +Note that Suricata can automatically detect HTTP traffic regardless of +the port it uses. So the HTTP_PORTS variable is not nearly as +important as it is with Snort, **if** you use a Suricata enabled +ruleset. + +Decoder alerts +-------------- + +snort.conf + +:: + + # Stop generic decode events: + config disable_decode_alerts + + # Stop Alerts on experimental TCP options + config disable_tcpopt_experimental_alerts + + # Stop Alerts on obsolete TCP options + config disable_tcpopt_obsolete_alerts + + # Stop Alerts on T/TCP alerts + config disable_tcpopt_ttcp_alerts + + # Stop Alerts on all other TCPOption type events: + config disable_tcpopt_alerts + + # Stop Alerts on invalid ip options + config disable_ipopt_alerts + +suricata.yaml + +Suricata has no specific decoder options. All decoder related alerts +are controlled by rules. See #Rules below. + +Checksum handling +----------------- + +snort.conf + +:: + + config checksum_mode: all + +suricata.yaml + +Suricata's checksum handling works *on-demand*. The stream engine +checks TCP and IP checksum by default: + +:: + + stream: + checksum-validation: yes # reject wrong csums + +Alerting on bad checksums can be done with normal rules. See #Rules, +decoder-events.rules specifically. + +Various configs +--------------- + +Active response +~~~~~~~~~~~~~~~ + +snort.conf + +:: + + # Configure active response for non inline operation. For more information, see REAMDE.active + # config response: eth0 attempts 2 + +suricata.yaml + +Active responses are handled automatically w/o config if rules with +the "reject" action are used. + +Dropping privileges +~~~~~~~~~~~~~~~~~~~ + +snort.conf + +:: + + + # Configure specific UID and GID to run snort as after dropping privs. For more information see snort -h command line options + # + # config set_gid: + # config set_uid: + +Suricata + +To set the user and group use the --user and --group + commandline options. + +Snaplen +~~~~~~~ + +snort.conf + +:: + + # Configure default snaplen. Snort defaults to MTU of in use interface. For more information see README + # + # config snaplen: + # + +Suricata always works at full snap length to provide full traffic visibility. + +Bpf +~~~ + +snort.conf + +:: + + # Configure default bpf_file to use for filtering what traffic reaches snort. For more information see snort -h command line options (-F) + # + # config bpf_file: + # + +suricata.yaml + +BPF filters can be set per packet acquisition method, with the "bpf-filter: " yaml option and in a file using the -F command line option. + +For example: + +:: + + pcap: + - interface: eth0 + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + #checksum-checks: auto + #threads: 16 + #promisc: no + #snaplen: 1518 + +Log directory +------------- + +snort.conf + +:: + + # Configure default log directory for snort to log to. For more information see snort -h command line options (-l) + # + # config logdir: + +suricata.yaml + +:: + + default-log-dir: /var/log/suricata/ + +This value is overridden by the -l commandline option. + +Packet acquisition +------------------ + +snort.conf + +:: + + # Configure DAQ related options for inline operation. For more information, see README.daq + # + # config daq: + # config daq_dir: + # config daq_mode: + # config daq_var: + # + # ::= pcap | afpacket | dump | nfq | ipq | ipfw + # ::= read-file | passive | inline + # ::= arbitrary = ::= path as to where to look for DAQ module so's + +suricata.yaml + +Suricata has all packet acquisition support built-in. It's +configuration format is very verbose. + +:: + + pcap: + - interface: eth0 + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + #checksum-checks: auto + #threads: 16 + #promisc: no + #snaplen: 1518 + pfring: + afpacket: + nfq: + ipfw: + +Passive vs inline vs reading files is determined by how Suricata is +invoked on the command line. + +Rules +----- + +snort.conf: + +In snort.conf a RULE_PATH variable is set, as well as variables for +shared object (SO) rules and preprocessor rules. + +:: + + var RULE_PATH ../rules + var SO_RULE_PATH ../so_rules + var PREPROC_RULE_PATH ../preproc_rules + + include $RULE_PATH/local.rules + include $RULE_PATH/emerging-activex.rules + ... + +suricata.yaml: + +In the suricata.yaml the default rule path is set followed by a list +of rule files. Suricata does not have a concept of shared object rules +or preprocessor rules. Instead of preprocessor rules, Suricata has +several rule files for events set by the decoders, stream engine, http +parser etc. + +:: + + default-rule-path: /etc/suricata/rules + rule-files: + - local.rules + - emerging-activex.rules + +The equivalent of preprocessor rules are loaded like normal rule files: + +:: + + rule-files: + - decoder-events.rules + - stream-events.rules + - http-events.rules + - smtp-events.rules diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst new file mode 100644 index 000000000000..363114ef2e1c --- /dev/null +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -0,0 +1,2217 @@ +Suricata.yaml +============= + +Suricata uses the Yaml format for configuration. The Suricata.yaml +file included in the source code, is the example configuration of +Suricata. This document will explain each option. + +At the top of the YAML-file you will find % YAML 1.1. Suricata reads +the file and identifies the file as YAML. + +.. _suricata-yaml-max-pending-packets: + +Max-pending-packets +------------------- + +With the max-pending-packets setting you can set the number of packets +you allow Suricata to process simultaneously. This can range from one +packet to tens of thousands/hundreds of thousands of packets. It is a +trade of higher performance and the use of more memory (RAM), or lower +performance and less use of memory. A high number of packets being +processed results in a higher performance and the use of more +memory. A low number of packets, results in lower performance and less +use of memory. Choosing a low number of packets being processed while +having many CPU's/CPU cores, can result in not making use of the whole +computer-capacity. (For instance: using one core while having three +waiting for processing packets.) + +:: + + max-pending-packets: 1024 + +Runmodes +-------- + +By default the runmode option is disabled With the runmodes setting +you can set the runmode you would like to use. For all runmodes +available, enter **--list-runmodes** in your command line. For more +information, see :doc:`../performance/runmodes`. + +:: + + runmode: autofp + +Default-packet-size +------------------- + +For the max-pending-packets option, Suricata has to keep packets in +memory. With the default-packet-size option, you can set the size of +the packets on your network. It is possible that bigger packets have +to be processed sometimes. The engine can still process these bigger +packets, but processing it will lower the performance. + +:: + + default-packet-size: 1514 + +User and group +-------------- + +It is possible to set the user and group to run Suricata as: + +:: + + run-as: + user: suri + group: suri + + +.. _suricata-yaml-action-order: + +Action-order +------------ + +All signatures have different properties. One of those is the Action +property. This one determines what will happen when a signature +matches. There are four types of Action. A summary of what will +happen when a signature matches and contains one of those Actions: + +1) Pass + +If a signature matches and contains pass, Suricata stops scanning the +packet and skips to the end of all rules (only for the current +packet). + +2) Drop + +This only concerns the IPS/inline mode. If the program finds a +signature that matches, containing drop, it stops immediately. The +packet will not be sent any further. Drawback: The receiver does not +receive a message of what is going on, resulting in a time-out +(certainly with TCP). Suricata generates an alert for this packet. + +3) Reject + +This is an active rejection of the packet. Both receiver and sender +receive a reject packet. There are two types of reject packets that +will be automatically selected. If the offending packet concerns TCP, +it will be a Reset-packet. For all other protocols it will be an +ICMP-error packet. Suricata also generates an alert. When in +Inline/IPS mode, the offending packet will also be dropped like with +the 'drop' action. + +4) Alert + +If a signature matches and contains alert, the packet will be treated +like any other non-threatening packet, except for this one an alert +will be generated by Suricata. Only the system administrator can +notice this alert. + +Inline/IPS can block network traffic in two ways. One way is by drop +and the other by reject. + +Rules will be loaded in the order of which they appear in files. But +they will be processed in a different order. Signatures have different +priorities. The most important signatures will be scanned first. There +is a possibility to change the order of priority. The default order +is: pass, drop, reject, alert. + +:: + + action-order: + - pass + - drop + - reject + - alert + +This means a pass rule is considered before a drop rule, a drop rule +before a reject rule and so on. + +Splitting configuration in multiple files +----------------------------------------- + +Some users might have a need or a wish to split their suricata.yaml +file in to seperate files, this is available vis the 'include' and +'!include' keyword. The first example is of taking the contents of the +outputs section and storing them in outputs.yaml + +:: + + # outputs.yaml + - fast + enabled: yes + filename: fast.log + append: yes + + - unified2-alert: + enabled: yes + + ... + +:: + + # suricata.yaml + ... + + outputs: !include outputs.yaml + + ... + +The second scenario is where multiple sections are migrated to a +different YAML file. + +:: + + # host_1.yaml + + max-pending-packets: 2048 + + outputs: + - fast + enabled: yes + filename: fast.log + append: yes + + - unified2-alert: + enabled: yes + +:: + + # suricata.yaml + + include: host_1.yaml + + ... + +If the same section, say outputs is later redefined after the include +statement it will overwrite the included file. Therefor any include +statement at the end of the document will overwrite the already +configured sections. + +Event output +------------ + +Default logging directory +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the /var/log/suricata directory, all of Suricata's output (alerts +and events) will be stored. + +:: + + default-log-dir: /var/log/suricata + +This directory can be overridden by entering the -l command line +parameter or by changing the directory directly in Yaml. To change it +with the -l command line parameter, enter the following: + +:: + + suricata -c suricata.yaml -i eth0 -l /var/log/suricata-logs/ + +Outputs +~~~~~~~ + +There are several types of output. The general structure is: + +:: + + outputs: + -fast: + enabled: yes + filename: fast.log + append: yes/no + +Enabling all of the logs, will result in a much lower performance and +the use of more disc space, so enable only the outputs you need. + +Line based alerts log (fast.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log contains alerts consisting of a single line. Example of the +appearance of a single fast.log-file line: + +:: + + 10/05/10-10:08:59.667372  [**] [1:2009187:4] ET WEB_CLIENT ACTIVEX iDefense + COMRaider ActiveX Control Arbitrary File Deletion [**] [Classification: Web + Application Attack] [Priority: 3] {TCP} xx.xx.232.144:80 -> 192.168.1.4:56068 + +:: + + -fast: #The log-name. + enabled:yes #This log is enabled. Set to 'no' to disable. + filename: fast.log #The name of the file in the default logging directory. + append: yes/no #If this option is set to yes, the last filled fast.log-file will not be + #overwritten while restarting Suricata. + +Eve (Extensible Event Format) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is an JSON output for alerts and events. It allows for easy +integration with 3rd party tools like logstash. + +:: + + # Extensible Event Format (nicknamed EVE) event log in JSON format + - eve-log: + enabled: yes + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + types: + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields + + # Enable the logging of tagged packets for rules using the + # "tag" keyword. + tagged-packets: yes + + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + #- drop: + # alerts: yes # log alerts that caused drops + # flows: all # start or all: 'start' logs only a single drop + # # per flow direction. All logs each dropped pkt. + - smtp: + #extended: yes # enable this for extended logging information + # this includes: bcc, message-id, subject, x_mailer, user-agent + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5, date + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] + + - ssh + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values + # bi-directional flows + - flow + # uni-directional flows + #- netflow + +For more advanced configuration options, see :ref:`Eve JSON Output `. + +The format is documented in :ref:`Eve JSON Format `. + +Alert output for use with Barnyard2 (unified2.alert) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log format is a binary format compatible with the unified2 output +of another popular IDS format and is designed for use with Barnyard2 +or other tools that consume the unified2 log format. + +By default a file with the given filename and a timestamp (unix epoch +format) will be created until the file hits the configured size limit, +then a new file, with a new timestamp will be created. It is the job +of other tools, such as Barnyard2 to cleanup old unified2 files. + +If the `nostamp` option is set the log file will not have a timestamp +appended. The file will be re-opened on SIGHUP like other log files +allowing external log rotation tools to work as expected. However, if +the limit is reach the file will be deleted and re-opened. + +This output supports IPv6 and IPv4 events. + +:: + + - unified2-alert: + enabled: yes + + # The filename to log to in the default log directory. A + # timestamp in unix epoch time will be appended to the filename + # unless nostamp is set to yes. + filename: unified2.alert + + # File size limit. Can be specified in kb, mb, gb. Just a number + # is parsed as bytes. + #limit: 32mb + + # By default unified2 log files have the file creation time (in + # unix epoch format) appended to the filename. Set this to yes to + # disable this behaviour. + #nostamp: no + + # Sensor ID field of unified2 alerts. + #sensor-id: 0 + + # Include payload of packets related to alerts. Defaults to true, set to + # false if payload is not required. + #payload: yes + + # HTTP X-Forwarded-For support by adding the unified2 extra header or + # overwriting the source or destination IP address (depending on flow + # direction) with the one reported in the X-Forwarded-For HTTP header. + # This is helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". Note + # that in the "overwrite" mode, if the reported IP address in the HTTP + # X-Forwarded-For header is of a different version of the packet + # received, it will fall-back to "extra-data" mode. + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + +This alert output needs Barnyard2. + +A line based log of HTTP requests (http.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log keeps track of all HTTP-traffic events. It contains the HTTP +request, hostname, URI and the User-Agent. This information will be +stored in the http.log (default name, in the suricata log +directory). This logging can also be performed through the use of the +:ref:`Eve-log capability `. + +Example of a HTTP-log line with non-extended logging: + +:: + + 07/01/2014-04:20:14.338309 vg.no [**] / [**] Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) + AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36 [**] + 192.168.1.6:64685 -> 195.88.54.16:80 + +Example of a HTTP-log line with extended logging: + +:: + + 07/01/2014-04:21:06.994705 vg.no [**] / [**] Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) + AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36 [**] [**] + GET [**] HTTP/1.1 [**] 301 => http://www.vg.no/ [**] 239 bytes [**] 192.168.1.6:64726 -> 195.88.54.16:80 + +:: + + - http-log: #The log-name. + enabled: yes #This log is enabled. Set 'no' to disable. + filename: http.log #The name of the file in the default logging directory. + append: yes/no #If this option is set to yes, the last filled http.log-file will not be + # overwritten while restarting Suricata. + extended: yes # If set to yes more information is written about the event. + +A line based log of DNS queries and replies (dns.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This log keeps track of all DNS events (queries and replies). It +contains the type of DNS activity that has been performed, the +requested / replied domain name and relevant data suck as client, +server, ttl, resource record data. This logging can also be performed +through the use of the :ref:`Eve-log capability ` which +offers easier parsing. + +Example of the apperance of a DNS log of a query with a preceding reply: + +:: + + 07/01/2014-04:07:08.768100 [**] Query TX 14bf [**] zeustracker.abuse.ch [**] A [**] 192.168.1.6:37681 -> 192.168.1.1:53 + 07/01/2014-04:07:08.768100 [**] Response TX 14bf [**] zeustracker.abuse.ch [**] A [**] TTL 60 [**] 205.188.95.206 [**] 192.168.1.1:53 -> 192.168.1.6:37681 + +Non-existant domains and other DNS errors are recorded by the text +representation of the rcode field in the reply (see RFC1035 and +RFC2136 for a list). In the example below a non-existent domain is +resolved and the NXDOMAIN error logged: + +:: + + 02/25/2015-22:58:40.499385 [**] Query TX a3ce [**] nosuchdomainwfqwdqwdqw.com [**] A [**] 192.168.40.10:48361 -> 192.168.40.2:53 + 02/25/2015-22:58:40.499385 [**] Response TX a3ce [**] NXDOMAIN [**] 192.168.40.2:53 -> 192.168.40.10:48361 + 02/25/2015-22:58:40.499385 [**] Response TX a3ce [**] NXDOMAIN [**] 192.168.40.2:53 -> 192.168.40.10:48361 + +Configuration options: + +:: + + - dns-log: # The log-name + enabled: yes # If this log is enabled. Set 'no' to disable + filename: dns.log # Name of this file this log is written to in the default logging directory + append: yes # If this option is set to yes, the (if any exists) dns.log file wil not be overwritten while restarting Suricata. + filetype: regular / unix_stream / unix_dgram + +Packet log (pcap-log) +~~~~~~~~~~~~~~~~~~~~~ + +With the pcap-log option you can save all packets, that are registered +by Suricata, in a log file named _log.pcap_. This way, you can take a +look at all packets whenever you want. In the normal mode a pcap file +is created in the default-log-dir. It can also be created elsewhere if +a absolute path is set in the yaml-file. + +The file that is saved in example the default -log-dir +/var/log/suricata, can be be opened with every program which supports +the pcap file format. This can be Wireshark, TCPdump, Suricata, Snort +and many others. + +The pcap-log option can be enabled and disabled. + +There is a size limit for the pcap-log file that can be set. The +default limit is 32 MB. If the log-file reaches this limit, the file +will be rotated and a new one will be created. The pcap-log option +has an extra functionality for "Sguil":http://sguil.sourceforge.net/ +that can be enabled in the 'mode' option. In the sguil mode the +"sguil_base_dir" indicates the base directory. In this base dir the +pcaps are created in a Sguil-specific directory structure that is +based on the day: + +:: + + $sguil_base_dir/YYYY-MM-DD/$filename. + +If you would like to use Suricata with Sguil, do not forget to enable +(and if necessary modify) the base dir in the suricata.yaml file. +Remember that in the 'normal' mode, the file will be saved in +default-log-dir or in the absolute path (if set). + +By default all packets are logged except: + +- TCP streams beyond stream.reassembly.depth +- encrypted streams after the key exchange + +:: + + - pcap-log: + enabled: yes + filename: log.pcap + + # Limit in MB. + limit: 32 + + mode: sguil # "normal" (default) or sguil. + sguil_base_dir: /nsm_data/ + +Verbose Alerts Log (alert-debug.log) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is a log type that gives supplementary information about an +alert. It is particularly convenient for people who investigate false +positives and who write signatures. However, it lowers the performance +because of the amount of information it has to store. + +:: + + - alert-debug: #The log-name. + enabled: no #This log is not enabled. Set 'yes' to enable. + filename: alert-debug.log #The name of the file in the default logging directory. + append: yes/no #If this option is set to yes, the last filled fast.log-file will not be + # overwritten while restarting Suricata. + +Alert output to prelude (alert-prelude) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To be able to use this type, you have to connect with the prelude +manager first. + +Prelude alerts contain a lot of information and fields, including the +IPfields in of the packet which triggered the alert. This information +can be divided in three parts: + +- The alert description (sensor name, date, ID (sid) of the rule, + etc). This is always included +- The packets headers (almost all IP fields, TCP UDP etc. if relevant) +- A binary form of the entire packet. + +Since the last two parts can be very big (especially since they are +stored in the Prelude SQL database), they are optional and controlled +by the two options 'log_packet_header' and 'log_packet_content'. The +default setting is to log the headers, but not the content. + +The profile name is the name of the Prelude profile used to connect to +the prelude manager. This profile must be registered using an external +command (prelude-admin), and must match the uid/gid of the user that +will run Suricata. The complete procedure is detailed in the `Prelude +Handbook +`_. + +:: + + - alert-prelude: #The log-name. + enabled: no #This log is not enabled. Set 'yes' to enable. + profile: suricata #The profile-name used to connect to the prelude manager. + log_packet_content: no #The log_packet_content is disabled by default. + log_packet_header: yes #The log _packet_header is enabled by default. + +Stats +~~~~~ + +In stats you can set the options for stats.log. When enabling +stats.log you can set the amount of time in seconds after which you +want the output-data to be written to the log file. + +:: + + - stats: + enabled: yes #By default, the stats-option is enabled + filename: stats.log #The log-name. Combined with the default logging directory + #(default-log-dir) it will result in /var/log/suricata/stats.log. + #This directory can be overruled with a absolute path. (A + #directory starting with / ). + interval: 8 #The default amount of time after which the file will be + #refreshed. + append: yes/no #If this option is set to yes, the last filled fast.log-file will not be + #overwritten while restarting Suricata. + +Syslog +~~~~~~ + +With this option it is possible to send all alert and event output to syslog. + +:: + + - syslog: #This is a output-module to direct log-output to several directions. + enabled: no #The use of this output-module is not enabled. + facility: local5 #In this option you can set a syslog facility. + level: Info #In this option you can set the level of output. The possible levels are: + #Emergency, Alert, Critical, Error, Warning, Notice, Info and Debug. + +Drop.log, a line based information for dropped packets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If Suricata works in IPS mode, it can drop packets based on +rules. Packets that are being dropped are saved in the drop.log file, +a Netfilter log format. + +:: + + - drop: + enabled: yes #The option is enabled. + filename: drop.log #The log-name of the file for dropped packets. + append: yes #If this option is set to yes, the last filled drop.log-file will not be + #overwritten while restarting Suricata. If set to 'no' the last filled drop.log file will be overwritten. + +Detection engine +---------------- + +Inspection configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +The detection-engine builds internal groups of signatures. Suricata loads signatures, with which the network traffic will be compared. The fact is, that many rules certainly will not be necessary. (For instance: if there appears a packet with the UDP-protocol, all signatures for the TCP-protocol won't be needed.) For that reason, all signatures will be divided in groups. However, a distribution containing many groups will make use of a lot of memory. Not every type of signature gets its own group. There is a possibility that different signatures with several properties in common, will be placed together in a group. The quantity of groups will determine the balance between memory and performance. A small amount of groups will lower the performance yet uses little memory. The opposite counts for a higher amount of groups. The engine allows you to manage the balance between memory and performance. To manage this, (by determining the amount of groups) there are several general options:high for good performance and more use of memory, low for low performance and little use of memory. The option medium is the balance between performance and memory usage. This is the default setting.The option custom is for advanced users. This option has values which can be managed by the user. + +:: + + detect: + profile: medium + custom-values: + toclient-groups: 2 + toserver-groups: 25 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 + +At all of these options, you can add (or change) a value. Most +signatures have the adjustment to focus on one direction, meaning +focusing exclusively on the server, or exclusively on the client. + +If you take a look at example 4, *the Detection-engine grouping tree*, +you see it has many branches. At the end of each branch, there is +actually a 'sig group head'. Within that sig group head there is a +container which contains a list with signatures that are significant +for that specific group/that specific end of the branch. Also within +the sig group head the settings for Multi-Pattern-Matcher (MPM) can be +found: the MPM-context. + +As will be described again at the part 'Pattern matching settings', +there are several MPM-algorithms of which can be chosen from. Because +every sig group head has its own MPM-context, some algorithms use a +lot of memory. For that reason there is the option sgh-mpm-context to +set whether the groups share one MPM-context, or to set that every +group has its own MPM-context. + +For setting the option sgh-mpm-context, you can choose from auto, full +or single. The default setting is 'auto', meaning Suricata selects +full or single based on the algorithm you use. 'Full' means that every +group has its own MPM-context, and 'single' that all groups share one +MPM-context. The two algorithms ac and ac-gfbs are new in 1.03. These +algorithms use a single MPM-context if the Sgh-MPM-context setting is +'auto'. The rest of the algorithms use full in that case. + +The inspection-recursion-limit option has to mitigate that possible +bugs in Suricata cause big problems. Often Suricata has to deal with +complicated issues. It could end up in an 'endless loop' due to a bug, +meaning it will repeat its actions over and over again. With the +option inspection-recursion-limit you can limit this action. + +*Example 4 Detection-engine grouping tree* + +.. image:: suricata-yaml/grouping_tree.png + +:: + + src Stands for source IP-address. + dst Stands for destination IP-address. + sp Stands for source port. + dp Stands for destination port. + +*Example 5 Detail grouping tree* + +.. image:: suricata-yaml/grouping_tree_detail.png + +.. _suricata-yaml-prefilter: + +Prefilter Engines +~~~~~~~~~~~~~~~~~ + +The concept of prefiltering is that there are far too many rules to inspect individually. The approach prefilter takes is that from each rule one condition is added to prefilter, which is then checked in one step. The most common example is MPM (also known as fast_pattern). This takes a single pattern per rule and adds it to the MPM. Only for those rules that have at least one pattern match in the MPM stage, individual inspection is performed. + +Next to MPM, other types of keywords support prefiltering. ICMP itype, icode, icmp_seq and icmp_id for example. TCP window, IP TTL are other examples. + +For a full list of keywords that support prefilter, see: + +:: + + suricata --list-keywords=all + +Suricata can automatically select prefilter options, or it can be set manually. + +:: + + detect: + prefilter: + default: mpm + +By default, only MPM/fast_pattern is used. + +The prefilter engines for other non-MPM keywords can then be enabled in specific rules by using the 'prefilter' keyword. + +E.g. + +:: + + alert ip any any -> any any (ttl:123; prefilter; sid:1;) + +To let Suricata make these decisions set default to 'auto': + +:: + + detect: + prefilter: + default: auto + + +CUDA (Compute United Device Architecture) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Suricata utilizes CUDA for offloading CPU intensive tasks to the +(NVIDIA) GPU (graphics processing unit). Suricata supports an +experimental multi-pattern-matcher using CUDA. Only if you have +compiled Suricata with CUDA (by entering --enable-cuda in the +configure stage) you can make use of these features. There are +several options for CUDA. The option 'packet_buffer_limit' designates +how many packets will be send to the GPU at the same time. Suricata +sends packets in 'batches', meaning it sends multiple packets at +once. As soon as Suricata has collected the amount of packets set in +the 'packet_buffer_limit' option, it sends them to the GPU. The +default amount of packets is 2400. + +The option 'packet_size_limit' makes sure that packets with payloads +bigger than a certain amount of bytes will not be send to the +GPU. Other packets will be send to the GPU. The default setting is +1500 bytes. + +The option 'packet_buffers' designates the amount of buffers that will +be filled with packets and will be processed. Buffers contain the +batches of packets. During the time these filled buffers are being +processed, new buffers will be filled. + +The option 'batching_timeout' can have all values higher than 0. If a +buffers is not fully filled after a period of time (set in this option +'batching_timeout'), the buffer will be send to the GPU anyway. + +The option 'page_locked' designates whether the page locked memory +will or will not be used. The advantage of page locked memory is that +it can not be swapped out to disk. You would not want your computer to +use your hard disk for Suricata, because it lowers the performance a +lot. In this option you can set whether you still want this for CUDA +or not. + +The option 'device_id' is an option within CUDA to determine which GPU +should be turned to account.(If there is only one GPU present at your +computer, there is no benefit making use of the 'device-id' option.) +To detect the id of your GPU's, enter the following in your command +line: + +:: + + suricata --list-cuda-cards + +With the option 'cuda_streams' you can determine how many cuda-streams +should be used for asynchronous processing. All values > 0 are +valid. For this option you need a device with Compute Capability > 1.0 +and page_locked enabled to have any effect. + +:: + + cuda: + -mpm: + packet_buffer_limit: 2400 + packet_size_limit: 1500 + packet_buffers: 10 + batching_timeout: 1 + page_locked: enabled + device_id: 0 + cuda_streams: 2 + +Pattern matcher settings +~~~~~~~~~~~~~~~~~~~~~~~~ + +The multi-pattern-matcher (MPM) is a part of the detection engine +within Suricata that searches for multiple patterns at +once. Generally, signatures have one ore more patterns. Of each +signature, one pattern is used by the multi-pattern-matcher. That way +Suricata can exclude many signatures from being examined, because a +signature can only match when all its patterns match. + +These are the proceedings: + +1)A packet comes in. + +2)The packed will be analysed by the Multi-pattern-matcher in search + of patterns that match. + +3)All patterns that match, will be further processed by Suricata (signatures). + +*Example 8 Multi-pattern-matcher* + +.. image:: suricata-yaml/MPM2.png + +Suricata offers various implementations of different +multi-pattern-matcher algorithm's. These can be found below. + +To set the multi-pattern-matcher algorithm: + +:: + + mpm-algo: b2gc + +After 'mpm-algo', you can enter one of the following algorithms: b2g, +b2gc, b2gm, b3g, wumanber, ac and ac-gfbs (These last two are new in +1.0.3). For more information about these last two, please read again +the the end of the part 'Detection engine'. These algorithms have no +options, so the fact that below there is no option being mentioned is +no omission. + +Subsequently, you can set the options for the mpm-algorithm's. + +The hash_size option determines the size of the hash-table that is +internal used by the pattern matcher. A low hash-size (small table) +causes lower memory usage, but decreases the performance. The opposite +counts for a high hash-size: higher memory usage, but (generally) +higher performance. The memory settings for hash size of the +algorithms can vary from lowest (2048) - low (4096) - medium (8192) - +high (16384) - higher (32768) – max (65536). (Higher is 'highest' in +YAML 1.0 -1.0.2) + +The bf_size option determines the size of the bloom filter, that is +used with the final step of the pattern matcher, namely the validation +of the pattern. For this option the same counts as for the hash-size +option: setting it to low will cause lower memory usage, but lowers +the performance. The opposite counts for a high setting of the +bf_size: higher memory usage, but (generally) higher performance. The +bloom-filter sizes can vary from low (512) - medium (1024) - high +(2048). + +:: + + pattern-matcher: + - b2gc: + search_algo: B2gSearchBNDMq + hash_size: low #Determines the size of the hash-table. + bf_size: medium #Determines the size of the bloom- filter. + - b3g: + search_algo: B3gSearchBNDMq + hash_size: low #See hash-size -b2gc. + bf_size: medium #See bf-size -b2gc. + - wumanber: + hash_size: low #See hash-size -b2gc. + bf_size: medium #See bf-size -b2gc. + +Threading +--------- + +Suricata is multi-threaded. Suricata uses multiple CPU' s/CPU cores so +it can process a lot of network packets simultaneously. (In a +single-core engine, the packets will be processed one at a time.) + +There are four thread-modules: Packet acquisition, decode and stream +application layer, detection, and outputs. + +# The packet acquisition module reads packets from the network. + +# The decode module decodes the packets and the stream application +application layer has three tasks: + +:: + + First: it performs stream-tracking, meaning it is making sure all steps will be taken to make a correct network-connection. + Second: TCP-network traffic comes in as packets. The Stream-Assembly engine reconstructs the original stream. + Finally: the application layer will be inspected. HTTP and DCERPC will be analyzed. + +# The detection threads will compare signatures. There can be several detection threads so they can operate simultaneously. + +# In Outputs all alerts and events will be processed. + +*Example 6 Threading* + +.. image:: suricata-yaml/threading.png + +:: + + Packet acquisition: Reads packets from the network + Decode: Decodes packets. + Stream app. Layer: Performs stream-tracking and reassembly. + Detect: Compares signatures. + Outputs: Processes all events and alerts. + +Most computers have multiple CPU's/ CPU cores. By default the +operating system determines which core works on which thread. When a +core is already occupied, another one will be designated to work on +the thread. So, which core works on which thread, can differ from time +to time. + +There is an option within threading: + +:: + + set-cpu-affinity: no + +With this option you can cause Suricata setting fixed cores for every +thread. In that case 1, 2 and 4 are at core 0 (zero). Each core has +its own detect thread. The detect thread running on core 0 has a lower +priority than the other threads running on core 0. If these other +cores are to occupied, the detect thread on core 0 has not much +packets to process. De detect threads running on other cores will +process more packets. This is only the case after setting the option +at 'yes'. + +*Example 7 Balancing workload* + +.. image:: suricata-yaml/balancing_workload.png + +You can set the detect-thread-ratio: + +:: + + detect-thread-ratio: 1.5 + +The detect thread-ratio will determine the amount of detect +threads. By default it will be 1.5 x the amount of CPU's/CPU cores +present at your computer. This will result in having more detection +threads then CPU's/ CPU cores. Meaning you are oversubscribing the +amount of cores. This may be convenient at times when there have to be +waited for a detection thread. The remaining detection thread can +become active. + + +In the option 'cpu affinity' you can set which CPU's/cores work on +which thread. In this option there are several sets of threads. The +management-, receive-, decode-, stream-, detect-, verdict-, reject- +and outputs-set. These are fixed names and can not be changed. For +each set there are several options: cpu, mode, and prio. In the +option 'cpu' you can set the numbers of the CPU's/cores which will run +the threads from that set. You can set this option to 'all', use a +range (0-3) or a comma separated list (0,1). The option 'mode' can be +set to 'balanced' or 'exclusive'. When set to 'balanced', the +individual threads can be processed by all cores set in the option +'cpu'. If the option 'mode' is set to 'exclusive', there will be fixed +cores for each thread. As mentioned before, threads can have +different priority's. In the option 'prio' you can set a priority for +each thread. This priority can be low, medium, high or you can set the +priority to 'default'. If you do not set a priority for a CPU, than +the settings in 'default' will count. By default Suricata creates one +'detect' thread per available CPU/CPU core. + +:: + + cpu-affinity: + - management-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - receive-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - decode-cpu-set: + cpu: [ 0, 1 ] + mode: "balanced" + - stream-cpu-set: + cpu: [ "0-1" ] + - detect-cpu-set: + cpu: [ "all" ] + mode: "exclusive" # run detect threads in these cpus + # Use explicitely 3 threads and don't compute number by using + # detect-thread-ratio variable: + # threads: 3 + prio: + low: [ 0 ] + medium: [ "1-2" ] + high: [ 3 ] + default: "medium" + - verdict-cpu-set: + cpu: [ 0 ] + prio: + default: "high" + - reject-cpu-set: + cpu: [ 0 ] + prio: + default: "low" + - output-cpu-set: + cpu: [ "all" ] + prio: + default: "medium" + +Relevant cpu-affinity settings for IDS/IPS modes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +IDS mode +~~~~~~~~ + +Runmode AutoFp:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + recive-cpu-set - used for receive and decode + detect-cpu-set - used for streamtcp,detect,output(logging),reject + +Rumode Workers:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + detect-cpu-set - used for receive,streamtcp,decode,detect,output(logging),respond/reject + + +IPS mode +~~~~~~~~ + +Runmode AutoFp:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + recive-cpu-set - used for receive and decode + detect-cpu-set - used for streamtcp,detect,output(logging) + verdict-cpu-set - used for verdict and respond/reject + +Runmode Workers:: + + management-cpu-set - used for management (example - flow.managers, flow.recyclers) + detect-cpu-set - used for receive,streamtcp,decode,detect,output(logging),respond/reject, verdict + + + +IP Defrag +--------- + +Occasionally network packets appear fragmented. On some networks it +occurs more often than on others. Fragmented packets exist of many +parts. Before Suricata is able to inspect these kind of packets +accurately, the packets have to be reconstructed. This will be done by +a component of Suricata; the defragment-engine. After a fragmented +packet is reconstructed by the defragment-engine, the engine sends on +the reassembled packet to rest of Suricata. + +There are three options within defrag: max-frags, prealloc and +timeout. At the moment Suricata receives a fragment of a packet, it +keeps in memory that other fragments of that packet will appear soon +to complete the packet. However, there is a possibility that one of +the fragments does not appear. To prevent Suricata for keeping waiting +for that packet (thereby using memory) there is a timespan after which +Suricata discards the fragments. This occurs by default after 60 +seconds. + +:: + + defrag: + max-frags: 65535 + prealloc: yes + timeout: 60 + +Flow and Stream handling +------------------------ + +.. _suricata-yaml-flow-settings: + +Flow Settings +~~~~~~~~~~~~~ + +Within Suricata, Flows are very important. They play a big part in the +way Suricata organizes data internally. A flow is a bit similar to a +connection, except a flow is more general.All packets having the same +Tuple (protocol, source IP, destination IP, source-port, +destination-port), belong to the same flow. Packets belonging to a +flow are connected to it internally. + +*Example 9 Flow* + +.. image:: suricata-yaml/flow.png + +*Example 10 Tuple* + +.. image:: suricata-yaml/Tuple1.png + +Keeping track of all these flows, uses memory. The more flows, the +more memory it will cost. + +To keep control over memory usage, there are several options: + +The option memcap for setting the maximum amount of bytes the +flow-engine will use, hash-size for setting the size of the hash-table +and prealloc for the following: + + For packets not yet belonging to a flow, Suricata creates a + new flow. This is a relative expensive action. The risk coming + with it, is that attackers /hackers can a attack the engine + system at this part. When they make sure a computer gets a lot + of packets with different tuples, the engine has to make a lot + of new flows. This way, an attacker could flood the system. To + mitigate the engine from being overloaded, this option + instructs Suricata to keep a number of flows ready in + memory. This way Suricata is less vulnerable to these kind of + attacks. + +The flow-engine has a management thread that operates independent from +the packet processing. This thread is called the flow-manager. This +thread ensures that wherever possible and within the memcap. there +will be 10000 flows prepared. + +:: + + flow: + memcap: 33554432 #The maximum amount of bytes the flow-engine will make use of. + hash_size: 65536 #Flows will be organized in a hash-table. With this option you can set the + #size of the hash-table. + Prealloc: 10000 #The amount of flows Suricata has to keep ready in memory. + +At the point the memcap will still be reached, despite prealloc, the +flow-engine goes into the emergency-mode. In this mode, the engine +will make use of shorter time-outs. It lets flows expire in a more +aggressive manner so there will be more space for new Flows. + +There are two options: emergency_recovery and prune_flows. The +emergency recovery is set on 30. This is the percentage of prealloc'd +flows after which the flow-engine will be back to normal (when 30 +percent of the 10000 flows is completed). + + If during the emergency-mode, the aggressive time-outs do not + have the desired result, this option is the final resort. It + ends some flows even if they have not reached their time-outs + yet. The prune-flows option shows how many flows there will be + terminated at each time a new flow is set up. + +:: + + emergency_recovery: 30 #Percentage of 1000 prealloc'd flows. + prune_flows: 5 #Amount of flows being terminated during the emergency mode. + +Flow Time-Outs +~~~~~~~~~~~~~~ + +The amount of time Suricata keeps a flow in memory is determined by +the Flow time-out. + +There are different states in which a flow can be. Suricata +distinguishes three flow-states for TCP and two for UDP. For TCP, +these are: New, Established and Closed,for UDP only new and +established. For each of these states Suricata can employ different +timeouts. + +The state new in a TCP-flow, means the period during the three way +handshake. The state established is the state when the three way +handshake is completed. The state closed in the TCP-flow: there a +several ways to end a flow. This is by means of Reset or the Four-way +FIN handshake. + +New in a UDP-flow: the state in which packets are send from only one +direction. + +Established in a UDP-flow: packets are send from both directions. + +In the example configuration the are settings for each protocol. TCP, +UDP, ICMP and default (all other protocols). + +:: + + flow-timeouts: + + default: + new: 30 #Time-out in seconds after the last activity in this flow in a New state. + established: 300 #Time-out in seconds after the last activity in this flow in a Established + #state. + emergency_new: 10 #Time-out in seconds after the last activity in this flow in a New state + #during the emergency mode. + emergency_established: 100 #Time-out in seconds after the last activity in this flow in a Established + #state in the emergency mode. + tcp: + new: 60 + established: 3600 + closed: 120 + emergency_new: 10 + emergency_established: 300 + emergency_closed: 20 + udp: + new: 30 + established: 300 + emergency_new: 10 + emergency_established: 100 + icmp: + new: 30 + established: 300 + emergency_new: 10 + emergency_established: 100 + +Stream-engine +~~~~~~~~~~~~~ + +The Stream-engine keeps track of the TCP-connections. The engine +exists of two parts: The stream tracking- and the reassembly-engine. + +The stream-tracking engine monitors the state of a connection. The +reassembly-engine reconstructs the flow as it used to be, so it will +be recognised by Suricata. + +The stream-engine has two memcaps that can be set. One for the +stream-tracking-engine and one for the reassembly-engine. + +The stream-tracking-engine keeps information of the flow in +memory. Information about the state, TCP-sequence-numbers and the TCP +window. For keeping this information, it can make use of the capacity +the memcap allows. + +TCP packets have a so-called checksum. This is an internal code which +makes it possible to see if a packet has arrived in a good state. The +stream-engine will not process packets with a wrong checksum. This +option can be set off by entering 'no' instead of 'yes'. + +:: + + stream: + memcap: 33554432 #Amount of flow-information (in bytes) to keep in memory. + checksum_validation: yes #Validate packet checksum, reject packets with invalid checksums. + +The option 'max_sessions' is the limit for concurrent sessions. It +prevents Suricata from using all memory for sessions. + +To mitigate Suricata from being overloaded by fast session creation, +the option prealloc_sessions instructs Suricata to keep a number of +sessions ready in memory. + +A TCP-session starts with the three-way-handshake. After that, data +can be send en received. A session can last a long time. It can happen +that Suricata will be running after a few sessions have already been +started. This way, Suricata misses the original setup of those +sessions. This setup always includes a lot of information. If you want +Suricata to check the stream from that time on, you can do so by +setting the option 'midstream' to 'true'. The default setting is +'false'. Normally Suricata is able to see all packets of a +connection. Some networks make it more complicated though. Some of the +network-traffic follows a different route than the other part, in +other words: the traffic goes asynchronous. To make sure Suricata will +check the one part it does see, instead of getting confused, the +option 'async-oneside' is brought to life. By default the option is +set to 'false'. + +Suricata inspects content in the normal/IDS mode in chunks. In the +inline/IPS mode it does that on the sliding window way (see example +..) In the case Suricata is set in inline mode, it has to inspect +packets immediately before sending it to the receiver. This way +Suricata is able to drop a packet directly if needed.(see example …) +It is important for Suricata to note which operating system it is +dealing with, because operating systems differ in the way they process +anomalies in streams. See :ref:`host-os-policy`. + +:: + + max_sessions: 262144 # 256k concurrent sessions + prealloc_sessions: 32768 # 32k sessions prealloc'd + midstream: false # do not allow midstream session pickups + async_oneside: false # do not enable async stream handling + inline: no # stream inline mode + +**Example 11 Normal/IDS mode** + +Suricata inspects traffic in chunks. + +.. image:: suricata-yaml/normal_ids.png + +**Example 12 Inline/IPS Sliding Window** + +Suricata inspects traffic in a sliding window manner. + +.. image:: suricata-yaml/inline_mode.png + +**Example 13 Normal/IDS (reasembly on ACK'D data)** + +.. image:: suricata-yaml/Normal_ids_ack_d.png + +**Example 14 Inline/IPS (reassembly on UNACK'D data)** + +.. image:: suricata-yaml/Inline_reassembly_unackd_data.png + +The reassembly-engine has to keep packets in memory to be able to make +a reassembled stream. It can make use of the amount of bytes set +below. Reassembling a stream is an expensive operation. In the option +depth you can set the depth (in a stream) of the reassembling. By +default this is 1MB. + +:: + + reassembly: + memcap: 67108864 #Amount of packets (in bytes) to keep in memory. + depth: 1048576 #The depth of the reassembling. + toserver_chunk_size: 2560 # inspect raw stream in chunks of at least this size + toclient_chunk_size: 2560 # inspect raw stream in chunks of at least + +*Example 15 Stream reassembly* + +.. image:: suricata-yaml/reassembly1.png + +.. image:: suricata-yaml/IDS_chunk_size.png + +Application Layer Parsers +------------------------- + +Asn1_max_frames (new in 1.0.3 and 1.1) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Asn1 (`Abstract Syntax One +`_) is a +standard notation to structure and describe data. + +Within Asn1_max_frames there are several frames. To protect itself, +Suricata will inspect a maximum of 256. You can set this amount +differently if wanted. + +Application layer protocols such as X.400 electronic mail, X.500 and +LDAP directory services, H.323 (VoIP), BACnet and SNMP, use ASN.1 to +describe the protocol data units (PDUs) they exchange. It is also +extensively used in the Access and Non-Access Strata of UMTS. + +Limit for the maximum number of asn1 frames to decode (default 256): + +:: + + asn1_max_frames: 256 + +.. _suricata-yaml-configure-libhtp: + +Configure HTTP (libhtp) +~~~~~~~~~~~~~~~~~~~~~~~ + +The library Libhtp is being used by Suricata to parse HTTP-sessions. + +While processing HTTP-traffic, Suricata has to deal with different +kind of servers which each process anomalies in HTTP-traffic +differently. The most common web-server is Apache. This is a open +source web -server program. + +Beside Apache, IIS (Internet Information Services/Server)a web-server +program of Microsoft is also well-known. + +Like with host-os-policy, it is important for Suricata to which +IP-address/network-address is used by which server. In Libhtp this +assigning of web-servers to IP-and network addresses is called +personality. + +Currently Available Personalities: + +* Minimal +* Generic +* IDS (default) +* IIS_4_0 +* IIS_5_0 +* IIS_5_1 +* IIS_6_0 +* IIS_7_0 +* IIS_7_5 +* Apache +* Apache_2_2 + +You can assign names to each block of settings. Which in this case +is -apache and -iis7. Under these names you can set IP-addresses, +network-addresses the personality and the request-body-limit. + +The version-specific personalities know exactly how web servers +behave, and emulate that. The IDS personality (will be GENERIC in the +future) would try to implement a best-effort approach that would work +reasonably well in the cases where you do not know the specifics. + +The default configuration also applies to every IP-address for which +no specific setting is available. + +HTTP request body's are often big, so they take a lot of time to +process which has a significant impact on the performance. With the +option 'request-body-limit' you can set the limit (in bytes) of the +client-body that will be inspected. Setting it to 0 will inspect all +of the body. + +HTTP response body's are often big, so they take a lot of time to +process which has a significant impact on the performance. With the +option 'response-body-limit' you can set the limit (in bytes) of the +server-body that will be inspected. Setting it to 0 will inspect all +of the body. + +:: + + libhtp: + + default-config: + personality: IDS + request-body-limit: 3072 + response-body-limit: 3072 + + server-config: + - apache: + address: [192.168.1.0/24, 127.0.0.0/8, "::1"] + personality: Apache_2_2 + request-body-limit: 0 + response-body-limit: 0 + + - iis7: + address: + - 192.168.0.0/24 + - 192.168.10.0/24 + personality: IIS_7_0 + request-body-limit: 4096 + response-body-limit: 8192 + +As of 1.4, Suricata makes available the whole set of libhtp +customisations for its users. + +You can now use these parameters in the conf to customise suricata's +use of libhtp. + +:: + + # Configures whether backslash characters are treated as path segment + # separators. They are not on Unix systems, but are on Windows systems. + # If this setting is enabled, a path such as "/one\two/three" will be + # converted to "/one/two/three". Accepted values - yes, no. + #path-backslash-separators: yes + + # Configures whether consecutive path segment separators will be + # compressed. When enabled, a path such as "/one//two" will be normalized + # to "/one/two". The backslash_separators and decode_separators + # parameters are used before compression takes place. For example, if + # backslash_separators and decode_separators are both enabled, the path + # "/one\\/two\/%5cthree/%2f//four" will be converted to + # "/one/two/three/four". Accepted values - yes, no. + #path-compress-separators: yes + + # This parameter is used to predict how a server will react when control + # characters are present in a request path, but does not affect path + # normalization. Accepted values - none or status_400 */ + #path-control-char-handling: none + + # Controls the UTF-8 treatment of request paths. One option is to only + # validate path as UTF-8. In this case, the UTF-8 flags will be raised + # as appropriate, and the path will remain in UTF-8 (if it was UTF-8 in + # the first place). The other option is to convert a UTF-8 path into a + # single byte stream using best-fit mapping. Accepted values - yes, no. + #path-convert-utf8: yes + + # Configures whether encoded path segment separators will be decoded. + # Apache does not do this, but IIS does. If enabled, a path such as + # "/one%2ftwo" will be normalized to "/one/two". If the + # backslash_separators option is also enabled, encoded backslash + # characters will be converted too (and subseqently normalized to + # forward slashes). Accepted values - yes, no. + #path-decode-separators: yes + + # Configures whether %u-encoded sequences in path will be decoded. Such + # sequences will be treated as invalid URL encoding if decoding is not + # desireable. Accepted values - yes, no. + #path-decode-u-encoding: yes + + # Configures how server reacts to invalid encoding in path. Accepted + # values - preserve_percent, remove_percent, decode_invalid, status_400 + #path-invalid-encoding-handling: preserve_percent + + # Configures how server reacts to invalid UTF-8 characters in path. + # This setting will not affect path normalization; it only controls what + # response status we expect for a request that contains invalid UTF-8 + # characters. Accepted values - none, status_400. + #path-invalid-utf8-handling: none + + # Configures how server reacts to encoded NUL bytes. Some servers will + # terminate path at NUL, while some will respond with 400 or 404. When + # the termination option is not used, the NUL byte will remain in the + # path. Accepted values - none, terminate, status_400, status_404. + # path-nul-encoded-handling: none + + # Configures how server reacts to raw NUL bytes. Some servers will + # terminate path at NUL, while some will respond with 400 or 404. When + # the termination option is not used, the NUL byte will remain in the + # path. Accepted values - none, terminate, status_400, status_404. + path-nul-raw-handling: none + + # Sets the replacement characater that will be used to in the lossy + # best-fit mapping from Unicode characters into single-byte streams. + # The question mark is the default replacement character. + #set-path-replacement-char: ? + + # Controls what the library does when it encounters an Unicode character + # where only a single-byte would do (e.g., the %u-encoded characters). + # Conversion always takes place; this parameter is used to correctly + # predict the status code used in response. In the future there will + # probably be an option to convert such characters to UCS-2 or UTF-8. + # Accepted values - bestfit, status_400 and status_404. + #set-path-unicode-mapping: bestfit + +Engine output +------------- + +Logging configuration +~~~~~~~~~~~~~~~~~~~~~ + +The logging subsystem can display all output except alerts and +events. It gives information at runtime about what the engine is +doing. This information can be displayed during the engine startup, at +runtime and while shutting the engine down. For informational +messages, errors, debugging, etc. + +The log-subsystem has several log levels: + +Error, warning, informational and debug. Note that debug level logging +will only be emitted if Suricata was compiled with the --enable-debug +configure option. + +The first option within the logging configuration is the +default-log-level. This option determines the severity/importance +level of information that will be displayed. Messages of lower levels +than the one set here, will not be shown. The default setting is +Info. This means that error, warning and info will be shown and the +other levels won't be. + +There are more levels: emergency, alert, critical and notice, but +those are not used by Suricata yet. This option can be changed in the +configuration, but can also be overridden in the command line by the +environment variable: SC_LOG_LEVEL . + +:: + + logging: + default-log-level: info + +Default log format +~~~~~~~~~~~~~~~~~~ + +A logging line exists of two parts. First it displays meta information +(thread id, date etc.), and finally the actual log message. Example: + +:: + + [27708] 15/10/2010 -- 11:40:07 - (suricata.c:425) (main) – This is Suricata version 1.0.2 + +(Here the part until the – is the meta info, “This is Suricata 1.0.2” +is the actual message.) + +It is possible to determine which information will be displayed in +this line and (the manner how it will be displayed) in which format it +will be displayed. This option is the so called format string:: + + default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " + +The % followed by a character, has a special meaning. There are eight +specified signs: + +:: + + t: Time, timestamp, time and date + example: 15/10/2010 - -11:40:07 + p: Process ID. Suricata's whole processing consists of multiple threads. + i: Thread ID. ID of individual threads. + m: Thread module name. (Outputs, Detect etc.) + d: Log-level of specific log-event. (Error, info, debug etc.) + f: Filename. Name of C-file (source code) where log-event is generated. + l: Line-number within the filename, where the log-event is generated in the source-code. + n: Function-name in the C-code (source code). + +The last three, f, l and n are mainly convenient for developers. + +The log-format can be overridden in the command line by the +environment variable: SC_LOG_FORMAT + +Output-filter +~~~~~~~~~~~~~ + +Within logging you can set an output-filter. With this output-filter +you can set which part of the event-logs should be displayed. You can +supply a regular expression (Regex). A line will be shown if the regex +matches. + +:: + + default-output-filter: #In this option the regular expression can be entered. + +This value is overridden by the environment var: SC_LOG_OP_FILTER + +Outputs +~~~~~~~ + +There are different ways of displaying output. The output can appear +directly on your screen, it can be placed in a file or via syslog. The +last mentioned is an advanced tool for log-management. The tool can be +used to direct log-output to different locations (files, other +computers etc.) + +:: + + outputs: + - console: #Output on your screen. + enabled: yes #This option is enabled. + - file: #Output stored in a file. + enabled: no #This option is not enabled. + filename: /var/log/suricata.log #Filename and location on disc. + - syslog: #This is a program to direct log-output to several directions. + enabled: no #The use of this program is not enabled. + facility: local5 #In this option you can set a syslog facility. + format: "[%i] <%d> -- " #The option to set your own format. + +Packet Acquisition +------------------ + +Pf-ring +~~~~~~~ + +The Pf_ring is a library that aims to improve packet capture +performance over libcap. It performs packet acquisition. There are +three options within Pf_ring: interface, cluster-id and cluster-type. + +:: + + pfring: + interface: eth0 # In this option you can set the network-interface + # on which you want the packets of the network to be read. + +Pf_ring will load balance packets based on flow. All packet +acquisition threads that will participate in the load balancing need +to have the same cluster-id. It is important to make sure this ID is +unique for this cluster of threads, so that no other engine / program +is making use of clusters with the same id. + +:: + + cluster-id: 99 + +Pf_ring can load balance traffic using pf_ring-clusters. All traffic +for pf_ring can be load balanced in one of two ways, in a round robin +manner or a per flow manner that are part of the same cluster. All +traffic for pf_ring will be load balanced across acquisition threads +of the same cluster id. + +The cluster_round_robin manner is a way of distributing packets one at +a time to each thread (like distributing playing cards to fellow +players). The cluster_flow manner is a way of distributing all packets +of the same flow to the same thread. The flows itself will be +distributed to the threads in a round-robin manner. + +:: + + cluster-type: cluster_round_robin + +.. _suricata-yaml-nfq: + +NFQ +~~~ + +Using NFQUEUE in iptables rules, will send packets to Suricata. If the +mode is set to 'accept', the packet that has been send to Suricata by +a rule using NFQ, will by default not be inspected by the rest of the +iptables rules after being processed by Suricata. There are a few more +options to NFQ to change this if desired. + +If the mode is set to 'repeat', the packets will be marked by Suricata +and be re-injected at the first rule of iptables. To mitigate the +packet from being going round in circles, the rule using NFQ will be +skipped because of the mark. + +If the mode is set to 'route', you can make sure the packet will be +send to another tool after being processed by Suricata. It is possible +to assign this tool at the mandatory option 'route_queue'. Every +engine/tool is linked to a queue-number. This number you can add to +the NFQ rule and to the route_queue option. + +Add the numbers of the options repeat_mark and route_queue to the NFQ-rule:: + + iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE + +:: + + nfq: + mode: accept #By default the packet will be accepted or dropped by Suricata + repeat_mark: 1 #If the mode is set to 'repeat', the packets will be marked after being + #processed by Suricata. + repeat_mask: 1 + route_queue: 2 #Here you can assign the queue-number of the tool that Suricata has to + #send the packets to after processing them. + +*Example 1 NFQ1* + +mode: accept + +.. image:: suricata-yaml/NFQ.png + +*Example 2 NFQ* + +mode: repeat + +.. image:: suricata-yaml/NFQ1.png + +*Example 3 NFQ* + +mode: route + +.. image:: suricata-yaml/NFQ2.png + +Ipfw +~~~~ + +Suricata does not only support Linux, it supports the FreeBSD +operating system (this is an open source Unix operating system) and +Mac OS X as well. The in-line mode on FreeBSD uses ipfw (IP-firewall). + +Certain rules in ipfw send network-traffic to Suricata. Rules have +numbers. In this option you can set the rule to which the +network-traffic will be placed back. Make sure this rule comes after +the one that sends the traffic to Suricata, otherwise it will go +around in circles. + +The following tells the engine to re-inject packets back into the ipfw +firewall at rule number 5500: + +:: + + ipfw: + ipfw-reinjection-rule-number: 5500 + +*Example 16 Ipfw-reinjection.* + +.. image:: suricata-yaml/ipfw_reinjection.png + +Rules +----- + +Rule-files +~~~~~~~~~~ + +For different categories of risk there are different rule-files +available containing one or more rules. There is a possibility to +instruct Suricata where to find these rules and which rules you want +to be load for use. You can set the directory where the files can be +found. + +:: + + default-rule-path: /etc/suricata/rules/ + rule-files: + - backdoor.rules + - bad-traffic.rules + - chat.rules + - ddos.rules + - .... + +The above mentioned is an example of rule-files of which can be chosen +from. There are much more rule-files available. + +If wanted, you can set a full path for a specific rule or +rule-file. In that case, the above directory (/etc/suricata/rules/) +will be ignored for that specific file. This is convenient in case you +write your own rules and want to store them separate from other rules +like that of VRT, ET or ET pro. + +If you set a file-name that appears to be not existing, Suricata will +ignore that entry and display a error-message during the engine +startup. It will continue with the startup as usual. + +Threshold-file +~~~~~~~~~~~~~~ + +Within this option, you can state the directory in which the +threshold-file will be stored. The default directory is: +/etc/suricata/threshold.config + +Classifications +~~~~~~~~~~~~~~~ + +The Classification-file is a file which makes the purpose of rules +clear. + +Some rules are just for providing information. Some of them are to +warn you for serious risks like when you are being hacked etc. + +In this classification-file, there is a part submitted to the rule to +make it possible for the system-administrator to distinguish events. + +A rule in this file exists of three parts: the short name, a +description and the priority of the rule (in which 1 has the highest +priority and 4 the lowest). + +You can notice these descriptions returning in the rule and events / alerts. + +:: + + Example: + + configuration classification: misc-activity,Misc activity,3 + + Rule: + + alert tcp $HOME_NET 21 -> $EXTERNAL_NET any (msg:"ET POLICY FTP Login Successful (non-anonymous)"; + flow:from_server,established;flowbits:isset,ET.ftp.user.login; flowbits:isnotset,ftp.user.logged_in; + flowbits:set,ftp.user.logged_in; content:"230 ";pcre:!"/^230(\s+USER)?\s+(anonymous|ftp)/smi"; + classtype:misc-activity; reference:urldoc.emergingthreats.net/2003410,; + reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/POLICY/POLICY_FTP_Login; sid:2003410; rev:7;) + + Event/Alert: + + 10/26/10-10:13:42.904785 [**] [1:2003410:7] ET POLICY FTP Login Successful (non-anonymous) [**] + [Classification: Misc activity[Priority: 3] {TCP} 192.168.0.109:21 -> x.x.x.x:34117 + +You can set the direction of the classification configuration. + +:: + + classification-file: /etc/suricata/classification.config + +.. _suricata-yaml-rule-vars: + +Rule-vars +~~~~~~~~~ + +There are variables which can be used in rules. + +Within rules, there is a possibility to set for which IP-address the +rule should be checked and for which IP-address it should not. + +This way, only relevant rules will be used. To prevent you from having +to set this rule by rule, there is an option in which you can set the +relevant IP-address for several rules. This option contains the +address group vars that will be passed in a rule. So, after HOME_NET +you can enter your home IP-address. + +:: + + vars: + address-groups: + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" #By using [], it is possible to set + #complicated variables. + EXTERNAL_NET: any + HTTP_SERVERS: "$HOME_NET" #The $-sign tells that what follows is + #a variable. + SMTP_SERVERS: "$HOME_NET" + SQL_SERVERS: "$HOME_NET" + DNS_SERVERS: "$HOME_NET" + TELNET_SERVERS: "$HOME_NET" + AIM_SERVERS: any + +It is a convention to use upper-case characters. + +There are two kinds of variables: Address groups and Port-groups. They +both have the same function: change the rule so it will be relevant to +your needs. + +In a rule there is a part assigned to the address and one to the +port. Both have their variable. + +All options have to be set. If it is not necessary to set a specific +address, you should enter 'any'. + +:: + + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + ORACLE_PORTS: 1521 + SSH_PORTS: 22 + +.. _host-os-policy: + +Host-os-policy +~~~~~~~~~~~~~~ + +Operating systems differ in the way they process fragmented packets +and streams. Suricata performs differently with anomalies for +different operating systems. It is important to set of which operating +system your IP-address makes use of, so Suricata knows how to process +fragmented packets and streams. For example in stream-reassembly there +can be packets with overlapping payloads. + +*Example 17 Overlapping payloads* + +.. image:: suricata-yaml/overlap.png + +In the configuration-file, the operating-systems are listed. You can +add your IP-address behind the name of the operating system you make +use of. + +:: + + host-os-policy: + windows: [0.0.0.0/0] + bsd: [] + bsd_right: [] + old_linux: [] + linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] + old_solaris: [] + solaris: ["::1"] + hpux10: [] + hpux11: [] + irix: [] + macos: [] + vista: [] + windows2k3: [] + +Engine analysis and profiling +----------------------------- + +Suricata offers several ways of analyzing performance of rules and the +engine itself. + +Engine-analysis +~~~~~~~~~~~~~~~ + +The option engine-analysis provides information for signature writers +about how Suricata organises signatures internally. + +Like mentioned before, signatures have zero or more patterns on which +they can match. Only one of these patterns will be used by the multi +pattern matcher (MPM). Suricata determines which patterns will be used +unless the fast-pattern rule option is used. + +The option engine-analysis creates a new log file in the default log +dir. In this file all information about signatures and patterns can be +found so signature writers are able to see which pattern is used and +change it if desired. + +To create this log file, you have to run Suricata with +./src/suricata -c suricata.yaml --engine-analysis. + +:: + + engine-analysis: + rules-fast-pattern: yes + +Example: + +:: + + [10703] 26/11/2010 -- 11:41:15 - (detect.c:560) (SigLoadSignatures) + -- Engine-Analyis for fast_pattern printed to file - /var/log/suricata/rules_fast_pattern.txt + + == Sid: 1292 == + Fast pattern matcher: content + Fast pattern set: no + Fast pattern only set: no + Fast pattern chop set: no + Content negated: no + Original content: Volume Serial Number + Final content: Volume Serial Number + + --- + + alert tcp any any -> any any (content:"abc"; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: no + Fast pattern only set: no + Fast pattern chop set: no + Content negated: no + Original content: defghi + Final content: defghi + + --- + + alert tcp any any -> any any (content:"abc"; fast_pattern:only; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: yes + Fast pattern only set: yes + Fast pattern chop set: no + Content negated: no + Original content: abc + Final content: abc + + --- + + alert tcp any any -> any any (content:"abc"; fast_pattern; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: yes + Fast pattern only set: no + Fast pattern chop set: no + Content negated: no + Original content: abc + Final content: abc + + --- + + alert tcp any any -> any any (content:"abc"; fast_pattern:1,2; content:"defghi"; sid:1;) + + == Sid: 1 == + Fast pattern matcher: content + Fast pattern set: yes + Fast pattern only set: no + Fast pattern chop set: yes + Fast pattern offset, length: 1, 2 + Content negated: no + Original content: abc + Final content: bc + +Rule and Packet Profiling settings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rule profiling is a part of Suricata to determine how expensive rules +are. Some rules are very expensive while inspecting traffic. Rule +profiling is convenient for people trying to track performance +problems and resolving them. Also for people writing signatures. + +Compiling Suricata with rule-profiling will have an impact on +performance, even if the option is disabled in the configuration file. + +To observe the rule-performance, there are several options. + +:: + + profiling: + rules: + enabled: yes + +This engine is not used by default. It can only be used if Suricata is +compiled with: + +:: + + -- enable-profiling + +At the end of each session, Suricata will display the profiling +statistics. The list will be displayed sorted. + +This order can be changed as pleased. The choice is between ticks, +avgticks, checks, maxticks and matches. The setting of your choice +will be displayed from high to low. + +The amount of time it takes to check the signatures, will be +administrated by Suricata. This will be counted in ticks. One tick is +one CPU computation. 3 GHz will be 3 billion ticks. + +Beside the amount of checks, ticks and matches it will also display +the average and the maximum of a rule per session at the end of the +line. + +The option Limit determines the amount of signatures of which the +statistics will be shown, based on the sorting. + +:: + + sort: avgticks + limit: 100 + +Example of how the rule statistics can look like; + +:: + + Rule Ticks % Checks Matches Max Tick Avg + Ticks + + 7560 107766621 0.02 138 37 105155334 780917.54 + 11963 1605394413 0.29 2623 1 144418923 612045.14 + 7040 1431034011 0.26 2500 0 106018209 572413.60 + 5726 1437574662 0.26 2623 1 115632900 548065.06 + 7037 1355312799 0.24 2562 0 116048286 529005.78 + 11964 1276449255 0.23 2623 1 96412347 486637.15 + 7042 1272562974 0.23 2623 1 96405993 485155.54 + 5719 1233969192 0.22 2562 0 106439661 481642.93 + 5720 1204053246 0.21 2562 0 125155431 469966.14 + +Packet Profiling +~~~~~~~~~~~~~~~~ + +:: + + packets: + + # Profiling can be disabled here, but it will still have a + # performance impact if compiled in. + + + enabled: yes #this option is enabled by default + filename: packet_stats.log #name of the file in which packet profiling information will be + #stored. + append: yes #If set to yes, new packet profiling information will be added to the + #information that was saved last in the file. + + # per packet csv output + csv: + + # Output can be disabled here, but it will still have a + # performance impact if compiled in. + + enabled: no #the sending of packet output to a csv-file is by default disabled. + filename: packet_stats.csv #name of the file in which csv packet profiling information will be + #stored + +Packet profiling is enabled by default in suricata.yaml but it will +only do its job if you compiled Suricata with --enable profiling. + +The filename in which packet profiling information will be stored, is +packet-stats.log. Information in this file can be added to the last +information that was saved there, or if the append option is set to +no, the existing file will be overwritten. + +Per packet, you can send the output to a csv-file. This file contains +one line for each packet with all profiling information of that +packet. This option can be used only if Suricata is build +with --enable-profiling and if the packet profiling option is enabled +in yaml. + +It is best to use runmode 'single' if you would like to profile the +speed of the code. When using a single thread, there is no situation +in which two threads have to wait for each other . When using two +threads, the time threads might have to wait for each other will be +taken in account when/during profiling packets. For more information +see :doc:`../performance/packet-profiling`. + +Application layers +------------------ + +SSL/TLS +~~~~~~~ + +SSL/TLS parsers track encrypted SSLv2, SSLv3, TLSv1, TLSv1.1 and TLSv1.2 +sessions. + +Protocol detection is done using patterns and a probing parser running +on only TCP/443 by default. The pattern based protocol detection is +port independent. + +:: + + tls: + enabled: yes + detection-ports: + dp: 443 + + # Completely stop processing TLS/SSL session after the handshake + # completed. If bypass is enabled this will also trigger flow + # bypass. If disabled (the default), TLS/SSL session is still + # tracked for Heartbleed and other anomalies. + #no-reassemble: yes + +Encrypted traffic +^^^^^^^^^^^^^^^^^ + +There is no decryption of encrypted traffic, so once the handshake is complete +continued tracking of the session is of limited use. The ``no-reassemble`` +option controls the behaviour after the handshake. + +If ``no-reassemble`` is set to ``true``, all processing of this session is +stopped. No further parsing and inspection happens. If ``bypass`` is enabled +this will lead to the flow being bypassed, either inside Suricata or by the +capture method if it supports it. + +If ``no-reassemble`` is set to ``false``, which is the default, Suricata will +continue to track the SSL/TLS session. Inspection will be limited, as +``content`` inspection will still be disabled. There is no point in doing +pattern matching on traffic known to be encrypted. Inspection for (encrypted) +Heartbleed and other protocol anomalies still happens. + +Modbus +~~~~~~ + +According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it +is recommended to keep the TCP connection opened with a remote device +and not to open and close it for each MODBUS/TCP transaction. +In that case, it is important to set the stream-depth of the modbus as +unlimited. + +:: + + modbus: + # Stream reassembly size for modbus, default is 0 + stream-depth: 0 + +Advanced Options +---------------- + +luajit +~~~~~~ + +states +^^^^^^ + +Luajit has a strange memory requirement, it's 'states' need to be in the +first 2G of the process' memory. For this reason when luajit is used the +states are allocated at the process startup. This option controls how many +states are preallocated. + +If the pool is depleted a warning is generated. Suricata will still try to +continue, but may fail if other parts of the engine take too much memory. +If the pool was depleted a hint will be printed at the engines exit. + +States are allocated as follows: for each detect script a state is used per +detect thread. For each output script, a single state is used. Keep in +mind that a rule reload temporary doubles the states requirement. diff --git a/doc/userguide/configuration/suricata-yaml/IDS_chunk_size.png b/doc/userguide/configuration/suricata-yaml/IDS_chunk_size.png new file mode 100644 index 000000000000..61dcb207d642 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/IDS_chunk_size.png differ diff --git a/doc/userguide/configuration/suricata-yaml/Inline_reassembly_unackd_data.png b/doc/userguide/configuration/suricata-yaml/Inline_reassembly_unackd_data.png new file mode 100644 index 000000000000..f27d972989ca Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/Inline_reassembly_unackd_data.png differ diff --git a/doc/userguide/configuration/suricata-yaml/MPM2.png b/doc/userguide/configuration/suricata-yaml/MPM2.png new file mode 100644 index 000000000000..27cd87caa66c Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/MPM2.png differ diff --git a/doc/userguide/configuration/suricata-yaml/NFQ.png b/doc/userguide/configuration/suricata-yaml/NFQ.png new file mode 100644 index 000000000000..df5c74aa0841 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/NFQ.png differ diff --git a/doc/userguide/configuration/suricata-yaml/NFQ1.png b/doc/userguide/configuration/suricata-yaml/NFQ1.png new file mode 100644 index 000000000000..34ecce51f120 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/NFQ1.png differ diff --git a/doc/userguide/configuration/suricata-yaml/NFQ2.png b/doc/userguide/configuration/suricata-yaml/NFQ2.png new file mode 100644 index 000000000000..de0b25d38393 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/NFQ2.png differ diff --git a/doc/userguide/configuration/suricata-yaml/Normal_ids_ack_d.png b/doc/userguide/configuration/suricata-yaml/Normal_ids_ack_d.png new file mode 100644 index 000000000000..ffb619d1cd5e Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/Normal_ids_ack_d.png differ diff --git a/doc/userguide/configuration/suricata-yaml/Tuple1.png b/doc/userguide/configuration/suricata-yaml/Tuple1.png new file mode 100644 index 000000000000..4bcddb81e6a0 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/Tuple1.png differ diff --git a/doc/userguide/configuration/suricata-yaml/balancing_workload.png b/doc/userguide/configuration/suricata-yaml/balancing_workload.png new file mode 100644 index 000000000000..37dce79bec5a Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/balancing_workload.png differ diff --git a/doc/userguide/configuration/suricata-yaml/flow.png b/doc/userguide/configuration/suricata-yaml/flow.png new file mode 100644 index 000000000000..9e05e921ecb0 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/flow.png differ diff --git a/doc/userguide/configuration/suricata-yaml/grouping_tree.png b/doc/userguide/configuration/suricata-yaml/grouping_tree.png new file mode 100644 index 000000000000..a88d9a207db7 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/grouping_tree.png differ diff --git a/doc/userguide/configuration/suricata-yaml/grouping_tree_detail.png b/doc/userguide/configuration/suricata-yaml/grouping_tree_detail.png new file mode 100644 index 000000000000..472e13a6d622 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/grouping_tree_detail.png differ diff --git a/doc/userguide/configuration/suricata-yaml/inline_mode.png b/doc/userguide/configuration/suricata-yaml/inline_mode.png new file mode 100644 index 000000000000..aadbdf2e3d5e Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/inline_mode.png differ diff --git a/doc/userguide/configuration/suricata-yaml/ipfw_reinjection.png b/doc/userguide/configuration/suricata-yaml/ipfw_reinjection.png new file mode 100644 index 000000000000..c59886707f37 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/ipfw_reinjection.png differ diff --git a/doc/userguide/configuration/suricata-yaml/normal_ids.png b/doc/userguide/configuration/suricata-yaml/normal_ids.png new file mode 100644 index 000000000000..4f3b70bd1452 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/normal_ids.png differ diff --git a/doc/userguide/configuration/suricata-yaml/overlap.png b/doc/userguide/configuration/suricata-yaml/overlap.png new file mode 100644 index 000000000000..3e26c3ee3c2f Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/overlap.png differ diff --git a/doc/userguide/configuration/suricata-yaml/reassembly1.png b/doc/userguide/configuration/suricata-yaml/reassembly1.png new file mode 100644 index 000000000000..afa1162f7743 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/reassembly1.png differ diff --git a/doc/userguide/configuration/suricata-yaml/threading.png b/doc/userguide/configuration/suricata-yaml/threading.png new file mode 100644 index 000000000000..eea27add1e43 Binary files /dev/null and b/doc/userguide/configuration/suricata-yaml/threading.png differ diff --git a/doc/userguide/convert.py b/doc/userguide/convert.py new file mode 100755 index 000000000000..680d5f4e36ef --- /dev/null +++ b/doc/userguide/convert.py @@ -0,0 +1,94 @@ +#! /usr/bin/env python + +import sys +import re +import urlparse +import os.path +import urllib2 +from StringIO import StringIO + +import requests + +def fetch_images(url, dest): + + print("Parsing image URLs from %s." % (url)) + urlparts = urlparse.urlparse(url) + r = requests.get(url) + for m in re.finditer(r"(/attachments/[^\s]+\.png)\"", r.text): + filename = os.path.basename(m.group(1)) + image_url = "%s://%s%s" % ( + urlparts.scheme, urlparts.netloc, m.group(1)) + + if not os.path.exists(dest): + os.makedirs(dest) + + if os.path.exists("%s/%s" % (dest, filename)): + print("Image %s already exists." % (filename)) + continue + + print("Fetching image %s." % (image_url)) + + open(os.path.join(dest, filename), "w").write( + urllib2.urlopen(image_url).read()) + +def main(): + + url = sys.argv[1] + output = sys.argv[2] + + fetch_images(url, output) + + print("Fetching %s." % (url)) + r = requests.get("%s.json" % url) + text = r.json()["wiki_page"]["text"] + text = text.replace("\r", "") + + inpre = False + + with open("%s.rst" % output, "w") as fileobj: + for line in StringIO(text): + + if line.startswith("
"):
+                inpre = True
+                line = line.replace("
", "\n::\n\n  ")
+                if line.find("
") > -1: + print("Removing
from end of line.") + line = line.replace("", "") + inpre = False + + if line.startswith(""): + inpre = False + line = "" + + if inpre and line: + line = " %s" % line + + # Images. + line = re.sub( + r"!([^\s]+)!", r"\n.. image:: %s/\1" % output, line) + + # h1. + if line.startswith("h1."): + line = re.sub("^h1\.\s+", "", line) + line += "=" * (len(line) - 1) + "\n" + + # h2. + if line.startswith("h2."): + line = re.sub("^h2\.\s+", "", line) + line += "-" * (len(line) - 1) + "\n" + + # h3. + if line.startswith("h3."): + line = re.sub("^h3\.\s+", "", line) + line += "~" * (len(line) - 1) + "\n" + + # *bold* -> **bold** + line = re.sub(r"(^|\s)\*([\w:]+)\*", r"\1**\2**", line) + + # _italic_ -> *italic* + line = re.sub(r"\s_(\w+)_\s", r" *\1* ", line) + + fileobj.write(line.encode("utf-8")) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/doc/userguide/file-extraction/file-extraction.rst b/doc/userguide/file-extraction/file-extraction.rst new file mode 100644 index 000000000000..cb7d10259c98 --- /dev/null +++ b/doc/userguide/file-extraction/file-extraction.rst @@ -0,0 +1,101 @@ +File Extraction +=============== + +Architecture +~~~~~~~~~~~~ + +The file extraction code works on top of the HTTP and SMTP parsers. The HTTP parser takes care of dechunking and unzipping the request and/or response data if necessary. The HTTP/SMTP parsers runs on top of the stream reassembly engine. + +This means that settings in the stream engine, reassembly engine and the HTTP parser all affect the workings of the file extraction. + +What files are actually extracted and stored to disk is controlled by the rule language. + + +Settings +~~~~~~~~ + +*stream.checksum_validation* controls whether or not the stream engine rejects packets with invalid checksums. A good idea normally, but the network interface performs checksum offloading a lot of packets may seem to be broken. This setting is enabled by default, and can be disabled by setting to "no". Note that the checksum handling can be controlled per interface, see "checksum_checks" in example configuration. + +*file-store.stream-depth* controls how far into a stream reassembly is done. Beyond this value no reassembly will be done. This means that after this value the HTTP session will no longer be tracked. By default a settings of 1 Megabyte is used. 0 sets it to unlimited. If set to no, it is disabled and stream.reassembly.depth is considered. + +*libhtp.default-config.request-body-limit* / *libhtp.server-config..request-body-limit* controls how much of the HTTP request body is tracked for inspection by the http_client_body keyword, but also used to limit file inspection. A value of 0 means unlimited. + +*libhtp.default-config.response-body-limit* / *libhtp.server-config..response-body-limit* is like the request body limit, only it applies to the HTTP response body. + + +Output +~~~~~~ + +For file extraction two separate output modules were created: +"file-log" and "file-store". They need to be enabled in the +:doc:`../configuration/suricata-yaml`. For "file-store", the "files" +drop dir must be configured. + + +:: + + + - file-store: + enabled: yes # set to yes to enable + log-dir: files # directory to store the files + force-magic: no # force logging magic on all stored files + force-md5: no # force logging of md5 checksums + stream-depth: 1mb # reassemble 1mb into a stream, set to no to disable + waldo: file.waldo # waldo file to store the file_id across runs + +Each file that is stored with have a name "file.". The id will be reset and files will be overwritten unless the waldo option is used. + + +:: + + + - file-log: + enabled: yes + filename: files-json.log + append: yes + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + force-magic: no # force logging magic on all logged files + force-md5: no # force logging of md5 checksums + + +Rules +~~~~~ + +Without rules in place no extraction will happen. The simplest rule would be: + + +:: + + + alert http any any -> any any (msg:"FILE store all"; filestore; sid:1; rev:1;) + +This will simply store all files to disk. + +Want to store all files with a pdf extension? + + +:: + + + alert http any any -> any any (msg:"FILE PDF file claimed"; fileext:"pdf"; filestore; sid:2; rev:1;) + +Or rather all actual pdf files? + + +:: + + + alert http any any -> any any (msg:"FILE pdf detected"; filemagic:"PDF document"; filestore; sid:3; rev:1;) + +Bundled with the Suricata download is a file with more example rules. In the archive, go to the rules/ directory and check the files.rules file. + +MD5 +~~~ + +Suricata can calculate MD5 checksums of files on the fly and log them. See :doc:`md5` for an explanation on how to enable this. + + +.. toctree:: + + md5 + public-sha1-md5-data-sets diff --git a/doc/userguide/file-extraction/md5.rst b/doc/userguide/file-extraction/md5.rst new file mode 100644 index 000000000000..7e992a7d28ef --- /dev/null +++ b/doc/userguide/file-extraction/md5.rst @@ -0,0 +1,141 @@ +.. _md5: + +Storing MD5s checksums +====================== + +Configuration +~~~~~~~~~~~~~ + +In the suricata yaml: + + +:: + + +  - file-store: +       enabled: yes       # set to yes to enable +       log-dir: files    # directory to store the files +       force-magic: yes   # force logging magic on all stored files +       force-md5: yes     # force logging of md5 checksums +       #waldo: file.waldo # waldo file to store the file_id across runs + +Optionally, for JSON output: + + +:: + + + - file-log: + enabled: yes + filename: files-json.log + append: no + +Other settings affecting :doc:`file-extraction` + + +:: + + + stream: + memcap: 64mb + checksum-validation: yes # reject wrong csums + inline: no # no inline mode + reassembly: + memcap: 32mb + depth: 0 # reassemble all of a stream + toserver-chunk-size: 2560 + toclient-chunk-size: 2560 + +Make sure we have *depth: 0* so all files can be tracked fully. + + +:: + + + libhtp: + default-config: + personality: IDS + # Can be specified in kb, mb, gb. Just a number indicates + # it's in bytes. + request-body-limit: 0 + response-body-limit: 0 + +Make sure we have *request-body-limit: 0* and *response-body-limit: 0* + +Testing +~~~~~~~ + +For the purpose of testing we use this rule only in a file.rules (a test/example file): + + +:: + + + alert http any any -> any any (msg:"FILE store all"; filestore; sid:1; rev:1;) + +This rule above will save all the file data for files that are opened/downloaded through HTTP + +Start Suricata (-S option loads ONLY the specified rule file, with disregard if any other rules that are enabled in suricata.yaml): + + +:: + + + suricata -c /etc/suricata/suricata.yaml -S file.rules -i eth0 + + +Meta data: + + +:: + + + TIME:              05/01/2012-11:09:52.425751 + SRC IP:            2.23.144.170 + DST IP:            192.168.1.91 + PROTO:             6 + SRC PORT:          80 + DST PORT:          51598 + HTTP URI:          /en/US/prod/collateral/routers/ps5855/prod_brochure0900aecd8019dc1f.pdf + HTTP HOST:         www.cisco.com + HTTP REFERER:      http://www.cisco.com/c/en/us/products/routers/3800-series-integrated-services-routers-isr/index.html + FILENAME:          /en/US/prod/collateral/routers/ps5855/prod_brochure0900aecd8019dc1f.pdf + MAGIC:             PDF document, version 1.6 + STATE:             CLOSED + MD5:               59eba188e52467adc11bf2442ee5bf57 + SIZE:              9485123 + +and in files-json.log (or eve.json) : + + +:: + + + { "id": 1, "timestamp": "05\/01\/2012-11:10:27.693583", "ipver": 4, "srcip": "2.23.144.170", "dstip": "192.168.1.91", "protocol": 6, "sp": 80, "dp": 51598, "http_uri": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "http_host": "www.cisco.com", "http_referer": "http:\/\/www.google.com\/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDAQFjAA&url=http%3A%2F%2Fwww.cisco.com%2Fen%2FUS%2Fprod%2Fcollateral%2Frouters%2Fps5855%2Fprod_brochure0900aecd8019dc1f.pdf&ei=OqyfT9eoJubi4QTyiamhAw&usg=AFQjCNGdjDBpBDfQv2r3VogSH41V6T5x9Q", "filename": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "magic": "PDF document, version 1.6", "state": "CLOSED", "md5": "59eba188e52467adc11bf2442ee5bf57", "stored": true, "size": 9485123 } + { "id": 12, "timestamp": "05\/01\/2012-11:12:57.421420", "ipver": 4, "srcip": "2.23.144.170", "dstip": "192.168.1.91", "protocol": 6, "sp": 80, "dp": 51598, "http_uri": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "http_host": "www.cisco.com", "http_referer": "http:\/\/www.google.com\/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDAQFjAA&url=http%3A%2F%2Fwww.cisco.com%2Fen%2FUS%2Fprod%2Fcollateral%2Frouters%2Fps5855%2Fprod_brochure0900aecd8019dc1f.pdf&ei=OqyfT9eoJubi4QTyiamhAw&usg=AFQjCNGdjDBpBDfQv2r3VogSH41V6T5x9Q", "filename": "\/en\/US\/prod\/collateral\/routers\/ps5855\/prod_brochure0900aecd8019dc1f.pdf", "magic": "PDF document, version 1.6", "state": "CLOSED", "md5": "59eba188e52467adc11bf2442ee5bf57", "stored": true, "size": 9485123 } + + +Log all MD5s without any rules +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you would like to log MD5s for everything and anything that passes through the traffic that you are inspecting with Suricata, but not log the files themselves, all you have to do is disable file-store and enable only the JSON output with forced MD5s - in suricata.yaml like so: + + +:: + + + - file-store: + enabled: no # set to yes to enable + log-dir: files # directory to store the files + force-magic: yes # force logging magic on all stored files + force-md5: yes # force logging of md5 checksums + #waldo: file.waldo # waldo file to store the file_id across runs + + - file-log: + enabled: yes + filename: files-json.log + append: no + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + force-magic: yes # force logging magic on all logged files + force-md5: yes # force logging of md5 checksums + diff --git a/doc/userguide/file-extraction/public-sha1-md5-data-sets.rst b/doc/userguide/file-extraction/public-sha1-md5-data-sets.rst new file mode 100644 index 000000000000..f5e7d09b3e32 --- /dev/null +++ b/doc/userguide/file-extraction/public-sha1-md5-data-sets.rst @@ -0,0 +1,4 @@ +Public SHA1 MD5 data sets +========================= + +National Software Reference Library - http://www.nsrl.nist.gov/Downloads.htm diff --git a/doc/userguide/index.rst b/doc/userguide/index.rst new file mode 100644 index 000000000000..13f4f6838f28 --- /dev/null +++ b/doc/userguide/index.rst @@ -0,0 +1,26 @@ +Suricata User Guide +=================== + +.. toctree:: + :numbered: + :titlesonly: + + what-is-suricata + install.rst + command-line-options + rules/index.rst + rule-management/index.rst + make-sense-alerts + performance/index.rst + configuration/index.rst + reputation/index.rst + initscripts + setting-up-ipsinline-for-linux + output/index.rst + file-extraction/file-extraction.rst + public-data-sets + capture-hardware/index.rst + unix-socket.rst + manpages/index.rst + acknowledgements + licenses/index.rst diff --git a/doc/userguide/initscripts.rst b/doc/userguide/initscripts.rst new file mode 100644 index 000000000000..a479df239247 --- /dev/null +++ b/doc/userguide/initscripts.rst @@ -0,0 +1,15 @@ +Init Scripts +============ + +For Ubuntu with Upstart, the following can be used in /etc/init/suricata.conf: + + +:: + + + # suricata + description "Intruder Detection System Daemon" + start on runlevel [2345] + stop on runlevel [!2345] + expect fork + exec suricata -D --pidfile /var/run/suricata.pid -c /etc/suricata/suricata.yaml -i eth1 diff --git a/doc/userguide/install.rst b/doc/userguide/install.rst new file mode 100644 index 000000000000..20bd332e7fe3 --- /dev/null +++ b/doc/userguide/install.rst @@ -0,0 +1,149 @@ +Installation +============ + +Before Suricata can be used it has to be installed. Suricata can be installed +on various distributions using binary packages: :ref:`install-binary-packages`. + +For people familiar with compiling their own software, the Source method is +recommended. + +Advanced users can check the advanced guides, see :ref:`install-advanced`. + +Source +------ + +Installing from the source distribution files gives the most control over the Suricata installation. + +Basic steps:: + + tar xzvf suricata-3.2beta1.tar.gz + cd suricata-3.2beta1 + ./configure + make + make install + +This will install Suricata into ``/usr/local/bin/``, use the default +configuration in ``/usr/local/etc/suricata/`` and will output to +``/usr/local/var/log/suricata`` + + +Common configure options +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. option:: --disable-gccmarch-native + + Do not optimize the binary for the hardware it is built on. Add this + flag if the binary is meant to be portable or if Suricata is to be used in a VM. + +.. option:: --prefix=/usr/ + + Installs the Suricata binary into /usr/bin/. Default ``/usr/local/`` + +.. option:: --sysconfdir=/etc + + Installs the Suricata configuration files into /etc/suricata/. Default ``/usr/local/etc/`` + +.. option:: --localstatedir=/var + + Setups Suricata for logging into /var/log/suricata/. Default ``/usr/local/var/log/suricata`` + +.. option:: --enable-lua + + Enables Lua support for detection and output. + +.. option:: --enable-geopip + + Enables GeoIP support for detection. + + +Dependencies +^^^^^^^^^^^^ + +For Suricata's compilation you'll need the following libraries and their development headers installed: + + libpcap, libpcre, libmagic, zlib, libyaml + +The following tools are required: + + make gcc (or clang) pkg-config + +For full features, also add: + + libjansson, libnss, libgeoip, liblua5.1, libhiredis + +Ubuntu/Debian +""""""""""""" + +Minimal:: + + apt-get install libpcre3 libpcre3-dbg libpcre3-dev build-essential libpcap-dev \ + libyaml-0-2 libyaml-dev pkg-config zlib1g zlib1g-dev \ + make libmagic-dev + +Recommended:: + + apt-get install libpcre3 libpcre3-dbg libpcre3-dev build-essential libpcap-dev \ + libnet1-dev libyaml-0-2 libyaml-dev pkg-config zlib1g zlib1g-dev \ + libcap-ng-dev libcap-ng0 make libmagic-dev libjansson-dev \ + libnss3-dev libgeoip-dev liblua5.1-dev libhiredis-dev + +Extra for iptables/nftables IPS integration:: + + apt-get install libnetfilter-queue-dev libnetfilter-queue1 \ + libnetfilter-log-dev libnetfilter-log1 \ + libnfnetlink-dev libnfnetlink0 + +.. _install-binary-packages: + +Binary packages +--------------- + +Ubuntu +^^^^^^ + +For Ubuntu, the OISF maintains a PPA ``suricata-stable`` that always contains the latest stable release. + +To use it:: + + sudo add-apt-repository ppa:oisf/suricata-stable + sudo apt-get update + sudo sudo apt-get install suricata + +Debian +^^^^^^ + +In Debian Jessie Suricata is out of date, but an updated version is in Debian Backports. + +As root do:: + + echo "deb http://http.debian.net/debian jessie-backports main" > \ + /etc/apt/sources.list.d/backports.list + apt-get update + apt-get install suricata -t jessie-backports + +Fedora +^^^^^^ + +:: + + dnf install suricata + +RHEL/CentOS +^^^^^^^^^^^ + +For RedHat Enterprise Linux 7 and CentOS 7 the EPEL repository can be used. + +:: + + yum install epel-release + yum install suricata + + +.. _install-advanced: + +Advanced Installation +--------------------- + +Various installation guides for installing from GIT and for other operating systems are maintained at: +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Installation + diff --git a/doc/userguide/licenses/cc-nc-4.0.rst b/doc/userguide/licenses/cc-nc-4.0.rst new file mode 100644 index 000000000000..2bbdf632630e --- /dev/null +++ b/doc/userguide/licenses/cc-nc-4.0.rst @@ -0,0 +1,169 @@ +Creative Commons Attribution-NonCommercial 4.0 International Public License +=========================================================================== + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. +------------------------ + +a. **Adapted Material** means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. **Adapter's License** means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. **Copyright and Similar Rights** means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +d. **Effective Technological Measures** means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +e. **Exceptions and Limitations** means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +f. **Licensed Material** means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +g. **Licensed Rights** means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +h. **Licensor** means the individual(s) or entity(ies) granting rights under this Public License. + +i. **NonCommercial** means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. + +j. **Share** means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +k. **Sui Generis Database Rights** means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +l. **You** means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. +------------------ + +a. **License grant.** + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and + + B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. + + 2. **Exceptions and Limitations.** For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. **Term.** The term of this Public License is specified in Section 6(a). + + 4. **Media and formats; technical modifications allowed.** The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. **Downstream recipients.** + + A. **Offer from the Licensor – Licensed Material.** Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. **No downstream restrictions.** You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. **No endorsement.** Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. **Other rights.** + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. + +Section 3 – License Conditions. +------------------------------- + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. **Attribution.** + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. + +Section 4 – Sui Generis Database Rights. +---------------------------------------- + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. +----------------------------------------------------------------- + +a. **Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.** + +b. **To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.** + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. +--------------------------------- + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. +--------------------------------------- + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. +--------------------------- + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +**Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” Except for the limited purpose of +indicating that material is shared under a Creative Commons public +license or as otherwise permitted by the Creative Commons policies +published at creativecommons.org/policies, Creative Commons does not +authorize the use of the trademark “Creative Commons” or any other +trademark or logo of Creative Commons without its prior written +consent including, without limitation, in connection with any +unauthorized modifications to any of its public licenses or any other +arrangements, understandings, or agreements concerning use of licensed +material. For the avoidance of doubt, this paragraph does not form +part of the public licenses.** + +**Creative Commons may be contacted at creativecommons.org.** diff --git a/doc/userguide/licenses/gnu-gpl-v2.0.rst b/doc/userguide/licenses/gnu-gpl-v2.0.rst new file mode 100644 index 000000000000..8bcc1b6b261d --- /dev/null +++ b/doc/userguide/licenses/gnu-gpl-v2.0.rst @@ -0,0 +1,340 @@ +GNU General Public License +========================== + +*Version 2, June 1991* +*Copyright © 1989, 1991 Free Software Foundation, Inc.* +*51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA* + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble +~~~~~~~~ + +The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: **(1)** copyright the software, and +**(2)** offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**0.** This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +**2.** You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +* **a)** You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. +* **b)** You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. +* **c)** If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +**3.** You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +* **a)** Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, +* **b)** Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, +* **c)** Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +**7.** If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +**9.** The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +**10.** If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +NO WARRANTY +~~~~~~~~~~~ + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +*END OF TERMS AND CONDITIONS* + +How to Apply These Terms to Your New Programs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type \`show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type \`show c' for details. + +The hypothetical commands \`show w` and \`show c` should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than \`show w' and \`show c`; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + \`Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/doc/userguide/licenses/index.rst b/doc/userguide/licenses/index.rst new file mode 100644 index 000000000000..1326930d943a --- /dev/null +++ b/doc/userguide/licenses/index.rst @@ -0,0 +1,20 @@ +Licenses +======== + +.. toctree:: + :titlesonly: + + gnu-gpl-v2.0 + cc-nc-4.0 + +Suricata Source Code +-------------------- + +The Suricata source code is licensed under version 2 of the +:doc:`gnu-gpl-v2.0`. + +Suricata Documentation +---------------------- + +The Suricata documentation (this documentation) is licensed under the +:doc:`cc-nc-4.0`. diff --git a/doc/userguide/make-sense-alerts.rst b/doc/userguide/make-sense-alerts.rst new file mode 100644 index 000000000000..735b1f9aa911 --- /dev/null +++ b/doc/userguide/make-sense-alerts.rst @@ -0,0 +1,77 @@ +Making sense out of Alerts +========================== + +When alert happens it's important to figure out what it means. Is it +serious? Relevant? A false positive? + +To find out more about the rule that fired, it's always a good idea to +look at the actual rule. + +The first thing to look at in a rule is the description that follows +the "msg" keyword. Lets consider an example: + +:: + + msg:"ET SCAN sipscan probe"; + +The "ET" indicates the rule came from the Emerging Threats +project. "SCAN" indicates the purpose of the rule is to match on some +form of scanning. Following that a more or less detailed description +is given. + +Most rules contain some pointers to more information in the form of +the "reference" keyword. + +Consider the following example rule: + +:: + + + alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS \ + (msg:"ET CURRENT_EVENTS Adobe 0day Shovelware"; \ + flow:established,to_server; content:"GET "; nocase; depth:4; \ + content:!"|0d 0a|Referer\:"; nocase; \ + uricontent:"/ppp/listdir.php?dir="; \ + pcre:"/\/[a-z]{2}\/[a-z]{4}01\/ppp\/listdir\.php\?dir=/U"; \ + classtype:trojan-activity; \ + reference:url,isc.sans.org/diary.html?storyid=7747; \ + reference:url,doc.emergingthreats.net/2010496; \ + reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/CURRENT_EVENTS/CURRENT_Adobe; \ + sid:2010496; rev:2;) + +In this rule the reference keyword indicates 3 url's to visit for more +information: + +:: + + isc.sans.org/diary.html?storyid=7747 + doc.emergingthreats.net/2010496 + www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/CURRENT_EVENTS/CURRENT_Adobe + +Some rules contain a reference like: "reference:cve,2009-3958;" should +allow you to find info about the specific CVE using your favourite +search engine. + +It's not always straight forward and sometimes not all of that +information is available publicly. Usually asking about it on the +signature support lists helps a lot then. + +For the Emerging Threats list this is: +http://lists.emergingthreats.net/mailman/listinfo/emerging-sigs + +For the VRT ruleset: +https://lists.sourceforge.net/lists/listinfo/snort-sigs + +In many cases, looking at just the alert and the packet that triggered +it won't be enough to be conclusive. When running an IDS engine like +Suricata, it's always recommended to combine it with full packet +capturing. Using tools like Sguil or Snorby, the full TCP session or +UDP flow can be inspected. + +For example, if a rule fired that indicates your web application is +attacked, looking at the full TCP session might reveal that the web +application replied with 404 not found. This will usually mean the +attack failed. Usually, not always. + +Obviously there is a lot more to Incidence Response, but this should +get you started. diff --git a/doc/userguide/manpages/index.rst b/doc/userguide/manpages/index.rst new file mode 100644 index 000000000000..3c257d2cb05f --- /dev/null +++ b/doc/userguide/manpages/index.rst @@ -0,0 +1,7 @@ +Man Pages +========= + +.. toctree:: + :maxdepth: 1 + + suricata diff --git a/doc/userguide/manpages/suricata.rst b/doc/userguide/manpages/suricata.rst new file mode 100644 index 000000000000..2cc213969da4 --- /dev/null +++ b/doc/userguide/manpages/suricata.rst @@ -0,0 +1,63 @@ +Suricata +======== + +SYNOPSIS +-------- + +**suricata** [OPTIONS] [BPF FILTER] + +DESCRIPTION +----------- + +Suricata is a high performance Network IDS, IPS and Network Security +Monitoring engine. Open Source and owned by a community run non-profit +foundation, the Open Information Security Foundation (OISF). + +OPTIONS +-------------- + +.. include:: ../partials/options.rst + +OPTIONS FOR DEVELOPERS +---------------------- + +.. include:: ../partials/options-unittests.rst + +SIGNALS +------- + +Suricata will respond to the following signals: + +SIGUSR2 + Causes Suricata to perform a live rule reload. + +SIGHUP + Causes Suricata to close and re-open all log files. This can be + used to re-open log files after they may have been moved away by + log rotation utilities. + +FILES AND DIRECTORIES +--------------------- + +|sysconfdir|/suricata/suricata.yaml + Default location of the Suricata configuration file. + +|localstatedir|/log/suricata + Default Suricata log directory. + +BUGS +---- + +Please visit Suricata's support page for information about submitting +bugs or feature requests. + +NOTES +----- + +* Suricata Home Page + + https://suricata-ids.org/ + +* Suricata Support Page + + https://suricata-ids.org/support/ diff --git a/doc/userguide/output/custom-http-logging.rst b/doc/userguide/output/custom-http-logging.rst new file mode 100644 index 000000000000..f7d21adac5d8 --- /dev/null +++ b/doc/userguide/output/custom-http-logging.rst @@ -0,0 +1,52 @@ +Custom http logging +=================== + +As of Suricata 1.3.1 you can enable a custom http logging option. + +In your Suricata.yaml, find the http-log section and edit as follows: + + +:: + + + - http-log: + enabled: yes + filename: http.log + custom: yes # enable the custom logging format (defined by custom format) + customformat: "%{%D-%H:%M:%S}t.%z %{X-Forwarded-For}i %{User-agent}i %H %m %h %u %s %B %a:%p -> %A:%P" + append: no + #extended: yes # enable this for extended logging information + #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + +And in your http.log file you would get the following, for example: + +:: + + 8/28/12-22:14:21.101619 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 HTTP/1.1 GET us.cnn.com /video/data/3.0/video/world/2012/08/28/hancocks-korea-typhoon-bolavan.cnn/index.xml 200 16856 192.168.1.91:45111 -> 157.166.255.18:80 + +:: + + 08/28/12-22:14:30.693856 - Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 HTTP/1.1 GET us.cnn.com /video/data/3.0/video/showbiz/2012/08/28/conan-reports-from-rnc-convention.teamcoco/index.xml 200 15789 192.168.1.91:45108 -> 157.166.255.18:80 + +The list of supported format strings is the following: + +* %h - Host HTTP Header (remote host name). ie: google.com +* %H - Request Protocol. ie: HTTP/1.1 +* %m - Request Method. ie: GET +* %u - URL including query string. ie: /search?q=suricata +* %{header_name}i - contents of the defined HTTP Request Header name. ie: + + * %{User-agent}i: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:11.0) Gecko/20100101 Firefox/11.0 + * %{X-Forwarded-For}i: outputs the IP address contained in the X-Forwarded-For HTTP header (inserted by a reverse proxy) + +* %s - return status code. In the case of 301 and 302 it will print the url in brackets. ie: 200 +* %B - response size in bytes. ie: 15789 +* %{header_name}o - contents of the defined HTTP Response Header name +* %{strftime_format]t - timestamp of the HTTP transaction in the selected strftime format. ie: 08/28/12-22:14:30 +* %z - precision time in useconds. ie: 693856 +* %a - client IP address +* %p - client port number +* %A - server IP address +* %P - server port number + +Any non printable character will be represented by its byte value in hexadecimal format (\|XX\|, where XX is the hex code) diff --git a/doc/userguide/output/custom-tls-logging.rst b/doc/userguide/output/custom-tls-logging.rst new file mode 100644 index 000000000000..b7031e9073db --- /dev/null +++ b/doc/userguide/output/custom-tls-logging.rst @@ -0,0 +1,43 @@ +Custom tls logging +=================== + +In your Suricata.yaml, find the tls-log section and edit as follows: + +:: + + + - tls-log: + enabled: yes # Log TLS connections. + filename: tls.log # File to store TLS logs. + append: yes + custom: yes # enabled the custom logging format (defined by customformat) + customformat: "%{%D-%H:%M:%S}t.%z %a:%p -> %A:%P %n %n %d %D" + +And in your tls.log file you would get the following, for example: + +:: + + 12/03/16-19:20:14.85859 10.10.10.4:58274 -> 192.0.78.24:443 VERSION='TLS 1.2' suricata-ids.org NOTBEFORE='2016-10-27T20:36:00' NOTAFTER='2017-01-25T20:36:00' + +:: + 12/03/16-19:20:20.36849 10.10.10.4:39472 -> 192.30.253.113:443 VERSION='TLS 1.2' github.com NOTBEFORE='2016-03-10T00:00:00' NOTAFTER='2018-05-17T12:00:00' + + +The list of supported format strings is the following: + +* %n - client SNI +* %v - TLS/SSL version +* %d - certificate date not before +* %D - certificate date not after +* %f - certificate fingerprint SHA1 +* %s - certificate subject +* %i - certificate issuer dn +* %E - extended format +* %{strftime_format}t - timestamp of the TLS transaction in the selected strftime format. ie: 08/28/12-22:14:30 +* %z - precision time in useconds. ie: 693856 +* %a - client IP address +* %p - client port number +* %A - server IP address +* %P - server port number + +Any non printable character will be represented by its byte value in hexadecimal format (\|XX\|, where XX is the hex code) diff --git a/doc/userguide/output/eve/eve-json-examplesjq.rst b/doc/userguide/output/eve/eve-json-examplesjq.rst new file mode 100644 index 000000000000..8bfbf49ef428 --- /dev/null +++ b/doc/userguide/output/eve/eve-json-examplesjq.rst @@ -0,0 +1,80 @@ +Eve JSON 'jq' Examples +====================== + +The jq tool is very useful for quickly parsing and filtering JSON files. This page is contains various examples of how it can be used with Suricata's Eve.json. + +The basics are discussed here: + +* https://www.stamus-networks.com/2015/05/18/looking-at-suricata-json-events-on-command-line/ + +Colorize output +--------------- + + +:: + + + tail -f eve.json | jq -c '.' + + +DNS NXDOMAIN +------------ + + +:: + + + tail -f eve.json|jq -c 'select(.dns.rcode=="NXDOMAIN")' + +Unique HTTP User Agents +----------------------- + + +:: + + + cat eve.json | jq -s '[.[]|.http.http_user_agent]|group_by(.)|map({key:.[0],value:(.|length)})|from_entries' + +Source: https://twitter.com/mattarnao/status/601807374647750657 + + +Data use for a host +------------------- + + +:: + + + tail -n500000 eve.json | jq -s 'map(select(.event_type=="netflow" and .dest_ip=="192.168.1.3").netflow.bytes)|add'|numfmt --to=iec + 1.3G + +Note: can use a lot of memory. +Source: https://twitter.com/pkt_inspector/status/605524218722148352 + + +Monitor part of the stats +------------------------- + + +:: + + + $ tail -f eve.json | jq -c 'select(.event_type=="stats")|.stats.decoder' + +Inspect Alert Data +------------------ + + +:: + + + cat eve.json | jq -r -c 'select(.event_type=="alert")|.payload'|base64 --decode + +Top 10 Destination Ports +------------------------ + + +:: + + + cat eve.json | jq -c 'select(.event_type=="flow")|[.proto, .dest_port]'|sort |uniq -c|sort -nr|head -n10 diff --git a/doc/userguide/output/eve/eve-json-format.rst b/doc/userguide/output/eve/eve-json-format.rst new file mode 100644 index 000000000000..7020f705c5e4 --- /dev/null +++ b/doc/userguide/output/eve/eve-json-format.rst @@ -0,0 +1,258 @@ +.. _eve-json-format: + +Eve JSON Format +=============== + +Example: + +:: + + + { + "timestamp": "2009-11-24T21:27:09.534255", + "event_type": "alert", + "src_ip": "192.168.2.7", + "src_port": 1041, + "dest_ip": "x.x.250.50", + "dest_port": 80, + "proto": "TCP", + "alert": { + "action": "allowed", + "gid": 1, + "signature_id" :2001999, + "rev": 9, + "signature": "ET MALWARE BTGrab.com Spyware Downloading Ads", + "category": "A Network Trojan was detected", + "severity": 1 + } + } + +Common Section +-------------- + +All the JSON log types share a common structure: + +:: + + + {"timestamp":"2009-11-24T21:27:09.534255","event_type":"TYPE", ...tuple... ,"TYPE":{ ... type specific content ... }} + +Event types +~~~~~~~~~~~ + +The common part has a field "event_type" to indicate the log type. + +:: + + + "event_type":"TYPE" + +Event type: Alert +----------------- + +Field action +~~~~~~~~~~~~ + +Possible values: "allowed" and "blocked" + +Example: + +:: + + + "action":"allowed" + +Action is set to "allowed" unless a rule used the "drop" action and Suricata is in IPS mode, or when the rule used the "reject" action. + +Event type: HTTP +---------------- + +Fields +~~~~~~ + +* "hostname": The hostname this HTTP event is attributed to +* "url": URL at the hostname that was accessed +* "http_user_agent": The user-agent of the software that was used +* "http_content_type": The type of data returned (ex: application/x-gzip) +* "cookie" + +In addition to these fields, if the extended logging is enabled in the suricata.yaml file the following fields are (can) also included: + +* "length": The content size of the HTTP body +* "status": HTTP statuscode +* "protocol": Protocol / Version of HTTP (ex: HTTP/1.1) +* "http_method": The HTTP method (ex: GET, POST, HEAD) +* "http_refer": The referer for this action + +In addition to the extended logging fields one can also choose to enable/add from 47 additional custom logging HTTP fields enabled in the suricata.yaml file. The additional fields can be enabled as following: + + +:: + + + - eve-log: + enabled: yes + type: file #file|syslog|unix_dgram|unix_stream + filename: eve.json + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + types: + - alert + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + custom: [accept, accept-charset, accept-encoding, accept-language, + accept-datetime, authorization, cache-control, cookie, from, + max-forwards, origin, pragma, proxy-authorization, range, te, via, + x-requested-with, dnt, x-forwarded-proto, accept-range, age, + allow, connection, content-encoding, content-language, + content-length, content-location, content-md5, content-range, + content-type, date, etags, last-modified, link, location, + proxy-authenticate, referrer, refresh, retry-after, server, + set-cookie, trailer, transfer-encoding, upgrade, vary, warning, + www-authenticate, x-flash-version, x-authenticated-user] + + +The benefits here of using the extended logging is to see if this action for example was a POST or perhaps if a download of an executable actually returned any bytes. + +Examples +~~~~~~~~ + +Event with non-extended logging: + +:: + + + "http": { + "hostname": "www.digip.org", + "url" :"\/jansson\/releases\/jansson-2.6.tar.gz", + "http_user_agent": "", + "http_content_type": "application\/x-gzip" + } + +Event with extended logging: + +:: + + + "http": { + "hostname": "direkte.vg.no", + "url":".....", + "http_user_agent": "", + "http_content_type": "application\/json", + "http_refer": "http:\/\/www.vg.no\/", + "http_method": "GET", + "protocol": "HTTP\/1.1", + "status":"200", + "length":310 + } + +Event type: DNS +--------------- + +Fields +~~~~~~ + +Outline of fields seen in the different kinds of DNS events: + +* "type": Indicating DNS message type, can be "answer" or "query". +* "id": +* "rrname": Resource Record Name (ex: a domain name) +* "rrtype": Resource Record Type (ex: A, AAAA, NS, PTR) +* "rdata": Resource Data (ex. IP that domain name resolves to) +* "ttl": Time-To-Live for this resource record + + +Examples +~~~~~~~~ + +Example of a DNS query for the IPv4 address of "twitter.com" (resource record type 'A'): + +:: + + + "dns": { + "type": "query", + "id": 16000, + "rrname": "twitter.com", + "rrtype":"A" + } + +Example of a DNS answer with an IPv4 (resource record type 'A') return: + +:: + + + "dns": { + "type": "answer", + "id":16000, + "rrname": "twitter.com", + "rrtype":"A", + "ttl":8, + "rdata": "199.16.156.6" + } + +Event type: TLS +--------------- + +Fields +~~~~~~ + +* "subject": The subject field from the TLS certificate +* "issuer": The issuer field from the TLS certificate + +If extended logging is enabled the following fields are also included: + +* "serial": The serial number of the TLS certificate +* "fingerprint": The (SHA1) fingerprint of the TLS certificate +* "sni": The Server Name Indication (SNI) extension sent by the client +* "version": The SSL/TLS version used +* "notbefore": The NotBefore field from the TLS certificate +* "notafter": The NotAfter field from the TLS certificate + +In addition to this, custom logging also allows the following fields: + +* "certificate": The TLS certificate base64 encoded +* "chain": The entire TLS certificate chain base64 encoded + +Examples +~~~~~~~~ + +Example of regular TLS logging: + +:: + + "tls": { + "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com", + "issuerdn": "C=US, O=Google Inc, CN=Google Internet Authority G2" + } + +Example of extended TLS logging: + +:: + + "tls": { + "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com", + "issuerdn": "C=US, O=Google Inc, CN=Google Internet Authority G2", + "serial": "0C:00:99:B7:D7:54:C9:F6:77:26:31:7E:BA:EA:7C:1C", + "fingerprint": "8f:51:12:06:a0:cc:4e:cd:e8:a3:8b:38:f8:87:59:e5:af:95:ca:cd", + "sni": "calendar.google.com", + "version": "TLS 1.2", + "notbefore": "2017-01-04T10:48:43", + "notafter": "2017-03-29T10:18:00" + } + +Example of certificate logging using TLS custom logging (subject, sni, certificate): + +:: + + "tls": { + "subject": "C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.googleapis.com + "sni": "www.googleapis.com", + "certificate": "MIIE3TCCA8WgAwIBAgIIQPsvobRZN0gwDQYJKoZIhvcNAQELBQAwSTELMA [...]" + } diff --git a/doc/userguide/output/eve/eve-json-output.rst b/doc/userguide/output/eve/eve-json-output.rst new file mode 100644 index 000000000000..60279470201d --- /dev/null +++ b/doc/userguide/output/eve/eve-json-output.rst @@ -0,0 +1,354 @@ +.. _eve-json-output: + +Eve JSON Output +=============== + +Suricata can output alerts, http events, dns events, tls events and file info through json. + +The most common way to use this is through 'EVE', which is a firehose approach where all these logs go into a single file. + + +:: + + # Extensible Event Format (nicknamed EVE) event log in JSON format + - eve-log: + enabled: yes + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + types: + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields + + # Enable the logging of tagged packets for rules using the + # "tag" keyword. + tagged-packets: yes + + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For + - http: + extended: yes # enable this for extended logging information + # custom allows additional http fields to be included in eve-log + # the example below adds three additional fields when uncommented + #custom: [Accept-Encoding, Accept-Language, Authorization] + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] + - tls: + extended: yes # enable this for extended logging information + # custom allows to control which tls fields that are included + # in eve-log + #custom: [subject, issuer, fingerprint, sni, version, not_before, not_after, certificate, chain] + + - files: + force-magic: no # force logging magic on all logged files + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + #- drop: + # alerts: yes # log alerts that caused drops + # flows: all # start or all: 'start' logs only a single drop + # # per flow direction. All logs each dropped pkt. + - smtp: + #extended: yes # enable this for extended logging information + # this includes: bcc, message-id, subject, x_mailer, user-agent + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5, date + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] + + - ssh + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values + # bi-directional flows + - flow + # uni-directional flows + #- netflow + +Each alert, http log, etc will go into this one file: 'eve.json'. This file +can then be processed by 3rd party tools like Logstash or jq. + +Output types +~~~~~~~~~~~~ + +EVE can output to multiple methods. ``regular`` is a normal file. Other +options are ``syslog``, ``unix_dgram``, ``unix_stream`` and ``redis``. + +Output types:: + + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry + # the following are valid when type: syslog above + #identity: "suricata" + #facility: local5 + #level: Info ## possible levels: Emergency, Alert, Critical, + ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer + +Alerts +~~~~~~ + +Alerts are event records for rule matches. They can be ammended with metadata, +such as the HTTP record an alert was generated for. + +Metadata:: + + - alert: + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields + +DNS +~~~ + +DNS records are logged one log record per query/answer record. + +YAML:: + + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] + +To reduce verbosity the output can be filtered by supplying the record types +to be logged under ``custom``. + +TLS +~~~ + +TLS records are logged one record per session. + +YAML:: + + - tls: + extended: yes # enable this for extended logging information + # custom allows to control which tls fields that are included + # in eve-log + #custom: [subject, issuer, serial, fingerprint, sni, version, not_before, not_after, certificate, chain] + +The default is to log certificate subject and issuer. If ``extended`` is +enabled, then the log gets more verbose. + +By using ``custom`` it is possible to select which TLS fields to log. + +Date modifiers in filename +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to use date modifiers in the eve-log filename. + +:: + + outputs: + - eve-log: + filename: eve-%s.json + +The example above adds epoch time to the filename. All the date modifiers from the +C library should be supported. See the man page for ``strftime`` for all supported +modifiers. + +Rotate log file +~~~~~~~~~~~~~~~ + +Eve-log can be configured to rotate based on time. + +:: + + outputs: + - eve-log: + filename: eve-%Y-%m-%d-%H:%M.json + rotate-interval: minute + +The example above creates a new log file each minute, where the filename contains +a timestamp. Other supported ``rotate-interval`` values are ``hour`` and ``day``. + +In addition to this, it is also possible to specify the ``rotate-interval`` as a +relative value. One example is to rotate the log file each X seconds. + +:: + + outputs: + - eve-log: + filename: eve-%Y-%m-%d-%H:%M:%S.json + rotate-interval: 30s + +The example above rotates eve-log each 30 seconds. This could be replaced with +``30m`` to rotate every 30 minutes, ``30h`` to rotate every 30 hours, ``30d`` +to rotate every 30 days, or ``30w`` to rotate every 30 weeks. + +Multiple Logger Instances +~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to have multiple 'EVE' instances, for example the following is valid: + +:: + + outputs: + - eve-log: + enabled: yes + type: file + filename: eve-ips.json + types: + - alert + - drop + + - eve-log: + enabled: yes + type: file + filename: eve-nsm.json + types: + - http + - dns + - tls + +So here the alerts and drops go into 'eve-ips.json', while http, dns and tls go into 'eve-nsm.json'. + +In addition to this, each log can be handled completely separately: + +:: + + outputs: + - alert-json-log: + enabled: yes + filename: alert-json.log + - dns-json-log: + enabled: yes + filename: dns-json.log + - drop-json-log: + enabled: yes + filename: drop-json.log + - http-json-log: + enabled: yes + filename: http-json.log + - ssh-json-log: + enabled: yes + filename: ssh-json.log + - tls-json-log: + enabled: yes + filename: tls-json.log + +For most output types, you can add multiple: + +:: + + outputs: + - alert-json-log: + enabled: yes + filename: alert-json1.log + - alert-json-log: + enabled: yes + filename: alert-json2.log + +Except for ``drop`` for which only a single logger instance is supported. + +File permissions +~~~~~~~~~~~~~~~~ + +Log file permissions can be set individually for each logger. ``filemode`` can be used to +control the permissions of a log file, e.g.: + +:: + + outputs: + - eve-log: + enabled: yes + filename: eve.json + filemode: 600 + +The example above sets the file permissions on ``eve.json`` to 600, which means that it is +only readable and writable by the owner of the file. + +JSON flags +~~~~~~~~~~ + +Several flags can be specified to control the JSON output in EVE: + +:: + + outputs: + - eve-log: + json: + # Sort object keys in the same order as they were inserted + preserve-order: yes + + # Make the output more compact + compact: yes + + # Escape all unicode characters outside the ASCII range + ensure-ascii: yes + + # Escape the '/' characters in string with '\/' + escape-slash: yes + +All these flags are enabled by default, and can be modified per EVE instance. diff --git a/doc/userguide/output/eve/index.rst b/doc/userguide/output/eve/index.rst new file mode 100644 index 000000000000..bb56991c2a0a --- /dev/null +++ b/doc/userguide/output/eve/index.rst @@ -0,0 +1,8 @@ +EVE +====== + +.. toctree:: + + eve-json-output + eve-json-format + eve-json-examplesjq diff --git a/doc/userguide/output/files-json/elk/Logstash1.png b/doc/userguide/output/files-json/elk/Logstash1.png new file mode 100644 index 000000000000..1d02def2e0c2 Binary files /dev/null and b/doc/userguide/output/files-json/elk/Logstash1.png differ diff --git a/doc/userguide/output/files-json/elk/Logstash2.png b/doc/userguide/output/files-json/elk/Logstash2.png new file mode 100644 index 000000000000..0eb545c82456 Binary files /dev/null and b/doc/userguide/output/files-json/elk/Logstash2.png differ diff --git a/doc/userguide/output/files-json/elk/Logstash3.png b/doc/userguide/output/files-json/elk/Logstash3.png new file mode 100644 index 000000000000..2c396df51d43 Binary files /dev/null and b/doc/userguide/output/files-json/elk/Logstash3.png differ diff --git a/doc/userguide/output/files-json/elk/Logstash4.png b/doc/userguide/output/files-json/elk/Logstash4.png new file mode 100644 index 000000000000..b5cfc148f48b Binary files /dev/null and b/doc/userguide/output/files-json/elk/Logstash4.png differ diff --git a/doc/userguide/output/files-json/elk/Logstash5.png b/doc/userguide/output/files-json/elk/Logstash5.png new file mode 100644 index 000000000000..64b029d5bdec Binary files /dev/null and b/doc/userguide/output/files-json/elk/Logstash5.png differ diff --git a/doc/userguide/output/files-json/elk/Logstash6.png b/doc/userguide/output/files-json/elk/Logstash6.png new file mode 100644 index 000000000000..97c1f1a20573 Binary files /dev/null and b/doc/userguide/output/files-json/elk/Logstash6.png differ diff --git a/doc/userguide/output/index.rst b/doc/userguide/output/index.rst new file mode 100644 index 000000000000..3c1666c100c1 --- /dev/null +++ b/doc/userguide/output/index.rst @@ -0,0 +1,10 @@ +Output +====== + +.. toctree:: + + eve/index.rst + lua-output + syslog-alerting-comp + custom-http-logging + custom-tls-logging diff --git a/doc/userguide/output/lua-output.rst b/doc/userguide/output/lua-output.rst new file mode 100644 index 000000000000..adef654a0543 --- /dev/null +++ b/doc/userguide/output/lua-output.rst @@ -0,0 +1,711 @@ +Lua Output +========== + +Note: this page new Lua scripting available for outputs. It will be +available in 2.1. + +Script structure +---------------- + +A script defines 4 functions: init, setup, log, deinit + +* init -- registers where the script hooks into the output engine +* setup -- does per output thread setup +* log -- logging function +* deinit -- clean up function + +Example: + +:: + + function init (args) + local needs = {} + needs["protocol"] = "http" + return needs + end + + function setup (args) + filename = SCLogPath() .. "/" .. name + file = assert(io.open(filename, "a")) + SCLogInfo("HTTP Log Filename " .. filename) + http = 0 + end + + function log(args) + http_uri = HttpGetRequestUriRaw() + if http_uri == nil then + http_uri = "" + end + http_uri = string.gsub(http_uri, "%c", ".") + + http_host = HttpGetRequestHost() + if http_host == nil then + http_host = "" + end + http_host = string.gsub(http_host, "%c", ".") + + http_ua = HttpGetRequestHeader("User-Agent") + if http_ua == nil then + http_ua = "" + end + http_ua = string.gsub(http_ua, "%g", ".") + + ts = SCPacketTimeString() + ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() + + file:write (ts .. " " .. http_host .. " [**] " .. http_uri .. " [**] " .. + http_ua .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp .. "\n") + file:flush() + + http = http + 1 + end + + function deinit (args) + SCLogInfo ("HTTP transactions logged: " .. http); + file:close(file) + end + +YAML +---- + +To enable the lua output, add the 'lua' output and add one or more +scripts like so: + +:: + + outputs: + - lua: + enabled: yes + scripts-dir: /etc/suricata/lua-output/ + scripts: + - tcp-data.lua + - flow.lua + +The scripts-dir option is optional. It makes Suricata load the scripts +from this directory. Otherwise scripts will be loaded from the current +workdir. + +packet +------ + +Initialize with: + +:: + + function init (args) + local needs = {} + needs["type"] = "packet" + return needs + end + +SCPacketTimestamp +~~~~~~~~~~~~~~~~~ + +Get packets timestamp as 2 numbers: seconds & microseconds elapsed since +1970-01-01 00:00:00 UTC. + +:: + + function log(args) + local sec, usec = SCPacketTimestamp() + end + +SCPacketTimeString +~~~~~~~~~~~~~~~~~~ + +Add SCPacketTimeString to get the packets time string in the format: +11/24/2009-18:57:25.179869 + +:: + + function log(args) + ts = SCPacketTimeString() + +SCPacketTuple +~~~~~~~~~~~~~ + +:: + + ipver, srcip, dstip, proto, sp, dp = SCPacketTuple() + +SCPacketPayload +~~~~~~~~~~~~~~~ + +:: + + p = SCPacketPayload() + +flow +---- + +:: + + function init (args) + local needs = {} + needs["type"] = "flow" + return needs + end + +SCFlowTimestamps +~~~~~~~~~~~~~~~~ + +Get timestamps (seconds and microseconds) of the first and the last packet from +the flow. + +:: + + startts, lastts = SCFlowTimestamps() + startts_s, lastts_s, startts_us, lastts_us = SCFlowTimestamps() + +SCFlowTimeString +~~~~~~~~~~~~~~~~ + +:: + + startts = SCFlowTimeString() + +SCFlowTuple +~~~~~~~~~~~ + +:: + + ipver, srcip, dstip, proto, sp, dp = SCFlowTuple() + +SCFlowAppLayerProto +~~~~~~~~~~~~~~~~~~~ + +Get alproto as string from the flow. If alproto is not (yet) known, it +returns "unknown". + +Example: + +:: + + function log(args) + alproto = SCFlowAppLayerProto() + if alproto ~= nil then + print (alproto) + end + end + +SCFlowHasAlerts +~~~~~~~~~~~~~~~ + +Returns true if flow has alerts. + +Example: + +:: + + function log(args) + has_alerts = SCFlowHasAlerts() + if has_alerts then + -- do something + end + end + +SCFlowStats +~~~~~~~~~~~ + +Gets the packet and byte counts per flow. + +:: + + tscnt, tsbytes, tccnt, tcbytes = SCFlowStats() + +http +---- + +Init with: + +:: + + function init (args) + local needs = {} + needs["protocol"] = "http" + return needs + end + +HttpGetRequestBody and HttpGetResponseBody. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Make normalized body data available to the script through +HttpGetRequestBody and HttpGetResponseBody. + +There no guarantees that all of the body will be availble. + +Example: + +:: + + function log(args) + a, o, e = HttpGetResponseBody(); + --print("offset " .. o .. " end " .. e) + for n, v in ipairs(a) do + print(v) + end + end + +HttpGetRequestHost +~~~~~~~~~~~~~~~~~~ + +Get the host from libhtp's tx->request_hostname, which can either be +the host portion of the url or the host portion of the Host header. + +Example: + +:: + + http_host = HttpGetRequestHost() + if http_host == nil then + http_host = "" + end + +HttpGetRequestHeader +~~~~~~~~~~~~~~~~~~~~ + +:: + + http_ua = HttpGetRequestHeader("User-Agent") + if http_ua == nil then + http_ua = "" + end + +HttpGetResponseHeader +~~~~~~~~~~~~~~~~~~~~~ + +:: + + server = HttpGetResponseHeader("Server"); + print ("Server: " .. server); + +HttpGetRequestLine +~~~~~~~~~~~~~~~~~~ + +:: + + rl = HttpGetRequestLine(); + print ("Request Line: " .. rl); + +HttpGetResponseLine +~~~~~~~~~~~~~~~~~~~ + +:: + + rsl = HttpGetResponseLine(); + print ("Response Line: " .. rsl); + +HttpGetRawRequestHeaders +~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + rh = HttpGetRawRequestHeaders(); + print ("Raw Request Headers: " .. rh); + +HttpGetRawResponseHeaders +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + rh = HttpGetRawResponseHeaders(); + print ("Raw Response Headers: " .. rh); + +HttpGetRequestUriRaw +~~~~~~~~~~~~~~~~~~~~ + +:: + + http_uri = HttpGetRequestUriRaw() + if http_uri == nil then + http_uri = "" + end + +HttpGetRequestUriNormalized +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + http_uri = HttpGetRequestUriNormalized() + if http_uri == nil then + http_uri = "" + end + +HttpGetRequestHeaders +~~~~~~~~~~~~~~~~~~~~~ + +:: + + a = HttpGetRequestHeaders(); + for n, v in pairs(a) do + print(n,v) + end + +HttpGetResponseHeaders +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + a = HttpGetResponseHeaders(); + for n, v in pairs(a) do + print(n,v) + end + +DNS +--- + +DnsGetQueries +~~~~~~~~~~~~~ + +:: + + dns_query = DnsGetQueries(); + if dns_query ~= nil then + for n, t in pairs(dns_query) do + rrname = t["rrname"] + rrtype = t["type"] + + print ("QUERY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " .. + "TODO" .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp) + end + end + +returns a table of tables + +DnsGetAnswers +~~~~~~~~~~~~~ + +:: + + dns_answers = DnsGetAnswers(); + if dns_answers ~= nil then + for n, t in pairs(dns_answers) do + rrname = t["rrname"] + rrtype = t["type"] + ttl = t["ttl"] + + print ("ANSWER: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " .. + ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp) + end + end + +returns a table of tables + +DnsGetAuthorities +~~~~~~~~~~~~~~~~~ + +:: + + dns_auth = DnsGetAuthorities(); + if dns_auth ~= nil then + for n, t in pairs(dns_auth) do + rrname = t["rrname"] + rrtype = t["type"] + ttl = t["ttl"] + + print ("AUTHORITY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " .. + ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " .. + dstip .. ":" .. dp) + end + end + +returns a table of tables + +DnsGetRcode +~~~~~~~~~~~ + +:: + + rcode = DnsGetRcode(); + if rcode == nil then + return 0 + end + print (rcode) + +returns a lua string with the error message, or nil + +DnsGetRecursionDesired +~~~~~~~~~~~~~~~~~~~~~~ + +:: + + if DnsGetRecursionDesired() == true then + print ("RECURSION DESIRED") + end + +returns a bool + +TLS +--- + +Initialize with: + +:: + + function init (args) + local needs = {} + needs["protocol"] = "tls" + return needs + end + +TlsGetCertInfo +~~~~~~~~~~~~~~ + +Make certificate information available to the script through TlsGetCertInfo. + +Example: + +:: + + function log (args) + version, subject, issuer, fingerprint = TlsGetCertInfo() + if version == nil then + return 0 + end + end + + +TlsGetCertSerial +~~~~~~~~~~~~~~~~ + +Get TLS certificate serial number through TlsGetCertSerial. + +Example: + +:: + + function log (args) + serial = TlsGetCertSerial() + if serial then + -- do something + end + end + +SSH +--- + +Initialize with: + +:: + + + function init (args) + local needs = {} + needs["protocol"] = "ssh" + return needs + end + +SshGetServerProtoVersion +~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH protocol version used by the server through SshGetServerProtoVersion. + +Example: + +:: + + function log (args) + version = SshGetServerProtoVersion() + if version == nil then + return 0 + end + end + +SshGetServerSoftwareVersion +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH software used by the server through SshGetServerSoftwareVersion. + +Example: + +:: + + + function log (args) + software = SshGetServerSoftwareVersion() + if software == nil then + return 0 + end + end + +SshGetClientProtoVersion +~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH protocol version used by the client through SshGetClientProtoVersion. + +Example: + +:: + + function log (args) + version = SshGetClientProtoVersion() + if version == nil then + return 0 + end + end + +SshGetClientSoftwareVersion +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get SSH software used by the client through SshGetClientSoftwareVersion. + +Example: + +:: + + function log (args) + software = SshGetClientSoftwareVersion() + if software == nil then + return 0 + end + end + +Files +----- + +To use the file logging API, the script's init() function needs to look like: + +:: + + function init (args) + local needs = {} + needs['type'] = 'file' + return needs + end + +SCFileInfo +~~~~~~~~~~ + +:: + + + fileid, txid, name, size, magic, md5 = SCFileInfo() + +returns fileid (number), txid (number), name (string), size (number), +magic (string), md5 in hex (string) + +SCFileState +~~~~~~~~~~~ + +:: + + state, stored = SCFileState() + +returns state (string), stored (bool) + +Alerts +------ + +Alerts are a subset of the 'packet' logger: + +:: + + function init (args) + local needs = {} + needs["type"] = "packet" + needs["filter"] = "alerts" + return needs + end + +SCRuleIds +~~~~~~~~~ + +:: + + sid, rev, gid = SCRuleIds() + +SCRuleMsg +~~~~~~~~~ + +:: + + msg = SCRuleMsg() + +SCRuleClass +~~~~~~~~~~~ + +:: + + + class, prio = SCRuleClass() + +Streaming Data +-------------- + +Streaming data can currently log out reassembled TCP data and +normalized HTTP data. The script will be invoked for each consecutive +data chunk. + +In case of TCP reassembled data, all possible overlaps are removed +according to the host OS settings. + +:: + + function init (args) + local needs = {} + needs["type"] = "streaming" + needs["filter"] = "tcp" + return needs + end + +In case of HTTP body data, the bodies are unzipped and dechunked if applicable. + +:: + + function init (args) + local needs = {} + needs["type"] = "streaming" + needs["protocol"] = "http" + return needs + end + +SCStreamingBuffer +~~~~~~~~~~~~~~~~~ + +:: + + function log(args) + data = SCStreamingBuffer() + hex_dump(data) + end + +Misc +---- + +SCThreadInfo +~~~~~~~~~~~~ + +:: + + tid, tname, tgroup = SCThreadInfo() + +It gives: tid (integer), tname (string), tgroup (string) + +SCLogError, SCLogWarning, SCLogNotice, SCLogInfo, SCLogDebug +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Print a message. It will go into the outputs defined in the +yaml. Whether it will be printed depends on the log level. + +Example: + +:: + + SCLogError("some error message") + +SCLogPath +~~~~~~~~~ + +Expose the log path. + +:: + + + name = "fast_lua.log" + function setup (args) + filename = SCLogPath() .. "/" .. name + file = assert(io.open(filename, "a")) + end diff --git a/doc/userguide/output/syslog-alerting-comp.rst b/doc/userguide/output/syslog-alerting-comp.rst new file mode 100644 index 000000000000..26472433ca6d --- /dev/null +++ b/doc/userguide/output/syslog-alerting-comp.rst @@ -0,0 +1,63 @@ +Syslog Alerting Compatibility +============================= + +Suricata can alert via sylog which is a very handy feature for central log collection, compliance, and reporting to a SIEM. Instructions on setting this up can be found in the .yaml file in the section where you can configure what type of alert (and other) logging you would like. + +However, there are different syslog daemons and there can be parsing issues with the syslog format a SIEM expects and what syslog format Suricata sends. The syslog format from Suricata is dependent on the syslog daemon running on the Suricata sensor but often the format it sends is not the format the SIEM expects and cannot parse it properly. + +Popular syslog daemons +---------------------- + +* **syslogd** - logs system messages +* **syslog-ng** - logs system messages but also suports TCP, TLS, and other enhanced enterprise features +* **rsyslogd** - logs system messages but also support TCP, TLS, multi-threading, and other enhanced features +* **klogd** - logs kernel messages +* **sysklogd** - basically a bundle of syslogd and klogd + +If the syslog format the Suricata sensor is sending is not compatible with what your SIEM or syslog collector expects, you will need to fix this. You can do this on your SIEM if it is capable of being able to be configured to interpret the message, or by configuring the syslog daemon on the Suricata sensor itself to send in a format you SIEM can parse. The latter can be done by applying a template to your syslog config file. + +Finding what syslog daemon you are using +---------------------------------------- + +There are many ways to find out what syslog daemon you are using but here is one way: + +:: + + + cd /etc/init.d + ls | grep syslog + +You should see a file with the word syslog in it, e.g. "syslog", "rsyslogd", etc. Obviously if the name is "rsyslogd" you can be fairly confident you are running rsyslogd. If unsure or the filename is just "syslog", take a look at that file. For example, if it was "rsyslogd", run: + +:: + + + less rsyslogd + +At the top you should see a comment line that looks something like this: + +:: + + + # rsyslog Starts rsyslogd/rklogd. + +Locate those files and look at them to give you clues as to what syslog daemon you are running. Also look in the *start()* section of the file you ran "less" on and see what binaries get started because that can give you clues as well. + +Example +------- + +Here is an example where the Suricata sensor is sending syslog messages in rsyslogd format but the SIEM is expecting and parsing them in a sysklogd format. In the syslog configuration file (ususally in /etc with a filename like rsyslog.conf or syslog.conf), first add the template: + +:: + + + $template sysklogd, "<%PRI%>%syslogtag:1:32%%msg:::sp-if-no-1st-sp%%msg%" + +Then send it to the syslog server with the template applied: + +:: + + + user.alert @10.8.75.24:514;sysklogd + +Of course this is just one example and it will probably be different in your environment depending on what syslog daemons and SIEM you use but hopefully this will point you in the right direction. diff --git a/doc/userguide/partials/options-unittests.rst b/doc/userguide/partials/options-unittests.rst new file mode 100644 index 000000000000..68087fa09105 --- /dev/null +++ b/doc/userguide/partials/options-unittests.rst @@ -0,0 +1,25 @@ +.. Options for developers - unittests. + +.. option:: -u + + Run the unit tests and exit. Requires that Suricata be compiled + with *--enable-unittests*. + +.. option:: -U, --unittest-filter=REGEX + + With the -U option you can select which of the unit tests you want + to run. This option uses REGEX. Example of use: suricata -u -U + http + +.. option:: --list-unittests + + List all unit tests. + +.. option:: --fatal-unittests + + Enables fatal failure on a unit test error. Suricata will exit + instead of continuuing more tests. + +.. option:: --unittests-coverage + + Display unit test coverage report. diff --git a/doc/userguide/partials/options.rst b/doc/userguide/partials/options.rst new file mode 100644 index 000000000000..70e2ae985d0e --- /dev/null +++ b/doc/userguide/partials/options.rst @@ -0,0 +1,222 @@ +.. Start with the most common basic options. + +.. option:: -h + + Display a brief usage overview. + +.. option:: -V + + Displays the version of Suricata. + +.. option:: -c + + Path to configuration file. + +.. option:: -T + + Test configuration. + +.. option:: -v + + The -v option enables more verbosity of Suricata's output. Supply + multiple times for more verbosity. + +.. Basic input options. + +.. option:: -r + + Run in pcap offline mode reading files from pcap file. + +.. option:: -i + + After the -i option you can enter the interface card you would like + to use to sniff packets from. This option will try to use the best + capture method available. + +.. option:: --pcap[=] + + Run in PCAP mode. If no device is provided the interfaces + provided in the *pcap* section of the configuration file will be + used. + +.. option:: --af-packet[=] + + Enable capture of packet using AF_PACKET on Linux. If no device is + supplied, the list of devices from the af-packet section in the + yaml is used. + +.. option:: -q + + Run inline of the NFQUEUE queue ID provided. May be provided + multiple times. + +.. Back to other basic options. + +.. option:: -s + + With the -s option you can set a file with signatures, which will + be loaded together with the rules set in the yaml. + +.. option:: -S + + With the -S option you can set a file with signatures, which will + be loaded exclusively, regardless of the rules set in the yaml. + +.. option:: -l + + With the -l option you can set the default log directory. If you + already have the default-log-dir set in yaml, it will not be used + by Suricata if you use the -l option. It will use the log dir that + is set with the -l option. If you do not set a directory with + the -l option, Suricata will use the directory that is set in yaml. + +.. option:: -D + + Normally if you run Suricata on your console, it keeps your console + occupied. You can not use it for other purposes, and when you close + the window, Suricata stops running. If you run Suricata as deamon + (using the -D option), it runs at the background and you will be + able to use the console for other tasks without disturbing the + engine running. + +.. option:: --runmode + + With the *--runmode* option you can set the runmode that you would + like to use. This command line option can override the yaml runmode + option. + + Runmodes are: *workers*, *autofp* and *single*. + + For more information about runmodes see :doc:`Runmodes + ` in the user guide. + +.. option:: -F + + Use BPF filter from file. + +.. option:: -k [all|none] + + Force (all) the checksum check or disable (none) all checksum + checks. + +.. option:: --user= + + Set the process user after initialization. Overrides the user + provided in the *run-as* section of the configuration file. + +.. option:: --group= + + Set the process group to group after initialization. Overrides the + group provided in the *run-as* section of the configuration file. + +.. option:: --pidfile + + Write the process ID to file. Overrides the *pid-file* option in + the configuration file and forces the file to be written when not + running as a daemon. + +.. option:: --init-errors-fatal + + Exit with a failure when errors are encountered loading signatures. + +.. option:: --disable-detection + + Disable the detection engine. + +.. Information options. + +.. option:: --dump-config + + Dump the configuration loaded from the configuration file to the + terminal and exit. + +.. option:: --build-info + + Display the build information the Suricata was built with. + +.. option:: --list-app-layer-protos + + List all supported application layer protocols. + +.. option:: --list-keywords=[all|csv|] + + List all supported rule keywords. + +.. option:: --list-runmodes + + List all supported run modes. + +.. Advanced options. + +.. option:: --set = + + Set a configuration value. Useful for overriding basic + configuration parameters in the configuration. For example, to + change the default log directory:: + + --set default-log-dir=/var/tmp + +.. option:: --engine-analysis + + Print reports on analysis of different sections in the engine and + exit. Please have a look at the conf parameter engine-analysis on + what reports can be printed + +.. option:: --unix-socket= + + Use file as the Suricata unix control socket. Overrides the + *filename* provided in the *unix-command* section of the + configuration file. + +.. Advanced input options. + +.. option:: --pcap-buffer-size= + + Set the size of the PCAP buffer (0 - 2147483647). + +.. option:: --netmap[=] + + Enable capture of packet using NETMAP on FreeBSD or Linux. If no + device is supplied, the list of devices from the netmap section + in the yaml is used. + +.. option:: --pfring[=] + + Enable PF_RING packet capture. If no device provided, the devices in + the Suricata configuration will be used. + +.. option:: --pfring-cluster-id + + Set the PF_RING cluster ID. + +.. option:: --pfring-cluster-type + + Set the PF_RING cluster type (cluster_round_robin, cluster_flow). + +.. option:: -d + + Run inline using IPFW divert mode. + +.. option:: --dag + + Enable packet capture off a DAG card. If capturing off a specific + stream the stream can be select using a device name like + "dag0:4". This option may be provided multiple times read off + multiple devices and/or streams. + +.. option:: --napatech + + Enable packet capture using the Napatech Streams API. + +.. option:: --mpipe + + Enable packet capture using the TileGX mpipe interface. + +.. option:: --erf-in= + + Run in offline mode reading the specific ERF file (Endace + extensible record format). + +.. option:: --simulate-ips + + Simulate IPS mode when running in a non-IPS mode. diff --git a/doc/userguide/performance/high-performance-config.rst b/doc/userguide/performance/high-performance-config.rst new file mode 100644 index 000000000000..19c5e8f62126 --- /dev/null +++ b/doc/userguide/performance/high-performance-config.rst @@ -0,0 +1,19 @@ +High Performance Configuration +============================== + +If you have enough RAM, consider the following options in suricata.yaml to off-load as much work from the CPU's as possible: + +:: + + detect: + profile: custom + custom-values: + toclient-groups: 200 + toserver-groups: 200 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 + +Be advised, however, that this may require lots of RAM for even modestly sized rule sets. Also be aware that having additional CPU's available provides a greater performance boost than having more RAM available. That is, it would be better to spend money on CPU's instead of RAM when configuring a system. + +It may also lead to significantly longer rule loading times. + diff --git a/doc/userguide/performance/hyperscan.rst b/doc/userguide/performance/hyperscan.rst new file mode 100644 index 000000000000..180c4226a9ad --- /dev/null +++ b/doc/userguide/performance/hyperscan.rst @@ -0,0 +1,136 @@ +Hyperscan +========= + +Introduction +~~~~~~~~~~~~ + +"Hyperscan is a high-performance multiple regex matching library." https://01.org/hyperscan + +In Suricata it can be used to perform multi pattern matching (mpm). Support was implemented by Justin Viiret and Jim Xu from Intel: https://github.com/inliniac/suricata/pull/1965, https://redmine.openinfosecfoundation.org/issues/1704 + +Compilation +~~~~~~~~~~~ + +It's possible to pass --with-libhs-includes=/usr/local/include/hs/ --with-libhs-libraries=/usr/local/lib/, although by default this shouldn't be necessary. Suricata should pick up Hyperscan's pkg-config file automagically. + +When Suricata's compilation succeeded, you should have: + +:: + + + suricata --build-info|grep Hyperscan + Hyperscan support: yes + + +Using Hyperscan +~~~~~~~~~~~~~~~ + +To use the hyperscan support edit your suricata.yaml. Change the mpm-algo and spm-algo values to 'hs'. + +Alternatively, use this commandline option: --set mpm-algo=hs --set spm-algo=hs + + + + +Ubuntu Hyperscan Installation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To use Suricata with Hyperscan support, install dependencies: + + +:: + + + apt-get install cmake ragel + +libboost headers +---------------- + +Hyperscan needs the libboost headers from 1.58+. + +On Ubuntu 15.10 or 16.04+, simply do: + + +:: + + + apt-get install libboost-dev + + +Trusty +------ + +Trusty has 1.57, so it's too old. We can grab a newer libboost version, but we *don't* install it system wide. It's only the headers we care about during compilation of Hyperscan. + + +:: + + + sudo apt-get python-dev libbz2-dev + wget http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz + tar xvzf boost_1_60_0.tar.gz + cd boost_1_60_0 + ./bootstrap.sh --prefix=~/tmp/boost-1.60 + ./b2 install + +Hyperscan +--------- + +We'll install version 4.2.0. + + +:: + + + git clone https://github.com/01org/hyperscan + cd hyperscan + mkdir build + cd build + cmake -DBUILD_STATIC_AND_SHARED=1 ../ + +If you have your own libboost headers, use this cmake line instead: + +:: + + + cmake -DBUILD_STATIC_AND_SHARED=1 -DBOOST_ROOT=~/tmp/boost-1.60 ../ + +Finally, make and make install: + +:: + + + make + sudo make install + +Compilation can take a long time, but it should in the end look something like this: + + +:: + + + Install the project... + -- Install configuration: "RELWITHDEBINFO" + -- Installing: /usr/local/lib/pkgconfig/libhs.pc + -- Up-to-date: /usr/local/include/hs/hs.h + -- Up-to-date: /usr/local/include/hs/hs_common.h + -- Up-to-date: /usr/local/include/hs/hs_compile.h + -- Up-to-date: /usr/local/include/hs/hs_runtime.h + -- Installing: /usr/local/lib/libhs_runtime.a + -- Installing: /usr/local/lib/libhs_runtime.so.4.2.0 + -- Installing: /usr/local/lib/libhs_runtime.so.4.2 + -- Installing: /usr/local/lib/libhs_runtime.so + -- Installing: /usr/local/lib/libhs.a + -- Installing: /usr/local/lib/libhs.so.4.2.0 + -- Installing: /usr/local/lib/libhs.so.4.2 + -- Installing: /usr/local/lib/libhs.so + +Note that you may have to add /usr/local/lib to your ld search path + + +:: + + + echo "/usr/local/lib" | sudo tee --append /etc/ld.so.conf.d/usrlocal.conf + sudo ldconfig + diff --git a/doc/userguide/performance/ignoring-traffic.rst b/doc/userguide/performance/ignoring-traffic.rst new file mode 100644 index 000000000000..01bef3197dd9 --- /dev/null +++ b/doc/userguide/performance/ignoring-traffic.rst @@ -0,0 +1,66 @@ +Ignoring Traffic +================ + +In some cases there are reasons to ignore certain traffic. Certain hosts +may be trusted, or perhaps a backup stream should be ignored. + +This document lists some strategies for ignoring traffic. + +capture filters (BPF) +--------------------- + +Through BPFs the capture methods pcap, af-packet and pf_ring can be +told what to send to Suricata, and what not. For example a simple +filter 'tcp' will only send tcp packets. + +If some hosts and or nets need to be ignored, use something like "not +(host IP1 or IP2 or IP3 or net NET/24)". + +Example:: + + not host 1.2.3.4 + +Capture filters are specified on the commandline after all other options:: + + suricata -i eth0 -v not host 1.2.3.4 + suricata -i eno1 -c suricata.yaml tcp or udp + +Capture filters can be set per interface in the pcap, af-packet, netmap +and pf_ring sections. It can also be put in a file:: + + echo "not host 1.2.3.4" > capture-filter.bpf + suricata -i ens5f0 -F capture-filter.bpf + +Using a capture filter limits what traffic Suricata processes. So the +traffic not seen by Suricata will not be inspected, logged or otherwise +recorded. + +pass rules +---------- + +Pass rules are Suricata rules that if matching, pass the packet and in +case of TCP the rest of the flow. They look like normal rules, except +that instead of 'alert' or 'drop' they start with 'pass'. + +Example: + +:: + + pass ip 1.2.3.4 any <> any any (msg:"pass all traffic from/to 1.2.3.4"; sid:1;) + +A big difference with capture filters is that logs such as Eve or http.log +are still generated for this traffic. + +suppress +-------- + +Suppress rules can be used to make sure no alerts are generated for a +host. This is not efficient however, as the suppression is only +considered post-matching. In other words, Suricata first inspects a +rule, and only then will it consider per-host suppressions. + +Example: + +:: + + suppress gen_id 0, sig_id 0, track by_src, ip 1.2.3.4 diff --git a/doc/userguide/performance/index.rst b/doc/userguide/performance/index.rst new file mode 100644 index 000000000000..d43fa658963e --- /dev/null +++ b/doc/userguide/performance/index.rst @@ -0,0 +1,15 @@ +Performance +=========== + +.. toctree:: + + runmodes + packet-capture + tuning-considerations + hyperscan + high-performance-config + statistics + ignoring-traffic + packet-profiling + rule-profiling + tcmalloc diff --git a/doc/userguide/performance/packet-capture.rst b/doc/userguide/performance/packet-capture.rst new file mode 100644 index 000000000000..e860ed597c5a --- /dev/null +++ b/doc/userguide/performance/packet-capture.rst @@ -0,0 +1,80 @@ +Packet Capture +============== + +Load balancing +-------------- + +To get the best performance, Suricata will need to run in 'workers' mode. This effectively means that there are multiple threads, each running a full packet pipeline and each receiving packets from the capture method. This means that we rely on the capture method to distribute the packets over the various threads. One critical aspect of this is that Suricata needs to get both sides of a flow in the same thread, in the correct order. + +The AF_PACKET and PF_RING capture methods both have options to select the 'cluster-type'. These default to 'cluster_flow' which instructs the capture method to hash by flow (5 tuple). This hash is symmetric. Netmap does not have a cluster_flow mode built-in. It can be added separately by using the "'lb' tool":https://github.com/luigirizzo/netmap/tree/master/apps/lb + +> **WARNING** Recent AF_PACKET changes have "broken":https://redmine.openinfosecfoundation.org/issues/1777 this symmetry. Work is under way to "address this":https://redmine.openinfosecfoundation.org/issues/1777#note-7, but for now stay on kernel <=4.2 or update to 4.4.16+, 4.6.5+ or 4.7+. + +On multi-queue NICs, which is almost any modern NIC, RSS settings need to be considered. + + +RSS +--- + +Receive Side Scaling is a technique used by network cards to distribute incoming traffic over various queues on the NIC. This is meant to improve performance but it is important to realize that it was designed for normal traffic, not for the IDS packet capture scenario. RSS using a hash algorithm to distribute the incoming traffic over the various queues. This hash is normally *not* symmetrical. This means that when receiving both sides of a flow, each side may end up in a different queue. Sadly, when deploying Suricata, this is the common scenario when using span ports or taps. + +The problem here is that by having both sides of the traffic in different queues, the order of processing of packets becomes unpredictable. Timing differences on the NIC, the driver, the kernel and in Suricata will lead to a high chance of packets coming in at a different order than on the wire. This is specifically about a mismatch between the two traffic directions. For example, Suricata tracks the TCP 3-way handshake. Due to this timing issue, the SYN/ACK may only be received by Suricata long after the client to server side has already started sending data. Suricata would see this traffic as invalid. + +None of the supported capture methods like AF_PACKET, PF_RING or NETMAP can fix this problem for us. It would require buffering and packet reordering which is expensive. + +To see how many queues are configured: + +:: + + + $ ethtool -l ens2f1 + Channel parameters for ens2f1: + Pre-set maximums: + RX: 0 + TX: 0 + Other: 1 + Combined: 64 + Current hardware settings: + RX: 0 + TX: 0 + Other: 1 + Combined: 8 + +Some NIC's allow you to set it into a symmetric mode. The Intel X(L)710 card can do this in theory, but the drivers aren't capable of enabling this yet (work is underway to try to address this). Another way to address is by setting a special "Random Secret Key" that will make the RSS symmetrical. See http://www.ndsl.kaist.edu/~kyoungsoo/papers/TR-symRSS.pdf (PDF). + +In most scenario's however, the optimal solution is to reduce the number of RSS queues to 1: + +Example: + +:: + + + # Intel X710 with i40e driver: + ethtool -L $DEV combined 1 + +Some drivers do not support setting the number of queues through ethtool. In some cases there is a module load time option. Read the driver docs for the specifics. + + +Offloading +---------- + +Network cards, drivers and the kernel itself have various techniques to speed up packet handling. Generally these will all have to be disabled. + +LRO/GRO lead to merging various smaller packets into big 'super packets'. These will need to be disabled as they break the dsize keyword as well as TCP state tracking. + +Checksum offloading can be left enabled on AF_PACKET and PF_RING, but needs to be disabled on PCAP, NETMAP and others. + + + +Recommendations +--------------- + +Read your drivers documentation! E.g. for i40e the ethtool change of RSS queues may lead to kernel panics if done wrong. + +Generic: set RSS queues to 1 or make sure RSS hashing is symmetric. Disable NIC offloading. + +AF_PACKET: 1 RSS queue and stay on kernel <=4.2 or make sure you have >=4.4.16, >=4.6.5 or >=4.7. Exception: if RSS is symmetric cluster-type 'cluster_qm' can be used to bind Suricata to the RSS queues. Disable NIC offloading except the rx/tx csum. + +PF_RING: 1 RSS queue and use cluster-type 'cluster_flow'. Disable NIC offloading except the rx/tx csum. + +NETMAP: 1 RSS queue. There is no flow based load balancing built-in, but the 'lb' tool can be helpful. Another option is to use the 'autofp' runmode. Exception: if RSS is symmetric, load balancing is based on the RSS hash and multiple RSS queues can be used. Disable all NIC offloading. diff --git a/doc/userguide/performance/packet-profiling.rst b/doc/userguide/performance/packet-profiling.rst new file mode 100644 index 000000000000..3912d26925a2 --- /dev/null +++ b/doc/userguide/performance/packet-profiling.rst @@ -0,0 +1,59 @@ +Packet Profiling +================ + +In this guide will be explained how to enable packet profiling and use +it with the most recent code of Suricata on Ubuntu. It is based on the +assumption that you have already installed Suricata once from the GIT +repository. + +Packet profiling is convenient in case you would like to know how long +packets take to be processed. It is a way to figure out why certain +packets are being processed quicker than others, and this way a good +tool for developing Suricata. + +Update Suricata by following the steps from `Installation from Git +`_. Start +at the end at + +:: + + cd suricata/oisf + git pull + +And follow the described next steps. To enable packet profiling, make +sure you enter the following during the configuring stage: + +:: + + ./configure --enable-profiling + +Find a folder in which you have pcaps. If you do not have pcaps yet, +you can get these with Wireshark. See `Sniffing Packets with Wireshark +`_. + +Go to the directory of your pcaps. For example: + +:: + + cd ~/Desktop + +With the ls command you can see the content of the folder. Choose a +folder and a pcap file + +for example: + +:: + + cd ~/Desktop/2011-05-05 + +Run Suricata with that pcap: + +:: + + suricata -c /etc/suricata/suricata.yaml -r log.pcap.(followed by the number/name of your pcap) + +for example: + +:: + + suricata -c /etc/suricata/suricata.yaml -r log.pcap.1304589204 diff --git a/doc/userguide/performance/rule-profiling.rst b/doc/userguide/performance/rule-profiling.rst new file mode 100644 index 000000000000..f05e8fb4e482 --- /dev/null +++ b/doc/userguide/performance/rule-profiling.rst @@ -0,0 +1,33 @@ +Rule Profiling +============== + +:: + + -------------------------------------------------------------------------- + Date: 9/5/2013 -- 14:59:58 + -------------------------------------------------------------------------- + Num Rule Gid Rev Ticks % Checks Matches Max Ticks Avg Ticks Avg Match Avg No Match + -------- ------------ -------- -------- ------------ ------ -------- -------- ----------- ----------- ----------- -------------- + 1 2210021 1 3 12037 4.96 1 1 12037 12037.00 12037.00 0.00 + 2 2210054 1 1 107479 44.26 12 0 35805 8956.58 0.00 8956.58 + 3 2210053 1 1 4513 1.86 1 0 4513 4513.00 0.00 4513.00 + 4 2210023 1 1 3077 1.27 1 0 3077 3077.00 0.00 3077.00 + 5 2210008 1 1 3028 1.25 1 0 3028 3028.00 0.00 3028.00 + 6 2210009 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 + 7 2210055 1 1 2945 1.21 1 0 2945 2945.00 0.00 2945.00 + 8 2210007 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 + 9 2210005 1 1 2871 1.18 1 0 2871 2871.00 0.00 2871.00 + 10 2210024 1 1 2846 1.17 1 0 2846 2846.00 0.00 2846.00 + +The meaning of the individual fields: + +* Ticks -- total ticks spent on this rule, so a sum of all inspections +* % -- share of this single sig in the total cost of inspection +* Checks -- number of times a signature was inspected +* Matches -- number of times it matched. This may not have resulted in an alert due to suppression and thresholding. +* Max ticks -- single most expensive inspection +* Avg ticks -- per inspection average, so "ticks" / "checks". +* Avg match -- avg ticks spent resulting in match +* Avg No Match -- avg ticks spent resulting in no match. + +The "ticks" are CPU clock ticks: http://en.wikipedia.org/wiki/CPU_time diff --git a/doc/userguide/performance/runmodes.rst b/doc/userguide/performance/runmodes.rst new file mode 100644 index 000000000000..8f05f8de9f38 --- /dev/null +++ b/doc/userguide/performance/runmodes.rst @@ -0,0 +1,35 @@ +Runmodes +======== + +Suricata consists of several 'building blocks' called threads, +thread-modules and queues. A thread is like a process that runs on a +computer. Suricata is multi-threaded, so multiple threads are active +at once. A thread-module is a part of a functionality. One module is +for example for decoding a packet, another is the detect-module and +another one the output-module. A packet can be processed by more than +one thread. The packet will be passed on to the next thread through a +queue. Packets will be processed by one thread at a time, but there +can be multiple packets being processed at a time by the engine. (see +:ref:`suricata-yaml-max-pending-packets`) A thread can have one or +more thread-modules. If they have more modules, they can only be +active on a a time. The way threads, modules and queues are arranged +together is called the Runmode. + +Different runmodes +~~~~~~~~~~~~~~~~~~ + +You can choose a runmode out of several predefined runmodes. The +command line option --list-runmodes shows all available runmodes. All +runmodes have a name: auto, single, autofp. The heaviest task is the +detection; a packet will be checked against thousands of signatures. + +Example of the default runmode: + +.. image:: runmodes/threading1.png + +In the pfring mode, every flow follows its own fixed route in the runmode. + +.. image:: runmodes/Runmode_autofp.png + +For more information about the command line options concerning the +runmode, see :doc:`../command-line-options`. diff --git a/doc/userguide/performance/runmodes/Runmode_autofp.png b/doc/userguide/performance/runmodes/Runmode_autofp.png new file mode 100644 index 000000000000..42db21d731d5 Binary files /dev/null and b/doc/userguide/performance/runmodes/Runmode_autofp.png differ diff --git a/doc/userguide/performance/runmodes/threading1.png b/doc/userguide/performance/runmodes/threading1.png new file mode 100644 index 000000000000..399bf67fcaca Binary files /dev/null and b/doc/userguide/performance/runmodes/threading1.png differ diff --git a/doc/userguide/performance/statistics.rst b/doc/userguide/performance/statistics.rst new file mode 100644 index 000000000000..c2f3a2570f73 --- /dev/null +++ b/doc/userguide/performance/statistics.rst @@ -0,0 +1,161 @@ +Statistics +========== + +The stats.log produces statistics records on a fixed interval, by +default every 8 seconds. + +stats.log file +-------------- + +:: + + ------------------------------------------------------------------- + Counter | TM Name | Value + ------------------------------------------------------------------- + flow_mgr.closed_pruned | FlowManagerThread | 154033 + flow_mgr.new_pruned | FlowManagerThread | 67800 + flow_mgr.est_pruned | FlowManagerThread | 100921 + flow.memuse | FlowManagerThread | 6557568 + flow.spare | FlowManagerThread | 10002 + flow.emerg_mode_entered | FlowManagerThread | 0 + flow.emerg_mode_over | FlowManagerThread | 0 + decoder.pkts | RxPcapem21 | 450001754 + decoder.bytes | RxPcapem21 | 409520714250 + decoder.ipv4 | RxPcapem21 | 449584047 + decoder.ipv6 | RxPcapem21 | 9212 + decoder.ethernet | RxPcapem21 | 450001754 + decoder.raw | RxPcapem21 | 0 + decoder.sll | RxPcapem21 | 0 + decoder.tcp | RxPcapem21 | 448124337 + decoder.udp | RxPcapem21 | 542040 + decoder.sctp | RxPcapem21 | 0 + decoder.icmpv4 | RxPcapem21 | 82292 + decoder.icmpv6 | RxPcapem21 | 9164 + decoder.ppp | RxPcapem21 | 0 + decoder.pppoe | RxPcapem21 | 0 + decoder.gre | RxPcapem21 | 0 + decoder.vlan | RxPcapem21 | 0 + decoder.avg_pkt_size | RxPcapem21 | 910 + decoder.max_pkt_size | RxPcapem21 | 1514 + defrag.ipv4.fragments | RxPcapem21 | 4 + defrag.ipv4.reassembled | RxPcapem21 | 1 + defrag.ipv4.timeouts | RxPcapem21 | 0 + defrag.ipv6.fragments | RxPcapem21 | 0 + defrag.ipv6.reassembled | RxPcapem21 | 0 + defrag.ipv6.timeouts | RxPcapem21 | 0 + tcp.sessions | Detect | 41184 + tcp.ssn_memcap_drop | Detect | 0 + tcp.pseudo | Detect | 2087 + tcp.invalid_checksum | Detect | 8358 + tcp.no_flow | Detect | 0 + tcp.reused_ssn | Detect | 11 + tcp.memuse | Detect | 36175872 + tcp.syn | Detect | 85902 + tcp.synack | Detect | 83385 + tcp.rst | Detect | 84326 + tcp.segment_memcap_drop | Detect | 0 + tcp.stream_depth_reached | Detect | 109 + tcp.reassembly_memuse | Detect | 67755264 + tcp.reassembly_gap | Detect | 789 + detect.alert | Detect | 14721 + +Detecting packet loss +~~~~~~~~~~~~~~~~~~~~~ + +At shut down, Suricata reports the packet loss statistics it gets from +pcap, pfring or afpacket + +:: + + [18088] 30/5/2012 -- 07:39:18 - (RxPcapem21) Packets 451595939, bytes 410869083410 + [18088] 30/5/2012 -- 07:39:18 - (RxPcapem21) Pcap Total:451674222 Recv:451596129 Drop:78093 (0.0%). + +Usually, this is not the complete story though. These are kernel drop +stats, but the NIC may also have dropped packets. Use ethtool to get +to those: + +:: + + # ethtool -S em2 + NIC statistics: + rx_packets: 35430208463 + tx_packets: 216072 + rx_bytes: 32454370137414 + tx_bytes: 53624450 + rx_broadcast: 17424355 + tx_broadcast: 133508 + rx_multicast: 5332175 + tx_multicast: 82564 + rx_errors: 47 + tx_errors: 0 + tx_dropped: 0 + multicast: 5332175 + collisions: 0 + rx_length_errors: 0 + rx_over_errors: 0 + rx_crc_errors: 51 + rx_frame_errors: 0 + rx_no_buffer_count: 0 + rx_missed_errors: 0 + tx_aborted_errors: 0 + tx_carrier_errors: 0 + tx_fifo_errors: 0 + tx_heartbeat_errors: 0 + tx_window_errors: 0 + tx_abort_late_coll: 0 + tx_deferred_ok: 0 + tx_single_coll_ok: 0 + tx_multi_coll_ok: 0 + tx_timeout_count: 0 + tx_restart_queue: 0 + rx_long_length_errors: 0 + rx_short_length_errors: 0 + rx_align_errors: 0 + tx_tcp_seg_good: 0 + tx_tcp_seg_failed: 0 + rx_flow_control_xon: 0 + rx_flow_control_xoff: 0 + tx_flow_control_xon: 0 + tx_flow_control_xoff: 0 + rx_long_byte_count: 32454370137414 + rx_csum_offload_good: 35270755306 + rx_csum_offload_errors: 65076 + alloc_rx_buff_failed: 0 + tx_smbus: 0 + rx_smbus: 0 + dropped_smbus: 0 + +Kernel drops +------------ + +stats.log contains interesting information in the +capture.kernel_packets and capture.kernel_drops. The meaning of them +is different following the capture mode. + +In AF_PACKET mode: + +* kernel_packets is the number of packets correctly sent to userspace +* kernel_drops is the number of packets that have been discarded instead of being sent to userspace + +In PF_RING mode: + +* kernel_packets is the total number of packets seen by pf_ring +* kernel_drops is the number of packets that have been discarded instead of being sent to userspace + +In the Suricata stats.log the TCP data gap counter is also an +indicator, as it accounts missing data packets in TCP streams: + +:: + + tcp.reassembly_gap | Detect | 789 + +Ideally, this number is 0. Not only pkt loss affects it though, also +bad checksums and stream engine running out of memory. + +Tools to plot graphs +-------------------- + +Some people made nice tools to plot graphs of the statistics file. + +* `ipython and matplotlib script `_ +* `Monitoring with Zabbix or other `_ and `Code on Github `_ diff --git a/doc/userguide/performance/tcmalloc.rst b/doc/userguide/performance/tcmalloc.rst new file mode 100644 index 000000000000..3f3ea815d7be --- /dev/null +++ b/doc/userguide/performance/tcmalloc.rst @@ -0,0 +1,39 @@ +Tcmalloc +======== + +‘tcmalloc’ is a library Google created as part of the google-perftools +suite for improving memory handling in a threaded program. It’s very +simple to use and does work fine with Suricata. It leads to minor +speed ups and also reduces memory usage quite a bit. + +Installation +~~~~~~~~~~~~ + +On Ubuntu, install the libtcmalloc-minimal0 package: + +:: + + apt-get install libtcmalloc-minimal0 + +On Fedora, install the gperftools-libs package: + +:: + + yum install gperftools-libs + +Usage +~~~~~ + +Use the tcmalloc by preloading it: + +Ubuntu: + +:: + + LD_PRELOAD=”/usr/lib/libtcmalloc_minimal.so.0" suricata -c suricata.yaml -i eth0 + +Fedora: + +:: + + LD_PRELOAD="/usr/lib64/libtcmalloc_minimal.so.4" suricata -c suricata.yaml -i eth0 diff --git a/doc/userguide/performance/tuning-considerations.rst b/doc/userguide/performance/tuning-considerations.rst new file mode 100644 index 000000000000..6549c1c5b6fa --- /dev/null +++ b/doc/userguide/performance/tuning-considerations.rst @@ -0,0 +1,49 @@ +Tuning Considerations +===================== + +Settings to check for optimal performance. + +max-pending-packets: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This setting controls the number simultaneous packets that the engine +can handle. Setting this higher generally keeps the threads more busy, +but setting it too high will lead to degradation. + +Suggested setting: 1000 or higher. Max is ~65000. + +mpm-algo: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Controls the pattern matcher algorithm. AC is the default. On supported platforms, :doc:`hyperscan` is the best option. + +detect.profile: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The detection engine tries to split out separate signatures into +groups so that a packet is only inspected against signatures that can +actually match. As in large rule set this would result in way too many +groups and memory usage similar groups are merged together. The +profile setting controls how aggressive this merging is done. Higher +is better but results in (much) higher memory usage. + +The "custom" setting allows modification of the group sizes: + +:: + + custom-values: + toclient-groups: 50 + toserver-groups: 50 + +In general, increasing will improve performance, but will lead to +higher memory usage. + +detect.sgh-mpm-context: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The multi pattern matcher can have it's context per signature group +(full) or globally (single). Auto selects between single and full +based on the **mpm-algo** selected. ac and ac-bs use "single". +All others "full". Setting this to "full" with AC requires a +lot of memory: 32GB+ for a reasonable rule set. + diff --git a/doc/userguide/public-data-sets.rst b/doc/userguide/public-data-sets.rst new file mode 100644 index 000000000000..d994cccad48b --- /dev/null +++ b/doc/userguide/public-data-sets.rst @@ -0,0 +1,16 @@ +Public Data Sets +================ + +Collections of pcaps for testing, profiling. + +DARPA sets: http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/ + +MAWI sets (pkt headers only, no payloads): http://mawi.wide.ad.jp/mawi/samplepoint-F/2012/ + +MACCDC: http://www.netresec.com/?page=MACCDC + +Netresec: http://www.netresec.com/?page=PcapFiles + +Wireshark: https://wiki.wireshark.org/SampleCaptures + +Security Onion collection: https://github.com/security-onion-solutions/security-onion/wiki/Pcaps diff --git a/doc/userguide/reputation/index.rst b/doc/userguide/reputation/index.rst new file mode 100644 index 000000000000..0166a2ae0c29 --- /dev/null +++ b/doc/userguide/reputation/index.rst @@ -0,0 +1,6 @@ +Reputation +========== + +.. toctree:: + + ipreputation/ip-reputation.rst diff --git a/doc/userguide/reputation/ipreputation/ip-reputation-config.rst b/doc/userguide/reputation/ipreputation/ip-reputation-config.rst new file mode 100644 index 000000000000..9a4cde88fecf --- /dev/null +++ b/doc/userguide/reputation/ipreputation/ip-reputation-config.rst @@ -0,0 +1,71 @@ +IP Reputation Config +==================== + +IP reputation has a few configuration directives, all disabled by default. + + +:: + + + # IP Reputation + #reputation-categories-file: /etc/suricata/iprep/categories.txt + #default-reputation-path: /etc/suricata/iprep + #reputation-files: + # - reputation.list + +reputation-categories-file +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The categories file mapping numbered category values to short names. + + +:: + + + reputation-categories-file: /etc/suricata/iprep/categories.txt + +default-reputation-path +~~~~~~~~~~~~~~~~~~~~~~~ + +Path where reputation files from the "reputation-files" directive are loaded from by default. + + +:: + + + default-reputation-path: /etc/suricata/iprep + +reputation-files +~~~~~~~~~~~~~~~~ + +YAML list of file names to load. In case of a absolute path the file is loaded directly, otherwise the path from "default-reputation-path" is pre-pended to form the final path. + + +:: + + + reputation-files: + - badhosts.list + - knowngood.list + - sharedhosting.list + +Hosts +~~~~~ + +IP reputation information is stored in the host table, so the settings of the host table affect it. + +Depending on the number of hosts reputation information is available for, the memcap and hash size may have to be increased. + +Reloads +~~~~~~~ + +If the "rule-reloads" option is enabled, sending Suricata a USR2 signal will reload the IP reputation data, along with the normal rules reload. + +During the reload the host table will be updated to contain the new data. The iprep information is versioned. When the reload is complete, Suricata will automatically clean up the old iprep information. + +Only the reputation files will be reloaded, the categories file won't be. If categories change, Suricata should be restarted. + +File format +~~~~~~~~~~~ + +The format of the reputation files is described in the :doc:`ip-reputation-format` page. diff --git a/doc/userguide/reputation/ipreputation/ip-reputation-format.rst b/doc/userguide/reputation/ipreputation/ip-reputation-format.rst new file mode 100644 index 000000000000..b6bf186a22a8 --- /dev/null +++ b/doc/userguide/reputation/ipreputation/ip-reputation-format.rst @@ -0,0 +1,56 @@ +IP Reputation Format +==================== + +Description of IP Reputation file formats. For the configuration see :doc:`ip-reputation-config` and :doc:`ip-reputation-rules` for the rule format. + +Categories file +~~~~~~~~~~~~~~~ + +The categories file provides a mapping between a category number, short name, and long description. It's a simple CSV file: + +:: + + + ,, + +Example: + +:: + + + 1,BadHosts,Known bad hosts + 2,Google,Known google host + +The maximum value for the category id is hard coded at 60 currently. + +Reputation file +~~~~~~~~~~~~~~~ + +The reputation file lists a reputation score for hosts in the categories. It's a simple CSV file: + +:: + + + ,, + +The IP is an IPv4 address in the quad-dotted notation. The category is the number as defined in the categories file. The reputation score is the confidence that this IP is in the specified category, represented by a number between 1 and 127 (0 means no data). + +Example: + +:: + + + 1.2.3.4,1,101 + 1.1.1.1,6,88 + +If an IP address has a score in multiple categories it should be listed in the file multiple times. + +Example: + +:: + + + 1.1.1.1,1,10 + 1.1.1.1,2,10 + +This lists 1.1.1.1 in categories 1 and 2, each with a score of 10. diff --git a/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst new file mode 100644 index 000000000000..1808c98f1539 --- /dev/null +++ b/doc/userguide/reputation/ipreputation/ip-reputation-rules.rst @@ -0,0 +1,45 @@ +IP Reputation Rules +=================== + +IP Reputation can be used in rules through a new rule directive "iprep". + +iprep +~~~~~ + +The iprep directive matches on the IP reputation information for a host. + +:: + + iprep:,,, + + +side to check: + +category: the category short name + +operator: <, >, = + +reputation score: 1-127 + +Example: + +:: + + + alert ip $HOME_NET any -> any any (msg:"IPREP internal host talking to CnC server"; flow:to_server; iprep:dst,CnC,>,30; sid:1; rev:1;) + +This rule will alert when a system in $HOME_NET acts as a client while communicating with any IP in the CnC category that has a reputation score set to greater than 30. + +IP-only +~~~~~~~ + +The "iprep" keyword is compatible to "IP-only" rules. This means that a rule like: + +:: + + + alert ip any any -> any any (msg:"IPREP High Value CnC"; iprep:src,CnC,>,100; sid:1; rev:1;) + +will only be checked once per flow-direction. + +For more information about IP Reputation see :doc:`ip-reputation-config` and :doc:`ip-reputation-format`. diff --git a/doc/userguide/reputation/ipreputation/ip-reputation.rst b/doc/userguide/reputation/ipreputation/ip-reputation.rst new file mode 100644 index 000000000000..edfc69a65a69 --- /dev/null +++ b/doc/userguide/reputation/ipreputation/ip-reputation.rst @@ -0,0 +1,15 @@ +IP Reputation +============= + +.. toctree:: + + ip-reputation-config + ip-reputation-rules + ip-reputation-format + +The purpose of the IP reputation component is the ranking of IP Addresses within the Suricata Engine. It will collect, store, update and distribute reputation intelligence on IP Addresses. The hub and spoke architecture will allows the central database (The Hub) to collect, store and compile updated IP reputation details that are then distributed to user-side sensor databases (Spokes) for inclusion in user security systems. The reputation data update frequency and security action taken, is defined in the user security configuration. + +The intent of IP Reputation is to allow sharing of intelligence regarding a vast number of IP addresses. This can be positive or negative intelligence classified into a number of categories. The technical implementation requires three major efforts; engine integration, the hub that redistributes reputation, and the communication protocol between hubs and sensors. The hub will have a number of responsibilities. This will be a separate module running on a separate system as any sensor. Most often it would run on a central database that all sensors already have communication with. It will be able to subscribe to one or more external feeds. The local admin should be able to define the feeds to be subscribed to, provide authentication credentials if required, and give a weight to that feed. The weight can be an overall number or a by category weight. This will allow the admin to minimize the influence a feed has on their overall reputation if they distrust a particular category or feed, or trust another implicitly. Feeds can be configured to accept feedback or not and will report so on connect. The admin can override and choose not to give any feedback, but the sensor should report these to the Hub upstream on connect. The hub will take all of these feeds and aggregate them into an average single score for each IP or IP Block, and then redistribute this data to all local sensors as configured. It should receive connections from sensors. The sensor will have to provide authentication and will provide feedback. The hub should redistribute that feedback from sensors to all other sensors as well as up to any feeds that accept feedback. The hub should also have an API to allow outside statistical analysis to be done to the database and fed back in to the stream. For instance a local site may choose to change the reputation on all Russian IP blocks, etc. + + +For more information about IP Reputation see :doc:`ip-reputation-config`, :doc:`ip-reputation-rules` and :doc:`ip-reputation-format`. diff --git a/doc/userguide/rule-management/adding-your-own-rules.rst b/doc/userguide/rule-management/adding-your-own-rules.rst new file mode 100644 index 000000000000..83305cdb9266 --- /dev/null +++ b/doc/userguide/rule-management/adding-your-own-rules.rst @@ -0,0 +1,60 @@ +Adding Your Own Rules +===================== + +If you would like to create a rule yourself and use it with Suricata, +this guide might be helpful. + +Start creating a file for your rule. Type for example the following in +your console: + +:: + + sudo nano local.rules + +Write your rule, see :doc:`../rules/intro` and save it. + +Open yaml + +:: + + sudo nano /etc/suricata/suricata.yaml + +and make sure your local.rules file is added to the list of rules. + +Now, run Suricata and see if your rule is being loaded. + +:: + + suricata -c /etc/suricata/suricata.yaml -i wlan0 + +If your rule failed to load, check if you have made a mistake anywhere +in the rule. Mind the details; look for mistakes in special +characters, spaces, capital characters etc. + +Next, check if your log-files are enabled in suricata.yaml. + +If you had to correct your rule and/or modify yaml, you have to +restart Suricata. + +If you see your rule is successfully loaded, you can double check your +rule by doing something that should trigger it. + +Enter: + +:: + + tail -f /var/log/suricata/fast.log + +If you would make a rule like this: + +:: + + alert http any any -> any any (msg:"Do not read gossip during work"; + content:"Scarlett"; nocase; classtype:policy-violation; sid:1; rev:1;) + +Your alert should look like this: + +:: + + 09/15/2011-16:50:27.725288 [**] [1:1:1] Do not read gossip during work [**] + [Classification: Potential Corporate Privacy Violation] [Priority: 1] {TCP} 192.168.0.32:55604 -> 68.67.185.210:80 diff --git a/doc/userguide/rule-management/index.rst b/doc/userguide/rule-management/index.rst new file mode 100644 index 000000000000..75caabfeb275 --- /dev/null +++ b/doc/userguide/rule-management/index.rst @@ -0,0 +1,8 @@ +Rule Management +=============== + +.. toctree:: + + oinkmaster + adding-your-own-rules + rule-reload diff --git a/doc/userguide/rule-management/oinkmaster.rst b/doc/userguide/rule-management/oinkmaster.rst new file mode 100644 index 000000000000..39036738487d --- /dev/null +++ b/doc/userguide/rule-management/oinkmaster.rst @@ -0,0 +1,187 @@ +Rule Management with Oinkmaster +=============================== + + +It is possible to download and install rules manually, but there is a +much easier and quicker way to do so. There are special programs which +you can use for downloading and installing rules. There is for example +`Pulled Pork `_ and +`Oinkmaster `_. In this documentation +the use of Oinkmaster will be described. + +To install Oinkmaster, enter: + +:: + + sudo apt-get install oinkmaster + +There are several rulesets. There is for example Emerging Threats (ET) +Emerging Threats Pro and VRT. In this example we are using Emerging +Threats. + +Oinkmaster has to know where the rules an be found. These rules can be found at: + +:: + + https://rules.emergingthreats.net/open/suricata-3.2/emerging.rules.tar.gz + +open oinkmaster.conf to add this link by entering: + +:: + + sudo nano /etc/oinkmaster.conf + +Place a # in front of the url that is already there and add the new url like this: + +.. image:: oinkmaster/oinkmasterconf.png + +(Close oinkmaster.conf by pressing ctrl x, followed by y and enter. ) + +The next step is to create a directory for the new rules. Enter: + +:: + + sudo mkdir /etc/suricata/rules + + +Next enter: + +:: + + cd /etc + sudo oinkmaster -C /etc/oinkmaster.conf -o /etc/suricata/rules + +In the new rules directory a classification.config and a +reference.config can be found. The directories of both have to be +added in the suricata.yaml file. Do so by entering: + +:: + + sudo nano /etc/suricata/suricata.yaml + +And add the new file locations instead of the file locations already +present, like this: + +.. image:: oinkmaster/suricata_yaml.png + +To see if everything works as pleased, run Suricata: + +:: + + suricata -c /etc/suricata/suricata.yaml -i wlan0 (or eth0) + +You will notice there are several rule-files Suricata tries to load, +but are not available. It is possible to disable those rule-sets in +suricata.yaml by deleting them or by putting a # in front of them. To +stop Suricata from running, press ctrl c. + +Emerging Threats contains more rules than loaded in Suricata. To see +which rules are available in your rules directory, enter: + +:: + + ls /etc/suricata/rules/*.rules + +Find those that are not yet present in suricata.yaml and add them in +yaml if desired. + +You can do so by entering : + +:: + + sudo nano /etc/suricata/suricata.yaml + +If you disable a rule in your rule file by putting a # in front of it, +it will be enabled again the next time you run Oinkmaster. You can +disable it through Oinkmaster instead, by entering the following: + +:: + + cd /etc/suricata/rules + +and find the sid of the rule(s) you want to disable. + +Subsequently enter: + +:: + + sudo nano /etc/oinkmaster.conf + +and go all the way to the end of the file. +Type there: + +:: + + disablesid 2010495 + +Instead of 2010495, type the sid of the rule you would like to +disable. It is also possible to disable multiple rules, by entering +their sids separated by a comma. + +If you run Oinkmaster again, you can see the amount of rules you have +disabled. You can also enable rules that are disabled by default. Do +so by entering: + +:: + + ls /etc/suricata/rules + +In this directory you can see several rule-sets +Enter for example: + +:: + + sudo nano /etc/suricata/rules/emerging-malware.rules + +In this file you can see which rules are enabled en which are not. +You can not enable them for the long-term just by simply removing +the #. Because each time you will run Oinkmaster, the rule will be +disabled again. Instead, look up the sid of the rule you want to +enable. Place the sid in the correct place of oinkmaster.config: + +:: + + sudo nano /etc/oinkmaster.conf + +do so by typing: + +:: + + enablesid: 2010495 + +Instead of 2010495, type the sid of the rule you would like to to +enable. It is also possible to enable multiple rules, by entering +their sids separated by a comma. + +In oinkmaster.conf you can modify rules. For example, if you use +Suricata as inline/IPS and you want to modify a rule that sends an +alert when it matches and you would like the rule to drop the packet +instead, you can do so by entering the following: + +:: + + sudo nano oinkmaster.conf + +At the part where you can modify rules, type: + +:: + + modifysid 2010495 “alert” | “drop” + +The sid 2010495 is an example. Type the sid of the rule you desire to +change, instead. + +Rerun Oinkmaster to notice the change. + +Updating your rules +~~~~~~~~~~~~~~~~~~~ + +If you have already downloaded a ruleset (in the way described in this +file), and you would like to update the rules, enter: + +:: + + sudo oinkmaster -C /etc/oinkmaster.conf -o /etc/suricata/rules + +It is recommended to update your rules frequently. Emerging Threats is +modified daily, VRT is updated weekly or multiple times a week. diff --git a/doc/userguide/rule-management/oinkmaster/oinkmasterconf.png b/doc/userguide/rule-management/oinkmaster/oinkmasterconf.png new file mode 100644 index 000000000000..6f8545519c68 Binary files /dev/null and b/doc/userguide/rule-management/oinkmaster/oinkmasterconf.png differ diff --git a/doc/userguide/rule-management/oinkmaster/suricata_yaml.png b/doc/userguide/rule-management/oinkmaster/suricata_yaml.png new file mode 100644 index 000000000000..3ae19b5412b3 Binary files /dev/null and b/doc/userguide/rule-management/oinkmaster/suricata_yaml.png differ diff --git a/doc/userguide/rule-management/rule-reload.rst b/doc/userguide/rule-management/rule-reload.rst new file mode 100644 index 000000000000..a857a21197de --- /dev/null +++ b/doc/userguide/rule-management/rule-reload.rst @@ -0,0 +1,23 @@ +Rule Reloads +============ + +Suricata can be told to reloads it's rules without restarting. + +This works by sending Suricata a signal or by using the unix socket. When Suricata is told to reload the rules these are the basic steps it takes: + +* Load new config +* Load new rules +* Construct new detection engine +* Swap old and new detection engines +* Make sure all threads are updated +* Free old detection engine + +Suricata will continue to process packets normally during this process. Keep in mind though, that the system should have enough memory for both detection engines. + +Signal:: + + kill -USR2 $(pidof suricata) + +Unix socket:: + + suricatasc -c reload-rules diff --git a/doc/userguide/rules/app-layer.rst b/doc/userguide/rules/app-layer.rst new file mode 100644 index 000000000000..8295d58ef3a9 --- /dev/null +++ b/doc/userguide/rules/app-layer.rst @@ -0,0 +1,80 @@ +Generic App Layer Keywords +========================== + +app-layer-protocol +------------------ + +Match on the detected app-layer protocol. + +Syntax:: + + app-layer-protocol:[!]; + +Examples:: + + app-layer-protocol:ssh; + app-layer-protocol:!tls; + app-layer-protocol:failed; + +A special value 'failed' can be used for matching on flows in which +protocol detection failed. This can happen if Suricata doesn't know +the protocol or when certain 'bail out' conditions happen. + +.. _proto-detect-bail-out: + +Bail out conditions +~~~~~~~~~~~~~~~~~~~ + +Protocol detection gives up in several cases: + +* both sides are inspected and no match was found +* side A detection failed, side B has no traffic at all (e.g. FTP data channel) +* side A detection failed, side B has so little data detection is inconclusive + +In these last 2 cases the ``app-layer-event:applayer_proto_detection_skipped`` +is set. + + +app-layer-event +--------------- + +Match on events generated by the App Layer Parsers and the protocol detection +engine. + +Syntax:: + + app-layer-event:; + +Examples:: + + app-layer-event:applayer_mismatch_protocol_both_directions; + app-layer-event:http.gzip_decompression_failed; + +Protocol Detection +~~~~~~~~~~~~~~~~~~ + +applayer_mismatch_protocol_both_directions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The toserver and toclient directions have different protocols. For example a +client talking HTTP to a SSH server. + +applayer_wrong_direction_first_data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some protocol implementations in Suricata have a requirement with regards to +the first data direction. The HTTP parser is an example of this. + +https://redmine.openinfosecfoundation.org/issues/993 + +applayer_detect_protocol_only_one_direction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Protocol detection only succeeded in one direction. For FTP and SMTP this is +expected. + +applayer_proto_detection_skipped +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Protocol detection was skipped because of :ref:`proto-detect-bail-out`. + diff --git a/doc/userguide/rules/dnp3-keywords.rst b/doc/userguide/rules/dnp3-keywords.rst new file mode 100644 index 000000000000..88763306158c --- /dev/null +++ b/doc/userguide/rules/dnp3-keywords.rst @@ -0,0 +1,149 @@ +DNP3 Keywords +============= + +The DNP3 keywords can be used to match on fields in decoded DNP3 +messages. The keywords are based on Snort's DNP3 keywords and aim to +be 100% compatible. + +dnp3_func +--------- + +This keyword will match on the application function code found in DNP3 +request and responses. It can be specified as the integer value or +the symbolic name of the function code. + +Syntax +~~~~~~ + +:: + + dnp3_func:; + +Where value is one of: + +* An integer value between 0 and 255 inclusive. +* Function code name: + + * confirm + * read + * write + * select + * operate + * direct_operate + * direct_operate_nr + * immed_freeze + * immed_freeze_nr + * freeze_clear + * freeze_clear_nr + * freeze_at_time + * freeze_at_time_nr + * cold_restart + * warm_restart + * initialize_data + * initialize_appl + * start_appl + * stop_appl + * save_config + * enable_unsolicited + * disable_unsolicited + * assign_class + * delay_measure + * record_current_time + * open_file + * close_file + * delete_file + * get_file_info + * authenticate_file + * abort_file + * activate_config + * authenticate_req + * authenticate_err + * response + * unsolicited_response + * authenticate_resp + +dnp3_ind +-------- + +This keyword matches on the DNP3 internal indicator flags in the +response application header. + +Syntax +~~~~~~ + +:: + + dnp3_ind:{,...} + + +Where flag is the name of the internal indicator: + +* all_stations +* class_1_events +* class_2_events +* class_3_events +* need_time +* local_control +* device_trouble +* device_restart +* no_func_code_support +* object_unknown +* parameter_error +* event_buffer_overflow +* already_executing +* config_corrupt +* reserved_2 +* reserved_1 + +This keyword will match of any of the flags listed are set. To match +on multiple flags (AND type match), use dnp3_ind for each flag that +must be set. + +Examples +~~~~~~~~ + +:: + + dnp3_ind:all_stations; + +:: + + dnp3_ind:class_1_events,class_2_events; + +dnp3_obj +-------- + +This keyword matches on the DNP3 application data objects. + +Syntax +~~~~~~ + +:: + + + dnp3_obj:, + +Where and are integer values between 0 and 255 inclusive. + +dnp3_data +--------- + +This keyword will cause the following content options to match on the +re-assembled application buffer. The reassembled application buffer is +a DNP3 fragment with CRCs removed (which occur every 16 bytes), and +will be the complete fragment, possibly reassembled from multiple DNP3 +link layer frames. + +Syntax +~~~~~~ + +:: + + dnp3_data; + +Example +~~~~~~~ + +:: + + dnp3_data; content:|c3 06|; diff --git a/doc/userguide/rules/dns-keywords.rst b/doc/userguide/rules/dns-keywords.rst new file mode 100644 index 000000000000..e7e4fc1d61b5 --- /dev/null +++ b/doc/userguide/rules/dns-keywords.rst @@ -0,0 +1,25 @@ +DNS Keywords +============ + +(from v2.0) + +There are some more content modifiers (If you are unfamiliar with +content modifiers, please visit the page :doc:`payload-keywords` These +ones make sure the signature checks a specific part of the +network-traffic. + + +dns_query +--------- + +With **dns_query** the DNS request queries are inspected. The dns_query +keyword works a bit different from the normal content modifiers. When +used in a rule all contents following it are affected by it. Example: + + alert dns any any -> any any (msg:"Test dns_query option"; + dns_query; content:"google"; nocase; sid:1;) + +.. image:: dns-keywords/dns_query.png + +The dns_query keyword affects all following contents, until pkt_data +is used or it reaches the end of the rule. diff --git a/doc/userguide/rules/dns-keywords/dns_query.png b/doc/userguide/rules/dns-keywords/dns_query.png new file mode 100644 index 000000000000..35d16ca23e0d Binary files /dev/null and b/doc/userguide/rules/dns-keywords/dns_query.png differ diff --git a/doc/userguide/rules/enip-keyword.rst b/doc/userguide/rules/enip-keyword.rst new file mode 100644 index 000000000000..d833e0923f50 --- /dev/null +++ b/doc/userguide/rules/enip-keyword.rst @@ -0,0 +1,40 @@ +ENIP/CIP Keywords +================= + +The enip_command and cip_service keywords can be used for matching on various properties of +ENIP requests. + +There are three ways of using this keyword: + +* matching on ENIP command with the setting "enip_command"; +* matching on CIP Service with the setting "cip_service". +* matching both the ENIP command and the CIP Service with "enip_command" and "cip_service" together + + +For the ENIP command, we are matching against the command field found in the ENIP encapsulation. + +For the CIP Service, we use a maximum of 3 comma seperated values representing the Service, Class and Attribute. +These values are described in the CIP specification. CIP Classes are associated with their Service, and CIP Attributes +are associated with their Service. If you only need to match up until the Service, then only provide the Service value. +If you want to match to the CIP Attribute, then you must provide all 3 values. + + +Syntax:: + + enip_command: + cip_service: + enip_command:, cip_service: + + +Examples:: + + enip_command:99 + cip_service:75 + cip_service:16,246,6 + enip_command:111, cip_service:5 + + +(cf. http://read.pudn.com/downloads166/ebook/763211/EIP-CIP-V1-1.0.pdf) + +Information on the protocol can be found here: +``_ diff --git a/doc/userguide/rules/fast-pattern-explained.rst b/doc/userguide/rules/fast-pattern-explained.rst new file mode 100644 index 000000000000..103d93a1c102 --- /dev/null +++ b/doc/userguide/rules/fast-pattern-explained.rst @@ -0,0 +1,157 @@ +Suricata Fast Pattern Determination Explained +============================================= + +If the 'fast_pattern' keyword is explicitly set in a rule, Suricata +will use that as the fast pattern match. The 'fast_pattern' keyword +can only be set once per rule. If 'fast_pattern' is not set, Suricata +automatically determines the content to use as the fast pattern match. + +The following explains the logic Suricata uses to automatically +determine the fast pattern match to use. + +Be aware that if there are positive (i.e. non-negated) content +matches, then negated content matches are ignored for fast pattern +determination. Otherwise, negated content matches are considered. + +The fast_pattern selection criteria are as follows: + +#. Suricata first identifies all content matches that have the highest + "priority" that are used in the signature. The priority is based + off of the buffer being matched on and generally 'http_*' buffers + have a higher priority (lower number is higher priority). See + :ref:`Appendix B ` for details + on which buffers have what priority. +#. Within the content matches identified in step 1 (the highest + priority content matches), the longest (in terms of character/byte + length) content match is used as the fast pattern match. +#. If multiple content matches have the same highest priority and + qualify for the longest length, the one with the highest + character/byte diversity score ("Pattern Strength") is used as the + fast pattern match. See :ref:`Appendix C + ` for details on the algorithm + used to determine Pattern Strength. +#. If multiple content matches have the same highest priority, qualify + for the longest length, and the same highest Pattern Strength, the + buffer ("list_id") that was *registered last* is used as the fast + pattern match. See :ref:`Appendix B + ` for the registration order of + the different buffers/lists. +#. If multiple content matches have the same highest priority, qualify + for the longest length, the same highest Pattern Strength, and have + the same list_id (i.e. are looking in the same buffer), then the + one that comes first (from left-to-right) in the rule is used as + the fast pattern match. + +It is worth noting that for content matches that have the same +priority, length, and Pattern Strength, 'http_stat_msg', +'http_stat_code', and 'http_method' take precedence over regular +'content' matches. + +Appendices +---------- + +.. _fast-pattern-explained-appendix-a: + +Appendix A - Buffers, list_id values, and Registration Order for Suricata 1.3.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This should be pretty much the same for Suricata 1.1.x - 1.4.x. + +======= ============================== ======================== ================== +list_id Content Modifier Keyword Buffer Name Registration Order +======= ============================== ======================== ================== +1 (regular content match) DETECT_SM_LIST_PMATCH 1 (first) +2 http_uri DETECT_SM_LIST_UMATCH 2 +6 http_client_body DETECT_SM_LIST_HCBDMATCH 3 +7 http_server_body DETECT_SM_LIST_HSBDMATCH 4 +8 http_header DETECT_SM_LIST_HHDMATCH 5 +9 http_raw_header DETECT_SM_LIST_HRHDMATCH 6 +10 http_method DETECT_SM_LIST_HMDMATCH 7 +11 http_cookie DETECT_SM_LIST_HCDMATCH 8 +12 http_raw_uri DETECT_SM_LIST_HRUDMATCH 9 +13 http_stat_msg DETECT_SM_LIST_HSMDMATCH 10 +14 http_stat_code DETECT_SM_LIST_HSCDMATCH 11 +15 http_user_agent DETECT_SM_LIST_HUADMATCH 12 (last) +======= ============================== ======================== ================== + +Note: registration order doesn't matter when it comes to determining the fast pattern match for Suricata 1.3.4 but list_id value does. + +.. _fast-pattern-explained-appendix-b: + +Appendix B - Buffers, list_id values, Priorities, and Registration Order for Suricata 2.0.7 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This should be pretty much the same for Suricata 2.0.x. + +========================================== ================== ============================== ============================= ======= +Priority (lower number is higher priority) Registration Order Content Modifier Keyword Buffer Name list_id +========================================== ================== ============================== ============================= ======= +3 11 (regular content match) DETECT_SM_LIST_PMATCH 1 +3 12 http_method DETECT_SM_LIST_HMDMATCH 12 +3 13 http_stat_code DETECT_SM_LIST_HSCDMATCH 9 +3 14 http_stat_msg DETECT_SM_LIST_HSMDMATCH 8 +2 1 (first) http_client_body DETECT_SM_LIST_HCBDMATCH 4 +2 2 http_server_body DETECT_SM_LIST_HSBDMATCH 5 +2 3 http_header DETECT_SM_LIST_HHDMATCH 6 +2 4 http_raw_header DETECT_SM_LIST_HRHDMATCH 7 +2 5 http_uri DETECT_SM_LIST_UMATCH 2 +2 6 http_raw_uri DETECT_SM_LIST_HRUDMATCH 3 +2 7 http_host DETECT_SM_LIST_HHHDMATCH 10 +2 8 http_raw_host DETECT_SM_LIST_HRHHDMATCH 11 +2 9 http_cookie DETECT_SM_LIST_HCDMATCH 13 +2 10 http_user_agent DETECT_SM_LIST_HUADMATCH 14 +2 15 (last) dns_query DETECT_SM_LIST_DNSQUERY_MATCH 20 +========================================== ================== ============================== ============================= ======= + +Note: list_id value doesn't matter when it comes to determining the +fast pattern match for Suricata 2.0.7 but registration order does. + +.. _fast-pattern-explained-appendix-c: + +Appendix C - Pattern Strength Algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +From detect-engine-mpm.c. Basically the Pattern Strength "score" +starts at zero and looks at each character/byte in the passed in byte +array from left to right. If the character/byte has not been seen +before in the array, it adds 3 to the score if it is an alpha +character; else it adds 4 to the score if it is a printable character, +0x00, 0x01, or 0xFF; else it adds 6 to the score. If the +character/byte has been seen before it adds 1 to the score. The final +score is returned. + +.. code-block:: c + + /** \brief Predict a strength value for patterns + * + * Patterns with high character diversity score higher. + * Alpha chars score not so high + * Other printable + a few common codes a little higher + * Everything else highest. + * Longer patterns score better than short patters. + * + * \param pat pattern + * \param patlen length of the patternn + * + * \retval s pattern score + */ + uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) { + uint8_t a[256]; + memset(&a, 0 ,sizeof(a)); + uint32_t s = 0; + uint16_t u = 0; + for (u = 0; u < patlen; u++) { + if (a[pat[u]] == 0) { + if (isalpha(pat[u])) + s += 3; + else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF) + s += 4; + else + s += 6; + a[pat[u]] = 1; + } else { + s++; + } + } + return s; + } diff --git a/doc/userguide/rules/fast-pattern.rst b/doc/userguide/rules/fast-pattern.rst new file mode 100644 index 000000000000..c32b79844fd0 --- /dev/null +++ b/doc/userguide/rules/fast-pattern.rst @@ -0,0 +1,63 @@ +Fast Pattern +============ + +.. toctree:: + + fast-pattern-explained + +Only one content of a signature will be used in the Multi Pattern +Matcher (MPM). If there are multiple contents, then Suricata uses the +'strongest' content. This means a combination of length, how varied a +content is, and what buffer it is looking in. Generally, the longer +and more varied the better. For full details on how Suricata +determines the fast pattern match, see :doc:`fast-pattern-explained`. + +Sometimes a signature writer concludes he wants Suricata to use +another content than it does by default. + +For instance:: + + User-agent: Mozilla/5.0 Badness; + + content:”User-Agent|3A|”; + content:”Badness”; distance:0; + +In this example you see the first content is longer and more varied +than the second one, so you know Suricata will use this content for +the MPM. Because 'User-Agent:' will be a match very often, and +'Badness' appears less often in network traffic, you can make Suricata +use the second content by using 'fast_pattern'. + +:: + + content:”User-Agent|3A|”; + content:”Badness”; distance:0; fast_pattern; + +The keyword fast_pattern modifies the content previous to it. + +.. image:: fast-pattern/fast_pattern.png + +Fast-pattern can also be combined with all previous mentioned +keywords, and all mentioned HTTP-modifiers. + +fast_pattern:only +----------------- + +Sometimes a signature contains only one content. In that case it is +not necessary Suricata will check it any further after a match has +been found in MPM. If there is only one content, the whole signature +matches. Suricata notices this automatically. In some signatures this +is still indicated with 'fast_pattern:only;'. Although Suricata does +not need fast_pattern:only, it does support it. + +Fast_pattern: 'chop' +-------------------- + +If you do not want the MPM to use the whole content, you can use +fast_pattern 'chop'. + +For example:: + + content: “aaaaaaaaabc”; fast_pattern:8,4; + +This way, MPM uses only the last four characters. diff --git a/doc/userguide/rules/fast-pattern/fast_pattern.png b/doc/userguide/rules/fast-pattern/fast_pattern.png new file mode 100644 index 000000000000..97163a50ab0c Binary files /dev/null and b/doc/userguide/rules/fast-pattern/fast_pattern.png differ diff --git a/doc/userguide/rules/file-keywords.rst b/doc/userguide/rules/file-keywords.rst new file mode 100644 index 000000000000..44c5b667a9ec --- /dev/null +++ b/doc/userguide/rules/file-keywords.rst @@ -0,0 +1,139 @@ +File Keywords +============= + +Suricata comes with several rule keywords to match on various file +properties. They depend on properly configured +:doc:`../file-extraction/file-extraction`. + +filename +-------- + +Matches on the file name. + +Syntax:: + + filename:; + +Example:: + + filename:"secret"; + +fileext +------- + +Matches on the extension of a file name. + +Syntax:: + + fileext:; + +Example:: + + fileext:"jpg"; + +filemagic +--------- + +Matches on the information libmagic returns about a file. + +Syntax:: + + filemagic:; + +Example:: + + filemagic:"executable for MS Windows"; + +Note: as libmagic versions differ between installations, the returned +information may also slightly change. See also #437. + +filestore +--------- + +Stores files to disk if the signature matched. + +Syntax:: + + filestore:,; + +direction can be: + +* request/to_server: store a file in the request / to_server direction +* response/to_client: store a file in the response / to_client direction +* both: store both directions + +scope can be: + +* file: only store the matching file (for filename,fileext,filemagic matches) +* tx: store all files from the matching HTTP transaction +* ssn/flow: store all files from the TCP session/flow. + +If direction and scope are omitted, the direction will be the same as +the rule and the scope will be per file. + +filemd5 +------- + +Match file :ref:`MD5 ` against list of MD5 checksums. + +Syntax:: + + filemd5:[!]filename; + +The filename is expanded to include the rule dir. In the default case +it will become /etc/suricata/rules/filename. Use the exclamation mark +to get a negated match. This allows for white listing. + +Examples:: + + filemd5:md5-blacklist; + filemd5:!md5-whitelist; + +*File format* + +The file format is simple. It's a text file with a single md5 per +line, at the start of the line, in hex notation. If there is extra +info on the line it is ignored. + +Output from md5sum is fine:: + + 2f8d0355f0032c3e6311c6408d7c2dc2 util-path.c + b9cf5cf347a70e02fde975fc4e117760 util-pidfile.c + 02aaa6c3f4dbae65f5889eeb8f2bbb8d util-pool.c + dd5fc1ee7f2f96b5f12d1a854007a818 util-print.c + +Just MD5's are good as well:: + + 2f8d0355f0032c3e6311c6408d7c2dc2 + b9cf5cf347a70e02fde975fc4e117760 + 02aaa6c3f4dbae65f5889eeb8f2bbb8d + dd5fc1ee7f2f96b5f12d1a854007a818 + +*Memory requirements* + +Each MD5 uses 16 bytes of memory. 20 Million MD5's use about 310 MiB of memory. + +See also: http://blog.inliniac.net/2012/06/09/suricata-md5-blacklisting/ + +filesize +-------- + +Match on the size of the file as it is being transferred. + +Syntax:: + + filesize:; + +Examples:: + + filesize:100; # exactly 100 bytes + filesize:100<>200; # greater than 100 and smaller than 200 + filesize:>100; # greater than 100 + filesize:<100; # smaller than 100 + +**Note**: For files that are not completely tracked because of packet +loss or stream.depth being reached on the "greater than" is +checked. This is because Suricata can know a file is bigger than a +value (it has seen some of it already), but it can't know if the final +size would have been within a range, an exact value or smaller than a +value. diff --git a/doc/userguide/rules/flow-keywords.rst b/doc/userguide/rules/flow-keywords.rst new file mode 100644 index 000000000000..f9f354539b07 --- /dev/null +++ b/doc/userguide/rules/flow-keywords.rst @@ -0,0 +1,132 @@ +Flow Keywords +============= + +Flowbits +~~~~~~~~ + +Flowbits consists of two parts. The first part describes the action it +is going to perform, the second part is the name of the flowbit. + +There are multiple packets that belong to one flow. Suricata keeps +those flows in memory. For more information see +:ref:`suricata-yaml-flow-settings`. Flowbits can make sure an alert +will be generated when for example two different packets match. An +alert will only be generated when both packets match. So, when the +second packet matches, Suricata has to know if the first packet was a +match too. Flowbits marks the flow if a packet matches so Suricata +'knows' it should generate an alert when the second packet matches as +well. + +Flowbits have different actions. These are: + +:: + + flowbits: set, name Will set the condition/'name', if present, in the flow. + flowbits: isset, name Can be used in the rule to make sure it generates an alert + when the rule matches and the condition is set in the flow. + flowbits: toggle, name Reverses the present setting. So for example if a condition is set, + it will be unset and vice-versa. + flowbits: unset, name Can be used to unset the condition in the flow. + flowbits: isnotset, name Can be used in the rule to make sure it generates an alert + when it matches and the condition is not set in the flow. + flowbits: noalert No alert will be generated by this rule. + +Example: + +.. image:: flow-keywords/Flowbit_3.png + +When you take a look at the first rule you will notice it would +generate an alert if it would match, if it were not for the 'flowbits: +noalert' at the end of that rule. The purpose of this rule is to check +for a match on 'userlogin' and mark that in the flow. So, there is no +need for generating an alert. The second rule has no effect without +the first rule. If the first rule matches, the flowbits sets that +specific condition to be present in the flow. Now with the second rule +there can be checked whether or not the previous packet fulfills the +first condition. If at that point the second rule matches, an alert +will be generated. + +It is possible to use flowbits several times in a rule and combine the +different functions. + +Flow +~~~~ + +The flow keyword can be used to match on direction of the flow, so to/from +client or to/from server. It can also match if the flow is established or not. +The flow keyword can also be use to say the signature has to match on stream +only (only_stream) or on packet only (no_stream). + +So with the flow keyword you can match on: + +to_client + Match on packets from server to client. +to_server + Match on packets from client to server. +from_client + Match on packets from client to server (same as to_server). +from_server + Match on packets from server to client (same as to_client). +established + Match on established connections. +not_established + Match on packets that are not part of an established connection. +stateless + Match on packets that are and are not part of an established connection. +only_stream + Match on packets that have been reassembled by the stream engine. +no_stream + Match on packets that have not been reassembled by the stream + engine. Will not match packets that have been reeassembled. +only_frag + Match packets that have been reassembled from fragments. +no_frag + Match packets that have not been reassembled from fragments. + +Multiple flow options can be combined, for example:: + + flow:to_client, established + flow:to_server, established, only_stream + flow:to_server, not_established, no_frag + +The determination of *established* depends on the protocol: + +* For TCP a connection will be established after a three way + handshake. + + .. image:: flow-keywords/Flow1.png + +* For other protocols (for example UDP), the connection will be + considered established after seeing traffic from both sides of the + connection. + + .. image:: flow-keywords/Flow2.png + +Flowint +~~~~~~~ + +For information, read the information on the :doc:`flowint` page. + +stream_size +~~~~~~~~~~~ + +The stream size option matches on traffic according to the registered +amount of bytes by the sequence numbers. There are several modifiers +to this keyword: + +:: + + > greater than + < less than + = equal + != not equal + >= greater than or equal + <= less than or equal + +Format + +:: + + stream_size:, , ; + +Example of the stream-size keyword in a rule: diff --git a/doc/userguide/rules/flow-keywords/Flow1.png b/doc/userguide/rules/flow-keywords/Flow1.png new file mode 100644 index 000000000000..8479a9139525 Binary files /dev/null and b/doc/userguide/rules/flow-keywords/Flow1.png differ diff --git a/doc/userguide/rules/flow-keywords/Flow2.png b/doc/userguide/rules/flow-keywords/Flow2.png new file mode 100644 index 000000000000..b1cd6ae272b0 Binary files /dev/null and b/doc/userguide/rules/flow-keywords/Flow2.png differ diff --git a/doc/userguide/rules/flow-keywords/Flowbit_3.png b/doc/userguide/rules/flow-keywords/Flowbit_3.png new file mode 100644 index 000000000000..ad846241301c Binary files /dev/null and b/doc/userguide/rules/flow-keywords/Flowbit_3.png differ diff --git a/doc/userguide/rules/flowint.rst b/doc/userguide/rules/flowint.rst new file mode 100644 index 000000000000..dc8aa6676d71 --- /dev/null +++ b/doc/userguide/rules/flowint.rst @@ -0,0 +1,144 @@ +Flowint +======= + +Flowint is a precursor to the Global Variables task we will be adding +to the engine very soon, which will allow the capture, storage and +comparison of data in a variable. It will be as the name implies +Global. So you can compare data from packets in unrelated streams. + +Flowint allows storage and mathematical operations using variables. It +operates much like flowbits but with the addition of mathematical +capabilities and the fact that an integer can be stored and +manipulated, not just a flag set. We can use this for a number of very +useful things, such as counting occurrences, adding or subtracting +occurrences, or doing thresholding within a stream in relation to +multiple factors. This will be expanded to a global context very soon, +so users can perform these operations between streams. + +The syntax is as follows: + +flowint: , ; + +Define a var (not required), or check that one is set or not set. + +flowint: , , ; + +flowint: , < +,-,=,>,<,>=,<=,==, != >, ; + +Compare or alter a var. Add, subtract, compare greater than or less +than, greater than or equal to, and less than or equal to are +available. The item to compare with can be an integer or another +variable. + +________________________________________ + +For example, if you want to count how many times a username is seen in +a particular stream and alert if it is over 5. + +:: + + alert tcp any any -> any any (msg:"Counting Usernames"; content:"jonkman"; \ + flowint: usernamecount, +, 1; noalert;) + +This will count each occurrence and increment the var usernamecount +and not generate an alert for each. + +Now say we want to generate an alert if there are more than five hits +in the stream. + +:: + + alert tcp any any -> any any (msg:"More than Five Usernames!"; content:"jonkman"; \ + flowint: usernamecount, +, 1; flowint:usernamecount, >, 5;) + +So we'll get an alert ONLY if usernamecount is over five. + +So now let’s say we want to get an alert as above but NOT if there +have been more occurrences of that username logging out. Assuming this +particular protocol indicates a log out with "jonkman logout", let’s +try: + +:: + + alert tcp any any -> any any (msg:"Username Logged out"; content:"logout jonkman"; \ + flowint: usernamecount, -, 1; flowint:usernamecount, >, 5;) + +So now we'll get an alert ONLY if there are more than five active +logins for this particular username. + +This is a rather simplistic example, but I believe it shows the power +of what such a simple function can do for rule writing. I see a lot of +applications in things like login tracking, IRC state machines, +malware tracking, and brute force login detection. + +Let’s say we're tracking a protocol that normally allows five login +fails per connection, but we have vulnerability where an attacker can +continue to login after that five attempts and we need to know about +it. + +:: + + alert tcp any any -> any any (msg:"Start a login count"; content:"login failed"; \ + flowint:loginfail, notset; flowint:loginfail, =, 1; noalert;) + +So we detect the initial fail if the variable is not yet set and set +it to 1 if so. Our first hit. + +:: + + alert tcp any any -> any any (msg:"Counting Logins"; content:"login failed"; \ + flowint:loginfail, isset; flowint:loginfail, +, 1; noalert;) + +We are now incrementing the counter if it's set. + +:: + + alert tcp any any -> any any (msg:"More than Five login fails in a Stream"; content:"login failed"; \ + flowint:loginfail, isset; flowint:loginfail, >, 5;) + + +Now we'll generate an alert if we cross five login fails in the same +stream. + +But let's also say we also need alert if there are two successful +logins and a failed login after that. + +:: + + alert tcp any any -> any any (msg:"Counting Good Logins"; content:"login successful"; \ + flowint:loginsuccess, +, 1; noalert;) + +Here we're counting good logins, so now we'll count good logins +relevant to fails: + +:: + + alert tcp any any -> any any (msg:"Login fail after two successes"; content:"login failed"; \ + flowint:loginsuccess, isset; flowint:loginsuccess, =, 2;) + +Here are some other general examples: + +:: + + alert tcp any any -> any any (msg:"Setting a flowint counter"; content:"GET"; \ + flowint:myvar, notset; flowint:maxvar,notset; flowint:myvar,=,1; flowint: maxvar,=,6;) + +:: + + alert tcp any any -> any any (msg:"Adding to flowint counter"; content:"Unauthorized"; \ + flowint:myvar,isset; flowint: myvar,+,2;) + +:: + + alert tcp any any -> any any (msg:"if the flowint counter is 3 create a new counter"; content:"Unauthorized"; \ + flowint:myvar, isset; flowint:myvar,==,3; flowint:cntpackets,notset; flowint:cntpackets, =, 0;) + +:: + + alert tcp any any -> any any (msg:"and count the rest of the packets received without generating alerts!!!"; \ + flowint:cntpackets,isset; flowint:cntpackets, +, 1; noalert;) + +:: + + alert tcp any any -> any any (msg:" and fire this when it reach 6"; flowint: cntpackets, isset; \ + flowint: maxvar,isset; flowint: cntpackets, ==, maxvar;) diff --git a/doc/userguide/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst new file mode 100644 index 000000000000..b0bfa79a6061 --- /dev/null +++ b/doc/userguide/rules/header-keywords.rst @@ -0,0 +1,388 @@ +Header Keywords +=============== + +IP-keywords +----------- + +ttl +^^^ + +The ttl keyword is used to check for a specific IP time-to-live value +in the header of a packet. The format is:: + + ttl: + +For example:: + + ttl:10; + +At the end of the ttl keyword you can enter the value on which you +want to match. The Time-to-live value determines the maximal amount +of time a packet can be in the Internet-system. If this field is set +to 0, then the packet has to be destroyed. The time-to-live is based +on hop count. Each hop/router the packet passes subtracts one of the +packet TTL counter. The purpose of this mechanism is to limit the +existence of packets so that packets can not end up in infinite +routing loops. + +Example of the ttl keyword in a rule: + +.. image:: header-keywords/ttl.png + +Ipopts +^^^^^^ + +With the ipopts keyword you can check if a specific ip option is +set. Ipopts has to be used at the beginning of a rule. You can only +match on one option per rule. There are several options on which can +be matched. These are: + +.. image:: header-keywords/ipopts.png + +Format of the ipopts keyword:: + + ipopts: + +For example:: + + ipopts: lsrr; + +Example of ipopts in a rule: + +.. image:: header-keywords/ipopts_rule.png + +sameip +^^^^^^ + +Every packet has a source IP-address and a destination IP-address. It +can be that the source IP is the same as the destination IP. With the +sameip keyword you can check if the IP address of the source is the +same as the IP address of the destination. The format of the sameip +keyword is:: + + sameip; + +Example of sameip in a rule: + +.. image:: header-keywords/sameip.png + +ip_proto +^^^^^^^^ + +With the ip_proto keyword you can match on the IP protocol in the +packet-header. You can use the name or the number of the protocol. +You can match for example on the following protocols:: + + 1 ICMP Internet Control Message + 6 TCP Transmission Control Protocol + 17 UDP User Datagram + 47 GRE General Routing Encapsulation + 50 ESP Encap Security Payload for IPv6 + 51 AH Authentication Header for Ipv6 + 58 IPv6-ICMP ICMP for Ipv6 + +For the complete list of protocols and their numbers see +http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers + +Example of ip_proto in a rule: + +.. image:: header-keywords/ip_proto.png + +The named variante of that example would be:: + + ip_proto:PIM + +Id +^^ + +With the id keyword, you can match on a specific IP ID value. The ID +identifies each packet sent by a host and increments usually with one +with each packet that is being send. The IP ID is uses as a fragment +identification number. Each packet has an IP ID, and when the packet +becomes fragmented, all fragments of this packet have the same ID. In +this way, the receiver of the packet knows which fragments belong to +the same packet. (IP ID does not take care of the order, in that case +offset is used. It clarifies the order of the fragments.) + +Format of id:: + + id:; + +Example of id in a rule: + +.. image:: header-keywords/id.png + +Geoip +^^^^^ + +The geoip keyword enables (you) to match on the source, destination or +source and destination IP addresses of network traffic, and to see to +which country it belongs. To be able to do this, Suricata uses GeoIP +API of Maxmind. + +The syntax of geoip:: + + geoip: src, RU; + geoip: both, CN, RU; + geoip: dst, CN, RU, IR; + geoip: both, US, CA, UK; + geoip: any, CN, IR; + +So, you can see you can use the following to make clear on which +direction you would like to match:: + + both: both directions have to match with the given geoip (geopip’s) + any: one of the directions have to match with the given geoip (’s). + dest: if the destination matches with the given geoip. + src: the source matches with the given geoip. + +Fragments +--------- + +Fragbits +^^^^^^^^ + +With the fragbits keyword, you can check if the fragmentation and +reserved bits are set in the IP header. The fragbits keyword should be +placed at the beginning of a rule. Fragbits is used to modify the +fragmentation mechanism. During routing of messages from one Internet +module to the other, it can occur that a packet is bigger than the +maximal packet size a network can process. In that case, a packet can +be send in fragments. This maximum of the packet size is called +Maximal Transmit Unit (MTU). + +You can match on the following bits:: + + M - More Fragments + D - Do not Fragment + R - Reserved Bit + +Matching on this bits can be more specified with the following +modifiers:: + + + match on the specified bits, plus any others + * match if any of the specified bits are set + ! match if the specified bits are not set + +Format:: + + fragbits:[*+!]<[MDR]>; + +Example of fragbits in a rule: + +.. image:: header-keywords/fragbits.png + +Fragoffset +^^^^^^^^^^ + +With the fragoffset keyword you can match on specific decimal values +of the IP fragment offset field. If you would like to check the first +fragments of a session, you have to combine fragoffset 0 with the More +Fragment option. The fragmentation offset field is convenient for +reassembly. The id is used to determine which fragments belong to +which packet and the fragmentation offset field clarifies the order of +the fragments. + +You can use the following modifiers:: + + < match if the value is smaller than the specified value + > match if the value is greater than the specified value + ! match if the specified value is not present + +Format of fragoffset:: + + fragoffset:[!|<|>]; + +Example of fragoffset in a rule: + +.. image:: header-keywords/fragoffset.png + +TCP keywords +------------ + +seq +^^^ + +The seq keyword can be used in a signature to check for a specific TCP +sequence number. A sequence number is a number that is generated +practically at random by both endpoints of a TCP-connection. The +client and the server both create a sequence number, which increases +with one with every byte that they send. So this sequence number is +different for both sides. This sequence number has to be acknowledged +by both sides of the connection. Through sequence numbers, TCP +handles acknowledgement, order and retransmission. Its number +increases with every data-byte the sender has send. The seq helps +keeping track of to what place in a data-stream a byte belongs. If the +SYN flag is set at 1, than the sequence number of the first byte of +the data is this number plus 1 (so, 2). + +Example:: + + seq:0; + +Example of seq in a signature: + +.. image:: header-keywords/seq.png + +Example of seq in a packet (Wireshark): + +.. image:: header-keywords/Wireshark_seq.png + + +ack +^^^ + +The ack is the acknowledgement of the receipt of all previous +(data)-bytes send by the other side of the TCP-connection. In most +occasions every packet of a TCP connection has an ACK flag after the +first SYN and a ack-number which increases with the receipt of every +new data-byte. The ack-keyword can be used in a signature to check +for a specific TCP acknowledgement number. + +Format of ack:: + + ack:1; + +Example of ack in a signature: + +.. image:: header-keywords/ack.png + +Example of ack in a packet (Wireshark): + +.. image:: header-keywords/Wireshark_ack.png + +window +^^^^^^ + +The window keyword is used to check for a specific TCP window size. +The TCP window size is a mechanism that has control of the +data-flow. The window is set by the receiver (receiver advertised +window size) and indicates the amount of bytes that can be +received. This amount of data has to be acknowledged by the receiver +first, before the sender can send the same amount of new data. This +mechanism is used to prevent the receiver from being overflowed by +data. The value of the window size is limited and can be 2 to 65.535 +bytes. To make more use of your bandwidth you can use a bigger +TCP-window. + +The format of the window keyword:: + + window:[!]; + +Example of window in a rule: + +.. image:: header-keywords/Window.png + +ICMP keywords +------------- + +ICMP (Internet Control Message Protocol) is a part of IP. IP at itself +is not reliable when it comes to delivering data (datagram). ICMP +gives feedback in case problems occur. It does not prevent problems +from happening, but helps in understanding what went wrong and +where. If reliability is necessary, protocols that use IP have to take +care of reliability themselves. In different situations ICMP messages +will be send. For instance when the destination is unreachable, if +there is not enough buffer-capacity to forward the data, or when a +datagram is send fragmented when it should not be, etcetera. More can +be found in the list with message-types. + +There are four important contents of a ICMP message on which can be +matched with corresponding ICMP-keywords. These are: the type, the +code, the id and the sequence of a message. + +itype +^^^^^ + +The itype keyword is for matching on a specific ICMP type (number). +ICMP has several kinds of messages and uses codes to clarify those +messages. The different messages are distinct by different names, but +more important by numeric values. For more information see the table +with message-types and codes. + +The format of the itype keyword:: + + itype:min<>max; + itype:[<|>]; + +Example +This example looks for an ICMP type greater than 10:: + + itype:>10; + +Example of the itype keyword in a signature: + +.. image:: header-keywords/icmp_type.png + +icode +^^^^^ + +With the icode keyword you can match on a specific ICMP code. The +code of a ICMP message clarifies the message. Together with the +ICMP-type it indicates with what kind of problem you are dealing with. +A code has a different purpose with every ICMP-type. + +The format of the icode keyword:: + + icode:min<>max; + icode:[<|>]; + +Example: +This example looks for an ICMP code greater than 5:: + + icode:>5; + +Example of the icode keyword in a rule: + +.. image:: header-keywords/icode.png + +icmp_id +^^^^^^^ + +With the icmp_id keyword you can match on specific ICMP id-values. +Every ICMP-packet gets an id when it is being send. At the moment the +receiver has received the packet, it will send a reply using the same +id so the sender will recognize it and connects it with the correct +ICMP-request. + +Format of the icmp_id keyword:: + + icmp_id:; + +Example: +This example looks for an ICMP ID of 0:: + + icmp_id:0; + +Example of the icmp_id keyword in a rule: + +.. image:: header-keywords/icmp_id.png + +icmp_seq +^^^^^^^^ + +You can use the icmp_seq keyword to check for a ICMP sequence number. +ICMP messages all have sequence numbers. This can be useful (together +with the id) for checking which reply message belongs to which request +message. + +Format of the icmp_seq keyword:: + + icmp_seq:; + +Example: +This example looks for an ICMP Sequence of 0:: + + icmp_seq:0; + +Example of icmp_seq in a rule: + +.. image:: header-keywords/icmp_seq.png + +Message types and numbers: + +.. image:: header-keywords/ICMP_types.png + +Meaning of type-numbers en codes combined: + +.. image:: header-keywords/ICMP_type_code.png diff --git a/doc/userguide/rules/header-keywords/ICMP_type_code.png b/doc/userguide/rules/header-keywords/ICMP_type_code.png new file mode 100644 index 000000000000..e14239e84e3e Binary files /dev/null and b/doc/userguide/rules/header-keywords/ICMP_type_code.png differ diff --git a/doc/userguide/rules/header-keywords/ICMP_types.png b/doc/userguide/rules/header-keywords/ICMP_types.png new file mode 100644 index 000000000000..a1589d8d89ef Binary files /dev/null and b/doc/userguide/rules/header-keywords/ICMP_types.png differ diff --git a/doc/userguide/rules/header-keywords/Window.png b/doc/userguide/rules/header-keywords/Window.png new file mode 100644 index 000000000000..1d1a53ee1097 Binary files /dev/null and b/doc/userguide/rules/header-keywords/Window.png differ diff --git a/doc/userguide/rules/header-keywords/Wireshark_ack.png b/doc/userguide/rules/header-keywords/Wireshark_ack.png new file mode 100644 index 000000000000..d90156b29f2e Binary files /dev/null and b/doc/userguide/rules/header-keywords/Wireshark_ack.png differ diff --git a/doc/userguide/rules/header-keywords/Wireshark_seq.png b/doc/userguide/rules/header-keywords/Wireshark_seq.png new file mode 100644 index 000000000000..ac2716354101 Binary files /dev/null and b/doc/userguide/rules/header-keywords/Wireshark_seq.png differ diff --git a/doc/userguide/rules/header-keywords/ack.png b/doc/userguide/rules/header-keywords/ack.png new file mode 100644 index 000000000000..b5bd788c7e69 Binary files /dev/null and b/doc/userguide/rules/header-keywords/ack.png differ diff --git a/doc/userguide/rules/header-keywords/fragbits.png b/doc/userguide/rules/header-keywords/fragbits.png new file mode 100644 index 000000000000..30d497f1eb88 Binary files /dev/null and b/doc/userguide/rules/header-keywords/fragbits.png differ diff --git a/doc/userguide/rules/header-keywords/fragoffset.png b/doc/userguide/rules/header-keywords/fragoffset.png new file mode 100644 index 000000000000..a5c1ecec7f35 Binary files /dev/null and b/doc/userguide/rules/header-keywords/fragoffset.png differ diff --git a/doc/userguide/rules/header-keywords/icmp_id.png b/doc/userguide/rules/header-keywords/icmp_id.png new file mode 100644 index 000000000000..6db0c5828fd8 Binary files /dev/null and b/doc/userguide/rules/header-keywords/icmp_id.png differ diff --git a/doc/userguide/rules/header-keywords/icmp_seq.png b/doc/userguide/rules/header-keywords/icmp_seq.png new file mode 100644 index 000000000000..bcfcdc704116 Binary files /dev/null and b/doc/userguide/rules/header-keywords/icmp_seq.png differ diff --git a/doc/userguide/rules/header-keywords/icmp_type.png b/doc/userguide/rules/header-keywords/icmp_type.png new file mode 100644 index 000000000000..7ca579e4588e Binary files /dev/null and b/doc/userguide/rules/header-keywords/icmp_type.png differ diff --git a/doc/userguide/rules/header-keywords/icode.png b/doc/userguide/rules/header-keywords/icode.png new file mode 100644 index 000000000000..3535e55ac0f7 Binary files /dev/null and b/doc/userguide/rules/header-keywords/icode.png differ diff --git a/doc/userguide/rules/header-keywords/id.png b/doc/userguide/rules/header-keywords/id.png new file mode 100644 index 000000000000..0285b8e4038b Binary files /dev/null and b/doc/userguide/rules/header-keywords/id.png differ diff --git a/doc/userguide/rules/header-keywords/ip_proto.png b/doc/userguide/rules/header-keywords/ip_proto.png new file mode 100644 index 000000000000..1e5bc503d9eb Binary files /dev/null and b/doc/userguide/rules/header-keywords/ip_proto.png differ diff --git a/doc/userguide/rules/header-keywords/ipopts.png b/doc/userguide/rules/header-keywords/ipopts.png new file mode 100644 index 000000000000..666c17842755 Binary files /dev/null and b/doc/userguide/rules/header-keywords/ipopts.png differ diff --git a/doc/userguide/rules/header-keywords/ipopts_rule.png b/doc/userguide/rules/header-keywords/ipopts_rule.png new file mode 100644 index 000000000000..c0f817ab80a5 Binary files /dev/null and b/doc/userguide/rules/header-keywords/ipopts_rule.png differ diff --git a/doc/userguide/rules/header-keywords/sameip.png b/doc/userguide/rules/header-keywords/sameip.png new file mode 100644 index 000000000000..56e0f32f623a Binary files /dev/null and b/doc/userguide/rules/header-keywords/sameip.png differ diff --git a/doc/userguide/rules/header-keywords/seq.png b/doc/userguide/rules/header-keywords/seq.png new file mode 100644 index 000000000000..aa0cea53676d Binary files /dev/null and b/doc/userguide/rules/header-keywords/seq.png differ diff --git a/doc/userguide/rules/header-keywords/ttl.png b/doc/userguide/rules/header-keywords/ttl.png new file mode 100644 index 000000000000..3b18792aeff4 Binary files /dev/null and b/doc/userguide/rules/header-keywords/ttl.png differ diff --git a/doc/userguide/rules/http-keywords.rst b/doc/userguide/rules/http-keywords.rst new file mode 100644 index 000000000000..4418ab8983e8 --- /dev/null +++ b/doc/userguide/rules/http-keywords.rst @@ -0,0 +1,428 @@ +:tocdepth: 2 + +HTTP Keywords +============= + +There are additional content modifiers that can provide protocol-specific +capabilities at the application layer. More information can be found at +:doc:`payload-keywords` These keywords make sure the signature checks only +specific parts of the network traffic. For instance, to check specifically on +the request URI, cookies, or the HTTP request or response body, etc. + +Types of modifiers +------------------ + +There are 2 types of modifiers. The older style 'content modifiers' look back in the rule. + +Example:: + + alert http any any -> any any (content:"index.php"; http_uri; sid:1;) + +In the above example the pattern 'index.php' is modified to inspect the HTTP uri buffer. + +The more recent type is called the 'sticky buffer'. It places the buffer name first and all keywords following it apply to that buffer. + +Example:: + + alert http any any -> any any (http_response_line; content:"403 Forbidden"; sid:1;) + +In the above example the pattern '403 Forbidden' is inspected against the HTTP response line because it follows the ``http_response_line`` keyword. + +The following request keywords are available: + +============================== ======================== ================== +Keyword Sticky or Modifier Direction +============================== ======================== ================== +http_uri Modifier Request +http_raw_uri Modifier Request +http_method Modifier Request +http_request_line Sticky Buffer Request +http_client_body Modifier Request +http_header Modifier Both +http_raw_header Modifier Both +http_cookie Modifier Both +http_user_agent Modifier Request +http_host Modifier Request +http_raw_host Modifier Request +============================== ======================== ================== + +The following response keywords are available: + +============================== ======================== ================== +Keyword Sticky or Modifier Direction +============================== ======================== ================== +http_stat_msg Modifier Response +http_stat_code Modifier Response +http_response_line Sticky Buffer Response +http_header Modifier Both +http_raw_header Modifier Both +http_cookie Modifier Both +http_server_body Modifier Response +file_data Sticky Buffer Response +============================== ======================== ================== + +It is important to understand the structure of HTTP requests and +responses. A simple example of a HTTP request and response follows: + +HTTP request +------------ + +:: + + GET /index.html HTTP/1.0\r\n + +GET is a request **method**. Examples of methods are: GET, POST, PUT, +HEAD, etc. The URI path is ``/index.html`` and the HTTP version is +``HTTP/1.0``. Several HTTP versions have been used over the years; of +the versions 0.9, 1.0 and 1.1, 1.0 and 1.1 are the most commonly used +today. + +HTTP response +------------- + +:: + + HTTP/1.0 200 OK\r\n + + some page + + +In this example, HTTP/1.0 is the HTTP version, 200 the response status +code and OK the response status message. + +Another more detailed example: + +Request: + +.. image:: http-keywords/request.png + +Response: + +.. image:: http-keywords/response1.png + +Request: + +.. image:: http-keywords/request2.png + +Although cookies are sent in an HTTP header, you can not match on them +with the ``http_header`` keyword. Cookies are matched with their own +keyword, namely ``http_cookie``. + +Each part of the table belongs to a so-called *buffer*. The HTTP +method belongs to the method buffer, HTTP headers to the header buffer +etc. A buffer is a specific portion of the request or response that +Suricata extracts in memory for inspection. + +All previous described keywords can be used in combination with a +buffer in a signature. The keywords ``distance`` and ``within`` are +relative modifiers, so they may only be used within the same +buffer. You can not relate content matches against different buffers +with relative modifiers. + +http_method +----------- + +With the ``http_method`` content modifier, it is possible to match +specifically and only on the HTTP method buffer. The keyword can be +used in combination with all previously mentioned content modifiers +such as: ``depth``, ``distance``, ``offset``, ``nocase`` and ``within``. + +Methods are: **GET**, **POST**, **PUT**, **HEAD**, **DELETE**, **TRACE**, +**OPTIONS**, **CONNECT** and **PATCH**. + +Example of a method in a HTTP request: + +.. image:: http-keywords/method2.png + +Example of the purpose of method: + +.. image:: http-keywords/method.png + +.. image:: http-keywords/Legenda_rules.png + +.. image:: http-keywords/method1.png + + +http_uri and http_raw_uri +------------------------- + +With the ``http_uri`` and the ``http_raw_uri`` content modifiers, it +is possible to match specifically and only on the request URI +buffer. The keyword can be used in combination with all previously +mentioned content modifiers like ``depth``, ``distance``, ``offset``, +``nocase`` and ``within``. + +To learn more about the difference between ``http_uri`` and +``http_raw_uri``, please read the information about +:doc:`http-uri-normalization`. + +Example of the URI in a HTTP request: + +.. image:: http-keywords/uri1.png + +Example of the purpose of ``http_uri``: + +.. image:: http-keywords/uri.png + +Example of the purpose of ``http_raw_uri``: + +#.. image:: http-keywords/raw_uri.png + +uricontent +---------- + +The ``uricontent`` keyword has the exact same effect as the +``http_uri`` content modifier. ``uricontent`` is a deprecated +(although still supported) way to match specifically and only on the +request URI buffer. + +Example of ``uricontent``: + +.. image:: http-keywords/uricontent.png + +The difference between ``http_uri`` and ``uricontent`` is the syntax: + +.. image:: http-keywords/uricontent1.png + +.. image:: http-keywords/http_uri.png + +When authoring new rules, it is recommended that the ``http_uri`` +content modifier be used rather than the deprecated ``uricontent`` +keyword. + +urilen +------ + +The ``urilen`` keyword is used to match on the length of the request +URI. It is possible to use the ``<`` and ``>`` operators, which +indicate respectively *smaller than* and *larger than*. + +The format of ``urilen`` is:: + + urilen:3; + +Other possibilities are:: + + urilen:1; + urilen:>1; + urilen:<10; + urilen:10<>20; (bigger than 10, smaller than 20) + +Example: + +.. image:: http-keywords/urilen.png + +Example of ``urilen`` in a signature: + +.. image:: http-keywords/urilen1.png + +You can also append ``norm`` or ``raw`` to define what sort of buffer you want +to use (normalized or raw buffer). + +http_request_line +----------------- + +The ``http_request_line`` forces the whole HTTP request line to be inspected. + +Example:: + + alert http any any -> any any (http_request_line; content:"GET / HTTP/1.0"; sid:1;) + +http_header and http_raw_header +------------------------------- + +With the ``http_header`` content modifier, it is possible to match +specifically and only on the HTTP header buffer. This contains all of +the extracted headers in a single buffer, except for those indicated +in the documentation that are not able to match by this buffer and +have their own content modifier (e.g. ``http_cookie``). The modifier +can be used in combination with all previously mentioned content +modifiers, like ``depth``, ``distance``, ``offset``, ``nocase`` and +``within``. + + **Note**: the header buffer is *normalized*. Any trailing + whitespace and tab characters are removed. See: + http://lists.openinfosecfoundation.org/pipermail/oisf-users/2011-October/000935.html. + To avoid that, use the ``http_raw_header`` keyword. + +Example of a header in a HTTP request: + +.. image:: http-keywords/header.png + +Example of the purpose of ``http_header``: + +.. image:: http-keywords/header1.png + +http_cookie +----------- + +With the ``http_cookie`` content modifier, it is possible to match +specifically and only on the cookie buffer. The keyword can be used in +combination with all previously mentioned content modifiers like +``depth``, ``distance``, ``offset``, ``nocase`` and ``within``. + +Note that cookies are passed in HTTP headers, but are extracted to a +dedicated buffer and matched using their own specific content +modifier. + +Example of a cookie in a HTTP request: + +.. image:: http-keywords/cookie.png + +Example of the purpose of ``http_cookie``: + +.. image:: http-keywords/cookie1.png + +http_user_agent +--------------- + +The ``http_user_agent`` content modifier is part of the HTTP request +header. It makes it possible to match specifically on the value of the +User-Agent header. It is normalized in the sense that it does not +include the _"User-Agent: "_ header name and separator, nor does it +contain the trailing carriage return and line feed (CRLF). The keyword +can be used in combination with all previously mentioned content +modifiers like ``depth``, ``distance``, ``offset``, ``nocase`` and +``within``. Note that the ``pcre`` keyword can also inspect this +buffer when using the ``/V`` modifier. + +An analysis into the performance of ``http_user_agent`` +vs. ``http_header`` is found at: +http://blog.inliniac.net/2012/07/09/suricata-http_user_agent-vs-http_header/ + +Normalization: leading spaces **are not** part of this buffer. So +"User-Agent: \r\n" will result in an empty ``http_user_agent`` buffer. + +Example of the User-Agent header in a HTTP request: + +.. image:: http-keywords/user_agent.png + +Example of the purpose of ``http_user_agent``: + +.. image:: http-keywords/user_agent_match.png + +http_client_body +---------------- + +With the ``http_client_body`` content modifier, it is possible to +match specifically and only on the HTTP request body. The keyword can +be used in combination with all previously mentioned content modifiers +like ``distance``, ``offset``, ``nocase``, ``within``, etc. + +Example of ``http_client_body`` in a HTTP request: + +.. image:: http-keywords/client_body.png + +Example of the purpose of ``http_client_body``: + +.. image:: http-keywords/client_body1.png + +Note: how much of the request/client body is inspected is controlled +in the :ref:`libhtp configuration section +` via the ``request-body-limit`` +setting. + +http_stat_code +-------------- + +With the ``http_stat_code`` content modifier, it is possible to match +specifically and only on the HTTP status code buffer. The keyword can +be used in combination with all previously mentioned content modifiers +like ``distance``, ``offset``, ``nocase``, ``within``, etc. + +Example of ``http_stat_code`` in a HTTP response: + +.. image:: http-keywords/stat_code.png + +Example of the purpose of ``http_stat_code``: + +.. image:: http-keywords/stat-code1.png + +http_stat_msg +------------- + +With the ``http_stat_msg`` content modifier, it is possible to match +specifically and only on the HTTP status message buffer. The keyword +can be used in combination with all previously mentioned content +modifiers like ``depth``, ``distance``, ``offset``, ``nocase`` and +``within``. + +Example of ``http_stat_msg`` in a HTTP response: + +.. image:: http-keywords/stat_msg.png + +Example of the purpose of ``http_stat_msg``: + +.. image:: http-keywords/stat_msg_1.png + +http_response_line +------------------ + +The ``http_response_line`` forces the whole HTTP response line to be inspected. + +Example:: + + alert http any any -> any any (http_response_line; content:"HTTP/1.0 200 OK"; sid:1;) + +http_server_body +---------------- + +With the ``http_server_body`` content modifier, it is possible to +match specifically and only on the HTTP response body. The keyword can +be used in combination with all previously mentioned content modifiers +like ``distance``, ``offset``, ``nocase``, ``within``, etc. + +Note: how much of the response/server body is inspected is controlled +in your :ref:`libhtp configuration section +` via the ``response-body-limit`` +setting. + +http_host and http_raw_host +--------------------------- + +With the ``http_host`` content modifier, it is possible to +match specifically and only the normalized hostname. +The ``http_raw_host`` inspects the raw hostname. + +The keyword can be used in combination with most of the content modifiers +like ``distance``, ``offset``, ``within``, etc. + +The ``nocase`` keyword ist not allowed anymore. Keep in mind that you need +to specify a lowercase pattern. + +file_data +--------- + +With ``file_data``, the HTTP response body is inspected, just like +with ``http_server_body``. The ``file_data`` keyword works a bit +differently from the normal content modifiers; when used in a rule, +all content matches following it in the rule are affected (modified) +by it. + +Example:: + + alert http any any -> any any (file_data; content:"abc"; content:"xyz";) + +.. image:: http-keywords/file_data.png + +The ``file_data`` keyword affects all following content matches, until +the ``pkt_data`` keyword is encountered or it reaches the end of the +rule. This makes it a useful shortcut for applying many content +matches to the HTTP response body, eliminating the need to modify each +content match individually. + +Note: how much of the response/server body is inspected is controlled +in your :ref:`libhtp configuration section +` via the ``response-body-limit`` +setting. + +pcre +---- + +For information about the ``pcre`` keyword, check the :doc:`pcre` page. + +fast_pattern +------------ + +For information about the ``fast_pattern`` keyword, check the +:doc:`fast-pattern` page. diff --git a/doc/userguide/rules/http-keywords/Legenda_rules.png b/doc/userguide/rules/http-keywords/Legenda_rules.png new file mode 100644 index 000000000000..c3e913340f71 Binary files /dev/null and b/doc/userguide/rules/http-keywords/Legenda_rules.png differ diff --git a/doc/userguide/rules/http-keywords/client_body.png b/doc/userguide/rules/http-keywords/client_body.png new file mode 100644 index 000000000000..d4ea6dba4756 Binary files /dev/null and b/doc/userguide/rules/http-keywords/client_body.png differ diff --git a/doc/userguide/rules/http-keywords/client_body1.png b/doc/userguide/rules/http-keywords/client_body1.png new file mode 100644 index 000000000000..5b9a7496324b Binary files /dev/null and b/doc/userguide/rules/http-keywords/client_body1.png differ diff --git a/doc/userguide/rules/http-keywords/cookie.png b/doc/userguide/rules/http-keywords/cookie.png new file mode 100644 index 000000000000..8e5c26262e4e Binary files /dev/null and b/doc/userguide/rules/http-keywords/cookie.png differ diff --git a/doc/userguide/rules/http-keywords/cookie1.png b/doc/userguide/rules/http-keywords/cookie1.png new file mode 100644 index 000000000000..12293c3f41df Binary files /dev/null and b/doc/userguide/rules/http-keywords/cookie1.png differ diff --git a/doc/userguide/rules/http-keywords/fast_pattern.png b/doc/userguide/rules/http-keywords/fast_pattern.png new file mode 100644 index 000000000000..97163a50ab0c Binary files /dev/null and b/doc/userguide/rules/http-keywords/fast_pattern.png differ diff --git a/doc/userguide/rules/http-keywords/file_data.png b/doc/userguide/rules/http-keywords/file_data.png new file mode 100644 index 000000000000..d604c0738ea2 Binary files /dev/null and b/doc/userguide/rules/http-keywords/file_data.png differ diff --git a/doc/userguide/rules/http-keywords/header.png b/doc/userguide/rules/http-keywords/header.png new file mode 100644 index 000000000000..d78714c27672 Binary files /dev/null and b/doc/userguide/rules/http-keywords/header.png differ diff --git a/doc/userguide/rules/http-keywords/header1.png b/doc/userguide/rules/http-keywords/header1.png new file mode 100644 index 000000000000..a255a0e61c0f Binary files /dev/null and b/doc/userguide/rules/http-keywords/header1.png differ diff --git a/doc/userguide/rules/http-keywords/http_server_body.png b/doc/userguide/rules/http-keywords/http_server_body.png new file mode 100644 index 000000000000..8fc84e12356d Binary files /dev/null and b/doc/userguide/rules/http-keywords/http_server_body.png differ diff --git a/doc/userguide/rules/http-keywords/http_uri.png b/doc/userguide/rules/http-keywords/http_uri.png new file mode 100644 index 000000000000..60a678609aa3 Binary files /dev/null and b/doc/userguide/rules/http-keywords/http_uri.png differ diff --git a/doc/userguide/rules/http-keywords/method.png b/doc/userguide/rules/http-keywords/method.png new file mode 100644 index 000000000000..b718c8b7c2ec Binary files /dev/null and b/doc/userguide/rules/http-keywords/method.png differ diff --git a/doc/userguide/rules/http-keywords/method1.png b/doc/userguide/rules/http-keywords/method1.png new file mode 100644 index 000000000000..70d8c78f9e5d Binary files /dev/null and b/doc/userguide/rules/http-keywords/method1.png differ diff --git a/doc/userguide/rules/http-keywords/method2.png b/doc/userguide/rules/http-keywords/method2.png new file mode 100644 index 000000000000..1084618167f5 Binary files /dev/null and b/doc/userguide/rules/http-keywords/method2.png differ diff --git a/doc/userguide/rules/http-keywords/request.png b/doc/userguide/rules/http-keywords/request.png new file mode 100644 index 000000000000..7298234e9359 Binary files /dev/null and b/doc/userguide/rules/http-keywords/request.png differ diff --git a/doc/userguide/rules/http-keywords/request2.png b/doc/userguide/rules/http-keywords/request2.png new file mode 100644 index 000000000000..b59b00c24949 Binary files /dev/null and b/doc/userguide/rules/http-keywords/request2.png differ diff --git a/doc/userguide/rules/http-keywords/response1.png b/doc/userguide/rules/http-keywords/response1.png new file mode 100644 index 000000000000..40430c9e1f37 Binary files /dev/null and b/doc/userguide/rules/http-keywords/response1.png differ diff --git a/doc/userguide/rules/http-keywords/stat-code1.png b/doc/userguide/rules/http-keywords/stat-code1.png new file mode 100644 index 000000000000..77758ee6c91c Binary files /dev/null and b/doc/userguide/rules/http-keywords/stat-code1.png differ diff --git a/doc/userguide/rules/http-keywords/stat_code.png b/doc/userguide/rules/http-keywords/stat_code.png new file mode 100644 index 000000000000..a865fe10bdb9 Binary files /dev/null and b/doc/userguide/rules/http-keywords/stat_code.png differ diff --git a/doc/userguide/rules/http-keywords/stat_msg.png b/doc/userguide/rules/http-keywords/stat_msg.png new file mode 100644 index 000000000000..f6f8ac8c7621 Binary files /dev/null and b/doc/userguide/rules/http-keywords/stat_msg.png differ diff --git a/doc/userguide/rules/http-keywords/stat_msg_1.png b/doc/userguide/rules/http-keywords/stat_msg_1.png new file mode 100644 index 000000000000..f26a075b6579 Binary files /dev/null and b/doc/userguide/rules/http-keywords/stat_msg_1.png differ diff --git a/doc/userguide/rules/http-keywords/uri.png b/doc/userguide/rules/http-keywords/uri.png new file mode 100644 index 000000000000..e43b4f792bb2 Binary files /dev/null and b/doc/userguide/rules/http-keywords/uri.png differ diff --git a/doc/userguide/rules/http-keywords/uri1.png b/doc/userguide/rules/http-keywords/uri1.png new file mode 100644 index 000000000000..d9fab6c14dcd Binary files /dev/null and b/doc/userguide/rules/http-keywords/uri1.png differ diff --git a/doc/userguide/rules/http-keywords/uricontent.png b/doc/userguide/rules/http-keywords/uricontent.png new file mode 100644 index 000000000000..b9e8aad2740e Binary files /dev/null and b/doc/userguide/rules/http-keywords/uricontent.png differ diff --git a/doc/userguide/rules/http-keywords/uricontent1.png b/doc/userguide/rules/http-keywords/uricontent1.png new file mode 100644 index 000000000000..fa0cfac20074 Binary files /dev/null and b/doc/userguide/rules/http-keywords/uricontent1.png differ diff --git a/doc/userguide/rules/http-keywords/urilen.png b/doc/userguide/rules/http-keywords/urilen.png new file mode 100644 index 000000000000..1697db1ca8af Binary files /dev/null and b/doc/userguide/rules/http-keywords/urilen.png differ diff --git a/doc/userguide/rules/http-keywords/urilen1.png b/doc/userguide/rules/http-keywords/urilen1.png new file mode 100644 index 000000000000..8a11075fcac5 Binary files /dev/null and b/doc/userguide/rules/http-keywords/urilen1.png differ diff --git a/doc/userguide/rules/http-keywords/user_agent.png b/doc/userguide/rules/http-keywords/user_agent.png new file mode 100644 index 000000000000..f4fa2e835eca Binary files /dev/null and b/doc/userguide/rules/http-keywords/user_agent.png differ diff --git a/doc/userguide/rules/http-keywords/user_agent_match.png b/doc/userguide/rules/http-keywords/user_agent_match.png new file mode 100644 index 000000000000..d99d85be0b3e Binary files /dev/null and b/doc/userguide/rules/http-keywords/user_agent_match.png differ diff --git a/doc/userguide/rules/http-uri-normalization.rst b/doc/userguide/rules/http-uri-normalization.rst new file mode 100644 index 000000000000..20d9b14bc69a --- /dev/null +++ b/doc/userguide/rules/http-uri-normalization.rst @@ -0,0 +1,10 @@ +HTTP-uri normalization +====================== + +The uri has two appearances in Suricata: the raw_uri and the +normalized uri. The space for example can be indicated with the +heximal notation %20. To convert this notation in a space, means +normalizing it. It is possible though to match specific on the +characters %20 in a uri. This means matching on the raw_uri. The +raw_uri and the normalized uri are separate buffers. So, the raw_uri +inspects the raw_uri buffer and can not inspect the normalized buffer. diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst new file mode 100644 index 000000000000..115458da101a --- /dev/null +++ b/doc/userguide/rules/index.rst @@ -0,0 +1,25 @@ +Suricata Rules +============== + +.. toctree:: + + intro + meta + header-keywords + prefilter + payload-keywords + http-keywords + flow-keywords + flowint + xbits + file-keywords + thresholding + dns-keywords + tls-keywords + modbus-keyword + dnp3-keywords + enip-keyword + app-layer + rule-lua-scripting + normalized-buffers + snort-compatibility diff --git a/doc/userguide/rules/intro.rst b/doc/userguide/rules/intro.rst new file mode 100644 index 000000000000..fb20a1c7ec7f --- /dev/null +++ b/doc/userguide/rules/intro.rst @@ -0,0 +1,189 @@ +Rules Introduction +================== + +.. contents:: + +Signatures play a very important role in Suricata. In most occasions +people are using existing rulesets. The most used are `Emerging +Threats `_, `Emerging Threats Pro +`_ and Sourcefire's `VRT +`_. A way to install rules is described in +:doc:`../rule-management/oinkmaster`. This Suricata Rules document explains all about +signatures; how to read-, adjust-and create them. + +A rule/signature consists of the following: + + The action, header and rule-options. + +Example of a signature: + +.. image:: intro/intro_sig.png + +Action +------ + +For more information read 'Action Order' see +:ref:`suricata-yaml-action-order`. + +Example: + +.. image:: intro/action.png + +In this example the red, bold-faced part is the action. + +Protocol +-------- + +This keyword in a signature tells Suricata which protocol it +concerns. You can choose between four settings. tcp (for +tcp-traffic), udp, icmp and ip. ip stands for 'all' or 'any'. +Suricata adds a few protocols : http, ftp, tls (this includes ssl), +smb and dns (from v2.0). These are the so-called application layer +protocols or layer 7 protocols. If you have a signature with for +instance a http-protocol, Suricata makes sure the signature can only +match if it concerns http-traffic. + +Example: + +.. image:: intro/protocol.png + +In this example the red, bold-faced part is the protocol. + +Source and destination +---------------------- + +In source you can assign IP-addresses; IPv4 and IPv6 combined as well +as separated. You can also set variables such as HOME_NET. (For more +information see :ref:`suricata-yaml-rule-vars`. In the Yaml-file you +can set IP-addresses for variables such as EXTERNAL_NET and +HOME_NET. These settings will be used when you use these variables in +a rule. In source and destination you can make use of signs like ! +And [ ]. + +For example:: + + ! 1.1.1.1 (Every IP address but 1.1.1.1) + ![1.1.1.1, 1.1.1.2] (Every IP address but 1.1.1.1 and 1.1.1.2) + $HOME_NET (Your setting of HOME_NET in yaml) + [$EXTERNAL_NET, !$HOME_NET] (EXTERNAL_NET and not HOME_NET) + [10.0.0.0/24, !10.0.0.5] (10.0.0.0/24 except for 10.0.0.5) + […..,[....]] + […. ,![.....]] + + +Pay attention to the following: + +If your settings in Yaml are:: + + HOME_NET: any + EXTERNAL_NET: ! $HOME_NET + +You can not write a signature using EXTERNAL_NET because it stands for +'not any'. This is a invalid setting. + +Example of source and destination in a signature: + +.. image:: intro/Source.png + +The red, bold-faced part is the source. + +.. image:: intro/destination.png + +The red, bold-faced part is the destination. + +Ports (source-and destination-port) +----------------------------------- + +Traffic comes in and goes out through ports. Different ports have +different port-numbers. The HTTP-port for example is 80 while 443 is +the port for HTTPS and MSN makes use of port 1863. Commonly the Source +port will be set as 'any'. This will be influenced by the +protocol. The source port is designated at random by the operating +system. Sometimes it is possible to filter/screen on the source In +setting ports you can make use of special signs as well, like +described above at 'source'. Signs like:: + + ! exception/negation + : range + [] signs to make clear which parts belong together + , separation + +Example:: + + [80, 81, 82] (port 80, 81 and 82) + [80: 82] (Range from 80 till 82) + [1024: ] (From 1024 till the highest port-number) + !80 (Every port but 80) + [80:100,!99] (Range from 80 till 100 but 99 excluded) + [1:80,![2,4]] + [….[.....]] + +Example of ports in a signature: + +.. image:: intro/Source-port.png + + +.. image:: intro/Dest_port.png + +In this example, the red, bold-faced part is the port. + +Direction +--------- + +The direction tells in which way the signature has to match. Nearly +every signature has an arrow to the right. This means that only +packets with the same direction can match. + +:: + + source -> destination + source <> destination (both directions) + +Example:: + + alert tcp 1.2.3.4 1024 - > 5.6.7.8 80 + +Example 1 tcp-session + +.. image:: intro/TCP-session.png + +In this example there will only be a match if the signature has the +same order/direction as the payload. + +Example of direction in a signature: + +.. image:: intro/Direction.png + +In this example the red, bold-faced part is the direction. + +Rule options +------------ + +Keywords have a set format:: + + name: settings; + +Sometimes it is just the name of the setting followed by ; . Like nocase; + +There are specific settings for: + +* meta-information. +* headers +* payloads +* flows + +.. note:: The characters ``;`` and ``"`` have special meaning in the + Suricata rule language and must be escaped when used in a + rule option value. For example:: + + msg:"Message with semicolon\;"; + +For more information about these settings, you can click on the +following headlines: + +* :doc:`meta` +* :doc:`payload-keywords` +* :doc:`http-keywords` +* :doc:`dns-keywords` +* :doc:`flow-keywords` +* :doc:`../reputation/ipreputation/ip-reputation-rules` diff --git a/doc/userguide/rules/intro/Dest_port.png b/doc/userguide/rules/intro/Dest_port.png new file mode 100644 index 000000000000..43e04147b886 Binary files /dev/null and b/doc/userguide/rules/intro/Dest_port.png differ diff --git a/doc/userguide/rules/intro/Direction.png b/doc/userguide/rules/intro/Direction.png new file mode 100644 index 000000000000..bdd2378e9fed Binary files /dev/null and b/doc/userguide/rules/intro/Direction.png differ diff --git a/doc/userguide/rules/intro/Source-port.png b/doc/userguide/rules/intro/Source-port.png new file mode 100644 index 000000000000..c046c49a53cb Binary files /dev/null and b/doc/userguide/rules/intro/Source-port.png differ diff --git a/doc/userguide/rules/intro/Source.png b/doc/userguide/rules/intro/Source.png new file mode 100644 index 000000000000..d0d1baaa3842 Binary files /dev/null and b/doc/userguide/rules/intro/Source.png differ diff --git a/doc/userguide/rules/intro/TCP-session.png b/doc/userguide/rules/intro/TCP-session.png new file mode 100644 index 000000000000..87d0eea07ed3 Binary files /dev/null and b/doc/userguide/rules/intro/TCP-session.png differ diff --git a/doc/userguide/rules/intro/action.png b/doc/userguide/rules/intro/action.png new file mode 100644 index 000000000000..4d67d152b0b6 Binary files /dev/null and b/doc/userguide/rules/intro/action.png differ diff --git a/doc/userguide/rules/intro/destination.png b/doc/userguide/rules/intro/destination.png new file mode 100644 index 000000000000..3fc44dbc6736 Binary files /dev/null and b/doc/userguide/rules/intro/destination.png differ diff --git a/doc/userguide/rules/intro/intro_sig.png b/doc/userguide/rules/intro/intro_sig.png new file mode 100644 index 000000000000..b726fc5dcb90 Binary files /dev/null and b/doc/userguide/rules/intro/intro_sig.png differ diff --git a/doc/userguide/rules/intro/protocol.png b/doc/userguide/rules/intro/protocol.png new file mode 100644 index 000000000000..2e0ef370a9f8 Binary files /dev/null and b/doc/userguide/rules/intro/protocol.png differ diff --git a/doc/userguide/rules/meta.rst b/doc/userguide/rules/meta.rst new file mode 100644 index 000000000000..7132f2dff6a3 --- /dev/null +++ b/doc/userguide/rules/meta.rst @@ -0,0 +1,181 @@ +Meta-settings +============= + +Meta-settings have no effect on Suricata's inspection; they do have an effect on the way Suricata reports events. + +msg (message) +------------- + +The keyword msg gives more information about the signature and the possible alert. The first part shows the class of the signature. It is a convention that part is written in uppercase +characters. + +The format of msg is: + +:: + + msg: "some description"; + +Examples: + +:: + + msg:"ATTACK-RESPONSES 403 Forbidden"; + msg:"ET EXPLOIT SMB-DS DCERPC PnP bind attempt"; + +It is a convention that msg is always the first keyword of a signature. + +Another example of msg in a signature: + +In this example the red, bold-faced part is the msg. + +.. note:: The following characters must be escaped inside the msg: + ``;`` ``\`` ``"`` + +Sid (signature id) +------------------ + +The keyword sid gives every signature its own id. This id is stated with a number. + +The format of sid is: + +:: + + sid:123; + +Example of sid in a signature: + +.. image:: meta/sid.png + +In this example the red, bold-faced part is the sid. + +Rev (Revision) +-------------- + +The sid keyword is almost every time accompanied by rev. Rev +represents the version of the signature. If a signature is modified, +the number of rev will be incremented by the signature writers. The +format of rev is: + +:: + + rev:123; + +*It is a convention that sid comes before rev, and both are the last +of all keywords.* + +Example of rev in a signature: + +.. image:: meta/rev.png + +In this example the red, bold-faced part is the rev. + +Gid (group id) +-------------- + +The gid keyword can be used to give different groups of signatures +another id value (like in sid). Suricata uses by default gid 1. It is +possible to modify this. It is not usual that it will be changed, and +changing it has no technical implications. You can only notice it in +the alert. + +Example of gid in a signature: + +.. image:: meta/gid.png + +This is an example from the fast.log. +In the part [1:2008124:2], 1 is the gid (2008124 is the the sid and 2 the rev). + +Classtype +--------- + +The classtype keyword gives information about the classification of +rules and alerts. It consists of a short name, a long name and a +priority. It can tell for example whether a rule is just informational +or is about a hack etcetera. For each classtype, the +classification.config has a priority which will be used in the rule. + +*It is a convention that classtype comes before sid and rev and after +the rest of the keywords.* + +Example classtype:: + + config classification: web-application-attack,Web Application Attack,1 + config classification: not-suspicious,Not Suspicious Traffic,3 + +.. image:: meta/classification.png + +In this example you see how classtype appears in signatures, the +classification.config and the alert. + +Another example of classtype in a signature: + +.. image:: meta/classtype.png + +In this example the red, bold-faced part is the classtype. + +Reference +--------- + +The reference keywords direct to places where information about the +signature and about the problem the signature tries to address, can be +found. The reference keyword can appear multiple times in a signature. +This keyword is meant for signature-writers and analysts who +investigate why a signature has matched. It has the following format: + +:: + + reference: url, www.info.nl + +In this example url is the type of reference. After that comes the +actual reference (notice here you can not use http before the url). + +There are different types of references: + +type: + +:: + + system URL Prefix + bugtraq http://www.securityfocus.com/bid + cve http://cve.mitre.org/cgi-bin/cvename.cgi?name= + nessus http://cgi.nessus.org/plugins/dump.php3?id= + arachnids (No longer available but you might still encounter this in signatures.) + http://www.whitehats.com/info/IDS + mcafee http://vil.nai.com/vil/dispVirus.asp?virus_k= + url http:// + +For example bugtraq will be replaced by the full url: + +:: + + reference: bugtraq, 123; http://www.securityfocus.com/bid + +Example of reference in a signature: + +.. image:: meta/reference.png + +In this example the red, bold-faced part is the action. + +Priority +-------- + +The priority keyword comes with a mandatory numeric value which can +range from 1 till 255. The numbers 1 to 4 are most often used. +Signatures with a higher priority will be examined first. The highest +priority is 1. Normally signatures have already a priority through +class type. This can be overruled with the keyword priority. The +format of priority is: + +:: + + priority:1; + +Metadata +-------- + +Suricata ignores the words behind meta data. Suricata supports this +keyword because it is part of the signature language. The format is: + +:: + + metadata:......; diff --git a/doc/userguide/rules/meta/classification.png b/doc/userguide/rules/meta/classification.png new file mode 100644 index 000000000000..456b1ee30a07 Binary files /dev/null and b/doc/userguide/rules/meta/classification.png differ diff --git a/doc/userguide/rules/meta/classtype.png b/doc/userguide/rules/meta/classtype.png new file mode 100644 index 000000000000..3d891943d2e9 Binary files /dev/null and b/doc/userguide/rules/meta/classtype.png differ diff --git a/doc/userguide/rules/meta/gid.png b/doc/userguide/rules/meta/gid.png new file mode 100644 index 000000000000..051eecbf5db7 Binary files /dev/null and b/doc/userguide/rules/meta/gid.png differ diff --git a/doc/userguide/rules/meta/msg.png b/doc/userguide/rules/meta/msg.png new file mode 100644 index 000000000000..8d1e1beeb993 Binary files /dev/null and b/doc/userguide/rules/meta/msg.png differ diff --git a/doc/userguide/rules/meta/reference.png b/doc/userguide/rules/meta/reference.png new file mode 100644 index 000000000000..8ed3057ef81e Binary files /dev/null and b/doc/userguide/rules/meta/reference.png differ diff --git a/doc/userguide/rules/meta/rev.png b/doc/userguide/rules/meta/rev.png new file mode 100644 index 000000000000..d6f039fbdb05 Binary files /dev/null and b/doc/userguide/rules/meta/rev.png differ diff --git a/doc/userguide/rules/meta/sid.png b/doc/userguide/rules/meta/sid.png new file mode 100644 index 000000000000..7952641d64a8 Binary files /dev/null and b/doc/userguide/rules/meta/sid.png differ diff --git a/doc/userguide/rules/modbus-keyword.rst b/doc/userguide/rules/modbus-keyword.rst new file mode 100644 index 000000000000..407c3e38e8fc --- /dev/null +++ b/doc/userguide/rules/modbus-keyword.rst @@ -0,0 +1,87 @@ +Modbus Keyword +============== + +The modbus keyword can be used for matching on various properties of +Modbus requests. + +There are two ways of using this keyword: + +* matching on functions properties with the setting "function"; +* matching on directly on data access with the setting "access". + +With the setting **function**, you can match on: + +* an action based on a function code field and a sub-function code when applicable; +* one of three categories of Modbus functions; +* public functions that are publicly defined (setting "public") +* user-defined functions (setting "user") +* reserved functions that are dedicated to proprietary extensions of Modbus (keyword "reserved") +* one of the two sub-groups of public functions: + + * assigned functions whose definition is already given in the Modbus specification (keyword "assigned"); + * unassigned functions, which are reserved for future use (keyword "unassigned"). + +Syntax:: + + modbus: function + modbus: function , subfunction + modbus: function [!] + +Sign '!' is negation + +Examples:: + + modbus: function 21 # Write File record function + modbus: function 4, subfunction 4 # Force Listen Only Mode (Diagnostics) function + modbus: function assigned # defined by Modbus Application Protocol Specification V1.1b3 + modbus: function public # validated by the Modbus.org community + modbus: function user # internal use and not supported by the specification + modbus: function reserved # used by some companies for legacy products and not available for public use + modbus: function !reserved # every function but reserved function + +With the **access** setting, you can match on: + +* a type of data access (read or write); +* one of primary tables access (Discretes Input, Coils, Input Registers and Holding Registers); +* a range of addresses access; +* a written value. + +Syntax:: + + modbus: access + modbus: access + modbus: access , address + modbus: access , address , value + +With __ setting matches on the address or value as it is being +accessed or written as follows:: + + address 100 # exactly address 100 + address 100<>200 # greater than address 100 and smaller than address 200 + address >100 # greater than address 100 + address <100 # smaller than address 100 + +Examples:: + + modbus: access read # Read access + modbus: access write # Write access + modbus: access read input # Read access to Discretes Input table + modbus: access write coils # Write access to Coils table + modbus: access read discretes, address <100 # Read access at address smaller than 100 of Discretes Input table + modbus: access write holding, address 500, value >200 # Write value greather than 200 at address 500 of Holding Registers table + +(cf. http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf) + +**Note:** Address of read and write are starting at 1. So if your system +is using a start at 0, you need to add 1 the address values. + +**Note:** According to MODBUS Messaging on TCP/IP Implementation Guide +V1.0b, it is recommended to keep the TCP connection opened with a +remote device and not to open and close it for each MODBUS/TCP +transaction. In that case, it is important to set the depth of the +stream reassembling as unlimited (stream.reassembly.depth: 0) + +(cf. http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf) + +Paper and presentation (in french) on Modbus support are available : +http://www.ssi.gouv.fr/agence/publication/detection-dintrusion-dans-les-systemes-industriels-suricata-et-le-cas-modbus/ diff --git a/doc/userguide/rules/normalized-buffers.rst b/doc/userguide/rules/normalized-buffers.rst new file mode 100644 index 000000000000..a3a282a95f83 --- /dev/null +++ b/doc/userguide/rules/normalized-buffers.rst @@ -0,0 +1,18 @@ +Normalized Buffers +================== + +.. toctree:: + + http-uri-normalization + +A packet consists of raw data. HTTP and reassembly make a copy of +those kinds of packets data. They erase anomalous content, combine +packets etcetera. What remains is a called the 'normalized buffer'. + +Example: + +.. image:: normalized-buffers/normalization1.png + +Because the data is being normalized, it is not what it used to be; it +is an interpretation. Normalized buffers are: all HTTP-keywords, +reassembled streams, TLS-, SSL-, SSH-, FTP- and dcerpc-buffers. diff --git a/doc/userguide/rules/normalized-buffers/normalization1.png b/doc/userguide/rules/normalized-buffers/normalization1.png new file mode 100644 index 000000000000..a99820cc144d Binary files /dev/null and b/doc/userguide/rules/normalized-buffers/normalization1.png differ diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst new file mode 100644 index 000000000000..2e0f4db0cafc --- /dev/null +++ b/doc/userguide/rules/payload-keywords.rst @@ -0,0 +1,303 @@ +Payload Keywords +================ + +.. toctree:: + :maxdepth: 2 + + pcre + fast-pattern + +Payload keywords inspect the content of the payload of a packet or +stream. + +Content +------- + +The content keyword is very important in signatures. Between the +quotation marks you can write on what you would like the signature to +match. The most simple format of content is:: + + content: ”............”; + +It is possible to use several contents in a signature. + +Contents match on bytes. There are 256 different values of a byte +(0-255). You can match on all characters; from a till z, upper case +and lower case and also on all special signs. But not all of the bytes +are printable characters. For these bytes heximal notations are +used. Many programming languages use 0x00 as a notation, where 0x +means it concerns a binary value, however the rule language uses +``|00|`` as a notation. This kind of notation can also be used for +printable characters. + +Example:: + + |61| is a + |61 61| is aa + |41| is A + |21| is ! + |0D| is carriage return + |0A| is line feed + +There are characters you can not use in the content because they are +already important in the signature. For matching on these characters +you should use the heximal notation. These are:: + + “ |22| + ; |3B| + : |3A| + | |7C| + +It is a convention to write the heximal notation in upper case characters. + +To write for instance ``http://`` in the content of a signature, you +should write it like this: ``content: “http|3A|//”;`` If you use a +heximal notation in a signature, make sure you always place it between +pipes. Otherwise the notation will be taken literally as part of the +content. + +A few examples:: + + content:“a|0D|bc”; + content:”|61 0D 62 63|"; + content:”a|0D|b|63|”; + +It is possible to let a signature check the whole payload for a match with the content or to let it check specific parts of the payload. We come to that later. +If you add nothing special to the signature, it will try to find a match in all the bytes of the payload. + +Example: + +.. image:: payload-keywords/content.png + +In this example, the red, bold-faced part is the content. + + +By default the pattern-matching is case sensitive. The content has to +be accurate, otherwise there will not be a match. + +.. image:: payload-keywords/content2.png + +Legend: + +.. image:: payload-keywords/Legenda_rules.png + +It is possible to use the ! for exceptions in contents as well. + +For example:: + + alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Outdated Firefox on + Windows"; content:"User-Agent|3A| Mozilla/5.0 |28|Windows|3B| "; + content:"Firefox/3."; distance:0; content:!"Firefox/3.6.13"; + distance:-10; sid:9000000; rev:1;) + +You see ``content:!”Firefox/3.6.13”;``. This means an alert will be +generated if the the used version of Firefox is not 3.6.13. + +.. note:: The following characters must be escaped inside the content: + ``;`` ``\`` ``"`` + +Nocase +------ + +If you do not want to make a distinction between uppercase and +lowercase characters, you can use nocase. The keyword nocase is a +content modifier. + +The format of this keyword is:: + + nocase; + +You have to place it behind the content you want to modify, like:: + + content: “abc”; nocase; + +Example nocase: + +.. image:: payload-keywords/content3.png + +It has no influence on other contents in the signature. + +Depth +----- + +The depth keyword is a absolute content modifier. It comes after the +content. The depth content modifier comes with a mandatory numeric +value, like:: + + depth:12; + +The number after depth designates how many bytes from the beginning of +the payload will be checked. + +Example: + +.. image:: payload-keywords/content4.png + +Offset +------ + +The offset keyword designates from which byte in the payload will be +checked to find a match. For instance offset:3; checks the fourth +byte and further. + +.. image:: payload-keywords/content5.png + +The keywords offset and depth can be combined and are often used together. + +For example:: + + content; “def”; offset:3; depth:3; + +If this was used in a signature, it would check the payload from the +third byte till the sixth byte. + +.. image:: payload-keywords/content6.png + + +Distance +-------- + +The keyword distance is a relative content modifier. This means it +indicates a relation between this content keyword and the content +preceding it. Distance has its influence after the preceding match. +The keyword distance comes with a mandatory numeric value. The value +you give distance, determines the byte in the payload from which will +be checked for a match relative to the previous match. Distance only +determines where Suricata will start looking for a pattern. So, +distance:5; means the pattern can be anywhere after the previous +match + 5 bytes. For limiting how far after the last match Suricata +needs to look, use 'within'. + +Examples of distance: + +.. image:: payload-keywords/distance5.png + +.. image:: payload-keywords/distance4.png + +.. image:: payload-keywords/distance.png + +.. image:: payload-keywords/distance1.png + +Distance can also be a negative number. It can be used to check for +matches with partly the same content (see example) or for a content +even completely before it. This is not very often used though. It is +possible to attain the same results with other keywords. + +.. image:: payload-keywords/distance3.png + +Within +------ + +The keyword within is relative to the preceding match. The keyword +within comes with a mandatory numeric value. Using within makes sure +there will only be a match if the content matches with the payload +within the set amount of bytes. Within can not be 0 (zero) + +Example: + +.. image:: payload-keywords/within2.png + +Example of matching with within: + +.. image:: payload-keywords/within1.png + +The second content has to fall/come 'within 3 ' from the first content. + +As mentioned before, distance and within can be very well combined in +a signature. If you want Suricata to check a specific part of the +payload for a match, use within. + +.. image:: payload-keywords/within_distance.png + +.. image:: payload-keywords/within_distance2.png + +Isdataat +-------- + +The purpose of the isdataat keyword is to look if there is still data +at a specific part of the payload. The keyword starts with a number +(the position) and then optional followed by 'relative' separated by a +comma and the option rawbytes. You use the word 'relative' to know if +there is still data at a specific part of the payload relative to the +last match. + +So you can use both examples:: + + isdataat:512; + + isdataat:50, relative; + +The first example illustrates a signature which searches for byte 512 +of the payload. The second example illustrates a signature searching +for byte 50 after the last match. + +You can also use the negation (!) before isdataat. + +.. image:: payload-keywords/isdataat1.png + +Dsize +----- + +With the dsize keyword, you can match on the size of the packet +payload. You can use the keyword for example to look for abnormal +sizes of payloads. This may be convenient in detecting buffer +overflows. + +Format:: + + dsize:; + +example of dsize in a rule: + +.. image:: payload-keywords/dsize.png + +rpc +---- + +The rpc keyword can be used to match in the SUNRPC CALL on the RPC +procedure numbers and the RPC version. + +You can modify the keyword by using a wild-card, defined with * With +this wild-card you can match on all version and/or procedure numbers. + +RPC (Remote Procedure Call) is an application that allows a computer +program to execute a procedure on another computer (or address +space). It is used for inter-process communication. See +http://en.wikipedia.org/wiki/Inter-process_communication + +Format:: + + rpc:, [|*], [|*]>; + +Example of the rpc keyword in a rule: + +.. image:: payload-keywords/rpc.png + +Replace +------- + +The replace content modifier can only be used in ips. It adjusts +network traffic. It changes the content it follows ('abc') into +another ('def'), see example: + +.. image:: payload-keywords/replace.png + +.. image:: payload-keywords/replace1.png + +The replace modifier has to contain as many characters as the content +it replaces. It can only be used with individual packets. It will not +work for :doc:`normalized-buffers` like HTTP uri or a content match in +the reassembled stream. + +The checksums will be recalculated by Suricata and changed after the +replace keyword is being used. + +pcre +---- + +For information about pcre check the :doc:`pcre` page. + +fast_pattern +------------ + +For information about fast_pattern check the :doc:`fast-pattern` page. diff --git a/doc/userguide/rules/payload-keywords/Legenda_rules.png b/doc/userguide/rules/payload-keywords/Legenda_rules.png new file mode 100644 index 000000000000..c3e913340f71 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/Legenda_rules.png differ diff --git a/doc/userguide/rules/payload-keywords/content.png b/doc/userguide/rules/payload-keywords/content.png new file mode 100644 index 000000000000..267f9ee51112 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/content.png differ diff --git a/doc/userguide/rules/payload-keywords/content2.png b/doc/userguide/rules/payload-keywords/content2.png new file mode 100644 index 000000000000..cdfe61cbe771 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/content2.png differ diff --git a/doc/userguide/rules/payload-keywords/content3.png b/doc/userguide/rules/payload-keywords/content3.png new file mode 100644 index 000000000000..a92acd6251ef Binary files /dev/null and b/doc/userguide/rules/payload-keywords/content3.png differ diff --git a/doc/userguide/rules/payload-keywords/content4.png b/doc/userguide/rules/payload-keywords/content4.png new file mode 100644 index 000000000000..943b6fdf4048 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/content4.png differ diff --git a/doc/userguide/rules/payload-keywords/content5.png b/doc/userguide/rules/payload-keywords/content5.png new file mode 100644 index 000000000000..41352ac448d4 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/content5.png differ diff --git a/doc/userguide/rules/payload-keywords/content6.png b/doc/userguide/rules/payload-keywords/content6.png new file mode 100644 index 000000000000..8a4f7bf278ed Binary files /dev/null and b/doc/userguide/rules/payload-keywords/content6.png differ diff --git a/doc/userguide/rules/payload-keywords/distance.png b/doc/userguide/rules/payload-keywords/distance.png new file mode 100644 index 000000000000..e6154dabfd01 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/distance.png differ diff --git a/doc/userguide/rules/payload-keywords/distance1.png b/doc/userguide/rules/payload-keywords/distance1.png new file mode 100644 index 000000000000..096c036fc364 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/distance1.png differ diff --git a/doc/userguide/rules/payload-keywords/distance3.png b/doc/userguide/rules/payload-keywords/distance3.png new file mode 100644 index 000000000000..4ec2b60c48bd Binary files /dev/null and b/doc/userguide/rules/payload-keywords/distance3.png differ diff --git a/doc/userguide/rules/payload-keywords/distance4.png b/doc/userguide/rules/payload-keywords/distance4.png new file mode 100644 index 000000000000..42d2d0416b2b Binary files /dev/null and b/doc/userguide/rules/payload-keywords/distance4.png differ diff --git a/doc/userguide/rules/payload-keywords/distance5.png b/doc/userguide/rules/payload-keywords/distance5.png new file mode 100644 index 000000000000..0481179aa668 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/distance5.png differ diff --git a/doc/userguide/rules/payload-keywords/dsize.png b/doc/userguide/rules/payload-keywords/dsize.png new file mode 100644 index 000000000000..5973f9d2a8f5 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/dsize.png differ diff --git a/doc/userguide/rules/payload-keywords/isdataat1.png b/doc/userguide/rules/payload-keywords/isdataat1.png new file mode 100644 index 000000000000..61606f0a4776 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/isdataat1.png differ diff --git a/doc/userguide/rules/payload-keywords/replace.png b/doc/userguide/rules/payload-keywords/replace.png new file mode 100644 index 000000000000..16e4746d2a0f Binary files /dev/null and b/doc/userguide/rules/payload-keywords/replace.png differ diff --git a/doc/userguide/rules/payload-keywords/replace1.png b/doc/userguide/rules/payload-keywords/replace1.png new file mode 100644 index 000000000000..69da275fa526 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/replace1.png differ diff --git a/doc/userguide/rules/payload-keywords/rpc.png b/doc/userguide/rules/payload-keywords/rpc.png new file mode 100644 index 000000000000..f5965eb8f3b1 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/rpc.png differ diff --git a/doc/userguide/rules/payload-keywords/within1.png b/doc/userguide/rules/payload-keywords/within1.png new file mode 100644 index 000000000000..0c816f967583 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/within1.png differ diff --git a/doc/userguide/rules/payload-keywords/within2.png b/doc/userguide/rules/payload-keywords/within2.png new file mode 100644 index 000000000000..c60857daf018 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/within2.png differ diff --git a/doc/userguide/rules/payload-keywords/within_distance.png b/doc/userguide/rules/payload-keywords/within_distance.png new file mode 100644 index 000000000000..7d74b2587286 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/within_distance.png differ diff --git a/doc/userguide/rules/payload-keywords/within_distance2.png b/doc/userguide/rules/payload-keywords/within_distance2.png new file mode 100644 index 000000000000..e45649372988 Binary files /dev/null and b/doc/userguide/rules/payload-keywords/within_distance2.png differ diff --git a/doc/userguide/rules/pcre.rst b/doc/userguide/rules/pcre.rst new file mode 100644 index 000000000000..9c0f4035c863 --- /dev/null +++ b/doc/userguide/rules/pcre.rst @@ -0,0 +1,138 @@ +pcre (Perl Compatible Regular Expressions) +========================================== + +The keyword pcre matches specific on regular expressions. More +information about regular expressions can be found here +http://en.wikipedia.org/wiki/Regular_expression. + +The complexity of pcre comes with a high price though: it has a +negative influence on performance. So, to mitigate Suricata from +having to check pcre often, pcre is mostly combined with 'content'. In +that case, the content has to match first, before pcre will be +checked. + +Format of pcre:: + + “//opts”; + +Example of pcre:: + + pcre:”/[0-9]{6}/”; + +In this example there will be a match if the payload contains six +numbers following. + +Example of pcre in a signature: + +.. image:: pcre/pcre.png + +There are a few qualities of pcre which can be modified: + +* By default pcre is case-sensitive. +* The . (dot) is a part of regex. It matches on every byte except for + newline characters. +* By default the payload will be inspected as one line. + +These qualities can be modified with the following characters:: + + i pcre is case insensitive + s pcre does check newline characters + m can make one line (of the payload) count as two lines + +These options are perl compatible modifiers. To use these modifiers, +you should add them to pcre, behind regex. Like this:: + + pcre: “//i”; + +*Pcre compatible modifiers* + +There are a few pcre compatible modifiers which can change the +qualities of pcre as well. These are: + +* ``A``: A pattern has to match at the beginning of a buffer. (In pcre + ^ is similar to A.) +* ``E``: Ignores newline characters at the end of the buffer/payload. +* ``G``: Inverts the greediness. + +.. note:: The following characters must be escaped inside the content: + ``;`` ``\`` ``"`` + +Suricata's modifiers +~~~~~~~~~~~~~~~~~~~~ + +Suricata has its own specific pcre modifiers. These are: + +* ``R``: Match relative to the last pattern match. It is similar to distance:0; +* ``U``: Makes pcre match on the normalized uri. It matches on the + uri_buffer just like uricontent and content combined with http_uri.U + can be combined with /R. Note that R is relative to the previous + match so both matches have to be in the HTTP-uri buffer. Read more + about :doc:`http-uri-normalization`. + +.. image:: pcre/pcre3.png + +.. image:: pcre/pcre4.png + +.. image:: pcre/pcre5.png + +.. image:: pcre/pcre6.png + +* ``I``: Makes pcre match on the HTTP-raw-uri. It matches on the same + buffer as http_raw_uri. I can be combined with /R. Note that R is + relative to the previous match so both matches have to be in the + HTTP-raw-uri buffer. Read more about :doc:`http-uri-normalization`. + +* ``P``: Makes pcre match on the HTTP- request-body. So, it matches on + the same buffer as http_client_body. P can be combined with /R. Note + that R is relative to the previous match so both matches have to be + in the HTTP-request body. + +* ``Q``: Makes pcre match on the HTTP- response-body. So, it matches + on the same buffer as http_server_body. Q can be combined with + /R. Note that R is relative to the previous match so both matches + have to be in the HTTP-response body. + +* ``H``: Makes pcre match on the HTTP-header. H can be combined with + /R. Note that R is relative to the previous match so both matches have + to be in the HTTP-header body. + +* ``D``: Makes pcre match on the unnormalized header. So, it matches + on the same buffer as http_raw_header. D can be combined with + /R. Note that R is relative to the previous match so both matches + have to be in the HTTP-raw-header. + +* ``M``: Makes pcre match on the request-method. So, it matches on the + same buffer as http_method. M can be combined with /R. Note that R + is relative to the previous match so both matches have to be in the + HTTP-method buffer. + +* ``C``: Makes pcre match on the HTTP-cookie. So, it matches on the + same buffer as http_cookie. C can be combined with /R. Note that R + is relative to the previous match so both matches have to be in the + HTTP-cookie buffer. + +* ``S``: Makes pcre match on the HTTP-stat-code. So, it matches on the + same buffer as http_stat_code. S can be combined with /R. Note that + R is relative to the previous match so both matches have to be in + the HTTP-stat-code buffer. + +* ``Y``: Makes pcre match on the HTTP-stat-msg. So, it matches on the + same buffer as http_stat_msg. Y can be combined with /R. Note that + R is relative to the previous match so both matches have to be in + the HTTP-stat-msg buffer. + +* ``B``: You can encounter B in signatures but this is just for + compatibility. So, Suricata does not use B but supports it so it + does not cause errors. + +* ``O``: Overrides the configures pcre match limit. + +* ``V``: Makes pcre match on the HTTP-User-Agent. So, it matches on + the same buffer as http_user_agent. V can be combined with /R. Note + that R is relative to the previous match so both matches have to be + in the HTTP-User-Agent buffer. + +* ``W``: Makes pcre match on the HTTP-Host. So, it matches on the same + buffer as http_host. W can be combined with /R. Note that R is + relative to the previous match so both matches have to be in the + HTTP-Host buffer. diff --git a/doc/userguide/rules/pcre/pcre.png b/doc/userguide/rules/pcre/pcre.png new file mode 100644 index 000000000000..83c3185671af Binary files /dev/null and b/doc/userguide/rules/pcre/pcre.png differ diff --git a/doc/userguide/rules/pcre/pcre3.png b/doc/userguide/rules/pcre/pcre3.png new file mode 100644 index 000000000000..3a55404fc98e Binary files /dev/null and b/doc/userguide/rules/pcre/pcre3.png differ diff --git a/doc/userguide/rules/pcre/pcre4.png b/doc/userguide/rules/pcre/pcre4.png new file mode 100644 index 000000000000..0b60132fac36 Binary files /dev/null and b/doc/userguide/rules/pcre/pcre4.png differ diff --git a/doc/userguide/rules/pcre/pcre5.png b/doc/userguide/rules/pcre/pcre5.png new file mode 100644 index 000000000000..7884e91b531d Binary files /dev/null and b/doc/userguide/rules/pcre/pcre5.png differ diff --git a/doc/userguide/rules/pcre/pcre6.png b/doc/userguide/rules/pcre/pcre6.png new file mode 100644 index 000000000000..ca73a902e9ac Binary files /dev/null and b/doc/userguide/rules/pcre/pcre6.png differ diff --git a/doc/userguide/rules/prefilter.rst b/doc/userguide/rules/prefilter.rst new file mode 100644 index 000000000000..0d136abbf789 --- /dev/null +++ b/doc/userguide/rules/prefilter.rst @@ -0,0 +1,13 @@ +Prefilter +========= + +The prefilter engines for other non-MPM keywords can be enabled in specific rules by using the 'prefilter' keyword. + +In the following rule the TTL test will be used in prefiltering instead of the single byte pattern: + +:: + + alert ip any any -> any any (ttl:123; prefilter; content:"a"; sid:1;) + +For more information on how to configure the prefilter engines, see :ref:`suricata-yaml-prefilter` + diff --git a/doc/userguide/rules/rule-lua-scripting.rst b/doc/userguide/rules/rule-lua-scripting.rst new file mode 100644 index 000000000000..8094ec85d034 --- /dev/null +++ b/doc/userguide/rules/rule-lua-scripting.rst @@ -0,0 +1,87 @@ +Lua Scripting +============= + +Syntax: + +:: + + lua:[!]; + +The script filename will be appended to your default rules location. + +The script has 2 parts, an init function and a match function. First, the init. + +Init function +------------- + + +.. code-block:: lua + + function init (args) + local needs = {} + needs["http.request_line"] = tostring(true) + return needs + end + +The init function registers the buffer(s) that need +inspection. Currently the following are available: + +* packet -- entire packet, including headers +* payload -- packet payload (not stream) +* http.uri +* http.uri.raw +* http.request_line +* http.request_headers +* http.request_headers.raw +* http.request_cookie +* http.request_user_agent +* http.request_body +* http.response_headers +* http.response_headers.raw +* http.response_body +* http.response_cookie + +All the HTTP buffers have a limitation: only one can be inspected by a +script at a time. + +Match function +-------------- + +.. code-block:: lua + + function match(args) + a = tostring(args["http.request_line"]) + if #a > 0 then + if a:find("^POST%s+/.*%.php%s+HTTP/1.0$") then + return 1 + end + end + + return 0 + end + +The script can return 1 or 0. It should return 1 if the condition(s) +it checks for match, 0 if not. + +Entire script: + +.. code-block:: lua + + function init (args) + local needs = {} + needs["http.request_line"] = tostring(true) + return needs + end + + function match(args) + a = tostring(args["http.request_line"]) + if #a > 0 then + if a:find("^POST%s+/.*%.php%s+HTTP/1.0$") then + return 1 + end + end + + return 0 + end + + return 0 diff --git a/doc/userguide/rules/snort-compatibility.rst b/doc/userguide/rules/snort-compatibility.rst new file mode 100644 index 000000000000..bf158edd3626 --- /dev/null +++ b/doc/userguide/rules/snort-compatibility.rst @@ -0,0 +1,73 @@ +Snort Compatibility +=================== + +.. contents:: + +Keyword: content +---------------- + +*Versions affected: All versions prior to 3.0.* + +Prior to Suricata 3.0, the argument provided to the content keyword +cannot be longer than 255 characters like it can in Snort. + +Suricata 3.0 and newer can accept content arguments longer than 255 +characters. + +See: + +* https://redmine.openinfosecfoundation.org/issues/1281 +* https://github.com/inliniac/suricata/pull/1475 + +Keyword: urilen +--------------- + +*Versions affected: all* + +In Snort the urilen range is inclusive, in Suricata it is not. + +Example:: + + urilen:5<>10 + +In Snort the above will match URIs that are greater than and equal to +5 and less than and equal to 10. *Note that this is not what is +documented in the Snort manual.* + +In Suricata the above will match URIs that are greater than 5 and less +than 10, so it will only mathch URIs that are 6, 7, 8, and 9 bytes +long. + +See: + +* https://redmine.openinfosecfoundation.org/issues/1416 + +Keyword: isdataat +----------------- + +*Versions affected: all* + +``isdataat`` is off by one from Snort. In Snort the offset starts at 0 +where Suricata starts at 1. + +Keyword: flowbits +----------------- + +*Versions affected: all prior to 2.0.9* + +Versions of Suricata prior to 2.0.9 treated leading and trailing +whitespace in flowbit names as part of the flowbit name where Snort +does not. + +This was fixed in Suricata 2.0.9. + +See: + +* https://redmine.openinfosecfoundation.org/issues/1481 + +Keyword: flow:not_established +----------------------------- + +*Versions affected: all* + +The ``not_established`` argument to the ``flow`` keyword is not supported. diff --git a/doc/userguide/rules/thresholding.rst b/doc/userguide/rules/thresholding.rst new file mode 100644 index 000000000000..196f20a3408a --- /dev/null +++ b/doc/userguide/rules/thresholding.rst @@ -0,0 +1,118 @@ +Rule Thresholding +================= + +Thresholding can be configured per rule and also globally, see +:doc:`../configuration/global-thresholds`. + +*Note: mixing rule and global thresholds is not supported in 1.3 and +before. See bug #425.* For the state of the support in 1.4 see +:ref:`global-thresholds-vs-rule-thresholds` + +threshold +--------- + +The threshold keyword can be used to control the rule's alert +frequency. It has 3 modes: threshold, limit and both. + +Syntax:: + + threshold: type , track , count , seconds + +type "threshold" +~~~~~~~~~~~~~~~~ + +This type can be used to set a minimum threshold for a rule before it +generates alerts. A threshold setting of N means on the Nth time the +rule matches an alert is generated. + +Example:: + + alert tcp !$HOME_NET any -> $HOME_NET 25 (msg:"ET POLICY Inbound Frequent Emails - Possible Spambot Inbound"; \ + flow:established; content:"mail from|3a|"; nocase; \ + threshold: type threshold, track by_src, count 10, seconds 60; \ + reference:url,doc.emergingthreats.net/2002087; classtype:misc-activity; sid:2002087; rev:10;) + +This signature only generates an alert if we get 10 inbound emails or +more from the same server in a time period of one minute. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet + (not only the one that meets the threshold condition).* + +type "limit" +~~~~~~~~~~~~ + +This type can be used to make sure you're not getting flooded with +alerts. If set to limit N, it alerts at most N times. + +Example:: + + alert http $HOME_NET any -> any $HTTP_PORTS (msg:"ET USER_AGENTS Internet Explorer 6 in use - Significant Security Risk"; \ + flow:to_server,established; content:"|0d 0a|User-Agent|3a| Mozilla/4.0 (compatible|3b| MSIE 6.0|3b|"; \ + threshold: type limit, track by_src, seconds 180, count 1; \ + reference:url,doc.emergingthreats.net/2010706; classtype:policy-violation; sid:2010706; rev:7;) + +In this example at most 1 alert is generated per host within a period +of 3 minutes if MSIE 6.0 is detected. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet + (not only the one that meets the limit condition).* + +type "both" +~~~~~~~~~~~ + +This type is a combination of the "threshold" and "limit" types. It +applies both thresholding and limiting. + +Example:: + + alert tcp $HOME_NET 5060 -> $EXTERNAL_NET any (msg:"ET VOIP Multiple Unauthorized SIP Responses TCP"; \ + flow:established,from_server; content:"SIP/2.0 401 Unauthorized"; depth:24; \ + threshold: type both, track by_src, count 5, seconds 360; \ + reference:url,doc.emergingthreats.net/2003194; classtype:attempted-dos; sid:2003194; rev:6;) + +This alert will only generate an alert if within 6 minutes there have +been 5 or more "SIP/2.0 401 Unauthorized" responses, and it will alert +only once in that 6 minutes. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet.* + +detection_filter +---------------- + +The detection_filter keyword can be used to alert on every match after +a threshold has been reached. It differs from the threshold with type +threshold in that it generates an alert for each rule match after the +initial threshold has been reached, where the latter will reset it's +internal counter and alert again when the threshold has been reached +again. + +Syntax:: + + detection_filter: track , count , seconds + +Example:: + + alert http $EXTERNAL_NET any -> $HOME_NET any \ + (msg:"ET WEB_SERVER WebResource.axd access without t (time) parameter - possible ASP padding-oracle exploit"; \ + flow:established,to_server; content:"GET"; http_method; content:"WebResource.axd"; http_uri; nocase; \ + content:!"&t="; http_uri; nocase; content:!"&|3b|t="; http_uri; nocase; \ + detection_filter:track by_src,count 15,seconds 2; \ + reference:url,netifera.com/research/; reference:url,www.microsoft.com/technet/security/advisory/2416728.mspx; \ + classtype:web-application-attack; sid:2011807; rev:5;) + +Alerts each time after 15 or more matches have occurred within 2 seconds. + +If a signature sets a flowbit, flowint, etc. those actions are still +performed for each of the matches. + + *Rule actions drop (IPS mode) and reject are applied to each packet + that generate an alert* diff --git a/doc/userguide/rules/tls-keywords.rst b/doc/userguide/rules/tls-keywords.rst new file mode 100644 index 000000000000..583eae24f7a2 --- /dev/null +++ b/doc/userguide/rules/tls-keywords.rst @@ -0,0 +1,171 @@ +SSL/TLS Keywords +================ + +Suricata comes with several rule keywords to match on various properties of TLS/SSL handshake. Matches are string inclusion matches. + +tls_cert_subject +---------------- + +Match TLS/SSL certificate Subject field. + +Examples:: + + tls_cert_subject; content:"CN=*.googleusercontent.com"; isdataat:!1,relative; + tls_cert_subject; content:"google.com"; nocase; pcre:"/google.com$/"; + +``tls_cert_subject`` is a 'Sticky buffer'. + +``tls_cert_subject`` can be used as ``fast_pattern``. + +tls_cert_issuer +--------------- + +Match TLS/SSL certificate Issuer field. + +Examples:: + + tls_cert_issuer; content:"WoSign"; nocase; isdataat:!1,relative; + tls_cert_issuer; content:"StartCom"; nocase; pcre:"/StartCom$/"; + +``tls_cert_issuer`` is a 'Sticky buffer'. + +``tls_cert_issuer`` can be used as ``fast_pattern``. + +tls_cert_serial +--------------- + +Match on the serial number in a certificate. + +Example:: + + alert tls any any -> any any (msg:"match cert serial"; \ + tls_cert_serial; content:"5C:19:B7:B1:32:3B:1C:A1"; sid:200012;) + +``tls_cert_serial`` is a 'Sticky buffer'. + +``tls_cert_serial`` can be used as ``fast_pattern``. + +tls_sni +------- + +Match TLS/SSL Server Name Indication field. + +Examples:: + + tls_sni; content:"oisf.net"; nocase; isdataat:!1,relative; + tls_sni; content:"oisf.net"; nocase; pcre:"/oisf.net$/"; + +``tls_sni`` is a 'Sticky buffer'. + +``tls_sni`` can be used as ``fast_pattern``. + +tls_cert_notbefore +------------------ + +Match on the NotBefore field in a certificate. + +Example:: + + alert tls any any -> any any (msg:"match cert NotBefore"; \ + tls_cert_notbefore:1998-05-01<>2008-05-01; sid:200005;) + +tls_cert_notafter +----------------- + +Match on the NotAfter field in a certificate. + +Example:: + + alert tls any any -> any any (msg:"match cert NotAfter"; \ + tls_cert_notafter:>2015; sid:200006;) + +tls_cert_expired +---------------- + +Match returns true if certificate is expired. It evaluates the validity date +from the certificate. + +Usage:: + + tls_cert_expired; + +tls_cert_valid +-------------- + +Match returns true if certificate is not expired. It only evaluates the +validity date. It does *not* do cert chain validation. It is the opposite +of ``tls_cert_expired``. + +Usage:: + + tls_cert_valid; + +tls.version +----------- + +Match on negotiated TLS/SSL version. + +Example values: "1.0", "1.1", "1.2" + +tls.subject +----------- + +Match TLS/SSL certificate Subject field. + +example: + + +:: + + tls.subject:"CN=*.googleusercontent.com" + +Case sensitve, can't use 'nocase'. + +Legacy keyword. ``tls_cert_subject`` is the replacement. + +tls.issuerdn +------------ + +match TLS/SSL certificate IssuerDN field + +example: + + +:: + + tls.issuerdn:!"CN=Google-Internet-Authority" + +Case sensitve, can't use 'nocase'. + +Legacy keyword. ``tls_cert_issuer`` is the replacement. + +tls.fingerprint +--------------- + +match TLS/SSL certificate SHA1 fingerprint + +example: + + +:: + + tls.fingerprint:!"f3:40:21:48:70:2c:31:bc:b5:aa:22:ad:63:d6:bc:2e:b3:46:e2:5a" + +Case sensitive, can't use 'nocase'. + +The tls.fingerprint buffer is lower case so you must use lower case letters for this to match. + +tls.store +--------- + +store TLS/SSL certificate on disk + +ssl_state +--------- + +The ``ssl_state`` keyword matches the state of the SSL connection. The possible states +are ``client_hello``, ``server_hello``, ``client_keyx``, ``server_keyx`` and ``unknown``. +You can specify several states with ``|`` (OR) to check for any of the specified states. + +Negation support is not available yet, see https://redmine.openinfosecfoundation.org/issues/1231 + diff --git a/doc/userguide/rules/xbits.rst b/doc/userguide/rules/xbits.rst new file mode 100644 index 000000000000..3af99cff94d5 --- /dev/null +++ b/doc/userguide/rules/xbits.rst @@ -0,0 +1,88 @@ +Xbits +===== + +Set, unset, toggle and check for bits stored per host or ip_pair. + +Syntax:: + + xbits:noalert; + xbits:,,track ; + xbits:,,track \ + [,expire ]; + xbits:,,track \ + [,expire ]; + +YAML settings +------------- + +Bits that are stored per host are stored in the Host table. + +Bits that are stored per IP pair are stored in the IPPair table. + +Threading +--------- + +Due to subtle timing issues between threads the order of sets and checks +can be slightly unpredictible. + +Unix Socket +----------- + +Hostbits can be added, removed and listed through the unix socket. + +Add:: + + suricatasc -c "add-hostbit " + suricatasc -c "add-hostbit 1.2.3.4 blacklist 3600" + +If an hostbit is added for an existing hostbit, it's expiry timer is updated. + +Remove:: + + suricatasc -c "remove-hostbit " + suricatasc -c "remove-hostbit 1.2.3.4 blacklist" + +List:: + + suricatasc -c "list-hostbit " + suricatasc -c "list-hostbit 1.2.3.4" + +This results in:: + + { + "message": + { + "count": 1, + "hostbits": + [{ + "expire": 89, + "name": "blacklist" + }] + }, + "return": "OK" + } + +Examples +-------- + +Creating a SSH blacklist +^^^^^^^^^^^^^^^^^^^^^^^^ + +Below is an example of rules incoming to a SSH server. + +The first 2 rules match on a SSH software version often used in bots. +They drop the traffic and create an 'xbit' 'badssh' for the source ip. +It expires in an hour:: + + drop ssh any any -> $MYSERVER 22 (msg:"DROP libssh incoming"; \ + flow:to_server,established; ssh.softwareversion:"libssh"; \ + xbits:set, badssh, track ip_src, expire 3600; sid:4000000005;) + drop ssh any any -> $MYSERVER 22 (msg:"DROP PUTTY incoming"; \ + flow:to_server,established; ssh.softwareversion:"PUTTY"; \ + xbits:set, badssh, track ip_src, expire 3600; sid:4000000007;) + +Then the following rule simply drops any incoming traffic to that server +that is on that 'badssh' list:: + + drop ssh any any -> $MYSERVER 22 (msg:"DROP BLACKLISTED"; \ + xbits:isset, badssh, track ip_src; sid:4000000006;) diff --git a/doc/userguide/setting-up-ipsinline-for-linux.rst b/doc/userguide/setting-up-ipsinline-for-linux.rst new file mode 100644 index 000000000000..0a73c87610be --- /dev/null +++ b/doc/userguide/setting-up-ipsinline-for-linux.rst @@ -0,0 +1,126 @@ +Setting up IPS/inline for Linux +================================ + +In this guide will be explained how to work with Suricata in layer3 inline mode and how to set iptables for that purpose. + +First start with compiling Suricata with NFQ support. For instructions +see `Ubuntu Installation +`_. +For more information about NFQ and iptables, see +:ref:`suricata-yaml-nfq`. + +To check if you have NFQ enabled in your Suricata, enter the following command: + + +:: + + + suricata --build-info + +and examine if you have NFQ between the features. + +To run suricata with the NFQ mode, you have to make use of the -q option. This option tells Suricata which of the queue numbers it should use. + + +:: + + + sudo suricata -c /etc/suricata/suricata.yaml -q 0 + + +Iptables configuration +~~~~~~~~~~~~~~~~~~~~~~ + +First of all it is important to know which traffic you would like to send to Suricata. Traffic that passes your computer or traffic that is generated by your computer. + + +.. image:: setting-up-ipsinline-for-linux/IPtables.png + +.. image:: setting-up-ipsinline-for-linux/iptables1.png + +If Suricata is running on a gateway and is meant to protect the computers behind that gateway you are dealing with the first scenario: *forward_ing* . +If Suricata has to protect the computer it is running on, you are dealing with the second scenario: *host* (see drawing 2). +These two ways of using Suricata can also be combined. + +The easiest rule in case of the gateway-scenario to send traffic to Suricata is: + + +:: + + + sudo iptables -I FORWARD -j NFQUEUE + +In this case, all forwarded traffic goes to Suricata. + + +In case of the host situation, these are the two most simple iptable rules; + + +:: + + + sudo iptables -I INPUT -j NFQUEUE + sudo iptables -I OUTPUT -j NFQUEUE + +It is possible to set a queue number. If you do not, the queue number will be 0 by default. + +Imagine you want Suricata to check for example just TCP-traffic, or all incoming traffic on port 80, or all traffic on destination-port 80, you can do so like this: + + +:: + + + sudo iptables -I INPUT -p tcp -j NFQUEUE + sudo iptables -I OUTPUT -p tcp -j NFQUEUE + +In this case, Suricata checks just TCP traffic. + + +:: + + + sudo iptables -I INPUT -p tcp --sport 80 -j NFQUEUE + sudo iptables -I OUTPUT -p tcp --dport 80 -j NFQUEUE + +In this example, Suricata checks all input and output on port 80. + +.. image:: setting-up-ipsinline-for-linux/iptables2.png + +.. image:: setting-up-ipsinline-for-linux/IPtables3.png + +To see if you have set your iptables rules correct make sure Suricata is running and enter: + +:: + + + sudo iptables -vnL + +In the example you can see if packets are being logged. + +.. image:: setting-up-ipsinline-for-linux/iptables_vnL.png + +This description of the use of iptables is the way to use it with IPv4. To use it with IPv6 all previous mentioned commands have to start with 'ip6tables'. It is also possible to let Suricata check both kinds of traffic. + +There is also a way to use iptables with multiple networks (and interface cards). Example: + + +.. image:: setting-up-ipsinline-for-linux/iptables4.png + + +:: + + + sudo iptables -I FORWARD -i eth0 -o eth1 -j NFQUEUE + sudo iptables -I FORWARD -i eth1 -o eth0 -j NFQUEUE + +The options -i (input) -o (output) can be combined with all previous mentioned options + +If you would stop Suricata and use internet, the traffic will not come through. To make internet work correctly, you have to erase all iptable rules. + +To erase all iptable rules, enter: + + +:: + + + sudo iptables -F diff --git a/doc/userguide/setting-up-ipsinline-for-linux/IPtables.png b/doc/userguide/setting-up-ipsinline-for-linux/IPtables.png new file mode 100644 index 000000000000..3798db3dcbeb Binary files /dev/null and b/doc/userguide/setting-up-ipsinline-for-linux/IPtables.png differ diff --git a/doc/userguide/setting-up-ipsinline-for-linux/IPtables3.png b/doc/userguide/setting-up-ipsinline-for-linux/IPtables3.png new file mode 100644 index 000000000000..1102fc99033d Binary files /dev/null and b/doc/userguide/setting-up-ipsinline-for-linux/IPtables3.png differ diff --git a/doc/userguide/setting-up-ipsinline-for-linux/iptables1.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables1.png new file mode 100644 index 000000000000..125387f8b923 Binary files /dev/null and b/doc/userguide/setting-up-ipsinline-for-linux/iptables1.png differ diff --git a/doc/userguide/setting-up-ipsinline-for-linux/iptables2.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables2.png new file mode 100644 index 000000000000..02d0df04aa81 Binary files /dev/null and b/doc/userguide/setting-up-ipsinline-for-linux/iptables2.png differ diff --git a/doc/userguide/setting-up-ipsinline-for-linux/iptables4.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables4.png new file mode 100644 index 000000000000..174ed967367a Binary files /dev/null and b/doc/userguide/setting-up-ipsinline-for-linux/iptables4.png differ diff --git a/doc/userguide/setting-up-ipsinline-for-linux/iptables_vnL.png b/doc/userguide/setting-up-ipsinline-for-linux/iptables_vnL.png new file mode 100644 index 000000000000..672c3d99deac Binary files /dev/null and b/doc/userguide/setting-up-ipsinline-for-linux/iptables_vnL.png differ diff --git a/doc/userguide/unix-socket.rst b/doc/userguide/unix-socket.rst new file mode 100644 index 000000000000..be7546c7dd4a --- /dev/null +++ b/doc/userguide/unix-socket.rst @@ -0,0 +1,228 @@ +Interacting via Unix Socket +=========================== + +Introduction +------------ + +Suricata can listen to a unix socket and accept commands from the user. The +exchange protocol is JSON-based and the format of the message has been done +to be generic. + +An example script called suricatasc is provided in the source and installed +automatically when installing/updating Suricata. + +The unix socket is enabled by default if libjansson is available. + +You need to have libjansson installed: + +* libjansson4 - C library for encoding, decoding and manipulating JSON data +* libjansson-dev - C library for encoding, decoding and manipulating JSON data (dev) +* python-simplejson - simple, fast, extensible JSON encoder/decoder for Python + +Debian/Ubuntu:: + + apt-get install libjansson4 libjansson-dev python-simplejson + +If libjansson is present on the system , unix socket will be compiled +in automatically. + +The creation of the socket is managed by setting enabled to 'yes' or 'auto' +under unix-command in Suricata YAML configuration file: + +:: + + unix-command: + enabled: yes + #filename: custom.socket # use this to specify an alternate file + +The ``filename`` variable can be used to set an alternate socket +filename. The filename is always relative to the local state base +directory. + +Clients are implemented for some language and can be used as code +example to write custom scripts: + +* Python: https://github.com/inliniac/suricata/blob/master/scripts/suricatasc/suricatasc.in (provided with suricata and used in this document) +* Perl: https://github.com/aflab/suricatac (a simple Perl client with interactive mode) +* C: https://github.com/regit/SuricataC (a unix socket mode client in C without interactive mode) + +Commands in standard running mode +--------------------------------- + + +The set of existing commands is the following: + +* command-list: list available commands +* shutdown: this shutdown suricata +* iface-list: list interfaces where Suricata is sniffing packets +* iface-stat: list statistic for an interface +* help: alias of command-list +* version: display Suricata's version +* uptime: display Suricata's uptime +* running-mode: display running mode (workers, autofp, simple) +* capture-mode: display capture system used +* conf-get: get configuration item (see example below) +* dump-counters: dump Suricata's performance counters + +You can access to these commands with the provided example script which +is named ``suricatasc``. A typical session with ``suricatasc`` will looks like: + +:: + + # suricatasc + Command list: shutdown, command-list, help, version, uptime, running-mode, capture-mode, conf-get, dump-counters, iface-stat, iface-list, quit + >>> iface-list + Success: {'count': 2, 'ifaces': ['eth0', 'eth1']} + >>> iface-stat eth0 + Success: {'pkts': 378, 'drop': 0, 'invalid-checksums': 0} + >>> conf-get unix-command.enabled + Success: + "yes" + +Commands on the cmd prompt +-------------------------- + +You can use suricatasc directly on the command prompt: + +:: + + + root@debian64:~# suricatasc -c version + {'message': '2.1beta2 RELEASE', 'return': 'OK'} + root@debian64:~# + root@debian64:~# suricatasc -c uptime + {'message': 35264, 'return': 'OK'} + root@debian64:~# + + +**NOTE:** +You need to quote commands involving more than one argument: + +:: + + + root@debian64:~# suricatasc -c "iface-stat eth0" + {'message': {'pkts': 5110429, 'drop': 0, 'invalid-checksums': 0}, 'return': 'OK'} + root@debian64:~# + + +Pcap processing mode +-------------------- + +This mode is one of main motivation behind this code. The idea is to +be able to ask to Suricata to treat different pcap files without +having to restart Suricata between the files. This provides you a huge +gain in time as you don’t need to wait for the signature engine to +initialize. + +To use this mode, start suricata with your preferred YAML file and +provide the option ``--unix-socket`` as argument: + +:: + + suricata -c /etc/suricata-full-sigs.yaml --unix-socket + +It is also possible to specify the socket filename as argument: + +:: + + suricata --unix-socket=custom.socket + +In this last case, you will need to provide the complete path to the +socket to ``suricatasc``. To do so, you need to pass the filename as +first argument of ``suricatasc``: + +:: + + suricatasc custom.socket + +Once Suricata is started, you can use the provided script +``suricatasc`` to connect to the command socket and ask for pcap +treatment: + +:: + + root@tiger:~# suricatasc + >>> pcap-file /home/benches/file1.pcap /tmp/file1 + Success: Successfully added file to list + >>> pcap-file /home/benches/file2.pcap /tmp/file2 + Success: Successfully added file to list + +You can add multiple files without waiting the result: they will be +sequentially processed and the generated log/alert files will be put +into the directory specified as second arguments of the pcap-file +command. You need to provide absolute path to the files and directory +as suricata don’t know from where the script has been run. + +To know how much files are waiting to get processed, you can do: + +:: + + >>> pcap-file-number + Success: 3 + +To get the list of queued files, do: + +:: + + >>> pcap-file-list + Success: {'count': 2, 'files': ['/home/benches/file1.pcap', '/home/benches/file2.pcap']} + +To get current processed file: + +:: + + >>> pcap-current + Success: + "/tmp/test.pcap" + +Build your own client +--------------------- + +The protocol is documented in the following page +https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Unix_Socket#Protocol + +The following session show what is send (SND) and received (RCV) by +the server. Initial negotiation is the following: + +:: + + # suricatasc + SND: {"version": "0.1"} + RCV: {"return": "OK"} + +Once this is done, command can be issued: + +:: + + >>> iface-list + SND: {"command": "iface-list"} + RCV: {"message": {"count": 1, "ifaces": ["wlan0"]}, "return": "OK"} + Success: {'count': 1, 'ifaces': ['wlan0']} + >>> iface-stat wlan0 + SND: {"command": "iface-stat", "arguments": {"iface": "wlan0"}} + RCV: {"message": {"pkts": 41508, "drop": 0, "invalid-checksums": 0}, "return": "OK"} + Success: {'pkts': 41508, 'drop': 0, 'invalid-checksums': 0} + +In pcap-file mode, this gives: + +:: + + >>> pcap-file /home/eric/git/oisf/benches/sandnet.pcap /tmp/bench + SND: {"command": "pcap-file", "arguments": {"output-dir": "/tmp/bench", "filename": "/home/eric/git/oisf/benches/sandnet.pcap"}} + RCV: {"message": "Successfully added file to list", "return": "OK"} + Success: Successfully added file to list + >>> pcap-file-number + SND: {"command": "pcap-file-number"} + RCV: {"message": 1, "return": "OK"} + >>> pcap-file-list + SND: {"command": "pcap-file-list"} + RCV: {"message": {"count": 1, "files": ["/home/eric/git/oisf/benches/sandnet.pcap"]}, "return": "OK"} + Success: {'count': 1, 'files': ['/home/eric/git/oisf/benches/sandnet.pcap']} + +There is one thing to be careful about: a suricata message is sent in +multiple send operations. This result in possible incomplete read on +client side. The worse workaround is to sleep a bit before trying a +recv call. An other solution is to use non blocking socket and retry a +recv if the previous one has failed. This method is used here: +source:scripts/suricatasc/suricatasc.in#L43 diff --git a/doc/userguide/what-is-suricata.rst b/doc/userguide/what-is-suricata.rst new file mode 100644 index 000000000000..8cd49cdca94a --- /dev/null +++ b/doc/userguide/what-is-suricata.rst @@ -0,0 +1,17 @@ +What is Suricata +================ + +Suricata is a high performance Network IDS, IPS and Network Security Monitoring engine. It is open source and owned by a community-run non-profit foundation, the Open Information Security Foundation (OISF). Suricata is developed by the OISF. + +About the Open Information Security Foundation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Open Information Security Foundation is a non-profit foundation organized to build community and to support open-source security technologies like Suricata, the world-class IDS/IPS engine. + + +License +------- + +The Suricata source code is licensed under version 2 of the +:doc:`licenses/gnu-gpl-v2.0`. This documentation is licensed under the +:doc:`licenses/cc-nc-4.0`. diff --git a/doxygen.cfg b/doxygen.cfg index 6edc71333bfe..0d77ce20ab37 100644 --- a/doxygen.cfg +++ b/doxygen.cfg @@ -1601,7 +1601,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = NFQ IPFW HAVE_PFRING HAVE_AF_PACKET PRELUDE HAVE_NAPATECH HAVE_DAG PROFILING +PREDEFINED = NFQ IPFW HAVE_PFRING HAVE_AF_PACKET PRELUDE HAVE_NAPATECH HAVE_DAG PROFILING UNITTESTS # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/m4/libprelude.m4 b/m4/libprelude.m4 index 07eebe0ca93e..64b6478e3970 100644 --- a/m4/libprelude.m4 +++ b/m4/libprelude.m4 @@ -101,7 +101,7 @@ main () prelude_check_version(NULL) ); printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n", "$min_libprelude_version" ); - printf("*** LIBPRELUDE is always available from http://www.prelude-ids.com/development/download/\n"); + printf("*** LIBPRELUDE is always available from http://www.prelude-siem.com/index.php/en/community/download\n"); printf("*** \n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the libprelude-config shell script is\n"); diff --git a/qa/coccinelle/banned-functions.cocci b/qa/coccinelle/banned-functions.cocci index bc2c60e6cbae..bab5e4ee69ed 100644 --- a/qa/coccinelle/banned-functions.cocci +++ b/qa/coccinelle/banned-functions.cocci @@ -3,7 +3,7 @@ identifier i; position p1; @@ -\(sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrdup@i\)(...)@p1 +\(strtok@i\|sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrnul@i\)(...)@p1 @script:python@ p1 << banned.p1; diff --git a/qa/coccinelle/siginit.cocci b/qa/coccinelle/siginit.cocci new file mode 100644 index 000000000000..9a2193be408d --- /dev/null +++ b/qa/coccinelle/siginit.cocci @@ -0,0 +1,26 @@ +@siginit@ +identifier func =~ "Detect.*Setup"; +expression E1; +position p1; +identifier de_ctx, s, str, error; +type DetectEngineCtx, Signature; +@@ + +func(DetectEngineCtx *de_ctx, Signature *s, char *str) { +... +SigMatchAppendSMToList(s, ...)@p1; +... +if (s->alproto != E1 && ...) { +... +goto error; +} +... +} + + +@script:python@ +p1 << siginit.p1; +@@ +print "SigMatch added at %s:%s but error handling can cause it to be freed later." % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/qa/coccinelle/struct-flags.cocci b/qa/coccinelle/struct-flags.cocci index d7204aada4b8..45fab73415da 100644 --- a/qa/coccinelle/struct-flags.cocci +++ b/qa/coccinelle/struct-flags.cocci @@ -1,18 +1,20 @@ @flags@ -TcpSegment *struct0; -identifier struct_flags0 =~ "^(?!SEGMENTTCP_FLAG).+"; -TcpStream *struct1; -identifier struct_flags1 =~ "^(?!STREAMTCP_STREAM_FLAG_).+"; -TcpSession *struct2; -identifier struct_flags2 =~ "^(?!STREAMTCP_FLAG).+"; -Packet *struct3; -identifier struct_flags3 =~ "^(?!FLOW_PKT_).+"; -SignatureHeader *struct4; -identifier struct_flags4 =~ "^(?!SIG_FLAG).+"; -Signature *struct5; -identifier struct_flags5 =~ "^(?!SIG_FLAG).+"; -Signature *struct6; -identifier struct_flags6 =~ "^(?!SIG_FLAG_INIT_).+"; +SignatureHeader *struct0; +identifier struct_flags0 =~ "^(?!SIG_FLAG).+"; +Signature *struct1; +identifier struct_flags1 =~ "^(?!SIG_FLAG).+"; +Signature *struct2; +identifier struct_flags2 =~ "^(?!SIG_FLAG_INIT_).+"; +Flow *struct3; +identifier struct_flags3 =~ "^(?!FLOW_).+"; +TcpSegment *struct4; +identifier struct_flags4 =~ "^(?!SEGMENTTCP_FLAG).+"; +TcpStream *struct5; +identifier struct_flags5 =~ "^(?!STREAMTCP_STREAM_FLAG_).+"; +TcpSession *struct6; +identifier struct_flags6 =~ "^(?!STREAMTCP_FLAG).+"; +Packet *struct7; +identifier struct_flags7 =~ "^(?!FLOW_PKT_).+"; position p1; @@ @@ -29,17 +31,17 @@ struct1->flags@p1 & struct_flags1 | struct1->flags@p1 &= ~struct_flags1 | -struct2->flags@p1 |= struct_flags2 +struct2->init_flags@p1 |= struct_flags2 | -struct2->flags@p1 & struct_flags2 +struct2->init_flags@p1 & struct_flags2 | -struct2->flags@p1 &= ~struct_flags2 +struct2->init_flags@p1 &= ~struct_flags2 | -struct3->flowflags@p1 |= struct_flags3 +struct3->flags@p1 |= struct_flags3 | -struct3->flowflags@p1 & struct_flags3 +struct3->flags@p1 & struct_flags3 | -struct3->flowflags@p1 &= ~struct_flags3 +struct3->flags@p1 &= ~struct_flags3 | struct4->flags@p1 |= struct_flags4 | @@ -53,11 +55,17 @@ struct5->flags@p1 & struct_flags5 | struct5->flags@p1 &= ~struct_flags5 | -struct6->init_flags@p1 |= struct_flags6 +struct6->flags@p1 |= struct_flags6 | -struct6->init_flags@p1 & struct_flags6 +struct6->flags@p1 & struct_flags6 | -struct6->init_flags@p1 &= ~struct_flags6 +struct6->flags@p1 &= ~struct_flags6 +| +struct7->flowflags@p1 |= struct_flags7 +| +struct7->flowflags@p1 & struct_flags7 +| +struct7->flowflags@p1 &= ~struct_flags7 ) @script:python@ diff --git a/qa/docker/buildbot.cfg b/qa/docker/buildbot.cfg new file mode 100644 index 000000000000..b2063ac9ca3b --- /dev/null +++ b/qa/docker/buildbot.cfg @@ -0,0 +1,235 @@ +# -*- python -*- +# ex: set syntax=python: + +# This is a sample buildmaster config file. It must be installed as +# 'master.cfg' in your buildmaster's base directory. + +# This is the dictionary that the buildmaster pays attention to. We also use +# a shorter alias to save typing. +c = BuildmasterConfig = {} + +####### BUILDSLAVES + +# The 'slaves' list defines the set of recognized buildslaves. Each element is +# a BuildSlave object, specifying a unique slave name and password. The same +# slave name and password must be configured on the slave. +from buildbot.buildslave import BuildSlave +c['slaves'] = [BuildSlave("buildslave", "Suridocker")] + +# 'slavePortnum' defines the TCP port to listen on for connections from slaves. +# This must match the value configured into the buildslaves (with their +# --master option) +c['slavePortnum'] = 9989 + +####### CHANGESOURCES + +# the 'change_source' setting tells the buildmaster how it should find out +# about source code changes. Here we point to the buildbot clone of pyflakes. + +from buildbot.changes.gitpoller import GitPoller +c['change_source'] = [] +c['change_source'].append(GitPoller( + '/data/oisf/.git/', + workdir='gitpoller-workdir', branches = ['master'], + pollinterval=300, project='suricata')) + +####### SCHEDULERS + +# Configure the Schedulers, which decide how to react to incoming changes. In this +# case, just kick off a 'runtests' build + +from buildbot.schedulers.basic import SingleBranchScheduler +#from buildbot.schedulers.forcesched import ForceScheduler +from buildbot.changes import filter +c['schedulers'] = [] +c['schedulers'].append(SingleBranchScheduler( + name="master", + change_filter=filter.ChangeFilter(branch='master'), + treeStableTimer=None, + builderNames=["features","profiling","clang"])) + +#c['schedulers'].append(ForceScheduler( +# name="force", +# builderNames=["builds","debug"])) + +####### BUILDERS + +# The 'builders' list defines the Builders, which tell Buildbot how to perform a build: +# what steps, and which slaves can execute them. Note that any particular build will +# only take place on one slave. + +from buildbot.process.factory import BuildFactory +#from buildbot.steps.source.git import Git +from buildbot.steps.source import Git +from buildbot.steps.shell import ShellCommand + +def SuriBuildFactory(repo='/data/oisf/'): + factory = BuildFactory() + factory.addStep(Git(repourl=repo, mode='copy')) + factory.addStep(ShellCommand(command=["rm", "-rf", "libhtp"])) + factory.addStep(ShellCommand(command=["git", "clone", "-b", "0.5.x", "/data/oisf/libhtp/.git/", "libhtp"])) + return factory + +factory = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory.addStep(ShellCommand(command=["./autogen.sh"])) +factory.addStep(ShellCommand(command=["./configure"])) +factory.addStep(ShellCommand(command=["make"])) +factory.addStep(ShellCommand(command=["make", "clean"])) +#factory.addStep(ShellCommand(command=["make", "distcheck"])) + +factory_devel = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_devel.addStep(ShellCommand(command=["./autogen.sh"])) +factory_devel.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests"])) +factory_devel.addStep(ShellCommand(command=["make"])) +factory_devel.addStep(ShellCommand(command=["make", "clean"])) +#factory_devel.addStep(ShellCommand(command=["make", "distcheck"], env={'DISTCHECK_CONFIGURE_FLAGS': "--enable-debug --enable-unittests"})) + +factory_profiling = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_profiling.addStep(ShellCommand(command=["./autogen.sh"])) +factory_profiling.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-profiling","--enable-unittests"])) +factory_profiling.addStep(ShellCommand(command=["make"])) +factory_profiling.addStep(ShellCommand(command=["make", "clean"])) +#factory_profiling.addStep(ShellCommand(command=["make", "distcheck"],env={'DISTCHECK_CONFIGURE_FLAGS': "--enable-debug --enable-profiling --enable-unittests"})) + +factory_clang = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_clang.addStep(ShellCommand(command=["./autogen.sh"])) +#factory_clang.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","CC=clang","CFLAGS=-fsanitize=address"])) +factory_clang.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","CC=clang","ac_cv_func_malloc_0_nonnull=yes","ac_cv_func_realloc_0_nonnull=yes"])) +factory_clang.addStep(ShellCommand(command=["make"])) +factory_clang.addStep(ShellCommand(command=["make", "clean"])) + +factory_clang_32 = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_clang_32.addStep(ShellCommand(command=["./autogen.sh"])) +factory_clang_32.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","CC=clang","CFLAGS=-fsanitize=address","ac_cv_func_malloc_0_nonnull=yes","ac_cv_func_realloc_0_nonnull=yes"])) +factory_clang_32.addStep(ShellCommand(command=["make"])) +factory_clang_32.addStep(ShellCommand(command=["make", "clean"])) + +factory_features = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_features.addStep(ShellCommand(command=["./autogen.sh"])) +factory_features.addStep(ShellCommand(command=["./configure","--enable-debug","--enable-unittests","--enable-nfqueue","--enable-nflog", "--enable-lua", "--enable-prelude"])) +factory_features.addStep(ShellCommand(command=["make"])) +factory_features.addStep(ShellCommand(command=["make", "clean"])) +import psutil +factory_features.addStep(ShellCommand(command=["make", "distcheck"],env={'DISTCHECK_CONFIGURE_FLAGS': "--enable-debug --enable-unittests --enable-nfqueue --enable-nflog --enable-lua --enable-prelude", "CONCURRENCY_LEVEL": str(psutil.cpu_count())})) + +import os +PCAP_PATH='/data/oisf/qa/docker/pcaps/' +(_, _, pcaps_list) = os.walk(PCAP_PATH).next() +pcaps_list = [ os.path.join(PCAP_PATH, pcap) for pcap in pcaps_list if pcap.endswith(".pcap") ] + +factory_stress_pcap = SuriBuildFactory() +# run the tests (note that this will require that 'trial' is installed) +factory_stress_pcap.addStep(ShellCommand(command=["./autogen.sh"])) +factory_stress_pcap.addStep(ShellCommand(command=["./configure","--enable-debug-validation"],env={"CFLAGS" : "-fsanitize=address -fno-omit-frame-pointer"})) +factory_stress_pcap.addStep(ShellCommand(command=["make"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "make","install"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "rm", "-f", "/usr/local/etc/suricata/suricata.yaml"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "make","install-conf"])) +factory_stress_pcap.addStep(ShellCommand(command=["make","clean"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "ldconfig"])) +for pfile in pcaps_list: + factory_stress_pcap.addStep(ShellCommand(command=["sudo", "/usr/local/bin/suricata","-r",pfile,"--init-errors-fatal","-S","/data/oisf/rules/http-events.rules"])) +factory_stress_pcap.addStep(ShellCommand(command=["sudo", "rm", "-rf", "/usr/local/var/log/suricata/"])) + +from buildbot.config import BuilderConfig + +def SuriBuilderConfig(*args, **kwargs): + if not kwargs.has_key('category'): + kwargs['category']='default' + return BuilderConfig(*args, **kwargs) + +c['builders'] = [] + +c['builders'].append( + SuriBuilderConfig(name="gcc", + slavename="buildslave", + factory=factory)) +c['schedulers'].append(SingleBranchScheduler( + name="build", + change_filter=filter.ChangeFilter(branch='master'), + treeStableTimer=None, + builderNames=["gcc"])) + +c['builders'].append( + SuriBuilderConfig(name="debug", + slavename="buildslave", + factory=factory_devel)) +c['schedulers'].append(SingleBranchScheduler( + name="debug", + change_filter=filter.ChangeFilter(branch='master'), + treeStableTimer=None, + builderNames=["debug"])) + +c['builders'].append( + SuriBuilderConfig(name="profiling", + slavename="buildslave", + factory=factory_profiling)) +c['builders'].append( + SuriBuilderConfig(name="clang", + slavename="buildslave", + factory=factory_clang_32)) +c['builders'].append( + SuriBuilderConfig(name="features", + slavename="buildslave", + factory=factory_features)) +c['builders'].append( + SuriBuilderConfig(name="pcaps", + slavename="buildslave", + factory=factory_stress_pcap)) + +from buildbot import locks +build_lock = locks.SlaveLock("slave_builds", maxCount = 1) + + +from buildbot.schedulers.forcesched import * +c['schedulers'].append(ForceScheduler(name="force", builderNames = [ builder.getConfigDict()['name'] for builder in c['builders'] ])) + +c['status'] = [] + +from buildbot.status import html +from buildbot.status.web import authz, auth + +authz_cfg=authz.Authz( + # change any of these to True to enable; see the manual for more + # options + #auth=auth.BasicAuth(users), + gracefulShutdown = False, + forceBuild = True, # use this to test your slave once it is set up + forceAllBuilds = True, + pingBuilder = True, + stopBuild = True, + stopAllBuilds = True, + cancelPendingBuild = True, +) +c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg)) + +####### PROJECT IDENTITY + +# the 'title' string will appear at the top of this buildbot +# installation's html.WebStatus home page (linked to the +# 'titleURL') and is embedded in the title of the waterfall HTML page. + +c['title'] = "Suricata" +c['titleURL'] = "https://redmine.openinfosecfoundation.org/projects/suricata" + +# the 'buildbotURL' string should point to the location where the buildbot's +# internal web server (usually the html.WebStatus page) is visible. This +# typically uses the port number set in the Waterfall 'status' entry, but +# with an externally-visible host name which the buildbot cannot figure out +# without some help. + +c['buildbotURL'] = "http://localhost:8010/" + +####### DB URL + +c['db'] = { + # This specifies what database buildbot uses to store its state. You can leave + # this at its default for all but the largest installations. + 'db_url' : "sqlite:///state.sqlite", +} diff --git a/qa/docker/pcaps/tls.pcap b/qa/docker/pcaps/tls.pcap new file mode 100644 index 000000000000..8aca21861188 Binary files /dev/null and b/qa/docker/pcaps/tls.pcap differ diff --git a/qa/drmemory.suppress b/qa/drmemory.suppress index fd79b022455f..cfd3fad137e2 100644 --- a/qa/drmemory.suppress +++ b/qa/drmemory.suppress @@ -14,3 +14,66 @@ name=useless warning, likely DrMemory bug * libpcre.so.3!pcre_get_substring +LEAK +name=libmagic minor leak 1 +libmagic.so.1!? +libmagic.so.1!? +libmagic.so.1!magic_load +suricata!MagicInit + +LEAK +name=libmagic minor leak 2 +libmagic.so.1!? +libmagic.so.1!magic_load +suricata!MagicInit + +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 1 +... +libhs.so.*!hs_compile_ext_multi +* + +UNINITIALIZED READ +name=Hyperscan false positives due to DrMemory limitations 2 +... +libhs.so.*!hs_compile +* + +WARNING +name=Prefetch warnings 1 +... +libhs.so.*!hs_scan +suricata!SCHSSearch +... +suricata!main + +WARNING +name=Prefetch warnings 2 +... +libhs.so.*!hs_scan +suricata!SCHSSearch +... +libc.so.6!__clone + +WARNING +name=Prefetch warnings 3 +... +libhs.so.*!hs_scan +suricata!HSScan +... +suricata!main + +WARNING +name=Prefetch warnings 4 +... +libhs.so.*!hs_scan +suricata!HSScan +... +libc.so.6!__clone + +WARNING +name=Prefetch warnings 5 +... +libhs.so.*!hs_scan +suricata!HSScan +* diff --git a/qa/lsan.suppress b/qa/lsan.suppress new file mode 100644 index 000000000000..01f9e9d270fc --- /dev/null +++ b/qa/lsan.suppress @@ -0,0 +1,2 @@ +# a bit heavy handed, but it seems that llvm-symbolizer can't figure out the symbols w/o compiling our own libmagic? +leak:libmagic.so diff --git a/qa/prscript.py b/qa/prscript.py index 7910ef7b5e17..21e989433131 100755 --- a/qa/prscript.py +++ b/qa/prscript.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright(C) 2013 Open Information Security Foundation +# Copyright(C) 2013, 2014, 2015 Open Information Security Foundation # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,49 +14,137 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Note to Docker users: +# If you are running SELinux in enforced mode, you may want to run +# chcon -Rt svirt_sandbox_file_t SURICATA_ROOTSRC_DIR +# or the buildbot will not be able to access to the data in /data/oisf +# and the git step will fail. + import urllib, urllib2, cookielib -import simplejson as json +try: + import simplejson as json +except: + import json import time import argparse import sys +import os +import copy +from subprocess import Popen, PIPE + +GOT_NOTIFY = True +try: + import pynotify +except: + GOT_NOTIFY = False + +GOT_DOCKER = True +try: + from docker import Client +except: + GOT_DOCKER = False # variables # - github user # - buildbot user and password BASE_URI="https://buildbot.openinfosecfoundation.org/" -BUILDERS_URI=BASE_URI+"builders/" -JSON_BUILDERS_URI=BASE_URI+"json/builders/" - GITHUB_BASE_URI = "https://api.github.com/repos/" GITHUB_MASTER_URI = "https://api.github.com/repos/inliniac/suricata/commits?sha=master" -parser = argparse.ArgumentParser(prog='prscript', description='Script checking validity of branch before PR') +if GOT_DOCKER: + parser = argparse.ArgumentParser(prog='prscript', description='Script checking validity of branch before PR') +else: + parser = argparse.ArgumentParser(prog='prscript', description='Script checking validity of branch before PR', + epilog='You need to install Python docker module to enable docker container handling options.') parser.add_argument('-u', '--username', dest='username', help='github and buildbot user') parser.add_argument('-p', '--password', dest='password', help='buildbot password') parser.add_argument('-c', '--check', action='store_const', const=True, help='only check last build', default=False) parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output', default=False) parser.add_argument('--norebase', action='store_const', const=True, help='do not test if branch is in sync with master', default=False) parser.add_argument('-r', '--repository', dest='repository', default='suricata', help='name of suricata repository on github') -parser.add_argument('branch', metavar='branch', help='github branch to build') +parser.add_argument('-l', '--local', action='store_const', const=True, help='local testing before github push', default=False) +if GOT_NOTIFY: + parser.add_argument('-n', '--notify', action='store_const', const=True, help='send desktop notification', default=False) + +docker_deps = "" +if not GOT_DOCKER: + docker_deps = " (disabled)" +parser.add_argument('-d', '--docker', action='store_const', const=True, help='use docker based testing', default=False) +parser.add_argument('-C', '--create', action='store_const', const=True, help='create docker container' + docker_deps, default=False) +parser.add_argument('-s', '--start', action='store_const', const=True, help='start docker container' + docker_deps, default=False) +parser.add_argument('-S', '--stop', action='store_const', const=True, help='stop docker container' + docker_deps, default=False) +parser.add_argument('-R', '--rm', action='store_const', const=True, help='remove docker container and image' + docker_deps, default=False) +parser.add_argument('branch', metavar='branch', help='github branch to build', nargs='?') args = parser.parse_args() username = args.username password = args.password cookie = None +if args.create or args.start or args.stop: + if GOT_DOCKER: + args.docker = True + args.local = True + else: + print "You need to install python docker to use docker handling features." + sys.exit(-1) + +if not args.local: + if not args.username: + print "You need to specify a github username (-u option) for this mode (or use -l to disable)" + sys.exit(-1) + +if args.docker: + BASE_URI="http://localhost:8010/" + BUILDERS_LIST = ["gcc", "clang", "debug", "features", "profiling", "pcaps"] +else: + BUILDERS_LIST = [username, username + "-pcap"] + +BUILDERS_URI=BASE_URI+"builders/" +JSON_BUILDERS_URI=BASE_URI+"json/builders/" + +if GOT_NOTIFY: + if args.notify: + pynotify.init("PRscript") + +def SendNotification(title, text): + if not GOT_NOTIFY: + return + if not args.notify: + return + n = pynotify.Notification(title, text) + n.show() + def TestRepoSync(branch): request = urllib2.Request(GITHUB_MASTER_URI) page = urllib2.urlopen(request) json_result = json.loads(page.read()) sha_orig = json_result[0]["sha"] - request = urllib2.Request(GITHUB_BASE_URI + username + "/" + args.repository + "/commits?sha=" + branch + "&per_page=100") - page = urllib2.urlopen(request) + check_command = ["git", "branch", "--contains", sha_orig ] + p1 = Popen(check_command, stdout=PIPE) + p2 = Popen(["grep", branch], stdin=p1.stdout, stdout=PIPE) + p1.stdout.close() + output = p2.communicate()[0] + if len(output) == 0: + return -1 + return 0 + +def TestGithubSync(branch): + request = urllib2.Request(GITHUB_BASE_URI + username + "/" + args.repository + "/commits?sha=" + branch + "&per_page=1") + try: + page = urllib2.urlopen(request) + except urllib2.HTTPError, e: + if e.code == 404: + return -2 + else: + raise(e) json_result = json.loads(page.read()) - found = -1 - for commit in json_result: - if commit["sha"] == sha_orig: - found = 1 - break - return found + sha_github = json_result[0]["sha"] + check_command = ["git", "rev-parse", branch] + p1 = Popen(check_command, stdout=PIPE) + sha_local = p1.communicate()[0].rstrip() + if sha_local != sha_github: + return -1 + return 0 def OpenBuildbotSession(): auth_params = { 'username':username,'passwd':password, 'name':'login'} @@ -69,12 +157,15 @@ def OpenBuildbotSession(): return cookie -def SubmitBuild(branch, extension = ""): +def SubmitBuild(branch, extension = "", builder_name = None): raw_params = {'branch':branch,'reason':'Testing ' + branch, 'name':'force_build', 'forcescheduler':'force'} params = urllib.urlencode(raw_params) - opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) - urllib2.install_opener(opener) - request = urllib2.Request(BUILDERS_URI + username + extension + '/force', params) + if not args.docker: + opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) + urllib2.install_opener(opener) + if builder_name == None: + builder_name = username + extension + request = urllib2.Request(BUILDERS_URI + builder_name + '/force', params) page = urllib2.urlopen(request) result = page.read() @@ -82,15 +173,24 @@ def SubmitBuild(branch, extension = ""): print "=== response ===" print result print "=== end of response ===" + if args.docker: + if "

Pending Build Requests:

" in result: + print "Build '" + builder_name + "' submitted" + return 0 + else: + return -1 if "Current Builds" in result: - print "Build submitted" + print "Build '" + builder_name + "' submitted" return 0 else: return -1 # TODO honor the branch argument -def FindBuild(branch, extension = ""): - request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/') +def FindBuild(branch, extension = "", builder_name = None): + if builder_name == None: + request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/') + else: + request = urllib2.Request(JSON_BUILDERS_URI + builder_name + '/') page = urllib2.urlopen(request) json_result = json.loads(page.read()) # Pending build is unnumbered @@ -102,9 +202,11 @@ def FindBuild(branch, extension = ""): return json_result["cachedBuilds"][-1] return -2 -def GetBuildStatus(builder, buildid, extension=""): +def GetBuildStatus(builder, buildid, extension="", builder_name = None): + if builder_name == None: + builder_name = username + extension # https://buildbot.suricata-ids.org/json/builders/build%20deb6/builds/11 - request = urllib2.Request(JSON_BUILDERS_URI + username + extension + '/builds/' + str(buildid)) + request = urllib2.Request(JSON_BUILDERS_URI + builder_name + '/builds/' + str(buildid)) page = urllib2.urlopen(request) result = page.read() if args.verbose: @@ -118,79 +220,172 @@ def GetBuildStatus(builder, buildid, extension=""): return 0 return -1 -def WaitForBuildResult(builder, buildid, extension=""): +def WaitForBuildResult(builder, buildid, extension="", builder_name = None): # fetch result every 10 secs till task is over + if builder_name == None: + builder_name = username + extension res = 1 while res == 1: - res = GetBuildStatus(username,buildid, extension=extension) + res = GetBuildStatus(username,buildid, builder_name = builder_name) if res == 1: time.sleep(10) # return the result if res == 0: - print "Build successful" + print "Build successful for " + builder_name else: - print "Build failure: " + BUILDERS_URI + username + extension + '/builds/' + str(buildid) + print "Build failure for " + builder_name + ": " + BUILDERS_URI + builder_name + '/builds/' + str(buildid) return res # check that github branch and inliniac master branch are sync -if TestRepoSync(args.branch) == -1: - if args.norebase: - print "Branch " + args.branch + " is not in sync with inliniac's master branch. Continuing due to --norebase option." - else: - print "Branch " + args.branch + " is not in sync with inliniac's master branch. Rebase needed." - sys.exit(-1) +if not args.local: + ret = TestGithubSync(args.branch) + if ret != 0: + if ret == -2: + print "Branch " + args.branch + " is not pushed to Github." + sys.exit(-1) + if args.norebase: + print "Branch " + args.branch + " is not in sync with corresponding Github branch. Continuing due to --norebase option." + else: + print "Branch " + args.branch + " is not in sync with corresponding Github branch. Push may be needed." + sys.exit(-1) + if TestRepoSync(args.branch) != 0: + if args.norebase: + print "Branch " + args.branch + " is not in sync with inliniac's master branch. Continuing due to --norebase option." + else: + print "Branch " + args.branch + " is not in sync with inliniac's master branch. Rebase needed." + sys.exit(-1) + +def CreateContainer(): + cli = Client() + # FIXME check if existing + print "Pulling docking image, first run should take long" + cli.pull('regit/suri-buildbot') + cli.create_container(name='suri-buildbot', image='regit/suri-buildbot', ports=[8010, 22], volumes=['/data/oisf', '/data/buildbot/master/master.cfg']) + sys.exit(0) + +def StartContainer(): + cli = Client() + suri_src_dir = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0] + print "Using base src dir: " + suri_src_dir + cli.start('suri-buildbot', port_bindings={8010:8010, 22:None}, binds={suri_src_dir: { 'bind': '/data/oisf', 'ro': True}, os.path.join(suri_src_dir,'qa','docker','buildbot.cfg'): { 'bind': '/data/buildbot/master/master.cfg', 'ro': True}} ) + sys.exit(0) + +def StopContainer(): + cli = Client() + cli.stop('suri-buildbot') + sys.exit(0) + +def RmContainer(): + cli = Client() + try: + cli.remove_container('suri-buildbot') + except: + print "Unable to remove suri-buildbot container" + pass + try: + cli.remove_image('regit/suri-buildbot:latest') + except: + print "Unable to remove suri-buildbot images" + pass + sys.exit(0) + +if GOT_DOCKER: + if args.create: + CreateContainer() + if args.start: + StartContainer() + if args.stop: + StopContainer() + if args.rm: + RmContainer() + +if not args.branch: + print "You need to specify a branch for this mode" + sys.exit(-1) # submit buildbot form to build current branch on the devel builder if not args.check: - cookie = OpenBuildbotSession() - if cookie == None: - print "Unable to connect to buildbot with provided credentials" - sys.exit(-1) - res = SubmitBuild(args.branch) - if res == -1: - print "Unable to start build. Check command line parameters" - sys.exit(-1) - res = SubmitBuild(args.branch, extension="-pcap") - if res == -1: - print "Unable to start pcap build. Check command line parameters" - sys.exit(-1) + if not args.docker: + cookie = OpenBuildbotSession() + if cookie == None: + print "Unable to connect to buildbot with provided credentials" + sys.exit(-1) + for build in BUILDERS_LIST: + res = SubmitBuild(args.branch, builder_name = build) + if res == -1: + print "Unable to start build. Check command line parameters" + sys.exit(-1) -# get build number and exit if we don't have -buildid = FindBuild(args.branch) -if buildid == -1: - print "Pending build tracking is not supported. Follow build by browsing " + BUILDERS_URI + username -elif buildid == -2: - print "No build found for " + BUILDERS_URI + username - sys.exit(0) -else: - print "You can watch build progress at " + BUILDERS_URI + username + "/builds/" + str(buildid) +buildids = {} + +if args.docker: + time.sleep(2) # get build number and exit if we don't have -buildidpcap = FindBuild(args.branch, extension = "-pcap") -if buildidpcap == -1: - print "Pending build tracking is not supported. Follow build by browsing " + BUILDERS_URI + username + "-pcap" -elif buildidpcap == -2: - print "No build found for " + BUILDERS_URI + username + "-pcap" - sys.exit(0) -else: - print "You can watch build progress at " + BUILDERS_URI + username + "-pcap/builds/" + str(buildidpcap) +for build in BUILDERS_LIST: + buildid = FindBuild(args.branch, builder_name = build) + if buildid == -1: + print "Pending build tracking is not supported. Follow build by browsing " + BUILDERS_URI + build + elif buildid == -2: + print "No build found for " + BUILDERS_URI + build + sys.exit(0) + else: + if not args.docker: + print "You can watch build progress at " + BUILDERS_URI + build + "/builds/" + str(buildid) + buildids[build] = buildid -if buildid != -1 or buildidpcap != -1: - print "Waiting for build completion" +if args.docker: + print "You can watch build progress at " + BASE_URI + "waterfall" -res = 0 -if buildid != -1: - res = WaitForBuildResult(username, buildid) +if len(buildids): + print "Waiting for build completion" +else: + sys.exit(0) -if buildidpcap != -1: - res += WaitForBuildResult(username, buildidpcap, extension="-pcap") +buildres = 0 +if args.docker: + while len(buildids): + up_buildids = copy.copy(buildids) + for build in buildids: + ret = GetBuildStatus(build, buildids[build], builder_name = build) + if ret == -1: + buildres = -1 + up_buildids.pop(build, None) + if len(up_buildids): + remains = " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" + else: + remains = "" + print "Build failure for " + build + ": " + BUILDERS_URI + build + '/builds/' + str(buildids[build]) + remains + elif ret == 0: + up_buildids.pop(build, None) + if len(up_buildids): + remains = " (remaining builds: " + ', '.join(up_buildids.keys()) + ")" + else: + remains = "" + print "Build successful for " + build + remains + time.sleep(5) + buildids = up_buildids + if res == -1: + SendNotification("PRscript failure", "Some builds have failed. Check waterfall for results.") + sys.exit(-1) + else: + print "PRscript completed successfully" + SendNotification("PRscript success", "Congrats! All builds have passed.") + sys.exit(0) +else: + for build in buildids: + res = WaitForBuildResult(build, buildids[build], builder_name = build) + if res == -1: + buildres = -1 -if res == 0: - if not args.norebase: +if buildres == 0: + if not args.norebase and not args.docker: print "You can copy/paste following lines into github PR" - print "- PR build: " + BUILDERS_URI + username + "/builds/" + str(buildid) - print "- PR pcaps: " + BUILDERS_URI + username + "-pcap/builds/" + str(buildidpcap) + for build in buildids: + print "- PR " + build + ": " + BUILDERS_URI + build + "/builds/" + str(buildids[build]) + SendNotification("OISF PRscript success", "Congrats! All builds have passed.") sys.exit(0) else: + SendNotification("OISF PRscript failure", "Some builds have failed. Check waterfall for results.") sys.exit(-1) diff --git a/qa/travis-libhtp.sh b/qa/travis-libhtp.sh index febe1fe7f4df..109d6d398bc6 100755 --- a/qa/travis-libhtp.sh +++ b/qa/travis-libhtp.sh @@ -1,3 +1,3 @@ #!/bin/sh set -ex -git clone https://github.com/ironbee/libhtp -b 0.5.x +git clone https://github.com/OISF/libhtp -b 0.5.x diff --git a/qa/wirefuzz.pl b/qa/wirefuzz.pl index 63708f0b214b..34f0b7d56c9f 100755 --- a/qa/wirefuzz.pl +++ b/qa/wirefuzz.pl @@ -2,7 +2,7 @@ #Author:William Metcalf #File:wirefuzz.pl -#Copyright (C) 2010 Open Information Security Foundation +#Copyright (C) 2010-2015 Open Information Security Foundation #You can copy, redistribute or modify this Program under the terms of #the GNU General Public License version 2 as published by the Free @@ -55,7 +55,7 @@ use List::Util 'shuffle'; use Devel::GDB; use File::Find; -use Getopt::Long; +use Getopt::Long qw(:config no_ignore_case); use File::Basename; #globals @@ -64,7 +64,9 @@ my @files; my $suricatabin; my $loopnum; +my $loopnum_per_file = 0; my $rules; +my $rules_exclusive = 0; my $logdir; my $configfile; my $editeratio; @@ -80,7 +82,7 @@ my $file_was_fuzzed = 0; Getopt::Long::Configure("prefix_pattern=(-|--)"); -GetOptions( \%config, qw(n=s r=s c=s e=s v=s p=s l=s s=s x=s k y z=s h help) ); +GetOptions( \%config, qw(n=s N=s r=s c=s e=s v=s p=s l=s s=s S=s x=s k y z=s h help) ); &parseopts(); @@ -97,7 +99,7 @@ sub parseopts { @tmpfiles = <$config{r}>; if(@tmpfiles eq 0){ print "parseopts: Pcap filemask was invalid we couldn't find any matching files\n"; - exit; + exit(1); } else { #escapes for filenames foreach my $file (@tmpfiles) { @@ -142,7 +144,7 @@ sub parseopts { } else { print "parseopts: suricata bin file is not a text or a bin exiting.\n"; - exit; + exit(1); } } else { @@ -150,16 +152,33 @@ sub parseopts { &printhelp(); } + if ( $config{n} && $config{N} ) { + print "ERROR: can't mix -n and -N\n"; + exit(1); + } + #number of times to loop if ( $config{n} ) { $loopnum = $config{n}; + $loopnum_per_file = 1; print "parseopts: looping through the pcaps " . $loopnum . " times or until we have an error\n"; } else { - print "parseopts: looping through the pcaps forever or until we have an error\n"; $loopnum = "infinity"; } + if ( $config{N} ) { + $loopnum = $config{N}; + print "parseopts: looping through the pcaps " . $loopnum . " times or until we have an error\n"; + } + else { + $loopnum = "infinity"; + } + + if ( $loopnum == "infinity") { + print "parseopts: looping through the pcaps forever or until we have an error\n"; + } + #rules file do we have a path and does it exist if ( $config{s} && -e $config{s} ) { $rules = $config{s}; @@ -169,9 +188,19 @@ sub parseopts { print("parseopts: rules file not specified or doesn't exist\n"); } + # exclusive rules file: do we have a path and does it exist + if ( $config{S} && -e $config{S} ) { + $rules = $config{S}; + $rules_exclusive = 1; + print "parseopts: telling suricata to use rules file exclusively " . $rules . "\n"; + } + else { + print("parseopts: rules file not specified or doesn't exist\n"); + } + #log dir does it exist if ( $config{l} && -e $config{l} ) { - $logdir = $config{l}; + $logdir = $config{l} . "/"; print "parseopts: using log dir " . $logdir . "\n"; } else { @@ -199,7 +228,7 @@ sub parseopts { } else { print "parseopts: error ratio specified but outside of range. Valid range is 0.00-1.0\n"; - exit; + exit(1); } } else { @@ -275,7 +304,9 @@ sub printhelp { -h or help -r= -n=<(optional) number of iterations or if not specified will run until error> + -N=<(optional) number of iterations of all files in the test set> -s=<(optional) path to ids rules file will be passed as -s to suricata> + -S=<(optional) path to ids rules file will be passed as -S to suricata> -e=<(optional) editcap error ratio to introduce if not specified will not fuzz. Valid range for this is 0.00 - 1.0> -p= -l=<(optional) log dir for output if not specified will use current directory.> @@ -352,7 +383,7 @@ sub printhelp { #this could still cause us to loop forever if all pcaps are bad but it's better than nothing. if ( @files < 2 ) { print "editcap: had an error and this was our only pcap:" . $editcaperr . "\n"; - exit; + exit(1); } else { print "editcap: had an error going to the next pcap:" . $editcaperr . "\n"; @@ -361,7 +392,7 @@ sub printhelp { } elsif ( $editcap_sys_signal eq 2 ) { print "editcap: system() got a ctl+c we are bailing as well\n"; - exit; + exit(1); } else { @@ -426,7 +457,11 @@ sub printhelp { . $fuzzedfile . " -l " . $logdir; if ( defined $rules ) { - $fullcmd = $fullcmd . " -s " . $rules; + if ($rules_exclusive == 1) { + $fullcmd = $fullcmd . " -S " . $rules; + } else { + $fullcmd = $fullcmd . " -s " . $rules; + } } print "suricata: $fullcmd \n"; my $starttime = time(); @@ -457,7 +492,9 @@ sub printhelp { $knownerr = 1; } if ( $knownerr eq 1 ) { - $successcnt++; + if ($loopnum_per_file == 1) { + $successcnt++; + } print "suricata: we have run with success " . $successcnt . " times\n"; if( $keeplogs eq "yes" ) { &keep_logs($fuzzedfilename); @@ -482,7 +519,7 @@ sub printhelp { }else{ &generate_report($report, $fullcmd, $out, $err, $exit, "none"); } - exit; + exit(1); } } elsif ( $suricata_sys_signal eq 2 ) { @@ -494,18 +531,10 @@ sub printhelp { exit; } else { - if ( $out =~ /Max memuse of stream engine \d+ \(in use (\d+)\)/ ) { - if ($1 != 0) { - $report = $logdir . $fuzzedfilename . "-OUT.txt"; - &generate_report($report, $fullcmd, $out, $err, $exit, "none"); - print "Stream leak detected " . $1 . " was still in use at exit see " . $report . " for more details\n"; - exit; - } - } else { - print "Stream mem counter could not be found in output\n"; + if ($loopnum_per_file == 1) { + $successcnt++; } - $successcnt++; print "suricata: we have run with success " . $successcnt . " times\n"; print "******************Suricata Complete**********************\n"; if( $keeplogs eq "yes" ) { @@ -516,6 +545,16 @@ sub printhelp { &clean_logs($fuzzedfilename,$file_was_fuzzed); print "******************Next Packet or Exit *******************\n"; } + + if ($successcnt >= $loopnum) { + last; + } + } + if ($loopnum_per_file == 0) { + $successcnt++; + } + if ($successcnt >= $loopnum) { + last; } } @@ -576,15 +615,14 @@ sub clean_logs { #system("$rmcmd"); } - if ( unlink(<$logdir . unified*>) > 0 ) { - print "clean_logs: removed unified logs for next run \n"; - } - else { - print "clean_logs: failed to delete unified logs\n:"; + foreach my $file (glob "$logdir/unified2.* $logdir/*.log $logdir/*.json") { + #print $file . "\n"; + if (unlink($file) <= 0) { + print "clean_logs: failed to delete log file $file\n"; + } } - print "******************Log Cleanup Complete**********************\n"; - return; + return; } sub keep_logs { diff --git a/reference.config b/reference.config index 1d1b42d8984a..ff4f53ddbcd1 100644 --- a/reference.config +++ b/reference.config @@ -3,6 +3,7 @@ config reference: bugtraq http://www.securityfocus.com/bid/ config reference: bid http://www.securityfocus.com/bid/ config reference: cve http://cve.mitre.org/cgi-bin/cvename.cgi?name= +#config reference: cve http://cvedetails.com/cve/ config reference: secunia http://www.secunia.com/advisories/ #whitehats is unfortunately gone @@ -12,8 +13,14 @@ config reference: McAfee http://vil.nai.com/vil/content/v_ config reference: nessus http://cgi.nessus.org/plugins/dump.php3?id= config reference: url http:// config reference: et http://doc.emergingthreats.net/ -config reference: etpro http://doc.emergingthreatpro.com/ +config reference: etpro http://doc.emergingthreatspro.com/ config reference: telus http:// - -config reference: md5 http://www.threatexpert.com/report.aspx?md5= - +config reference: osvdb http://osvdb.org/show/osvdb/ +config reference: threatexpert http://www.threatexpert.com/report.aspx?md5= +config reference: md5 http://www.threatexpert.com/report.aspx?md5= +config reference: exploitdb http://www.exploit-db.com/exploits/ +config reference: openpacket https://www.openpacket.org/capture/grab/ +config reference: securitytracker http://securitytracker.com/id? +config reference: secunia http://secunia.com/advisories/ +config reference: xforce http://xforce.iss.net/xforce/xfdb/ +config reference: msft http://technet.microsoft.com/security/bulletin/ diff --git a/rules/Makefile.am b/rules/Makefile.am index bb11b919f186..98a484d3a5b2 100644 --- a/rules/Makefile.am +++ b/rules/Makefile.am @@ -5,4 +5,7 @@ smtp-events.rules \ http-events.rules \ dns-events.rules \ tls-events.rules \ -files.rules +modbus-events.rules \ +app-layer-events.rules \ +files.rules \ +dnp3-events.rules diff --git a/rules/app-layer-events.rules b/rules/app-layer-events.rules new file mode 100644 index 000000000000..4d2ac28bbc97 --- /dev/null +++ b/rules/app-layer-events.rules @@ -0,0 +1,14 @@ +# App layer event rules +# +# SID's fall in the 2260000+ range. See http://doc.emergingthreats.net/bin/view/Main/SidAllocation +# +# These sigs fire at most once per connection. +# +# A flowint applayer.anomaly.count is incremented for each match. By default it will be 0. +# +alert ip any any -> any any (msg:"SURICATA Applayer Mismatch protocol both directions"; flow:established; app-layer-event:applayer_mismatch_protocol_both_directions; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260000; rev:1;) +alert ip any any -> any any (msg:"SURICATA Applayer Wrong direction first Data"; flow:established; app-layer-event:applayer_wrong_direction_first_data; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260001; rev:1;) +alert ip any any -> any any (msg:"SURICATA Applayer Detect protocol only one direction"; flow:established; app-layer-event:applayer_detect_protocol_only_one_direction; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260002; rev:1;) +alert ip any any -> any any (msg:"SURICATA Applayer Protocol detection skipped"; flow:established; app-layer-event:applayer_proto_detection_skipped; flowint:applayer.anomaly.count,+,1; classtype:protocol-command-decode; sid:2260003; rev:1;) + +#next sid is 2260004 diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index cee0b065c46b..73728706055f 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -52,10 +52,14 @@ alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown code"; decode-even alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 truncated packet"; decode-event:icmpv4.ipv4_trunc_pkt; sid:2200026; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv4 unknown version"; decode-event:icmpv4.ipv4_unknown_ver; sid:2200027; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 packet too small"; decode-event:icmpv6.pkt_too_small; sid:2200028; rev:1;) -alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown type"; decode-event:icmpv6.unknown_type; sid:2200029; rev:1;) +# uncomment the following sginature if you plan to update suricata code to support more ICMPv6 type +#alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown type"; decode-event:icmpv6.unknown_type; sid:2200029; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown code"; decode-event:icmpv6.unknown_code; sid:2200030; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 truncated packet"; decode-event:icmpv6.ipv6_trunc_pkt; sid:2200031; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unknown version"; decode-event:icmpv6.ipv6_unknown_version; sid:2200032; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 MLD hop limit not 1"; decode-event:icmpv6.mld_message_with_invalid_hl; sid:2200102; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 unassigned type"; decode-event:icmpv6.unassigned_type; sid:2200108; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ICMPv6 private experimentation type"; decode-event:icmpv6.experimentation_type; sid:2200109; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP packet too small"; decode-event:tcp.pkt_too_small; sid:2200033; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP header length too small"; decode-event:tcp.hlen_too_small; sid:2200034; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA TCP invalid option length"; decode-event:tcp.invalid_optlen; sid:2200035; rev:1;) @@ -95,9 +99,9 @@ alert pkthdr any any -> any any (msg:"SURICATA VLAN unknown type"; decode-event: alert pkthdr any any -> any any (msg:"SURICATA VLAN too many layers"; decode-event:vlan.too_many_layers; sid:2200091; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA IP raw invalid IP version "; decode-event:ipraw.invalid_ip_version; sid:2200068; rev:1;) -alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Packet size too large"; decode-event:ipv4.frag_too_large; sid:2200069; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Packet size too large"; decode-event:ipv4.frag_pkt_too_large; sid:2200069; rev:2;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv4 Fragmentation overlap"; decode-event:ipv4.frag_overlap; sid:2200070; rev:1;) -alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Packet size too large"; decode-event:ipv6.frag_too_large; sid:2200071; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Packet size too large"; decode-event:ipv6.frag_pkt_too_large; sid:2200071; rev:2;) alert pkthdr any any -> any any (msg:"SURICATA FRAG IPv6 Fragmentation overlap"; decode-event:ipv6.frag_overlap; sid:2200072; rev:1;) # checksum rules @@ -117,10 +121,25 @@ alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 packet too short"; d alert pkthdr any any -> any any (msg:"SURICATA IPv6-in-IPv6 invalid protocol"; decode-event:ipv6.ipv6_in_ipv6_wrong_version; sid:2200085; rev:1;) # MPLS rules +alert pkthdr any any -> any any (msg:"SURICATA MPLS header too small"; decode-event:mpls.header_too_small; sid:2200111; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS bad router alert label"; decode-event:mpls.bad_label_router_alert; sid: 2200098; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS bad implicit null label"; decode-event:mpls.bad_label_implicit_null; sid: 2200099; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS reserved label"; decode-event:mpls.bad_label_reserved; sid: 2200100; rev:1;) alert pkthdr any any -> any any (msg:"SURICATA MPLS unknown payload type"; decode-event:mpls.unknown_payload_type; sid: 2200101; rev:1;) -# next sid is 2200102 +# linktype null +alert pkthdr any any -> any any (msg:"SURICATA NULL pkt too small"; decode-event:ltnull.pkt_too_small; sid: 2200103; rev:1;) +# packet has type not supported by Suricata's decoders +alert pkthdr any any -> any any (msg:"SURICATA NULL unsupported type"; decode-event:ltnull.unsupported_type; sid: 2200104; rev:1;) + +# ERSPAN +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN pkt too small"; decode-event:erspan.header_too_small; sid: 2200105; rev:1;) +# packet has type not supported by Suricata's decoders +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN unsupported version"; decode-event:erspan.unsupported_version; sid: 2200106; rev:1;) +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN too many vlan layers"; decode-event:erspan.too_many_vlan_layers; sid: 2200107; rev:1;) + +# Cisco Fabric Path/DCE +alert pkthdr any any -> any any (msg:"SURICATA DCE packet too small"; decode-event:dce.pkt_too_small; sid:2200110; rev:1;) + +# next sid is 2200112 diff --git a/rules/dnp3-events.rules b/rules/dnp3-events.rules new file mode 100644 index 000000000000..dfb1cf2217d7 --- /dev/null +++ b/rules/dnp3-events.rules @@ -0,0 +1,26 @@ +# DNP3 application decoder event rules. +# +# This SIDs fall in the 2270000+ range. See: +# http://doc.emergingthreats.net/bin/view/Main/SidAllocation + +# Flooded. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Request flood detected"; \ + app-layer-event:dnp3.flooded; sid:2270000; rev:1;) + +# Length to small for PDU type. For example, link specifies the type +# as user data, but the length field is not large enough for user +# data. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Length too small"; \ + app-layer-event:dnp3.len_too_small; sid:2270001; rev:2;) + +# Bad link layer CRC. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad link CRC"; \ + app-layer-event:dnp3.bad_link_crc; sid:2270002; rev:1;) + +# Bad transport layer CRC. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad transport CRC"; \ + app-layer-event:dnp3.bad_transport_crc; sid:2270003; rev:1;) + +# Unknown object. +alert dnp3 any any -> any any (msg:"SURICATA DNP3 Unknown object"; \ + app-layer-event:dnp3.unknown_object; sid:2270004; rev:1;) diff --git a/rules/dns-events.rules b/rules/dns-events.rules index 693f2f1b3b36..82ee63311368 100644 --- a/rules/dns-events.rules +++ b/rules/dns-events.rules @@ -1,8 +1,8 @@ # Response (answer) we didn't see a Request for. Could be packet loss. -alert dns any any -> any any (msg:"SURICATA DNS Unsollicited response"; flow:to_client; app-layer-event:dns.unsollicited_response; sid:2240001; rev:1;) +alert dns any any -> any any (msg:"SURICATA DNS Unsolicited response"; flow:to_client; app-layer-event:dns.unsollicited_response; sid:2240001; rev:1;) # Malformed data in request. Malformed means length fields are wrong, etc. -alert dns any any -> any any (msg:"SURICATA DNS malformed request data"; flow:to_client; app-layer-event:dns.malformed_data; sid:2240002; rev:1;) -alert dns any any -> any any (msg:"SURICATA DNS malformed response data"; flow:to_server; app-layer-event:dns.malformed_data; sid:2240003; rev:1;) +alert dns any any -> any any (msg:"SURICATA DNS malformed request data"; flow:to_server; app-layer-event:dns.malformed_data; sid:2240002; rev:1;) +alert dns any any -> any any (msg:"SURICATA DNS malformed response data"; flow:to_client; app-layer-event:dns.malformed_data; sid:2240003; rev:1;) # Response flag set on to_server packet alert dns any any -> any any (msg:"SURICATA DNS Not a request"; flow:to_server; app-layer-event:dns.not_a_request; sid:2240004; rev:1;) # Response flag not set on to_client packet diff --git a/rules/files.rules b/rules/files.rules index 0f770902f8d9..c747727f3968 100644 --- a/rules/files.rules +++ b/rules/files.rules @@ -26,7 +26,7 @@ # Store all JPG files, don't alert. #alert http any any -> any any (msg:"FILE magic"; filemagic:"JFIF"; filestore; noalert; sid:16; rev:1;) -#alert http any any -> any any (msg:"FILE magic"; filemagic:"GIF"; filestore; noalert; sid:16; rev:1;) +#alert http any any -> any any (msg:"FILE magic"; filemagic:"GIF"; filestore; noalert; sid:23; rev:1;) #alert http any any -> any any (msg:"FILE magic"; filemagic:"PNG"; filestore; noalert; sid:17; rev:1;) # Store all Windows executables @@ -43,3 +43,5 @@ # Alert and store pdf attachment but not pdf file #alert http any any -> any any (msg:"FILE pdf claimed, but not pdf"; flow:established,to_client; fileext:"pdf"; filemagic:!"PDF document"; filestore; sid:22; rev:1;) +# Alert and store files over SMTP +#alert smtp any any -> any any (msg:"File Found over SMTP and stored"; filestore; sid:27; rev:1;) diff --git a/rules/http-events.rules b/rules/http-events.rules index d5bb0f19a7e0..3c83a68411f8 100644 --- a/rules/http-events.rules +++ b/rules/http-events.rules @@ -41,6 +41,12 @@ alert http any any -> any any (msg:"SURICATA HTTP request server port doesn't ma alert http any any -> any any (msg:"SURICATA HTTP Host part of URI is invalid"; flow:established,to_server; app-layer-event:http.request_uri_host_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221027; rev:1;) # Host header is invalid alert http any any -> any any (msg:"SURICATA HTTP Host header invalid"; flow:established,to_server; app-layer-event:http.request_header_host_invalid; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221028; rev:1;) +# URI is terminated by non-compliant characters. RFC allows for space (0x20), but many implementations permit others like tab and more. +alert http any any -> any any (msg:"SURICATA HTTP URI terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.uri_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221029; rev:1;) +# Method is terminated by non-compliant characters. RFC allows for space (0x20), but many implementations permit others like tab and more. +alert http any any -> any any (msg:"SURICATA HTTP METHOD terminated by non-compliant character"; flow:established,to_server; app-layer-event:http.method_delim_non_compliant; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221030; rev:1;) +# Request line started with whitespace +alert http any any -> any any (msg:"SURICATA HTTP Request line with leading whitespace"; flow:established,to_server; app-layer-event:http.request_line_leading_whitespace; flowint:http.anomaly.count,+,1; classtype:protocol-command-decode; sid:2221031; rev:1;) -# next sid 2221029 +# next sid 2221032 diff --git a/rules/modbus-events.rules b/rules/modbus-events.rules new file mode 100644 index 000000000000..f87997150c63 --- /dev/null +++ b/rules/modbus-events.rules @@ -0,0 +1,18 @@ +# Modbus Protocol version field is incorrect (Modbus version = 0) +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Protocol version"; app-layer-event:modbus.invalid_protocol_id; sid:2250001; rev:1;) +# Response (answer) we didn't see a Request for. Could be packet loss. +alert modbus any any -> any any (msg:"SURICATA Modbus unsolicited response"; app-layer-event:modbus.unsolicited_response; sid:2250002; rev:1;) +# Malformed request or response. Malformed means length field is wrong +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Length"; app-layer-event:modbus.invalid_length; sid:2250003; rev:1;) +# Unit identifier field is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Unit Identifier"; app-layer-event:modbus.invalid_unit_identifier; sid:2250004; rev:1;) +# Modbus Function code is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Function code"; app-layer-event:modbus.invalid_function_code; sid:2250005; rev:1;) +# Modbus Request/Response value field is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus invalid Value"; app-layer-event:modbus.invalid_value; sid:2250006; rev:1;) +# Modbus Expception code is incorrect +alert modbus any any -> any any (msg:"SURICATA Modbus Exception code invalid"; flow:to_client; app-layer-event:modbus.invalid_exception_code; sid:2250007; rev:1;) +# Value field in Modbus Response does not match with Modbus Request +alert modbus any any -> any any (msg:"SURICATA Modbus Data mismatch"; flow:to_client; app-layer-event:modbus.value_mismatch; sid:2250008; rev:1;) +# Request Flood Detected +alert modbus any any -> any any (msg:"SURICATA Modbus Request flood detected"; flow:to_server; app-layer-event:modbus.flooded; sid:2250009; rev:1;) diff --git a/rules/smtp-events.rules b/rules/smtp-events.rules index a20c6155a167..89c25acbc735 100644 --- a/rules/smtp-events.rules +++ b/rules/smtp-events.rules @@ -16,3 +16,17 @@ alert smtp any any -> any any (msg:"SURICATA SMTP no server welcome message"; fl alert smtp any any -> any any (msg:"SURICATA SMTP tls rejected"; flow:established; app-layer-event:smtp.tls_rejected; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220007; rev:1;) alert smtp any any -> any any (msg:"SURICATA SMTP data command rejected"; flow:established,to_client; app-layer-event:smtp.data_command_rejected; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220008; rev:1;) +# SMTP MIME events +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime parser failed"; flow:established; app-layer-event:smtp.mime_parse_failed; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220009; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime malformed message found"; flow:established; app-layer-event:smtp.mime_malformed_msg; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220010; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime base64-decoding failed"; flow:established; app-layer-event:smtp.mime_invalid_base64; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220011; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime header name len exceeded"; flow:established; app-layer-event:smtp.mime_long_header_name; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220012; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime header value len exceeded"; flow:established; app-layer-event:smtp.mime_long_header_value; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220013; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime quoted-printable-decoding failed"; flow:established; app-layer-event:smtp.mime_invalid_qp; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220014; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime line len exceeded"; flow:established; app-layer-event:smtp.mime_long_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220015; rev:1;) +#alert smtp any any -> any any (msg:"SURICATA SMTP Mime encoded line len exceeded"; flow:established; app-layer-event:smtp.mime_long_enc_line; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220016; rev:1;) +alert smtp any any -> any any (msg:"SURICATA SMTP Mime boundary length exceeded"; flow:established,to_server; app-layer-event:smtp.mime_long_boundary; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220017; rev:1;) + +alert smtp any any -> any any (msg:"SURICATA SMTP duplicate fields"; flow:established,to_server; app-layer-event:smtp.duplicate_fields; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220018; rev:1;) +alert smtp any any -> any any (msg:"SURICATA SMTP unparsable content"; flow:established,to_server; app-layer-event:smtp.unparsable_content; flowint:smtp.anomaly.count,+,1; classtype:protocol-command-decode; sid:2220019; rev:1;) +# next sid 2220020 diff --git a/rules/tls-events.rules b/rules/tls-events.rules index f9e886894f05..2555f1895283 100644 --- a/rules/tls-events.rules +++ b/rules/tls-events.rules @@ -18,10 +18,14 @@ alert tls any any -> any any (msg:"SURICATA TLS certificate invalid length"; flo alert tls any any -> any any (msg:"SURICATA TLS certificate invalid string"; flow:established; app-layer-event:tls.certificate_invalid_string; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230008; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS error message encountered"; flow:established; app-layer-event:tls.error_message_encountered; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230009; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid record/traffic"; flow:established; app-layer-event:tls.invalid_ssl_record; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230010; rev:1;) - alert tls any any -> any any (msg:"SURICATA TLS heartbeat encountered"; flow:established; app-layer-event:tls.heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230011; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS overflow heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.overflow_heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230012; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.invalid_heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230013; rev:1;) alert tls any any -> any any (msg:"SURICATA TLS invalid encrypted heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.dataleak_heartbeat_mismatch; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230014; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS multiple SNI extensions"; flow:established,to_server; app-layer-event:tls.multiple_sni_extensions; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230016; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS invalid SNI type"; flow:established,to_server; app-layer-event:tls.invalid_sni_type; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230017; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS invalid SNI length"; flow:established,to_server; app-layer-event:tls.invalid_sni_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230018; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS handshake invalid length"; flow:established; app-layer-event:tls.handshake_invalid_length; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230019; rev:1;) +alert tls any any -> any any (msg:"SURICATA TLS too many records in packet"; flow:established; app-layer-event:tls.too_many_records_in_packet; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; sid:2230020; rev:1;) -#next sid is 2230016 +#next sid is 2230021 diff --git a/scripts/afl/listcrashedseries.sh b/scripts/afl/listcrashedseries.sh new file mode 100644 index 000000000000..16b7e3b72e4d --- /dev/null +++ b/scripts/afl/listcrashedseries.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +NAME=$1 + +SERIES=$(ls ${NAME}/dump/ |sort|cut -f 1 -d'.'|sort -u) + +for S in $SERIES; do + FILEPATH="${NAME}/dump/${S}.999" + if [ ! -f $FILEPATH ]; then + echo "SERIE $S incomplete, possible crash" + fi +done + diff --git a/scripts/afl/runafl.sh b/scripts/afl/runafl.sh new file mode 100644 index 000000000000..2bab3ad1c8fd --- /dev/null +++ b/scripts/afl/runafl.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +PROTO=$1 + +if [ ! -d $1 ]; then + mkdir -p $1/output + mkdir -p $1/dump + mkdir -p $1/input + echo "1" > $1/input/seed.txt +else + CRASHES=$(ls ${1}/output/crashes|wc -l) + if [ $CRASHED -ne "0" ]; then + DIRNAME=$(date +%s) + mkdir "${1}/$DIRNAME" + mv -f ${1}/output/crashes/* ${1}/$DIRNAME/ + fi + mv -f $1/output/queue/id* $1/input/ + rm -r $1/output/ + mkdir $1/output +fi +cd $1 +export ASAN_OPTIONS="detect_leaks=0 abort_on_error=1 symbolize=0" +export AFL_SKIP_CPUFREQ=1 +/usr/local/bin/afl-fuzz -T ${PROTO} -t 1000 -m none -i input/ -o output/ -- ../../src/suricata --afl-${PROTO}=@@ diff --git a/scripts/dnp3-gen/dnp3-gen.py b/scripts/dnp3-gen/dnp3-gen.py new file mode 100755 index 000000000000..67cee0e2bcaa --- /dev/null +++ b/scripts/dnp3-gen/dnp3-gen.py @@ -0,0 +1,729 @@ +#! /usr/bin/env python +# +# Copyright (C) 2015 Open Information Security Foundation +# +# You can copy, redistribute or modify this Program under the terms of +# the GNU General Public License version 2 as published by the Free +# Software Foundation. +# +# 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 +# version 2 along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This script generates DNP3 related source code based on definitions +# of DNP3 objects (currently the object structs). + +from __future__ import print_function + +import sys +import re +from cStringIO import StringIO +import yaml +import types + +import jinja2 + +IN_PLACE_START = "/* START GENERATED CODE */" +IN_PLACE_END = "/* END GENERATED CODE */" + +util_lua_dnp3_objects_c_template = """/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * {{command_line}} + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" + +/** + * \\brief Push an object point item onto the stack. + */ +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, + DNP3Point *point) +{ + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { +{% for object in objects %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): { + DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data; +{% for field in object.fields %} +{% if is_integer_type(field.type) %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushinteger(luastate, data->{{field.name}}); + lua_settable(luastate, -3); +{% elif field["type"] in ["flt32", "flt64"] %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushnumber(luastate, data->{{field.name}}); + lua_settable(luastate, -3); +{% elif field["type"] == "chararray" %} + lua_pushliteral(luastate, "{{field.name}}"); + LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}}, + strlen(data->{{field.name}})); + lua_settable(luastate, -3); +{% elif field["type"] == "vstr4" %} + lua_pushliteral(luastate, "{{field.name}}"); + LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}}, + strlen(data->{{field.name}})); + lua_settable(luastate, -3); +{% elif field.type == "bytearray" %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushlstring(luastate, (const char *)data->{{field.name}}, + data->{{field.len_field}}); + lua_settable(luastate, -3); +{% elif field.type == "bstr8" %} +{% for field in field.fields %} + lua_pushliteral(luastate, "{{field.name}}"); + lua_pushinteger(luastate, data->{{field.name}}); + lua_settable(luastate, -3); +{% endfor %} +{% else %} +{{ raise("Unhandled datatype: %s" % (field.type)) }} +{% endif %} +{% endfor %} + break; + } +{% endfor %} + default: + break; + } +} + +#endif /* HAVE_LUA */ + +""" + +output_json_dnp3_objects_template = """/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * {{command_line}} + */ + +#include "suricata-common.h" + +#include "util-crypt.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LIBJANSSON + +void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object, + DNP3Point *point) +{ + + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { +{% for object in objects %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): { + DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data; +{% for field in object.fields %} +{% if is_integer_type(field.type) %} + json_object_set_new(js, "{{field.name}}", + json_integer(data->{{field.name}})); +{% elif field.type in ["flt32", "flt64"] %} + json_object_set_new(js, "{{field.name}}", + json_real(data->{{field.name}})); +{% elif field.type == "bytearray" %} + unsigned long {{field.name}}_b64_len = data->{{field.len_field}} * 2; + uint8_t {{field.name}}_b64[{{field.name}}_b64_len]; + Base64Encode(data->{{field.name}}, data->{{field.len_field}}, + {{field.name}}_b64, &{{field.name}}_b64_len); + json_object_set_new(js, "data->{{field.name}}", + json_string((char *){{field.name}}_b64)); +{% elif field.type == "vstr4" %} + json_object_set_new(js, "data->{{field.name}}", json_string(data->{{field.name}})); +{% elif field.type == "chararray" %} + if (data->{{field.len_field}} > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->{{field.len_field}} + 1]; + memcpy(tmpbuf, data->{{field.name}}, data->{{field.len_field}}); + tmpbuf[data->{{field.len_field}}] = '\\0'; + json_object_set_new(js, "{{field.name}}", json_string(tmpbuf)); + } else { + json_object_set_new(js, "{{field.name}}", json_string("")); + } +{% elif field.type == "bstr8" %} +{% for field in field.fields %} + json_object_set_new(js, "{{field.name}}", + json_integer(data->{{field.name}})); +{% endfor %} +{% else %} +{{ raise("Unhandled datatype: %s" % (field.type)) }} +{% endif %} +{% endfor %} + break; + } +{% endfor %} + default: + SCLogDebug("Unknown object: %d:%d", object->group, + object->variation); + break; + } + +} + +#endif /* HAVE_LIBJANSSON */ + +""" + +def has_freeable_types(fields): + freeable_types = [ + "bytearray", + ] + for field in fields: + if field["type"] in freeable_types: + return True + return False + +def is_integer_type(datatype): + integer_types = [ + "uint64", + "uint32", + "uint24", + "uint16", + "uint8", + "int64", + "int32", + "int16", + "int8", + "dnp3time", + ] + return datatype in integer_types + +def to_type(datatype): + type_map = { + "uint8": "uint8_t", + } + if datatype in type_map: + return type_map[datatype] + else: + raise Exception("Unknown datatype: %s" % (datatype)) + +def generate(template, filename, context): + print("Generating %s." % (filename)) + try: + env = jinja2.Environment(trim_blocks=True) + output = env.from_string(template).render(context) + with open(filename, "w") as fileobj: + fileobj.write(output) + except Exception as err: + print("Failed to generate %s: %s" % (filename, err)) + sys.exit(1) + +def raise_helper(msg): + raise Exception(msg) + +def gen_object_structs(context): + """ Generate structs for all the define DNP3 objects. """ + + template = """ + +/* Code generated by: + * {{command_line}} + */ + +{% for object in objects %} +typedef struct DNP3ObjectG{{object.group}}V{{object.variation}}_ { +{% for field in object.fields %} +{% if field.type == "bstr8" %} +{% for field in field.fields %} + uint8_t {{field.name}}:{{field.width}}; +{% endfor %} +{% else %} +{% if field.type == "int16" %} + int16_t {{field.name}}; +{% elif field.type == "int32" %} + int32_t {{field.name}}; +{% elif field.type == "uint8" %} + uint8_t {{field.name}}; +{% elif field.type == "uint16" %} + uint16_t {{field.name}}; +{% elif field.type == "uint24" %} + uint32_t {{field.name}}; +{% elif field.type == "uint32" %} + uint32_t {{field.name}}; +{% elif field.type == "uint64" %} + uint64_t {{field.name}}; +{% elif field.type == "flt32" %} + float {{field.name}}; +{% elif field.type == "flt64" %} + double {{field.name}}; +{% elif field.type == "dnp3time" %} + uint64_t {{field.name}}; +{% elif field.type == "bytearray" %} + uint8_t *{{field.name}}; +{% elif field.type == "vstr4" %} + char {{field.name}}[5]; +{% elif field.type == "chararray" %} + char {{field.name}}[{{field.size}}]; +{% else %} + {{ raise("Unknown datatype type '%s' for object %d:%d" % ( + field.type, object.group, object.variation)) }} +{% endif %} +{% endif %} +{% endfor %} +{% if object.extra_fields %} +{% for field in object.extra_fields %} +{% if field.type == "uint8" %} + uint8_t {{field.name}}; +{% elif field.type == "uint16" %} + uint16_t {{field.name}}; +{% elif field.type == "uint32" %} + uint32_t {{field.name}}; +{% else %} + {{ raise("Unknown datatype: %s" % (field.type)) }} +{% endif %} +{% endfor %} +{% endif %} +} DNP3ObjectG{{object.group}}V{{object.variation}}; + +{% endfor %} +""" + + filename = "src/app-layer-dnp3-objects.h" + try: + env = jinja2.Environment(trim_blocks=True) + code = env.from_string(template).render(context) + content = open(filename).read() + content = re.sub( + "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)), + r"\1%s\2" % (code), content, 1, re.M | re.DOTALL) + open(filename, "w").write(content) + print("Updated %s." % (filename)) + except Exception as err: + print("Failed to update %s: %s" % (filename, err), file=sys.stderr) + sys.exit(1) + +def gen_object_decoders(context): + """ Generate decoders for all defined DNP3 objects. """ + + template = """ + +/* Code generated by: + * {{command_line}} + */ + +{% for object in objects %} +{% if object.packed %} +static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + {{object.fields[0].width}}) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + +{% if object.fields[0].width == 1 %} + object->{{object.fields[0].name}} = (octet >> j) & 0x1; +{% elif object.fields[0].width == 2 %} + object->{{object.fields[0].name}} = (octet >> j) & 0x3; +{% else %} +#error "Unhandled field width: {{object.fields[0].width}}" +{% endif %} + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +{% else %} +static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; +{% if object._track_offset %} + uint32_t offset; +{% endif %} +{% if object.constraints %} + +{% for (key, val) in object.constraints.items() %} +{% if key == "require_size_prefix" %} + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } +{% elif key == "require_prefix_code" %} + if (prefix_code != {{val}}) { + goto error; + } +{% else %} +{{ raise("Unhandled constraint: %s" % (key)) }} +{% endif %} +{% endfor %} +{% endif %} + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } +{% if object._track_offset %} + + offset = *len; +{% endif %} + +{% for field in object.fields %} +{% if field.type == "int16" %} + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->{{field.name}})) { + goto error; + } +{% elif field.type == "int32" %} + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint8" %} + if (!DNP3ReadUint8(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint16" %} + if (!DNP3ReadUint16(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint24" %} + if (!DNP3ReadUint24(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint32" %} + if (!DNP3ReadUint32(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "uint64" %} + if (!DNP3ReadUint64(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "flt32" %} + if (!DNP3ReadFloat32(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "flt64" %} + if (!DNP3ReadFloat64(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "dnp3time" %} + if (!DNP3ReadUint48(buf, len, &object->{{field.name}})) { + goto error; + } +{% elif field.type == "vstr4" %} + if (*len < 4) { + goto error; + } + memcpy(object->{{field.name}}, *buf, 4); + object->{{field.name}}[4] = '\\\\0'; + *buf += 4; + *len -= 4; +{% elif field.type == "bytearray" %} +{% if field.len_from_prefix %} + object->{{field.len_field}} = prefix - (offset - *len); +{% endif %} + if (object->{{field.len_field}} > 0) { + if (*len < object->{{field.len_field}}) { + /* Not enough data. */ + goto error; + } + object->{{field.name}} = SCCalloc(1, object->{{field.len_field}}); + if (unlikely(object->{{field.name}} == NULL)) { + goto error; + } + memcpy(object->{{field.name}}, *buf, object->{{field.len_field}}); + *buf += object->{{field.len_field}}; + *len -= object->{{field.len_field}}; + } +{% elif field.type == "chararray" %} +{% if field.len_from_prefix %} + object->{{field.len_field}} = prefix - (offset - *len); +{% endif %} + if (object->{{field.len_field}} > 0) { + memcpy(object->{{field.name}}, *buf, object->{{field.len_field}}); + *buf += object->{{field.len_field}}; + *len -= object->{{field.len_field}}; + } + object->{{field.name}}[object->{{field.len_field}}] = '\\\\0'; +{% elif field.type == "bstr8" %} + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } +{% set shift = 0 %} +{% for field in field.fields %} +{% if field.width == 1 %} + object->{{field.name}} = (octet >> {{shift}}) & 0x1; +{% elif field.width == 2 %} + object->{{field.name}} = (octet >> {{shift}}) & 0x3; +{% elif field.width == 4 %} + object->{{field.name}} = (octet >> {{shift}}) & 0xf; +{% elif field.width == 7 %} + object->{{field.name}} = (octet >> {{shift}}) & 0x7f; +{% else %} +{{ raise("Unhandled width of %d." % (field.width)) }} +{% endif %} +{% set shift = shift + field.width %} +{% endfor %} + } +{% else %} +{{ raise("Unhandled datatype '%s' for object %d:%d." % (field.type, + object.group, object.variation)) }} +{% endif %} +{% endfor %} + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +{% endif %} +{% endfor %} + +void DNP3FreeObjectPoint(int group, int variation, void *point) +{ + switch(DNP3_OBJECT_CODE(group, variation)) { +{% for object in objects %} +{% if f_has_freeable_types(object.fields) %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): { + DNP3ObjectG{{object.group}}V{{object.variation}} *object = (DNP3ObjectG{{object.group}}V{{object.variation}} *) point; +{% for field in object.fields %} +{% if field.type == "bytearray" %} + if (object->{{field.name}} != NULL) { + SCFree(object->{{field.name}}); + } +{% endif %} +{% endfor %} + break; + } +{% endif %} +{% endfor %} + default: + break; + } + SCFree(point); +} + +/** + * \\\\brief Decode a DNP3 object. + * + * \\\\retval 0 on success. On failure a positive integer corresponding + * to a DNP3 application layer event will be returned. + */ +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, + uint32_t *len, uint8_t prefix_code, uint32_t start, + uint32_t count, DNP3PointList *points) +{ + int rc = 0; + + switch (DNP3_OBJECT_CODE(group, variation)) { +{% for object in objects %} + case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): + rc = DNP3DecodeObjectG{{object.group}}V{{object.variation}}(buf, len, prefix_code, start, count, + points); + break; +{% endfor %} + default: + return DNP3_DECODER_EVENT_UNKNOWN_OBJECT; + } + + return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED; +} + +""" + + try: + filename = "src/app-layer-dnp3-objects.c" + env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True) + code = env.from_string(template).render(context) + content = open(filename).read() + content = re.sub( + "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)), + r"\1%s\n\2" % (code), content, 1, re.M | re.DOTALL) + open(filename, "w").write(content) + print("Updated %s." % (filename)) + except Exception as err: + print("Failed to update %s: %s" % (filename, err), file=sys.stderr) + sys.exit(1) + +def preprocess_object(obj): + + valid_keys = [ + "group", + "variation", + "constraints", + "extra_fields", + "fields", + "packed", + ] + + valid_field_keys = [ + "type", + "name", + "width", + "len_from_prefix", + "len_field", + "fields", + "size", + ] + + if "unimplemented" in obj: + print("Object not implemented: %s:%s: %s" % ( + str(obj["group"]), str(obj["variation"]), obj["unimplemented"])) + return None + + for key, val in obj.items(): + + if key not in valid_keys: + print("Invalid key '%s' in object %d:%d" % ( + key, obj["group"], obj["variation"]), file=sys.stderr) + sys.exit(1) + + for field in obj["fields"]: + + for key in field.keys(): + if key not in valid_field_keys: + print("Invalid key '%s' in object %d:%d" % ( + key, obj["group"], obj["variation"]), file=sys.stderr) + sys.exit(1) + + if "len_from_prefix" in field and field["len_from_prefix"]: + obj["_track_offset"] = True + break + + if field["type"] == "bstr8": + width = 0 + for subfield in field["fields"]: + width += int(subfield["width"]) + assert(width == 8) + + return obj + +def main(): + + definitions = yaml.load(open("scripts/dnp3-gen/dnp3-objects.yaml")) + print("Loaded %s objects." % (len(definitions["objects"]))) + definitions["objects"] = map(preprocess_object, definitions["objects"]) + + # Filter out unimplemented objects. + definitions["objects"] = [ + obj for obj in definitions["objects"] if obj != None] + + context = { + "raise": raise_helper, + "objects": definitions["objects"], + "is_integer_type": is_integer_type, + "f_to_type": to_type, + "f_has_freeable_types": has_freeable_types, + "command_line": " ".join(sys.argv), + } + + gen_object_structs(context) + gen_object_decoders(context) + generate(util_lua_dnp3_objects_c_template, + "src/util-lua-dnp3-objects.c", + context) + generate(output_json_dnp3_objects_template, + "src/output-json-dnp3-objects.c", + context) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/dnp3-gen/dnp3-objects.yaml b/scripts/dnp3-gen/dnp3-objects.yaml new file mode 100644 index 000000000000..529910f78d44 --- /dev/null +++ b/scripts/dnp3-gen/dnp3-objects.yaml @@ -0,0 +1,2995 @@ +objects: + + - group: 1 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 1 + + - group: 1 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + name: online + width: 1 + - type: uint8 + name: restart + width: 1 + - name: comm_lost + type: uint8 + width: 1 + - name: remote_forced + type: uint8 + width: 1 + - name: local_forced + type: uint8 + width: 1 + - name: chatter_filter + type: uint8 + width: 1 + - name: reserved + type: uint8 + width: 1 + - name: state + type: uint8 + width: 1 + + - group: 2 + variation: 1 + fields: + - type: uint8 + name: state + width: 1 + + - group: 2 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + name: online + width: 1 + - type: uint8 + name: restart + width: 1 + - name: comm_lost + type: uint8 + width: 1 + - name: remote_forced + type: uint8 + width: 1 + - name: local_forced + type: uint8 + width: 1 + - name: chatter_filter + type: uint8 + width: 1 + - name: reserved + type: uint8 + width: 1 + - name: state + type: uint8 + width: 1 + - type: dnp3time + name: timestamp + + - group: 2 + variation: 3 + fields: + - type: bstr8 + fields: + - type: uint8 + name: online + width: 1 + - type: uint8 + name: restart + width: 1 + - name: comm_lost + type: uint8 + width: 1 + - name: remote_forced + type: uint8 + width: 1 + - name: local_forced + type: uint8 + width: 1 + - name: chatter_filter + type: uint8 + width: 1 + - name: reserved + type: uint8 + width: 1 + - name: state + type: uint8 + width: 1 + - type: uint16 + name: timestamp + + - group: 3 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 2 + + - group: 3 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + + - group: 4 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + + - group: 4 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + - type: dnp3time + name: timestamp + + - group: 4 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: chatter_filter + width: 1 + - name: state + width: 2 + - type: uint16 + name: relative_time_ms + + - group: 10 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 1 + + - group: 10 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - name: state + width: 1 + + - group: 11 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - name: state + width: 1 + + - group: 11 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - name: state + width: 1 + - type: dnp3time + name: timestamp + + - group: 12 + variation: 1 + fields: + - type: bstr8 + fields: + - name: op_type + type: uint8 + width: 4 + - name: qu + type: uint8 + width: 1 + - name: cr + type: uint8 + width: 1 + - name: tcc + type: uint8 + width: 2 + - name: count + type: uint8 + - name: ontime + type: uint32 + - name: offtime + type: uint32 + - type: bstr8 + fields: + - name: status_code + type: uint8 + width: 7 + - name: reserved + type: uint32 + width: 1 + + - group: 12 + variation: 2 + fields: + - type: bstr8 + fields: + - name: op_type + type: uint8 + width: 4 + - name: qu + type: uint8 + width: 1 + - name: cr + type: uint8 + width: 1 + - name: tcc + type: uint8 + width: 2 + - name: count + type: uint8 + - name: ontime + type: uint32 + - name: offtime + type: uint32 + - type: bstr8 + fields: + - name: status_code + type: uint8 + width: 7 + - name: reserved + type: uint32 + width: 1 + + - group: 12 + variation: 3 + packed: true + fields: + - type: uint8 + name: point + width: 1 + + - group: 13 + variation: 1 + fields: + - type: bstr8 + fields: + - type: uint8 + width: 7 + name: status_code + - type: uint8 + width: 1 + name: commanded_state + + - group: 13 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + width: 7 + name: status_code + - type: uint8 + width: 1 + name: commanded_state + - type: dnp3time + name: timestamp + + - group: 20 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 20 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + + - group: 20 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 20 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 20 + variation: 5 + fields: + - type: uint32 + name: count + + - group: 20 + variation: 6 + fields: + - type: uint16 + name: count + + - group: 20 + variation: 7 + fields: + - type: uint32 + name: count + + - group: 20 + variation: 8 + fields: + - type: uint16 + name: count + + - group: 21 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 21 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + + - group: 21 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 21 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 21 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 21 + variation: 9 + fields: + - type: uint32 + name: count + + - group: 21 + variation: 10 + fields: + - type: uint16 + name: count + + - group: 21 + variation: 11 + fields: + - type: uint32 + name: count + + - group: 21 + variation: 12 + fields: + - type: uint16 + name: count + + - group: 22 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 22 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + + - group: 22 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 22 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 22 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 22 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 22 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 22 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + + - group: 23 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 23 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + + - group: 23 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + + - group: 23 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: discontinuity + width: 1 + - name: reserved0 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint32 + name: count + - type: dnp3time + name: timestamp + + - group: 23 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: rollover + width: 1 + - name: reserved0 + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: count + - type: dnp3time + name: timestamp + + - group: 30 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 30 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 30 + variation: 3 + fields: + - type: int32 + name: value + + - group: 30 + variation: 4 + fields: + - type: int16 + name: value + + - group: 30 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 30 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 31 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 31 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 31 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 31 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 31 + variation: 5 + fields: + - type: int32 + name: value + + - group: 31 + variation: 6 + fields: + - type: int16 + name: value + + - group: 31 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 31 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 32 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 32 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 32 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 32 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 32 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 32 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 32 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + - type: dnp3time + name: timestamp + + - group: 32 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + # XXX Spec says FLT32, pretty sure its FLT64 and OpenDNP uses a 64 bit + # float as well. + - type: flt64 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 33 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 33 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 33 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 33 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + - type: dnp3time + name: timestamp + + - group: 33 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + # XXX Spec says FLT32, I think its FLT64. + - type: flt64 + name: value + - type: dnp3time + name: timestamp + + - group: 34 + variation: 1 + fields: + - type: uint16 + name: deadband_value + + - group: 34 + variation: 2 + fields: + - type: uint32 + name: deadband_value + + - group: 34 + variation: 3 + fields: + - type: flt32 + name: deadband_value + + - group: 40 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 40 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 40 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 40 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 41 + variation: 1 + fields: + - type: int32 + name: value + - type: uint8 + name: control_status + + - group: 41 + variation: 2 + fields: + - type: int16 + name: value + - type: uint8 + name: control_status + + - group: 41 + variation: 3 + fields: + - type: flt32 + name: value + - type: uint8 + name: control_status + + - group: 41 + variation: 4 + fields: + - type: flt64 + name: value + - type: uint8 + name: control_status + + - group: 42 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + + - group: 42 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + + - group: 42 + variation: 3 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int32 + name: value + - type: dnp3time + name: timestamp + + - group: 42 + variation: 4 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: int16 + name: value + - type: dnp3time + name: timestamp + + - group: 42 + variation: 5 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + + - group: 42 + variation: 6 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + + - group: 42 + variation: 7 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt32 + name: value + - type: dnp3time + name: timestamp + + - group: 42 + variation: 8 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: over_range + width: 1 + - name: reference_err + width: 1 + - name: reserved0 + width: 1 + - type: flt64 + name: value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 1 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int32 + name: commanded_value + + - group: 43 + variation: 2 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int16 + name: commanded_value + + - group: 43 + variation: 3 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int32 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 4 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: int16 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 5 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt32 + name: commanded_value + + - group: 43 + variation: 6 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt64 + name: commanded_value + + - group: 43 + variation: 7 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt32 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 43 + variation: 8 + fields: + - type: bstr8 + fields: + - type: uint8 + name: status_code + width: 7 + - type: uint8 + name: reserved0 + width: 1 + - type: flt64 + name: commanded_value + - type: dnp3time + name: timestamp + + - group: 50 + variation: 1 + fields: + - type: dnp3time + name: timestamp + + - group: 50 + variation: 2 + fields: + - type: dnp3time + name: timestamp + - type: uint32 + name: interval + + - group: 50 + variation: 3 + fields: + - type: dnp3time + name: timestamp + + - group: 50 + variation: 4 + fields: + - type: dnp3time + name: timestamp + - type: uint32 + name: interval_count + - type: uint8 + name: interval_units + + - group: 51 + variation: 1 + fields: + - type: dnp3time + name: timestamp + + - group: 51 + variation: 2 + fields: + - type: dnp3time + name: timestamp + + - group: 52 + variation: 1 + fields: + - type: uint16 + name: delay_secs + + - group: 52 + variation: 2 + fields: + - type: uint16 + name: delay_ms + + # 1815-2012: New DNP3 implementation should avoid using this object. + - group: 70 + variation: 1 + fields: + - type: uint16 + name: filename_size + - type: uint8 + name: filetype_code + - type: uint8 + name: attribute_code + - type: uint16 + name: start_record + - type: uint16 + name: end_record + - type: uint32 + name: file_size + - type: dnp3time + name: created_timestamp + # XXX Actually bit flags. + - type: uint16 + name: permission + - type: uint32 + name: file_id + - type: uint32 + name: owner_id + - type: uint32 + name: group_id + - type: uint8 + name: file_function_code + - type: uint8 + name: status_code + - type: chararray + name: filename + size: 65535 + len_field: filename_size + - type: uint16 + name: data_size + - type: chararray + name: data + size: 65535 + len_field: data_size + + - group: 70 + variation: 2 + fields: + - type: uint16 + name: username_offset + - type: uint16 + name: username_size + - type: uint16 + name: password_offset + - type: uint16 + name: password_size + - type: uint32 + name: authentication_key + - type: chararray + name: username + size: 65535 + len_field: username_size + - type: chararray + name: password + size: 65535 + len_field: password_size + + - group: 70 + variation: 3 + fields: + - type: uint16 + name: filename_offset + - type: uint16 + name: filename_size + - type: dnp3time + name: created + # XXX Break out to bit flags. + - type: uint16 + name: permissions + - type: uint32 + name: authentication_key + - type: uint32 + name: file_size + - type: uint16 + name: operational_mode + - type: uint16 + name: maximum_block_size + - type: uint16 + name: request_id + - type: chararray + name: filename + size: 65535 + len_field: filename_size + + # Checked. + - group: 70 + variation: 4 + constraints: + require_size_prefix: true + extra_fields: + - type: uint8 + name: optional_text_len + fields: + - type: uint32 + name: file_handle + - type: uint32 + name: file_size + - type: uint16 + name: maximum_block_size + - type: uint16 + name: request_id + - type: uint8 + name: status_code + - type: chararray + name: optional_text + size: 0xff + len_from_prefix: true + len_field: optional_text_len + + # Checked. + - group: 70 + variation: 5 + constraints: + require_size_prefix: true + extra_fields: + - type: uint8 + name: file_data_len + fields: + - type: uint32 + name: file_handle + - type: uint32 + name: block_number # Includes "last" flag. + - type: chararray + name: file_data + size: 0xff + len_from_prefix: true + len_field: file_data_len + + # Checked. + - group: 70 + variation: 6 + constraints: + require_size_prefix: true + extra_fields: + - type: uint8 + name: optional_text_len + fields: + - type: uint32 + name: file_handle + - type: uint32 + name: block_number # Includes "last" flag. + - type: uint8 + name: status_code + - type: chararray + name: optional_text + size: 0xff + len_from_prefix: true + len_field: optional_text_len + + # Checked. + - group: 70 + variation: 7 + fields: + - type: uint16 + name: filename_offset + - type: uint16 + name: filename_size + - type: uint16 + name: file_type + - type: uint32 + name: file_size + - type: dnp3time + name: created_timestamp + - type: uint16 + name: permissions + - type: uint16 + name: request_id + - type: chararray + name: filename + size: 0xffff + len_field: filename_size + + # Checked. + - group: 70 + variation: 8 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: file_specification_len + fields: + - type: chararray + name: file_specification + size: 0xffff + len_from_prefix: true + len_field: file_specification_len + + # Checked. + - group: 80 + variation: 1 + packed: true + fields: + - type: uint8 + name: state + width: 1 + + # Checked. + - group: 81 + variation: 1 + fields: + - type: bstr8 + fields: + - type: uint8 + width: 7 + name: fill_percentage + - type: uint8 + width: 1 + name: overflow_state + - type: uint8 + name: group + - type: uint8 + name: variation + + - group: 82 + variation: 1 + unimplemented: object header types not yet supported + + - group: 83 + variation: 1 + fields: + - type: vstr4 + name: vendor_code + - type: uint16 + name: object_id + - type: uint16 + name: length + - type: bytearray + name: data_objects + len_field: length + + - group: 83 + variation: 2 + unimplemented: set objects not yet supported + + - group: 85 + variation: 1 + unimplemented: set objects not yet supported + + - group: 86 + variation: 1 + unimplemented: set objects not yet supported + + # Checked. + - group: 86 + variation: 2 + fields: + - type: bstr8 + fields: + - name: rd + width: 1 + - name: wr + width: 1 + - name: st + width: 1 + - name: ev + width: 1 + - name: df + width: 1 + - name: padding0 + width: 1 + - name: padding1 + width: 1 + - name: padding2 + width: 1 + + - group: 86 + variation: 3 + unimplemented: set objects not yet supported + + - group: 87 + variation: 1 + unimplemented: set objects not yet supported + + - group: 88 + variation: 1 + unimplemented: set objects not yet supported + + - group: 90 + variation: 1 + unimplemented: set objects not yet supported + + - group: 91 + variation: 1 + unimplemented: set objects not yet supported + + - group: 100 + variation: "*" + unimplemented: obsolete object type + + - group: 101 + variation: 1 + unimplemented: bcd types not yet supported + + - group: 101 + variation: 2 + unimplemented: bcd types not yet supported + + - group: 101 + variation: 3 + unimplemented: bcd types not yet supported + + # Checked. + - group: 102 + variation: 1 + fields: + - type: uint8 + name: value + + - group: 110 + variation: "*" + unimplemented: variation all not yet supported + + - group: 111 + variation: "*" + unimplemented: variation all not yet supported + + - group: 112 + variation: "*" + unimplemented: variation all not yet supported + + - group: 113 + variation: "*" + unimplemented: variation all not yet supported + + # Checked. + - group: 120 + variation: 1 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: challenge_data_len + fields: + - type: uint32 + name: csq + - type: uint16 + name: usr + - type: uint8 + name: mal + - type: uint8 + name: reason + - type: bytearray + name: challenge_data + len_from_prefix: true + len_field: challenge_data_len + + - group: 120 + variation: 2 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: mac_value_len + fields: + - type: uint32 + name: csq + - type: uint16 + name: usr + - type: bytearray + name: mac_value + len_from_prefix: true + len_field: mac_value_len + + # Checked. + - group: 120 + variation: 3 + fields: + - type: uint32 + name: csq + - type: uint16 + name: user_number + + # Checked. + - group: 120 + variation: 4 + fields: + - type: uint16 + name: user_number + + # Checked. + - group: 120 + variation: 5 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: mac_value_len + fields: + - type: uint32 + name: ksq + - type: uint16 + name: user_number + - type: uint8 + name: key_wrap_alg + - type: uint8 + name: key_status + - type: uint8 + name: mal + - type: uint16 + name: challenge_data_len + - type: bytearray + name: challenge_data + len_field: challenge_data_len + - type: bytearray + name: mac_value + len_from_prefix: true + len_field: mac_value_len + + # Checked. + - group: 120 + variation: 6 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: wrapped_key_data_len + fields: + - type: uint24 + name: ksq + - type: uint16 + name: usr + - type: bytearray + name: wrapped_key_data + len_from_prefix: true + len_field: wrapped_key_data_len + + # Checked. + - group: 120 + variation: 7 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: error_text_len + fields: + - type: uint32 + name: sequence_number + - type: uint16 + name: usr + - type: uint16 + name: association_id + - type: uint8 + name: error_code + - type: dnp3time + name: time_of_error + - type: chararray + name: error_text + size: 65535 + len_from_prefix: true + len_field: error_text_len + + # Checked. + - group: 120 + variation: 8 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: certificate_len + fields: + - type: uint8 + name: key_change_method + - type: uint8 + name: certificate_type + - type: bytearray + name: certificate + len_from_prefix: true + len_field: certificate_len + + # Checked. + - group: 120 + variation: 9 + extra_fields: + - type: uint16 + name: mac_value_len + fields: + - type: bytearray + name: mac_value + len_from_prefix: true + len_field: mac_value_len + + # Checked. + - group: 120 + variation: 10 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint8 + name: key_change_method + - type: uint8 + name: operation + - type: uint32 + name: scs + - type: uint16 + name: user_role + - type: uint16 + name: user_role_expiry_interval + - type: uint16 + name: username_len + - type: uint16 + name: user_public_key_len + - type: uint16 + name: certification_data_len + - type: chararray + name: username + size: 65535 + len_field: username_len + - type: bytearray + name: user_public_key + len_field: user_public_key_len + - type: bytearray + name: certification_data + len_field: certification_data_len + + # Checked. + - group: 120 + variation: 11 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint8 + name: key_change_method + - type: uint16 + name: username_len + - type: uint16 + name: master_challenge_data_len + - type: chararray + size: 65535 + name: username + len_field: username_len + - type: bytearray + name: master_challenge_data + len_field: master_challenge_data_len + + # Checked. + - group: 120 + variation: 12 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint32 + name: ksq + - type: uint16 + name: user_number + - type: uint16 + name: challenge_data_len + - type: bytearray + name: challenge_data + len_field: challenge_data_len + + # Checked. + - group: 120 + variation: 13 + constraints: + require_prefix_code: 0x5 + fields: + - type: uint32 + name: ksq + - type: uint16 + name: user_number + - type: uint16 + name: encrypted_update_key_len + - type: bytearray + name: encrypted_update_key_data + len_field: encrypted_update_key_len + + # Checked. + - group: 120 + variation: 14 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint16 + name: digital_signature_len + fields: + - type: bytearray + name: digital_signature + len_from_prefix: true + len_field: digital_signature_len + + # Checked. + - group: 120 + variation: 15 + constraints: + require_prefix_code: 0x5 + extra_fields: + - type: uint32 + name: mac_len + fields: + - type: bytearray + name: mac + len_field: mac_len + len_from_prefix: true + + # Checked. + - group: 121 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: association_id + - type: uint32 + name: count_value + + # Checked. + - group: 122 + variation: 1 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: association_id + - type: uint32 + name: count_value + + # Checked. + - group: 122 + variation: 2 + fields: + - type: bstr8 + fields: + - name: online + width: 1 + - name: restart + width: 1 + - name: comm_lost + width: 1 + - name: remote_forced + width: 1 + - name: local_forced + width: 1 + - name: reserved0 + width: 1 + - name: discontinuity + width: 1 + - name: reserved1 + width: 1 + - type: uint16 + name: association_id + - type: uint32 + name: count_value + - type: dnp3time + name: timestamp diff --git a/scripts/setup-app-layer-detect.sh b/scripts/setup-app-layer-detect.sh new file mode 100755 index 000000000000..8127370962eb --- /dev/null +++ b/scripts/setup-app-layer-detect.sh @@ -0,0 +1,235 @@ +#! /usr/bin/env bash +# +# Script to provision a new application layer detector and parser. + +set -e + +function usage() { + cat < + +This script will provision content inspection for app-layer decoded +buffers. + +Examples: + + $0 DNP3 + $0 Gopher + +EOF +} + +fail_if_exists() { + path="$1" + if test -e "${path}"; then + echo "error: ${path} already exists." + exit 1 + fi +} + +function copy_template_file() { + src="$1" + dst="$2" + + echo "Creating ${dst}." + + sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \ + -e "s/TEMPLATE/${protoname_upper}/g" \ + -e "s/template/${protoname_lower}/g" \ + -e "s/Template/${protoname}/g" \ + > ${dst} < ${src} +} + +function copy_templates() { + detect_h_dst="src/detect-${protoname_lower}-buffer.h" + detect_c_dst="src/detect-${protoname_lower}-buffer.c" + detect_engine_h_dst="src/detect-engine-${protoname_lower}.h" + detect_engine_c_dst="src/detect-engine-${protoname_lower}.c" + + fail_if_exists ${detect_h_dst} + fail_if_exists ${detect_c_dst} + fail_if_exists ${detect_engine_h_dst} + fail_if_exists ${detect_engine_c_dst} + + copy_template_file "src/detect-template-buffer.h" ${detect_h_dst} + copy_template_file "src/detect-template-buffer.c" ${detect_c_dst} + copy_template_file "src/detect-engine-template.h" ${detect_engine_h_dst} + copy_template_file "src/detect-engine-template.c" ${detect_engine_c_dst} +} + +function patch_makefile_am() { + filename="src/Makefile.am" + echo "Patching ${filename}." + ed -s ${filename} > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < + +This script will provision a new JSON application layer transaction +logger for the protocol name specified on the command line. This is +done by copying and patching src/output-json-template.h and +src/output-json-template.c then link the new files into the build +system. + +It is required that the application layer parser has already been +provisioned by the setup-app-layer.sh script. + +Examples: + + $0 DNP3 + $0 Gopher + +EOF +} + +fail_if_exists() { + path="$1" + if test -e "${path}"; then + echo "error: ${path} already exists." + exit 1 + fi +} + +function copy_template_file() { + src="$1" + dst="$2" + + echo "Creating ${dst}." + + sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \ + -e "s/TEMPLATE/${protoname_upper}/g" \ + -e "s/template/${protoname_lower}/g" \ + -e "s/Template/${protoname}/g" \ + > ${dst} < ${src} +} + +function copy_templates() { + src_h="src/output-json-template.h" + dst_h="src/output-json-${protoname_lower}.h" + src_c="src/output-json-template.c" + dst_c="src/output-json-${protoname_lower}.c" + + fail_if_exists ${dst_h} + fail_if_exists ${dst_c} + + copy_template_file ${src_h} ${dst_h} + copy_template_file ${src_c} ${dst_c} +} + +function patch_makefile_am() { + filename="src/Makefile.am" + echo "Patching ${filename}." + ed -s ${filename} > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null 2>&1; then + echo "error: the program \"ed\" is required for this script" + exit 1 +fi + +function usage() { + cat < + +This script will provision a new app-layer parser for the protocol +name specified on the command line. This is done by copying and +patching src/app-layer-template.[ch] then linking the new files into +the build system. + +Examples: + + $0 DNP3 + $0 Gopher + +EOF +} + +fail_if_exists() { + path="$1" + if test -e "${path}"; then + echo "error: ${path} already exists." + exit 1 + fi +} + +function copy_template_file() { + src="$1" + dst="$2" + + echo "Creating ${dst}." + + sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \ + -e "s/TEMPLATE/${protoname_upper}/g" \ + -e "s/template/${protoname_lower}/g" \ + -e "s/Template/${protoname}/g" \ + > ${dst} < ${src} +} + +function copy_app_layer_templates { + src_h="src/app-layer-template.h" + dst_h="src/app-layer-${protoname_lower}.h" + src_c="src/app-layer-template.c" + dst_c="src/app-layer-${protoname_lower}.c" + + fail_if_exists ${dst_h} + fail_if_exists ${dst_c} + + copy_template_file ${src_h} ${dst_h} + copy_template_file ${src_c} ${dst_c} +} + +function patch_makefile_am { + filename="src/Makefile.am" + echo "Patching ${filename}." + ed -s ${filename} > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < +# + +set -e +#set -x + +function Usage { + echo + echo "$(basename $0) -- script to provision a decoder. The script" + echo "makes a copy of the decode-template, sets the name and updates" + echo " the build system." + echo + echo "Call from the 'src' directory, with one argument: the decoder name." + echo + echo "E.g. inside 'src': ../scripts/$(basename $0) ipv7" + echo +} + +function Done { + echo + echo "Decoder $NR has been set up in $FILE_C and $FILE_H and the" + echo "build system has been updated." + echo + echo "The decoder should now compile cleanly. Try running 'make'." + echo + echo "Next steps are to edit the files to implement the actual" + echo "decoding of $NR." + echo +} + +if [ $# -ne "1" ]; then + Usage + echo "ERROR: call with one argument" + exit 1 +fi + +INPUT=$1 +# lowercase +LC=${INPUT,,} +#echo $LC +# UPPERCASE +UC=${LC^^} +#echo $UC +# Normal +NR=${LC^} +#echo $NR + +FILE_C="decode-${LC}.c" +FILE_H="decode-${LC}.h" +#echo $FILE_C +#echo $FILE_H + +if [ ! -e ../configure.ac ] || [ ! -e Makefile.am ]; then + Usage + echo "ERROR: call from src/ directory" + exit 1 +fi +if [ ! -e decode-template.c ] || [ ! -e decode-template.h ]; then + Usage + echo "ERROR: input files decode-template.c and/or decode-template.h are missing" + exit 1 +fi +if [ -e $FILE_C ] || [ -e $FILE_H ]; then + Usage + echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" + exit 1 +fi + +cp decode-template.c $FILE_C +cp decode-template.h $FILE_H + +# search and replaces +sed -i "s/TEMPLATE/${UC}/g" $FILE_C +sed -i "s/TEMPLATE/${UC}/g" $FILE_H +sed -i "s/Template/${NR}/g" $FILE_C +sed -i "s/Template/${NR}/g" $FILE_H +sed -i "s/template/${LC}/g" $FILE_C +sed -i "s/template/${LC}/g" $FILE_H +sed -i "s/decode-template.c decode-template.h \\\/decode-template.c decode-template.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am + +Done +exit 0 diff --git a/scripts/setup_simple_detect.sh b/scripts/setup_simple_detect.sh new file mode 100644 index 000000000000..309b47cc2966 --- /dev/null +++ b/scripts/setup_simple_detect.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# +# Script to setup a new 'simple' detect module. +# Written by Victor Julien +# + +set -e +#set -x + +function Usage { + echo + echo "$(basename $0) -- script to provision a detect module. The script" + echo "makes a copy of detect-template, sets the name and updates" + echo "the build system." + echo + echo "Call from the 'src' directory, with one argument: the detect module" + echo "name." + echo + echo "E.g. inside 'src': ../scripts/$(basename $0) helloworld" + echo +} + +function Done { + echo + echo "Detect module $NR has been set up in $FILE_C and $FILE_H" + echo "and the build system has been updated." + echo + echo "The detect module should now compile cleanly. Try running 'make'." + echo + echo "Next steps are to edit the files to implement the actual" + echo "detection logic of $NR." + echo +} + +if [ $# -ne "1" ]; then + Usage + echo "ERROR: call with one argument" + exit 1 +fi + +INPUT=$1 +# lowercase +LC=${INPUT,,} +#echo $LC +# UPPERCASE +UC=${LC^^} +#echo $UC +# Normal +NR=${LC^} +#echo $NR + +FILE_C="detect-${LC}.c" +FILE_H="detect-${LC}.h" +#echo $FILE_C +#echo $FILE_H + +if [ ! -e ../configure.ac ] || [ ! -e Makefile.am ]; then + Usage + echo "ERROR: call from src/ directory" + exit 1 +fi +if [ ! -e detect-template.c ] || [ ! -e detect-template.h ]; then + Usage + echo "ERROR: input files detect-template.c and/or detect-template.h are missing" + exit 1 +fi +if [ -e $FILE_C ] || [ -e $FILE_H ]; then + Usage + echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" + exit 1 +fi + +cp detect-template.c $FILE_C +cp detect-template.h $FILE_H + +# search and replaces +sed -i "s/TEMPLATE/${UC}/g" $FILE_C +sed -i "s/TEMPLATE/${UC}/g" $FILE_H +sed -i "s/Template/${NR}/g" $FILE_C +sed -i "s/Template/${NR}/g" $FILE_H +sed -i "s/template/${LC}/g" $FILE_C +sed -i "s/template/${LC}/g" $FILE_H +# add to Makefile.am +sed -i "s/detect-template.c detect-template.h \\\/detect-template.c detect-template.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am +# update enum +sed -i "s/DETECT_TEMPLATE,/DETECT_TEMPLATE,\\n DETECT_${UC},/g" detect.h +# add include to detect.c +sed -i "s/#include \"detect-template.h\"/#include \"detect-template.h\"\\n#include \"${FILE_H}\"/g" detect.c +# add reg func to detect.c +sed -i "s/DetectTemplateRegister();/DetectTemplateRegister();\\n Detect${NR}Register();/g" detect.c + +Done +exit 0 diff --git a/scripts/suricatasc/src/suricatasc.py b/scripts/suricatasc/src/suricatasc.py index d3babe188ea7..ae62cf205ea3 100644 --- a/scripts/suricatasc/src/suricatasc.py +++ b/scripts/suricatasc/src/suricatasc.py @@ -14,11 +14,15 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import simplejson as json +try: + import simplejson as json +except: + import json import re import readline from socket import socket, AF_UNIX, error from time import sleep +import select import sys SURICATASC_VERSION = "0.9" @@ -69,14 +73,14 @@ def __call__(self, text, state): if state == 0: self.generator = self.complete(text) try: - return self.generator.next() + return next(self.generator) except StopIteration: return None return None class SuricataSC: def __init__(self, sck_path, verbose=False): - self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat'] + self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat','register-tenant','unregister-tenant','register-tenant-handler','unregister-tenant-handler', 'add-hostbit', 'remove-hostbit', 'list-hostbit'] self.sck_path = sck_path self.verbose = verbose @@ -86,11 +90,14 @@ def json_recv(self): data = "" while i < 5: i += 1 - data += self.socket.recv(SIZE) + if sys.version < '3': + data += self.socket.recv(SIZE) + else: + data += self.socket.recv(SIZE).decode('iso-8859-1') try: cmdret = json.loads(data) break - except json.decoder.JSONDecodeError: + except: sleep(0.3) return cmdret @@ -103,15 +110,23 @@ def send_command(self, command, arguments = None): if (arguments != None): cmdmsg['arguments'] = arguments if self.verbose: - print "SND: " + json.dumps(cmdmsg) - self.socket.send(json.dumps(cmdmsg)) - cmdret = self.json_recv() + print("SND: " + json.dumps(cmdmsg)) + if sys.version < '3': + self.socket.send(json.dumps(cmdmsg)) + else: + self.socket.send(bytes(json.dumps(cmdmsg), 'iso-8859-1')) + + ready = select.select([self.socket], [], [], 600) + if ready[0]: + cmdret = self.json_recv() + else: + cmdret = None if cmdret == None: raise SuricataReturnException("Unable to get message from server") if self.verbose: - print "RCV: "+ json.dumps(cmdret) + print("RCV: "+ json.dumps(cmdret)) return cmdret @@ -119,23 +134,29 @@ def connect(self): try: self.socket = socket(AF_UNIX) self.socket.connect(self.sck_path) - except error, err: + except error as err: raise SuricataNetException(err) self.socket.settimeout(10) #send version if self.verbose: - print "SND: " + json.dumps({"version": VERSION}) - self.socket.send(json.dumps({"version": VERSION})) + print("SND: " + json.dumps({"version": VERSION})) + if sys.version < '3': + self.socket.send(json.dumps({"version": VERSION})) + else: + self.socket.send(bytes(json.dumps({"version": VERSION}), 'iso-8859-1')) - # get return - cmdret = self.json_recv() + ready = select.select([self.socket], [], [], 600) + if ready[0]: + cmdret = self.json_recv() + else: + cmdret = None if cmdret == None: raise SuricataReturnException("Unable to get message from server") if self.verbose: - print "RCV: "+ json.dumps(cmdret) + print("RCV: "+ json.dumps(cmdret)) if cmdret["return"] == "NOK": raise SuricataReturnException("Error: %s" % (cmdret["message"])) @@ -156,15 +177,21 @@ def parse_command(self, command): if command.split(' ', 2)[0] in self.cmd_list: if "pcap-file " in command: try: - [cmd, filename, output] = command.split(' ', 2) + parts = command.split(' '); except: raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, filename, output = parts[0], parts[1], parts[2] + tenant = None + if len(parts) > 3: + tenant = parts[3] if cmd != "pcap-file": raise SuricataCommandException("Invalid command '%s'" % (command)) else: arguments = {} arguments["filename"] = filename arguments["output-dir"] = output + if tenant != None: + arguments["tenant"] = int(tenant) elif "iface-stat" in command: try: [cmd, iface] = command.split(' ', 1) @@ -185,6 +212,105 @@ def parse_command(self, command): else: arguments = {} arguments["variable"] = variable + elif "unregister-tenant-handler" in command: + try: + parts = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, tenantid, htype = parts[0], parts[1], parts[2] + hargs = None + if len(parts) > 3: + hargs = parts[3] + if cmd != "unregister-tenant-handler": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["htype"] = htype + if hargs != None: + arguments["hargs"] = int(hargs) + elif "register-tenant-handler" in command: + try: + parts = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + cmd, tenantid, htype = parts[0], parts[1], parts[2] + hargs = None + if len(parts) > 3: + hargs = parts[3] + if cmd != "register-tenant-handler": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["htype"] = htype + if hargs != None: + arguments["hargs"] = int(hargs) + elif "unregister-tenant" in command: + try: + [cmd, tenantid] = command.split(' ', 1) + except: + raise SuricataCommandException("Unable to split command '%s'" % (command)) + if cmd != "unregister-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + elif "register-tenant" in command: + try: + [cmd, tenantid, filename] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "register-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["filename"] = filename + elif "reload-tenant" in command: + try: + [cmd, tenantid, filename] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "reload-tenant": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["id"] = int(tenantid) + arguments["filename"] = filename + elif "add-hostbit" in command: + try: + [cmd, ipaddress, hostbit, expire] = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "add-hostbit": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["ipaddress"] = ipaddress + arguments["hostbit"] = hostbit + arguments["expire"] = int(expire) + elif "remove-hostbit" in command: + try: + [cmd, ipaddress, hostbit] = command.split(' ', 2) + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "remove-hostbit": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["ipaddress"] = ipaddress + arguments["hostbit"] = hostbit + elif "list-hostbit" in command: + try: + [cmd, ipaddress] = command.split(' ') + except: + raise SuricataCommandException("Arguments to command '%s' is missing" % (command)) + if cmd != "list-hostbit": + raise SuricataCommandException("Invalid command '%s'" % (command)) + else: + arguments = {} + arguments["ipaddress"] = ipaddress else: cmd = command else: @@ -192,27 +318,30 @@ def parse_command(self, command): return (cmd, arguments) def interactive(self): - print "Command list: " + ", ".join(self.cmd_list) + print("Command list: " + ", ".join(self.cmd_list)) try: readline.set_completer(SuricataCompleter(self.cmd_list)) readline.set_completer_delims(";") readline.parse_and_bind('tab: complete') while True: - command = raw_input(">>> ").strip() + if sys.version < '3': + command = raw_input(">>> ").strip() + else: + command = input(">>> ").strip() if command == "quit": break; try: (cmd, arguments) = self.parse_command(command) - except SuricataCommandException, err: - print err + except SuricataCommandException as err: + print(err) continue cmdret = self.send_command(cmd, arguments) #decode json message if cmdret["return"] == "NOK": - print "Error:" - print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) + print("Error:") + print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) else: - print "Success:" - print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) + print("Success:") + print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) except KeyboardInterrupt: - print "[!] Interrupted" + print("[!] Interrupted") diff --git a/scripts/suricatasc/suricatasc.in b/scripts/suricatasc/suricatasc.in index 30d482dcd280..63b4ebfaf5ab 100755 --- a/scripts/suricatasc/suricatasc.in +++ b/scripts/suricatasc/suricatasc.in @@ -15,6 +15,8 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +from __future__ import print_function +import sys import argparse from suricatasc import * @@ -25,35 +27,39 @@ parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to args = parser.parse_args() if args.socket != None: - SOCKET_PATH = "@e_localstatedir@/" + args.socket[0] + SOCKET_PATH = args.socket else: SOCKET_PATH = "@e_localstatedir@/suricata-command.socket" sc = SuricataSC(SOCKET_PATH, verbose=args.verbose) try: sc.connect() -except SuricataNetException, err: - print "Unable to connect to socket %s: %s" % (SOCKET_PATH, err) +except SuricataNetException as err: + print("Unable to connect to socket %s: %s" % (SOCKET_PATH, err), file=sys.stderr) sys.exit(1) -except SuricataReturnException, err: - print "Unable to negotiate version with server: %s" % (err) +except SuricataReturnException as err: + print("Unable to negotiate version with server: %s" % (err), file=sys.stderr) sys.exit(1) if args.command: (command, arguments) = sc.parse_command(args.command) - print sc.send_command(command, arguments) + res = sc.send_command(command, arguments) + print(json.dumps(res)) sc.close() - sys.exit(0) + if res['return'] == 'OK': + sys.exit(0) + else: + sys.exit(1) try: sc.interactive() -except SuricataNetException, err: - print "Communication error: %s" % (err) +except SuricataNetException as err: + print("Communication error: %s" % (err)) sys.exit(1) -except SuricataReturnException, err: - print "Invalid return from server: %s" % (err) +except SuricataReturnException as err: + print("Invalid return from server: %s" % (err)) sys.exit(1) -print "[+] Quit command client" +print("[+] Quit command client") sc.close() diff --git a/src/Makefile.am b/src/Makefile.am index 8213892f1805..9d4b46b51f60 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ bin_PROGRAMS = suricata suricata_SOURCES = \ alert-debuglog.c alert-debuglog.h \ alert-fastlog.c alert-fastlog.h \ +alert-hpfeeds.c alert-hpfeeds.h \ alert-prelude.c alert-prelude.h \ alert-syslog.c alert-syslog.h \ alert-unified2-alert.c alert-unified2-alert.h \ @@ -16,9 +17,13 @@ app-layer.c app-layer.h \ app-layer-dcerpc.c app-layer-dcerpc.h \ app-layer-dcerpc-udp.c app-layer-dcerpc-udp.h \ app-layer-detect-proto.c app-layer-detect-proto.h \ +app-layer-dnp3.c app-layer-dnp3.h \ +app-layer-dnp3-objects.c app-layer-dnp3-objects.h \ app-layer-dns-common.c app-layer-dns-common.h \ app-layer-dns-tcp.c app-layer-dns-tcp.h \ app-layer-dns-udp.c app-layer-dns-udp.h \ +app-layer-enip.c app-layer-enip.h \ +app-layer-enip-common.c app-layer-enip-common.h \ app-layer-events.c app-layer-events.h \ app-layer-ftp.c app-layer-ftp.h \ app-layer-htp-body.c app-layer-htp-body.h \ @@ -26,11 +31,14 @@ app-layer-htp.c app-layer-htp.h \ app-layer-htp-file.c app-layer-htp-file.h \ app-layer-htp-libhtp.c app-layer-htp-libhtp.h \ app-layer-htp-mem.c app-layer-htp-mem.h \ +app-layer-htp-xff.c app-layer-htp-xff.h \ +app-layer-modbus.c app-layer-modbus.h \ app-layer-parser.c app-layer-parser.h \ app-layer-protos.c app-layer-protos.h \ app-layer-smb2.c app-layer-smb2.h \ app-layer-smb.c app-layer-smb.h \ app-layer-smtp.c app-layer-smtp.h \ +app-layer-template.c app-layer-template.h \ app-layer-ssh.c app-layer-ssh.h \ app-layer-ssl.c app-layer-ssl.h \ app-layer-tls-handshake.c app-layer-tls-handshake.h \ @@ -39,6 +47,8 @@ conf-yaml-loader.c conf-yaml-loader.h \ counters.c counters.h \ data-queue.c data-queue.h \ decode.c decode.h \ +decode-afl.c \ +decode-erspan.c decode-erspan.h \ decode-ethernet.c decode-ethernet.h \ decode-events.c decode-events.h \ decode-gre.c decode-gre.h \ @@ -46,6 +56,7 @@ decode-icmpv4.c decode-icmpv4.h \ decode-icmpv6.c decode-icmpv6.h \ decode-ipv4.c decode-ipv4.h \ decode-ipv6.c decode-ipv6.h \ +decode-null.c decode-null.h \ decode-ppp.c decode-ppp.h \ decode-pppoe.c decode-pppoe.h \ decode-raw.c decode-raw.h \ @@ -56,6 +67,7 @@ decode-teredo.c decode-teredo.h \ decode-udp.c decode-udp.h \ decode-vlan.c decode-vlan.h \ decode-mpls.c decode-mpls.h \ +decode-template.c decode-template.h \ defrag-config.c defrag-config.h \ defrag.c defrag.h \ defrag-hash.c defrag-hash.h \ @@ -65,11 +77,13 @@ detect-ack.c detect-ack.h \ detect-app-layer-event.c detect-app-layer-event.h \ detect-app-layer-protocol.c detect-app-layer-protocol.h \ detect-asn1.c detect-asn1.h \ +detect-base64-data.c detect-base64-data.h \ +detect-base64-decode.c detect-base64-decode.h \ detect-byte-extract.c detect-byte-extract.h \ detect-bytejump.c detect-bytejump.h \ detect-bytetest.c detect-bytetest.h \ +detect-bypass.c detect-bypass.h \ detect.c detect.h \ -detect-simd.c \ detect-classtype.c detect-classtype.h \ detect-content.c detect-content.h \ detect-csum.c detect-csum.h \ @@ -79,23 +93,30 @@ detect-dce-stub-data.c detect-dce-stub-data.h \ detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h \ +detect-dnp3.c detect-dnp3.h \ detect-dns-query.c detect-dns-query.h \ +detect-tls-sni.c detect-tls-sni.h \ +detect-tls-cert-issuer.c detect-tls-cert-issuer.h \ +detect-tls-cert-subject.c detect-tls-cert-subject.h \ +detect-tls-cert-serial.c detect-tls-cert-serial.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ detect-engine-address-ipv6.c detect-engine-address-ipv6.h \ detect-engine-alert.c detect-engine-alert.h \ detect-engine-analyzer.c detect-engine-analyzer.h \ -detect-engine-apt-event.c detect-engine-apt-event.h \ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c detect-engine-content-inspection.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ detect-engine-dns.c detect-engine-dns.h \ +detect-engine-tls.c detect-engine-tls.h \ +detect-engine-modbus.c detect-engine-modbus.h \ +detect-engine-enip.c detect-engine-enip.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ +detect-engine-filedata-smtp.c detect-engine-filedata-smtp.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ detect-engine-hcd.c detect-engine-hcd.h \ -detect-engine-hhd.c detect-engine-hhd.h \ detect-engine-hhhd.c detect-engine-hhhd.h \ detect-engine-hmd.c detect-engine-hmd.h \ detect-engine-hrhd.c detect-engine-hrhd.h \ @@ -106,21 +127,29 @@ detect-engine-hscd.c detect-engine-hscd.h \ detect-engine-hsmd.c detect-engine-hsmd.h \ detect-engine-hua.c detect-engine-hua.h \ detect-engine-iponly.c detect-engine-iponly.h \ +detect-engine-loader.c detect-engine-loader.h \ detect-engine-mpm.c detect-engine-mpm.h \ detect-engine-payload.c detect-engine-payload.h \ detect-engine-port.c detect-engine-port.h \ +detect-engine-prefilter.c detect-engine-prefilter.h \ +detect-engine-prefilter-common.c detect-engine-prefilter-common.h \ detect-engine-proto.c detect-engine-proto.h \ +detect-engine-profile.c detect-engine-profile.h \ detect-engine-siggroup.c detect-engine-siggroup.h \ detect-engine-sigorder.c detect-engine-sigorder.h \ detect-engine-state.c detect-engine-state.h \ detect-engine-tag.c detect-engine-tag.h \ +detect-engine-template.c detect-engine-template.h \ detect-engine-threshold.c detect-engine-threshold.h \ detect-engine-uri.c detect-engine-uri.h \ detect-fast-pattern.c detect-fast-pattern.h \ detect-file-data.c detect-file-data.h \ +detect-file-hash-common.c detect-file-hash-common.h \ detect-fileext.c detect-fileext.h \ detect-filemagic.c detect-filemagic.h \ detect-filemd5.c detect-filemd5.h \ +detect-filesha1.c detect-filesha1.h \ +detect-filesha256.c detect-filesha256.h \ detect-filename.c detect-filename.h \ detect-filesize.c detect-filesize.h \ detect-filestore.c detect-filestore.h \ @@ -134,15 +163,22 @@ detect-fragoffset.c detect-fragoffset.h \ detect-ftpbounce.c detect-ftpbounce.h \ detect-geoip.c detect-geoip.h \ detect-gid.c detect-gid.h \ +detect-hostbits.c detect-hostbits.h \ detect-http-client-body.c detect-http-client-body.h \ detect-http-cookie.c detect-http-cookie.h \ detect-http-header.c detect-http-header.h \ +detect-http-header-common.c detect-http-header-common.h \ +detect-http-header-names.c detect-http-header-names.h \ detect-http-hh.c detect-http-hh.h \ detect-http-hrh.c detect-http-hrh.h \ detect-http-method.c detect-http-method.h \ +detect-http-protocol.c detect-http-protocol.h \ detect-http-raw-header.c detect-http-raw-header.h \ detect-http-raw-uri.c detect-http-raw-uri.h \ +detect-http-request-line.c detect-http-request-line.h \ +detect-http-response-line.c detect-http-response-line.h \ detect-http-server-body.c detect-http-server-body.h \ +detect-http-start.c detect-http-start.h \ detect-http-stat-code.c detect-http-stat-code.h \ detect-http-stat-msg.c detect-http-stat-msg.h \ detect-http-ua.c detect-http-ua.h \ @@ -169,6 +205,7 @@ detect-parse.c detect-parse.h \ detect-pcre.c detect-pcre.h \ detect-pkt-data.c detect-pkt-data.h \ detect-pktvar.c detect-pktvar.h \ +detect-prefilter.c detect-prefilter.h \ detect-priority.c detect-priority.h \ detect-rawbytes.c detect-rawbytes.h \ detect-reference.c detect-reference.h \ @@ -178,14 +215,19 @@ detect-rpc.c detect-rpc.h \ detect-sameip.c detect-sameip.h \ detect-seq.c detect-seq.h \ detect-sid.c detect-sid.h \ +detect-ssh-proto.c detect-ssh-proto.h \ detect-ssh-proto-version.c detect-ssh-proto-version.h \ +detect-ssh-software.c detect-ssh-software.h \ detect-ssh-software-version.c detect-ssh-software-version.h \ detect-ssl-state.c detect-ssl-state.h \ detect-ssl-version.c detect-ssl-version.h \ detect-stream_size.c detect-stream_size.h \ detect-tag.c detect-tag.h \ +detect-template.c detect-template.h \ +detect-template-buffer.c detect-template-buffer.h \ detect-threshold.c detect-threshold.h \ detect-tls.c detect-tls.h \ +detect-tls-cert-validity.c detect-tls-cert-validity.h \ detect-tls-version.c detect-tls-version.h \ detect-tos.c detect-tos.h \ detect-ttl.c detect-ttl.h \ @@ -193,6 +235,9 @@ detect-uricontent.c detect-uricontent.h \ detect-urilen.c detect-urilen.h \ detect-window.c detect-window.h \ detect-within.c detect-within.h \ +detect-modbus.c detect-modbus.h \ +detect-xbits.c detect-xbits.h \ +detect-cipservice.c detect-cipservice.h \ flow-bit.c flow-bit.h \ flow.c flow.h \ flow-hash.c flow-hash.h \ @@ -202,33 +247,51 @@ flow-storage.c flow-storage.h \ flow-timeout.c flow-timeout.h \ flow-util.c flow-util.h \ flow-var.c flow-var.h \ +flow-worker.c flow-worker.h \ host.c host.h \ +host-bit.c host-bit.h \ host-queue.c host-queue.h \ host-storage.c host-storage.h \ host-timeout.c host-timeout.h \ +ippair.c ippair.h \ +ippair-bit.c ippair-bit.h \ +ippair-queue.c ippair-queue.h \ +ippair-storage.c ippair-storage.h \ +ippair-timeout.c ippair-timeout.h \ log-dnslog.c log-dnslog.h \ log-droplog.c log-droplog.h \ log-file.c log-file.h \ log-filestore.c log-filestore.h \ +log-cf-common.c log-cf-common.h \ log-httplog.c log-httplog.h \ log-pcap.c log-pcap.h \ +log-stats.c log-stats.h \ log-tcp-data.c log-tcp-data.h \ log-tlslog.c log-tlslog.h \ +log-tlsstore.c log-tlsstore.h \ output.c output.h \ output-file.c output-file.h \ output-filedata.c output-filedata.h \ output-flow.c output-flow.h \ output-json-alert.c output-json-alert.h \ output-json-dns.c output-json-dns.h \ +output-json-dnp3.c output-json-dnp3.h \ +output-json-dnp3-objects.c output-json-dnp3-objects.h \ output-json-drop.c output-json-drop.h \ +output-json-email-common.c output-json-email-common.h \ output-json-file.c output-json-file.h \ output-json-flow.c output-json-flow.h \ output-json-netflow.c output-json-netflow.h \ output-json-http.c output-json-http.h \ +output-json-smtp.c output-json-smtp.h \ output-json-ssh.c output-json-ssh.h \ +output-json-stats.c output-json-stats.h \ output-json-tls.c output-json-tls.h \ +output-json-template.c output-json-template.h \ +output-json-vars.c output-json-vars.h \ output-lua.c output-lua.h \ output-packet.c output-packet.h \ +output-stats.c output-stats.h \ output-streaming.c output-streaming.h \ output-tx.c output-tx.h \ output-json.c output-json.h \ @@ -242,6 +305,7 @@ runmode-erf-dag.c runmode-erf-dag.h \ runmode-erf-file.c runmode-erf-file.h \ runmode-ipfw.c runmode-ipfw.h \ runmode-napatech.c runmode-napatech.h \ +runmode-netmap.c runmode-netmap.h \ runmode-nfq.c runmode-nfq.h \ runmode-nflog.c runmode-nflog.h \ runmode-pcap.c runmode-pcap.h \ @@ -257,6 +321,7 @@ source-erf-file.c source-erf-file.h \ source-ipfw.c source-ipfw.h \ source-mpipe.c source-mpipe.h \ source-napatech.c source-napatech.h \ +source-netmap.c source-netmap.h \ source-nfq.c source-nfq.h \ source-nflog.c source-nflog.h \ source-pcap.c source-pcap.h \ @@ -283,6 +348,7 @@ tm-threads.c tm-threads.h tm-threads-common.h \ unix-manager.c unix-manager.h \ util-action.c util-action.h \ util-atomic.c util-atomic.h \ +util-base64.c util-base64.h \ util-bloomfilter-counting.c util-bloomfilter-counting.h \ util-bloomfilter.c util-bloomfilter.h \ util-buffer.c util-buffer.h \ @@ -304,6 +370,7 @@ util-debug-filters.c util-debug-filters.h \ util-decode-asn1.c util-decode-asn1.h \ util-decode-der.c util-decode-der.h \ util-decode-der-get.c util-decode-der-get.h \ +util-decode-mime.c util-decode-mime.h \ util-device.c util-device.h \ util-enum.c util-enum.h \ util-error.c util-error.h \ @@ -315,13 +382,21 @@ util-hashlist.c util-hashlist.h \ util-hash-lookup3.c util-hash-lookup3.h \ util-host-os-info.c util-host-os-info.h \ util-host-info.c util-host-info.h \ +util-hyperscan.c util-hyperscan.h \ util-ioctl.h util-ioctl.c \ util-ip.h util-ip.c \ util-logopenfile.h util-logopenfile.c \ util-logopenfile-tile.h util-logopenfile-tile.c \ util-lua.c util-lua.h \ +util-luajit.c util-luajit.h \ util-lua-common.c util-lua-common.h \ +util-lua-dnp3.c util-lua-dnp3.h \ +util-lua-dnp3-objects.c util-lua-dnp3-objects.h \ +util-lua-dns.c util-lua-dns.h \ util-lua-http.c util-lua-http.h \ +util-lua-tls.c util-lua-tls.h \ +util-lua-ssh.c util-lua-ssh.h \ +util-lua-smtp.c util-lua-smtp.h \ util-magic.c util-magic.h \ util-memcmp.c util-memcmp.h \ util-memcpy.h \ @@ -330,26 +405,24 @@ util-memrchr.c util-memrchr.h \ util-misc.c util-misc.h \ util-mpm-ac-bs.c util-mpm-ac-bs.h \ util-mpm-ac.c util-mpm-ac.h \ -util-mpm-ac-gfbs.c util-mpm-ac-gfbs.h \ util-mpm-ac-tile.c util-mpm-ac-tile.h \ util-mpm-ac-tile-small.c \ -util-mpm-b2gc.c util-mpm-b2gc.h \ -util-mpm-b2g.c util-mpm-b2g.h \ -util-mpm-b2gm.c util-mpm-b2gm.h \ -util-mpm-b3g.c util-mpm-b3g.h \ +util-mpm-hs.c util-mpm-hs.h \ util-mpm.c util-mpm.h \ -util-mpm-wumanber.c util-mpm-wumanber.h \ util-optimize.h \ +util-pages.c util-pages.h \ util-path.c util-path.h \ util-pidfile.c util-pidfile.h \ util-pool.c util-pool.h \ util-pool-thread.c util-pool-thread.h \ +util-prefilter.c util-prefilter.h \ util-print.c util-print.h \ util-privs.c util-privs.h \ util-profiling.c util-profiling.h \ util-profiling-locks.c util-profiling-locks.h \ util-profiling-rules.c \ util-profiling-keywords.c \ +util-profiling-rulegroups.c \ util-proto-name.c util-proto-name.h \ util-radix-tree.c util-radix-tree.h \ util-random.c util-random.h \ @@ -363,8 +436,10 @@ util-signal.c util-signal.h \ util-spm-bm.c util-spm-bm.h \ util-spm-bs2bm.c util-spm-bs2bm.h \ util-spm-bs.c util-spm-bs.h \ +util-spm-hs.c util-spm-hs.h \ util-spm.c util-spm.h util-clock.h \ util-storage.c util-storage.h \ +util-streaming-buffer.c util-streaming-buffer.h \ util-strlcatu.c \ util-strlcpyu.c \ util-syslog.c util-syslog.h \ @@ -386,7 +461,7 @@ EXTRA_DIST = util-mpm-ac-cuda-kernel.cu ptxdump.py AM_CPPFLAGS = $(all_includes) # the library search path. -suricata_LDFLAGS = $(all_libraries) +suricata_LDFLAGS = $(all_libraries) ${SECLDFLAGS} suricata_LDADD = $(HTP_LDADD) # Rules to build CUDA ptx modules @@ -398,36 +473,15 @@ util-mpm-ac-cuda-kernel.cu NVCCFLAGS=-O2 -SUFFIXES = \ -.ptx_sm_10 \ -.ptx_sm_11 \ -.ptx_sm_12 \ -.ptx_sm_13 \ -.ptx_sm_20 \ -.ptx_sm_21 \ -.ptx_sm_30 \ -.ptx_sm_35 - -PTXS = $(suricata_CUDA_KERNELS:.cu=.ptx_sm_10) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_11) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_12) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_13) -PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_20) +PTXS = $(suricata_CUDA_KERNELS:.cu=.ptx_sm_20) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_21) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_30) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_32) PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_35) - -.cu.ptx_sm_10: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_10 -ptx $< - -.cu.ptx_sm_11: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_11 -ptx $< - -.cu.ptx_sm_12: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_12 -ptx $< - -.cu.ptx_sm_13: - $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_13 -ptx $< +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_37) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_50) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_52) +PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_53) .cu.ptx_sm_20: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_20 -ptx $< @@ -438,18 +492,38 @@ PTXS += $(suricata_CUDA_KERNELS:.cu=.ptx_sm_35) .cu.ptx_sm_30: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_30 -ptx $< +.cu.ptx_sm_32: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_32 -ptx $< + .cu.ptx_sm_35: $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_35 -ptx $< +.cu.ptx_sm_37: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_37 -ptx $< + +.cu.ptx_sm_50: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_50 -ptx $< + +.cu.ptx_sm_52: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_52 -ptx $< + +.cu.ptx_sm_53: + $(NVCC) $(NVCCFLAGS) -o $@ -arch=sm_53 -ptx $< + cuda-ptxdump.h: $(PTXS) $(PYTHON) ptxdump.py cuda-ptxdump $(PTXS) CLEANFILES = $(PTXS) cuda-ptxdump.h endif +# default CFLAGS +AM_CFLAGS = ${OPTIMIZATION_CFLAGS} ${GCC_CFLAGS} ${CLANG_CFLAGS} ${SECCFLAGS} ${PCAP_CFLAGS} -Wall -Wno-unused-parameter -std=gnu99 -DLOCAL_STATE_DIR=\"$(localstatedir)\" +# different flags for different cases +if DEBUG +AM_CFLAGS += -ggdb -O0 +endif -#suricata_CFLAGS = -Wall -fno-strict-aliasing -AM_CFLAGS = -DLOCAL_STATE_DIR=\"$(localstatedir)\" +AM_LDFLAGS = ${SECLDFLAGS} if BUILD_UNITTESTS check-am: diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index 0a7402047256..4ab39c97d0c1 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -54,6 +54,8 @@ #include "util-logopenfile.h" #include "util-time.h" +#include "stream-tcp-reassemble.h" + #define DEFAULT_LOG_FILENAME "alert-debug.log" #define MODULE_NAME "AlertDebugLog" @@ -76,12 +78,21 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) const GenericVar *gv = p->flow->flowvar; uint16_t i; while (gv != NULL) { - if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { + if (gv->type == DETECT_FLOWBITS) { + FlowBit *fb = (FlowBit *)gv; + const char *fbname = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); + if (fbname) { + MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", + fbname); + } + } else if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { FlowVar *fv = (FlowVar *) gv; if (fv->datatype == FLOWVAR_TYPE_STR) { - MemBufferWriteString(aft->buffer, "FLOWVAR idx(%"PRIu32"): ", - fv->idx); + const char *fvname = VarNameStoreLookupById(fv->idx, + VAR_TYPE_FLOW_VAR); + MemBufferWriteString(aft->buffer, "FLOWVAR: \"%s\" => \"", + fvname); for (i = 0; i < fv->data.fv_str.value_len; i++) { if (isprint(fv->data.fv_str.value[i])) { MemBufferWriteString(aft->buffer, "%c", @@ -91,41 +102,18 @@ static void AlertDebugLogFlowVars(AlertDebugLogThread *aft, const Packet *p) fv->data.fv_str.value[i]); } } + MemBufferWriteString(aft->buffer, "\"\n"); } else if (fv->datatype == FLOWVAR_TYPE_INT) { - MemBufferWriteString(aft->buffer, "FLOWVAR idx(%"PRIu32"): " - " %" PRIu32 "\"", fv->idx, fv->data.fv_int.value); + const char *fvname = VarNameStoreLookupById(fv->idx, + VAR_TYPE_FLOW_INT); + MemBufferWriteString(aft->buffer, "FLOWINT: \"%s\" =>" + " %"PRIu32"\n", fvname, fv->data.fv_int.value); } } gv = gv->next; } } -/** - * \brief Function to log the FlowBits in to alert-debug.log - * - * \param aft Pointer to AltertDebugLog Thread - * \param p Pointer to the packet - * - * \todo const Packet ptr, requires us to change the - * debuglog_flowbits_names logic. - */ -static void AlertDebugLogFlowBits(AlertDebugLogThread *aft, Packet *p) -{ - int i; - for (i = 0; i < p->debuglog_flowbits_names_len; i++) { - if (p->debuglog_flowbits_names[i] != NULL) { - MemBufferWriteString(aft->buffer, "FLOWBIT: %s\n", - p->debuglog_flowbits_names[i]); - } - } - - SCFree(p->debuglog_flowbits_names); - p->debuglog_flowbits_names = NULL; - p->debuglog_flowbits_names_len = 0; - - return; -} - /** * \brief Function to log the PktVars in to alert-debug.log * @@ -137,8 +125,9 @@ static void AlertDebugLogPktVars(AlertDebugLogThread *aft, const Packet *p) { const PktVar *pv = p->pktvar; - while(pv != NULL) { - MemBufferWriteString(aft->buffer, "PKTVAR: %s\n", pv->name); + while (pv != NULL) { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + MemBufferWriteString(aft->buffer, "PKTVAR: %s\n", varname); PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, pv->value, pv->value_len); pv = pv->next; @@ -147,7 +136,7 @@ static void AlertDebugLogPktVars(AlertDebugLogThread *aft, const Packet *p) /** \todo doc * assume we have aft lock */ -static int AlertDebugPrintStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int AlertDebugPrintStreamSegmentCallback(const Packet *p, void *data, const uint8_t *buf, uint32_t buflen) { AlertDebugLogThread *aft = (AlertDebugLogThread *)data; @@ -213,7 +202,8 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da p->flowflags & FLOW_PKT_TOCLIENT ? "TRUE" : "FALSE"); if (p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); + int applayer = 0; + applayer = StreamTcpAppLayerIsDisabled(p->flow); CreateTimeString(&p->flow->startts, timebuf, sizeof(timebuf)); MemBufferWriteString(aft->buffer, "FLOW Start TS: %s\n", timebuf); MemBufferWriteString(aft->buffer, "FLOW PKTS TODST: %"PRIu32"\n" @@ -231,11 +221,9 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da p->flow->flags & FLOW_ACTION_DROP ? "TRUE" : "FALSE", p->flow->flags & FLOW_NOPACKET_INSPECTION ? "TRUE" : "FALSE", p->flow->flags & FLOW_NOPAYLOAD_INSPECTION ? "TRUE" : "FALSE", - p->flow->flags & FLOW_NO_APPLAYER_INSPECTION ? "TRUE" : "FALSE", + applayer ? "TRUE" : "FALSE", (p->flow->alproto != ALPROTO_UNKNOWN) ? "TRUE" : "FALSE", p->flow->alproto); AlertDebugLogFlowVars(aft, p); - AlertDebugLogFlowBits(aft, (Packet *)p); /* < no const */ - FLOWLOCK_UNLOCK(p->flow); } AlertDebugLogPktVars(aft, p); @@ -316,11 +304,8 @@ static TmEcode AlertDebugLogger(ThreadVars *tv, const Packet *p, void *thread_da } } - SCMutexLock(&aft->file_ctx->fp_mutex); - (void)MemBufferPrintToFPAsString(aft->buffer, aft->file_ctx->fp); - fflush(aft->file_ctx->fp); - aft->file_ctx->alerts += p->alerts.cnt; - SCMutexUnlock(&aft->file_ctx->fp_mutex); + aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), + MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); return TM_ECODE_OK; } @@ -379,11 +364,8 @@ static TmEcode AlertDebugLogDecoderEvent(ThreadVars *tv, const Packet *p, void * PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, GET_PKT_DATA(p), GET_PKT_LEN(p)); - SCMutexLock(&aft->file_ctx->fp_mutex); aft->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), aft->file_ctx); - aft->file_ctx->alerts += p->alerts.cnt; - SCMutexUnlock(&aft->file_ctx->fp_mutex); return TM_ECODE_OK; } @@ -397,7 +379,7 @@ static TmEcode AlertDebugLogThreadInit(ThreadVars *t, void *initdata, void **dat if(initdata == NULL) { - SCLogDebug("Error getting context for DebugLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for AlertDebugLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -430,21 +412,10 @@ static TmEcode AlertDebugLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -static void AlertDebugLogExitPrintStats(ThreadVars *tv, void *data) -{ - AlertDebugLogThread *aft = (AlertDebugLogThread *)data; - if (aft == NULL) { - return; - } - - SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, aft->file_ctx->alerts); -} - static void AlertDebugLogDeInitCtx(OutputCtx *output_ctx) { if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } @@ -469,10 +440,9 @@ static OutputCtx *AlertDebugLogInitCtx(ConfNode *conf) goto error; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { goto error; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); OutputCtx *output_ctx = SCMalloc(sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) @@ -508,17 +478,9 @@ static int AlertDebugLogLogger(ThreadVars *tv, void *thread_data, const Packet * return TM_ECODE_OK; } -void TmModuleAlertDebugLogRegister (void) +void AlertDebugLogRegister(void) { - tmm_modules[TMM_ALERTDEBUGLOG].name = MODULE_NAME; - tmm_modules[TMM_ALERTDEBUGLOG].ThreadInit = AlertDebugLogThreadInit; - tmm_modules[TMM_ALERTDEBUGLOG].Func = NULL; - tmm_modules[TMM_ALERTDEBUGLOG].ThreadExitPrintStats = AlertDebugLogExitPrintStats; - tmm_modules[TMM_ALERTDEBUGLOG].ThreadDeinit = AlertDebugLogThreadDeinit; - tmm_modules[TMM_ALERTDEBUGLOG].RegisterTests = NULL; - tmm_modules[TMM_ALERTDEBUGLOG].cap_flags = 0; - tmm_modules[TMM_ALERTDEBUGLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "alert-debug", - AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition); + OutputRegisterPacketModule(LOGGER_ALERT_DEBUG, MODULE_NAME, "alert-debug", + AlertDebugLogInitCtx, AlertDebugLogLogger, AlertDebugLogCondition, + AlertDebugLogThreadInit, AlertDebugLogThreadDeinit, NULL); } diff --git a/src/alert-debuglog.h b/src/alert-debuglog.h index 8eb38d977c2a..f7c411c3ab3e 100644 --- a/src/alert-debuglog.h +++ b/src/alert-debuglog.h @@ -24,7 +24,7 @@ #ifndef __ALERT_DEBUGLOG_H__ #define __ALERT_DEBUGLOG_H__ -void TmModuleAlertDebugLogRegister (void); +void AlertDebugLogRegister(void); #endif /* __ALERT_DEBUGLOG_H__ */ diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 27fdbe44592c..d475a6a38c3a 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -41,7 +41,6 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -#include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -70,25 +69,18 @@ TmEcode AlertFastLogThreadInit(ThreadVars *, void *, void **); TmEcode AlertFastLogThreadDeinit(ThreadVars *, void *); -void AlertFastLogExitPrintStats(ThreadVars *, void *); void AlertFastLogRegisterTests(void); static void AlertFastLogDeInitCtx(OutputCtx *); int AlertFastLogCondition(ThreadVars *tv, const Packet *p); int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p); -void TmModuleAlertFastLogRegister (void) +void AlertFastLogRegister(void) { - tmm_modules[TMM_ALERTFASTLOG].name = MODULE_NAME; - tmm_modules[TMM_ALERTFASTLOG].ThreadInit = AlertFastLogThreadInit; - tmm_modules[TMM_ALERTFASTLOG].ThreadExitPrintStats = AlertFastLogExitPrintStats; - tmm_modules[TMM_ALERTFASTLOG].ThreadDeinit = AlertFastLogThreadDeinit; - tmm_modules[TMM_ALERTFASTLOG].RegisterTests = AlertFastLogRegisterTests; - tmm_modules[TMM_ALERTFASTLOG].cap_flags = 0; - tmm_modules[TMM_ALERTFASTLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "fast", - AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition); + OutputRegisterPacketModule(LOGGER_ALERT_FAST, MODULE_NAME, "fast", + AlertFastLogInitCtx, AlertFastLogger, AlertFastLogCondition, + AlertFastLogThreadInit, AlertFastLogThreadDeinit, NULL); + AlertFastLogRegisterTests(); } typedef struct AlertFastLogThread_ { @@ -104,12 +96,8 @@ int AlertFastLogCondition(ThreadVars *tv, const Packet *p) static inline void AlertFastLogOutputAlert(AlertFastLogThread *aft, char *buffer, int alert_size) { - SCMutex *file_lock = &aft->file_ctx->fp_mutex; /* Output the alert string and count alerts. Only need to lock here. */ - SCMutexLock(file_lock); - aft->file_ctx->alerts++; aft->file_ctx->Write(buffer, alert_size, aft->file_ctx); - SCMutexUnlock(file_lock); } int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p) @@ -227,16 +215,6 @@ TmEcode AlertFastLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void AlertFastLogExitPrintStats(ThreadVars *tv, void *data) -{ - AlertFastLogThread *aft = (AlertFastLogThread *)data; - if (aft == NULL) { - return; - } - - SCLogInfo("Fast log output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); -} - /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. @@ -250,11 +228,10 @@ OutputCtx *AlertFastLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } - OutputRegisterFileRotationFlag(&logfile_ctx->rotation_flag); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) @@ -268,7 +245,6 @@ OutputCtx *AlertFastLogInitCtx(ConfNode *conf) static void AlertFastLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); SCFree(output_ctx); } @@ -298,23 +274,20 @@ static int AlertFastLogTest01() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " "Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt == 1) + if (p->alerts.cnt == 1) { result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); - else - result = 0; + } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -346,32 +319,22 @@ static int AlertFastLogTest02() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"FastLog test\"; content:\"GET\"; " "Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); - if (result == 0) - printf("sig parse failed: "); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1) { - result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown Traffic") != 0); - if (result == 0) - printf("p->alerts.alerts[0].class_msg %s: ", p->alerts.alerts[0].s->class_msg); - result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); if (result == 0) printf("p->alerts.alerts[0].class_msg %s: ", p->alerts.alerts[0].s->class_msg); - } else { - result = 0; } SigGroupCleanup(de_ctx); @@ -393,8 +356,8 @@ void AlertFastLogRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01, 1); - UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02, 1); + UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01); + UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02); #endif /* UNITTESTS */ diff --git a/src/alert-fastlog.h b/src/alert-fastlog.h index ac3c45a7cf9d..96bd0118abc9 100644 --- a/src/alert-fastlog.h +++ b/src/alert-fastlog.h @@ -24,7 +24,7 @@ #ifndef __ALERT_FASTLOG_H__ #define __ALERT_FASTLOG_H__ -void TmModuleAlertFastLogRegister(void); +void AlertFastLogRegister(void); void TmModuleAlertFastLogIPv4Register(void); void TmModuleAlertFastLogIPv6Register(void); OutputCtx *AlertFastLogInitCtx(ConfNode *); diff --git a/src/alert-hpfeeds.c b/src/alert-hpfeeds.c new file mode 100644 index 000000000000..96b1a69511c9 --- /dev/null +++ b/src/alert-hpfeeds.c @@ -0,0 +1,756 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +#include "suricata-common.h" +#include "debug.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "tm-threads.h" +#include "threadvars.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-reference.h" + +#include "output.h" +#include "alert-hpfeeds.h" + +#include "util-classification-config.h" +#include "util-debug.h" +#include "util-print.h" +#include "util-proto-name.h" +#include "util-optimize.h" + +#ifndef OS_WIN32 + +#define MODULE_NAME "AlertHPFeeds" +#define HPFEEDS_DEFAULT_PORT 10000 +#define READ_BLOCK_SIZE 32767 +#define BUF_LEN 32 + +#define HPFEEDS_NOK 0 +#define HPFEEDS_AUTH_DONE 1 +#define HPFEEDS_READY 2 + +typedef enum { + S_INIT, + S_AUTH, + S_AUTH_DONE, + S_ERROR, + S_TERMINATE +} hpfeeds_session_state_t; + +/* HPFeeds data used in every thread */ +typedef struct AlertHPFeedsCtx_ { + /* hpfeeds connection parameter */ + char *hpfeeds_host; + char *hpfeeds_ident; + char *hpfeeds_secret; + char *hpfeeds_channel; + intmax_t hpfeeds_port; + + /* Reconnect ?! */ + int reconnect; + + /* socket */ + int sock; + struct pollfd pfd; + + /* Connection status */ + int status; + + /* Mutex used for synchronization */ + SCMutex mutex; +} AlertHPFeedsCtx; + +/* Thread structure */ +typedef struct AlertHPFeedsThread_ { + AlertHPFeedsCtx *ctx; +} AlertHPFeedsThread; + +void HPFeedsPublish(json_t *json, AlertHPFeedsCtx *config); +void HPFeedsConnect(AlertHPFeedsCtx *config, int reconnect); +void HPFeedsCloseConnection(int * sock); + +/** + * \brief Function to clear the memory of the output context + * + * \param output_ctx pointer to the output context to be cleared + */ + +static void AlertHPFeedsDeInitCtx(OutputCtx *output_ctx) +{ + AlertHPFeedsCtx *ctx = (AlertHPFeedsCtx *)output_ctx->data; + + if (ctx->hpfeeds_host) SCFree(ctx->hpfeeds_host); + if (ctx->hpfeeds_ident) SCFree(ctx->hpfeeds_ident); + if (ctx->hpfeeds_secret) SCFree(ctx->hpfeeds_secret); + if (ctx->hpfeeds_channel) SCFree(ctx->hpfeeds_channel); + + HPFeedsCloseConnection(&ctx->sock); + + SCFree(ctx); +} + +/** + * \brief Create a new AlertHPFeedsCtx. + * + * \param conf The configuration node for this output. + * \return A OutputCtx pointer on success, NULL on failure. + */ + +OutputCtx *AlertHPFeedsInitCtx(ConfNode *conf) +{ + OutputCtx *output_ctx; + AlertHPFeedsCtx *ctx; + + ctx = SCMalloc(sizeof(AlertHPFeedsCtx)); + + if (unlikely(ctx == NULL)) + SCReturnPtr(NULL, "AlertHPFeedsCtx"); + + ctx->status = HPFEEDS_NOK; + ctx->hpfeeds_port = HPFEEDS_DEFAULT_PORT; + ctx->sock = -1; + + ConfGetChildValue(conf, "host", &ctx->hpfeeds_host); + ConfGetChildValue(conf, "ident", &ctx->hpfeeds_ident); + ConfGetChildValue(conf, "secret", &ctx->hpfeeds_secret); + ConfGetChildValue(conf, "channel", &ctx->hpfeeds_channel); + ConfGetChildValueInt(conf, "port", &ctx->hpfeeds_port); + ConfGetChildValueBool(conf, "reconnect", &ctx->reconnect); + + SCMutexInit(&ctx->mutex, NULL); + + output_ctx = SCMalloc(sizeof(OutputCtx)); + + if (unlikely(output_ctx == NULL)) { + SCFree(ctx); + SCReturnPtr(NULL, "AlertPHPFeedsCtx"); + } + + output_ctx->data = ctx; + output_ctx->DeInit = AlertHPFeedsDeInitCtx; + + if (ctx->hpfeeds_host && ctx->hpfeeds_ident && ctx->hpfeeds_secret && ctx->hpfeeds_channel) + HPFeedsConnect(ctx, 0); + + SCReturnPtr((void*)output_ctx, "OutputCtx"); +} + +/** + * \brief Function to initialize the AlertHPFeedsThread and sets the output + * context pointer + * + * \param tv Pointer to the threadvars + * \param initdata Pointer to the output context + * \param data pointer to pointer to point to the AlertHPFeedsThread + */ + +static TmEcode AlertHPFeedsThreadInit(ThreadVars *t, void *initdata, void **data) +{ + AlertHPFeedsThread *thread_ctx; + + SCEnter(); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for hpfeeds."); + SCReturnInt(TM_ECODE_FAILED); + } + + thread_ctx = SCMalloc(sizeof(AlertHPFeedsThread)); + + if (unlikely(thread_ctx == NULL)) + SCReturnInt(TM_ECODE_FAILED); + + memset(thread_ctx, 0, sizeof(AlertHPFeedsThread)); + + /** Use the Ouput Context */ + thread_ctx->ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)thread_ctx; + + SCReturnInt(TM_ECODE_OK); + return TM_ECODE_OK; +} + +/** + * \brief Function to deinitialize the AlertHPFeedsThread + * + * \param tv Pointer to the threadvars + * \param data pointer to the AlertHPFeedsThread to be cleared + */ + +static TmEcode AlertHPFeedsThreadDeinit(ThreadVars *t, void *data) +{ + AlertHPFeedsThread *thread_ctx = (AlertHPFeedsThread *)data; + + if (thread_ctx == NULL) + return TM_ECODE_OK; + + /* clear memory */ + memset(thread_ctx, 0, sizeof(AlertHPFeedsThread)); + SCFree(thread_ctx); + + return TM_ECODE_OK; +} + +/* Input is packet and an nine-byte (including NULL) character array. Results + * are put into the character array. + */ + +void CreateTCPFlagString(const Packet * p, char *flagBuffer) +{ + /* parse TCP flags */ + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_CWR) ? '1' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_ECN) ? '2' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_URG) ? 'U' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_ACK) ? 'A' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_PUSH) ? 'P' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_RST) ? 'R' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_SYN) ? 'S' : '*'); + *flagBuffer++ = (char) ((p->tcph->th_flags & TH_FIN) ? 'F' : '*'); + *flagBuffer = '\0'; +} + +/** + * \brief Function which is called to create json alert + * + * \param tv Pointer to the threadvars + * \param p Pointer to the packet + * \param data pointer to the AlertHPFeedsThread + * + * \return On succes return TM_ECODE_OK + */ + +static int CreatePacketData(ThreadVars *tv, const Packet *p, json_t * js) +{ + char srcip[46], dstip[46]; + char construct_buf[BUF_LEN]; + + char timestamp[64]; + struct tm* lt = localtime(&p->ts.tv_sec); + strftime((char*)timestamp, 64, "%Y/%m/%d %H:%M:%S", lt); + + char timestamp_usec[68]; + + snprintf(timestamp_usec, 68, "%s.%d", timestamp, (int)p->ts.tv_usec); + + json_object_set_new(js, "timestamp", json_string((char *)timestamp_usec)); + + srcip[0] = '\0'; + dstip[0] = '\0'; + + /* IPv4/v6 */ + if (PKT_IS_IPV4(p)) { + + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + + json_object_set_new(js, "destination_ip", json_string(dstip)); + json_object_set_new(js, "source_ip", json_string(srcip)); + + json_object_set_new(js, "ip_tos", json_integer(IPV4_GET_IPTOS(p))); + json_object_set_new(js, "ip_ttl", json_integer(IPV4_GET_IPTTL(p))); + json_object_set_new(js, "ip_id", json_integer(IPV4_GET_IPID(p))); + + + } else if (PKT_IS_IPV6(p)) { + + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + + json_object_set_new(js, "destination_ip", json_string(dstip)); + json_object_set_new(js, "source_ip", json_string(srcip)); + + } + + char proto[16]; + if (SCProtoNameValid(IP_GET_IPPROTO(p)) == TRUE) { + strlcpy(proto, known_proto[IP_GET_IPPROTO(p)], sizeof(proto)); + } else { + snprintf(proto, sizeof(proto), "%03" PRIu32, IP_GET_IPPROTO(p)); + } + + json_object_set_new(js, "proto", json_string(proto)); + + /* Ethernet */ + if (p->ethh != NULL) { + + snprintf(construct_buf, BUF_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", p->ethh->eth_src[0], + p->ethh->eth_src[1], p->ethh->eth_src[2], p->ethh->eth_src[3], + p->ethh->eth_src[4], p->ethh->eth_src[5]); + json_object_set_new(js, "eth_src", json_string((char *) construct_buf)); + + snprintf(construct_buf, BUF_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", p->ethh->eth_dst[0], + p->ethh->eth_dst[1], p->ethh->eth_dst[2], p->ethh->eth_dst[3], + p->ethh->eth_dst[4], p->ethh->eth_dst[5]); + json_object_set_new(js, "eth_dst", json_string((char *) construct_buf)); + + snprintf(construct_buf, BUF_LEN, "0x%X", ntohs(p->ethh->eth_type)); + json_object_set_new(js, "eth_type", json_string((char *)construct_buf)); + + snprintf(construct_buf, BUF_LEN,"0x%X", p->pktlen); + json_object_set_new(js, "eth_len", json_string((char *)construct_buf)); + } + + + /* TCP */ + if (PKT_IS_TCP(p)) { + + snprintf(construct_buf, BUF_LEN,"0x%X", p->tcph->th_seq); + json_object_set_new(js, "tcp_seq", json_string((char *)construct_buf)); + + snprintf(construct_buf, BUF_LEN, "0x%X", p->tcph->th_ack); + json_object_set_new(js, "tcp_ack", json_string((char *)construct_buf)); + + snprintf(construct_buf, BUF_LEN, "0x%lX", (u_long)ntohl(p->tcph->th_win)); + json_object_set_new(js, "tcp_win", json_string((char *)construct_buf)); + + json_object_set_new(js, "tcp_len", json_integer(TCP_GET_RAW_OFFSET(p->tcph) << 2)); + + json_object_set_new(js, "source_port", json_integer(p->sp)); + json_object_set_new(js, "destination_port", json_integer(p->dp)); + + char tcpflags[9]; + CreateTCPFlagString(p, tcpflags); + json_object_set_new(js, "tcp_flags", json_string((char *)tcpflags)); + } + + /* UDP */ + else if (PKT_IS_UDP(p)) { + json_object_set_new(js, "udp_len", json_integer(UDP_GET_LEN(p))); + json_object_set_new(js, "source_port", json_integer(p->sp)); + json_object_set_new(js, "destination_port", json_integer(p->dp)); + } + + /* ICMPv4/v6 */ + else if (p->proto == IPPROTO_ICMP) { + + if (PKT_IS_ICMPV4(p)) { + + json_object_set_new(js, "icmp_version", json_integer(4)); + json_object_set_new(js, "icmp_id", json_integer(ICMPV4_GET_ID(p))); + json_object_set_new(js, "icmp_seq", json_integer(ICMPV4_GET_SEQ(p))); + json_object_set_new(js, "icmp_type",json_integer(ICMPV4_GET_TYPE(p))); + json_object_set_new(js, "icmp_code",json_integer(ICMPV4_GET_CODE(p))); + + } else if(PKT_IS_ICMPV6(p)) { + + json_object_set_new(js, "icmp_version", json_integer(6)); + json_object_set_new(js, "icmp_id", json_integer(ICMPV6_GET_ID(p))); + json_object_set_new(js, "icmp_seq", json_integer(ICMPV6_GET_SEQ(p))); + json_object_set_new(js, "icmp_type",json_integer(ICMPV6_GET_TYPE(p))); + json_object_set_new(js, "icmp_code",json_integer(ICMPV6_GET_CODE(p))); + } + + } + + return 1; + +} + +static int AlertHPFeedsCondition(ThreadVars *tv, const Packet *p) +{ + return (p->alerts.cnt > 0 ? TRUE : FALSE); +} + +static int AlertHPFeedsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + AlertHPFeedsThread *thread_ctx = (AlertHPFeedsThread *)thread_data; + AlertHPFeedsCtx *ctx = (AlertHPFeedsCtx *)thread_ctx->ctx; + + /* Return if packet is NULL or socket isn't open */ + if(p == NULL || ctx->sock == -1) + return TM_ECODE_OK; + + SCMutex *mtx = &ctx->mutex; + + SCMutexLock(mtx); + + json_t *record = json_object(); + json_object_set_new(record, "sensor", json_string(ctx->hpfeeds_ident)); + + if (!CreatePacketData(tv, p, record)) + { + json_decref(record); + SCMutexUnlock(mtx); + return TM_ECODE_OK; + } + + int i = 0; + + for ( ; i < p->alerts.cnt; i++) { + + const PacketAlert *pa = &p->alerts.alerts[i]; + + if (unlikely(pa->s == NULL)) { + continue; + } + + char *action = "allowed"; + if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { + action = "blocked"; + } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { + action = "blocked"; + } + + json_object_set_new(record, "action", json_string(action)); + + // header + // priority + // classification + + json_object_set_new(record, "signature_id", json_integer(pa->s->id)); + json_object_set_new(record, "signature_rev", json_integer(pa->s->rev)); + json_object_set_new(record, "signature", json_string((pa->s->msg) ? pa->s->msg : "")); + } + + HPFeedsPublish(record, ctx); + + json_decref(record); + + SCMutexUnlock(mtx); + + return TM_ECODE_OK; +} + + +/* == Reused function for hpfeeds == + * + * Functions: HPFeedsReadMsg + * HPFeedsGetError + * HPFeedsCloseConnection + * HPFeedsConnect + * HPFeedsPublish + */ + +u_char *HPFeedsReadMsg(int sock) +{ + u_char *buffer; + int msglen; + + int len; + int templen; + char tempbuf[READ_BLOCK_SIZE]; + + if (read(sock, &msglen, 4) != 4) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal read()"); + return NULL; + } + + if ((buffer = malloc(ntohl(msglen))) == NULL) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal malloc()"); + return NULL; + } + + *(unsigned int *) buffer = msglen; + msglen = ntohl(msglen); + + len = 4; + templen = len; + while ((templen > 0) && (len < msglen)) + { + templen = read(sock, tempbuf, READ_BLOCK_SIZE); + memcpy(buffer + len, tempbuf, templen); + len += templen; + } + + if (len != msglen) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal read()"); + free(buffer); + return NULL; + } + + return buffer; +} + +void HPFeedsGetError(hpf_msg_t *msg, int sock) +{ + + u_char *errmsg; + + if (msg) + { + if ((errmsg = calloc(1, msg->hdr.msglen - sizeof(msg->hdr))) == NULL) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal write()"); + hpf_msg_delete(msg); + return; + } + + memcpy(errmsg, msg->data, ntohl(msg->hdr.msglen) - sizeof(msg->hdr)); + + SCLogNotice("alert-hpfeeds: server error: '%s'", errmsg); + + free(errmsg); + hpf_msg_delete(msg); + } +} + + +void HPFeedsCloseConnection(int *sock) +{ + if (*sock != -1) { + close(*sock); + *sock = -1; + } +} + +void HPFeedsConnect(AlertHPFeedsCtx *config, int reconnect) +{ + + /* socket already on - returning */ + if (config->sock != -1) return; + + hpf_msg_t *msg = NULL; + hpf_chunk_t *chunk; + + unsigned int nonce = 0; + + struct hostent *he; + struct sockaddr_in host; + + memset(&host, 0, sizeof(struct sockaddr_in)); + host.sin_family = AF_INET; + host.sin_port = htons(config->hpfeeds_port); + + if ((he = gethostbyname((char *)config->hpfeeds_host)) == NULL) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal gethostbyname()\n"); + return; + } + + host.sin_addr = *(struct in_addr *) he->h_addr; + + if ((config->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal socket()"); + return; + } + + if (connect(config->sock, (struct sockaddr *) &host, sizeof(host)) == -1) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal connect()"); + return; + } + + /* Set poll fd */ + config->pfd.fd = config->sock; + config->pfd.events = POLLIN; + config->pfd.revents = 0; + + /* Set connection keep alive */ + int optval = 1; + + if(setsockopt(config->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) + { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal setsockopt()"); + HPFeedsCloseConnection(&config->sock); + return; + } + + hpfeeds_session_state_t hpfeeds_state = S_INIT; + + for (;;) + { + + switch (hpfeeds_state) + { + + case S_INIT: + + if ((msg = (hpf_msg_t *) HPFeedsReadMsg(config->sock)) == NULL) { + HPFeedsCloseConnection(&config->sock); + break; + } + + switch (msg->hdr.opcode) + { + + case OP_INFO: + + chunk = hpf_msg_get_chunk((u_char *)msg + sizeof(msg->hdr), ntohl(msg->hdr.msglen) - sizeof(msg->hdr)); + + if (!chunk) + { + SCLogNotice("alert-hpfeeds: invalid message format"); + hpfeeds_state = S_TERMINATE; + break; + } + + nonce = *(unsigned int *) ((u_char *)msg + sizeof(msg->hdr) + chunk->len + 1); + hpfeeds_state = S_AUTH; + + hpf_msg_delete(msg); + break; + + case OP_ERROR: + hpfeeds_state = S_ERROR; + break; + + default: + hpf_msg_delete(msg); + hpfeeds_state = S_TERMINATE; + SCLogNotice("alert-hpfeeds: unknown server message (type %u)", msg->hdr.opcode); + break; + } + + case S_AUTH: + + SCLogNotice("alert-hpfeeds: sending authentication."); + + msg = hpf_msg_auth(nonce, (u_char *) config->hpfeeds_ident, strlen(config->hpfeeds_ident) \ + ,(u_char *) config->hpfeeds_secret, strlen(config->hpfeeds_secret)); + + if (write(config->sock, (u_char *) msg, ntohl(msg->hdr.msglen)) == -1) { + SCLogError(SC_LOG_ERROR,"alert-hpfeeds: Fatal write()"); + hpfeeds_state = S_TERMINATE; + hpf_msg_delete(msg); + break; + } + + if (reconnect == 0) { + + int rv = poll(&config->pfd, 1, 1000); + + if (rv > 0 && config->pfd.revents && POLLIN) + { + hpfeeds_state = S_ERROR; + + msg = (hpf_msg_t *) HPFeedsReadMsg(config->sock); + break; + } + } + + hpfeeds_state = S_AUTH_DONE; + config->status = HPFEEDS_AUTH_DONE; + + SCLogNotice("alert-hpfeeds: authentication done."); + hpf_msg_delete(msg); + + break; + + case S_ERROR: + + if (msg) { + HPFeedsGetError(msg, config->sock); + } + + hpfeeds_state = S_TERMINATE; + break; + + case S_TERMINATE: + default: + HPFeedsCloseConnection(&config->sock); + SCLogNotice("alert-hpfeeds: connection terminated..."); + break; + } + + if (hpfeeds_state == S_AUTH_DONE || config->sock == -1) + break; + } +} + + +void HPFeedsPublish(json_t *json, AlertHPFeedsCtx *config) +{ + + char *data = json_dumps(json, 0); + unsigned int len = strlen(data); + + hpf_msg_t *msg; + + msg = hpf_msg_publish((u_char *)config->hpfeeds_ident, strlen(config->hpfeeds_ident) \ + ,(u_char *)config->hpfeeds_channel, strlen(config->hpfeeds_channel), (u_char *)data, len); + + if (write(config->sock, (char *) msg, ntohl(msg->hdr.msglen)) == -1) { + + SCLogNotice("alert-hpfeeds: Publish failed on write.\n"); + HPFeedsCloseConnection(&config->sock); + + if (config->reconnect) { + HPFeedsConnect(config, config->reconnect); + HPFeedsPublish(json, config); + } + + free(data); + hpf_msg_delete(msg); + + return; + } + + /* Do another socket poll - in case of wrong channel */ + if (config->status != HPFEEDS_READY) + { + + int rv = poll(&config->pfd, 1, 1000); + + if (rv == 0) + { + config->status = HPFEEDS_READY; + SCLogNotice("alert-hpfeeds: Initial publish done.\n"); + } + else if (rv > 0 && config->pfd.revents && POLLIN) + { + + config->status = HPFEEDS_NOK; + hpf_msg_t *error_msg = NULL; + + if ((error_msg = (hpf_msg_t *) HPFeedsReadMsg(config->sock)) != NULL) + { + HPFeedsGetError(error_msg, config->sock); + SCLogNotice("alert-hpfeeds: Failed to publish.\n"); + } + else + { + SCLogNotice("alert-hpfeeds: Something went wrong\n"); + } + + HPFeedsCloseConnection(&config->sock); + } + } + + free(data); + hpf_msg_delete(msg); +} + +#endif /* !OS_WIN32 */ + + + +/** \brief Function to register the AlertHPFeed module */ +void AlertHPFeeds(void) +{ +#ifndef OS_WIN32 + + tmm_modules[TMM_ALERTHPFEEDS].name = MODULE_NAME; + tmm_modules[TMM_ALERTHPFEEDS].ThreadInit = AlertHPFeedsThreadInit; + tmm_modules[TMM_ALERTHPFEEDS].Func = NULL; + tmm_modules[TMM_ALERTHPFEEDS].ThreadDeinit = AlertHPFeedsThreadDeinit; + tmm_modules[TMM_ALERTHPFEEDS].cap_flags = 0; + tmm_modules[TMM_ALERTHPFEEDS].flags = TM_FLAG_LOGAPI_TM; + + OutputRegisterPacketModule(LOGGER_HPFEEDS, MODULE_NAME, "alert-hpfeeds", + AlertHPFeedsInitCtx, AlertHPFeedsLogger, AlertHPFeedsCondition, AlertHPFeedsThreadInit, AlertHPFeedsThreadDeinit, NULL); + +#endif /* !OS_WIN32 */ +} diff --git a/src/alert-hpfeeds.h b/src/alert-hpfeeds.h new file mode 100644 index 000000000000..c6b56ba4a29e --- /dev/null +++ b/src/alert-hpfeeds.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __ALERT_HPFEEDS_H__ +#define __ALERT_HPFEEDS_H__ + +void AlertHPFeeds(void); + +#endif /* __ALERT_HPFEEDS_H__ */ + diff --git a/src/alert-prelude.c b/src/alert-prelude.c index a8e41ac339d2..9c55b2815417 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -62,22 +62,9 @@ /* Handle the case where no PRELUDE support is compiled in. */ -static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogDebug("Can't init Prelude output thread - Prelude support was disabled during build."); - return TM_ECODE_FAILED; -} - -static TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) -{ - return TM_ECODE_FAILED; -} - -void TmModuleAlertPreludeRegister (void) +void AlertPreludeRegister(void) { - tmm_modules[TMM_ALERTPRELUDE].name = "AlertPrelude"; - tmm_modules[TMM_ALERTPRELUDE].ThreadInit = AlertPreludeThreadInit; - tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; + SCLogDebug("Can't register Prelude output thread - Prelude support was disabled during build."); } #else /* implied we do have PRELUDE support */ @@ -115,6 +102,7 @@ typedef struct AlertPreludeCtx_ { typedef struct AlertPreludeThread_ { /** Pointer to the global context */ AlertPreludeCtx *ctx; + idmef_analyzer_t *analyzer; } AlertPreludeThread; @@ -131,24 +119,56 @@ static int SetupAnalyzer(idmef_analyzer_t *analyzer) SCEnter(); ret = idmef_analyzer_new_model(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer model: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } + ret = prelude_string_set_constant(string, ANALYZER_MODEL); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer model: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, ANALYZER_MODEL); + } ret = idmef_analyzer_new_class(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer class: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, ANALYZER_CLASS); + } + ret = prelude_string_set_constant(string, ANALYZER_CLASS); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer class: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } ret = idmef_analyzer_new_manufacturer(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer manufacturer: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } + ret = prelude_string_set_constant(string, ANALYZER_MANUFACTURER); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer manufacturer: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, ANALYZER_MANUFACTURER); + } ret = idmef_analyzer_new_version(analyzer, &string); - if (ret < 0) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating analyzer version: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); - prelude_string_set_constant(string, VERSION); + } + ret = prelude_string_set_constant(string, VERSION); + if (unlikely(ret < 0)) { + SCLogDebug("%s: error setting analyzer version: %s.", + prelude_strsource(ret), prelude_strerror(ret)); + SCReturnInt(ret); + } SCReturnInt(0); } @@ -174,12 +194,18 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * SCEnter(); ret = idmef_alert_new_assessment(alert, &assessment); - if (ret < 0) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating assessment: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); + } ret = idmef_assessment_new_impact(assessment, &impact); - if (ret < 0) + if (unlikely(ret < 0)) { + SCLogDebug("%s: error creating assessment impact: %s.", + prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(ret); + } if ( (unsigned int)pa->s->prio < mid_priority ) severity = IDMEF_IMPACT_SEVERITY_HIGH; @@ -195,11 +221,14 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * idmef_impact_set_severity(impact, severity); - if (PACKET_TEST_ACTION(p, ACTION_DROP)) { + if (PACKET_TEST_ACTION(p, ACTION_DROP) || + PACKET_TEST_ACTION(p, ACTION_REJECT) || + PACKET_TEST_ACTION(p, ACTION_REJECT_DST) || + PACKET_TEST_ACTION(p, ACTION_REJECT_BOTH) ) { idmef_action_t *action; ret = idmef_action_new(&action); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); idmef_action_set_category(action, IDMEF_ACTION_CATEGORY_BLOCK_INSTALLED); @@ -208,7 +237,7 @@ static int EventToImpact(const PacketAlert *pa, const Packet *p, idmef_alert_t * if (pa->s->class_msg) { ret = idmef_impact_new_description(impact, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_ref(str, pa->s->class_msg); @@ -259,11 +288,11 @@ static int EventToSourceTarget(const Packet *p, idmef_alert_t *alert) SCReturnInt(0); ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_source_new_service(source, &service); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( p->tcph || p->udph ) @@ -273,25 +302,25 @@ static int EventToSourceTarget(const Packet *p, idmef_alert_t *alert) idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_source_new_node(source, &node); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_ref(string, saddr); ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_target_new_service(target, &service); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( p->tcph || p->udph ) @@ -301,15 +330,15 @@ static int EventToSourceTarget(const Packet *p, idmef_alert_t *alert) idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_target_new_node(target, &node); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); prelude_string_set_ref(string, daddr); @@ -335,25 +364,25 @@ static int AddByteData(idmef_alert_t *alert, const char *meaning, const unsigned SCReturnInt(0); ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(0); ret = idmef_additional_data_set_byte_string_ref(ad, data, size); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error setting byte string data: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = idmef_additional_data_new_meaning(ad, &str); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error creating additional-data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = prelude_string_set_ref(str, meaning); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error setting byte string data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); @@ -377,20 +406,20 @@ static int AddIntData(idmef_alert_t *alert, const char *meaning, uint32_t data) SCEnter(); ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); idmef_additional_data_set_integer(ad, data); ret = idmef_additional_data_new_meaning(ad, &str); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error creating additional-data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); } ret = prelude_string_set_ref(str, meaning); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("%s: error setting integer data meaning: %s.", prelude_strsource(ret), prelude_strerror(ret)); SCReturnInt(-1); @@ -434,7 +463,17 @@ static int PacketToDataV4(const Packet *p, const PacketAlert *pa, idmef_alert_t */ static int PacketToDataV6(const Packet *p, const PacketAlert *pa, idmef_alert_t *alert) { - return 0; + SCEnter(); + + AddIntData(alert, "ip_ver", IPV6_GET_VER(p)); + AddIntData(alert, "ip_class", IPV6_GET_CLASS(p)); + AddIntData(alert, "ip_flow", IPV6_GET_FLOW(p)); + AddIntData(alert, "ip_nh", IPV6_GET_NH(p)); + AddIntData(alert, "ip_plen", IPV6_GET_PLEN(p)); + AddIntData(alert, "ip_hlim", IPV6_GET_HLIM(p)); + AddIntData(alert, "ip_proto", IPV6_GET_L4PROTO(p)); + + SCReturnInt(0); } @@ -449,7 +488,7 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a { SCEnter(); - if ( ! p ) + if (unlikely(p == NULL)) SCReturnInt(0); AddIntData(alert, "snort_rule_sid", pa->s->id); @@ -463,29 +502,50 @@ static int PacketToData(const Packet *p, const PacketAlert *pa, idmef_alert_t *a PacketToDataV6(p, pa, alert); if ( PKT_IS_TCP(p) ) { - AddIntData(alert, "tcp_seq", ntohl(p->tcph->th_seq)); - AddIntData(alert, "tcp_ack", ntohl(p->tcph->th_ack)); - - AddIntData(alert, "tcp_off", TCP_GET_RAW_OFFSET(p->tcph)); - AddIntData(alert, "tcp_res", TCP_GET_RAW_X2(p->tcph)); - AddIntData(alert, "tcp_flags", p->tcph->th_flags); - - AddIntData(alert, "tcp_win", ntohs(p->tcph->th_win)); - AddIntData(alert, "tcp_sum", ntohs(p->tcph->th_sum)); - AddIntData(alert, "tcp_urp", ntohs(p->tcph->th_urp)); - + AddIntData(alert, "tcp_seq", TCP_GET_SEQ(p)); + AddIntData(alert, "tcp_ack", TCP_GET_ACK(p)); + + AddIntData(alert, "tcp_off", TCP_GET_OFFSET(p)); + AddIntData(alert, "tcp_res", TCP_GET_X2(p)); + AddIntData(alert, "tcp_flags", TCP_GET_FLAGS(p)); + + AddIntData(alert, "tcp_win", TCP_GET_WINDOW(p)); + AddIntData(alert, "tcp_sum", TCP_GET_SUM(p)); + AddIntData(alert, "tcp_urp", TCP_GET_URG_POINTER(p)); + if (p->tcpvars.ts_val != 0) { + AddIntData(alert, "tcp_tsval", TCP_GET_TSVAL(p)); + } + if (p->tcpvars.ts_ecr != 0) { + AddIntData(alert, "tcp_tsecr", TCP_GET_TSECR(p)); + } + if (p->tcph != NULL) { + AddIntData(alert, "tcp_wscale", TCP_GET_WSCALE(p)); + } + if (TCP_HAS_SACKOK(p)) { + AddIntData(alert, "tcp_sackok", TCP_GET_SACKOK(p)); + } + if (TCP_HAS_SACK(p)) { + AddIntData(alert, "tcp_sack_cnt", TCP_GET_SACK_CNT(p)); + } + AddIntData(alert, "tcp_hlen", TCP_GET_HLEN(p)); } else if ( PKT_IS_UDP(p) ) { - AddIntData(alert, "udp_len", ntohs(p->udph->uh_len)); - AddIntData(alert, "udp_sum", ntohs(p->udph->uh_sum)); + AddIntData(alert, "udp_len", UDP_GET_LEN(p)); + AddIntData(alert, "udp_sum", UDP_GET_SUM(p)); } else if ( PKT_IS_ICMPV4(p) ) { - AddIntData(alert, "icmp_type", p->icmpv4h->type); - AddIntData(alert, "icmp_code", p->icmpv4h->code); - AddIntData(alert, "icmp_sum", ntohs(p->icmpv4h->checksum)); + AddIntData(alert, "icmp_type", ICMPV4_GET_TYPE(p)); + AddIntData(alert, "icmp_code", ICMPV4_GET_CODE(p)); + AddIntData(alert, "icmp_sum", ICMPV4_GET_RAW_CSUM(p)); + + } + else if ( PKT_IS_ICMPV6(p) ) { + AddIntData(alert, "icmp_type", ICMPV6_GET_TYPE(p)); + AddIntData(alert, "icmp_code", ICMPV6_GET_CODE(p)); + AddIntData(alert, "icmp_csum", ICMPV6_GET_RAW_CSUM(p)); } } @@ -513,11 +573,11 @@ static int AddSnortReference(idmef_classification_t *class, int gen_id, int sig_ SCReturnInt(0); ret = idmef_classification_new_reference(class, &ref, IDMEF_LIST_APPEND); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_reference_new_name(ref, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); idmef_reference_set_origin(ref, IDMEF_REFERENCE_ORIGIN_VENDOR_SPECIFIC); @@ -527,19 +587,19 @@ static int AddSnortReference(idmef_classification_t *class, int gen_id, int sig_ else ret = prelude_string_sprintf(str, "%u:%u", gen_id, sig_id); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_reference_new_meaning(ref, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = prelude_string_sprintf(str, "Snort Signature ID"); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = idmef_reference_new_url(ref, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( gen_id == 0 ) @@ -566,18 +626,18 @@ static int EventToReference(const PacketAlert *pa, const Packet *p, idmef_classi SCEnter(); ret = idmef_classification_new_ident(class, &str); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); if ( pa->s->gid == 0 ) ret = prelude_string_sprintf(str, "%u", pa->s->id); else ret = prelude_string_sprintf(str, "%u:%u", pa->s->gid, pa->s->id); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); ret = AddSnortReference(class, pa->s->gid, pa->s->id); - if (ret < 0) + if (unlikely(ret < 0)) SCReturnInt(ret); SCReturnInt(0); @@ -606,9 +666,9 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data SCEnter(); - if(initdata == NULL) - { - SCLogDebug("Error getting context for Prelude. \"initdata\" argument NULL"); + if (unlikely(initdata == NULL)) { + SCLogError(SC_ERR_INITIALIZATION, + "Error getting context for Prelude. \"initdata\" argument NULL"); SCReturnInt(TM_ECODE_FAILED); } @@ -617,9 +677,28 @@ static TmEcode AlertPreludeThreadInit(ThreadVars *t, void *initdata, void **data SCReturnInt(TM_ECODE_FAILED); memset(aun, 0, sizeof(AlertPreludeThread)); - /** Use the Ouput Context */ + /* Use the Ouput Context */ aun->ctx = ((OutputCtx *)initdata)->data; + /* Create a per-thread idmef analyzer */ + if (unlikely(idmef_analyzer_new(&aun->analyzer) < 0)) { + SCLogError(SC_ERR_INITIALIZATION, + "Error creating idmef analyzer for Prelude."); + + SCFree(aun); + SCReturnInt(TM_ECODE_FAILED); + } + + /* Setup the per-thread idmef analyzer */ + if (unlikely(SetupAnalyzer(aun->analyzer) < 0)) { + SCLogError(SC_ERR_INITIALIZATION, + "Error configuring idmef analyzer for Prelude."); + + idmef_analyzer_destroy(aun->analyzer); + SCFree(aun); + SCReturnInt(TM_ECODE_FAILED); + } + *data = (void *)aun; SCReturnInt(TM_ECODE_OK); } @@ -635,12 +714,13 @@ static TmEcode AlertPreludeThreadDeinit(ThreadVars *t, void *data) SCEnter(); - if (aun == NULL) { + if (unlikely(aun == NULL)) { SCLogDebug("AlertPreludeThreadDeinit done (error)"); SCReturnInt(TM_ECODE_FAILED); } /* clear memory */ + idmef_analyzer_destroy(aun->analyzer); memset(aun, 0, sizeof(AlertPreludeThread)); SCFree(aun); @@ -677,7 +757,7 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) SCEnter(); ret = prelude_init(0, NULL); - if (ret < 0) { + if (unlikely(ret < 0)) { prelude_perror(ret, "unable to initialize the prelude library"); SCReturnPtr(NULL, "AlertPreludeCtx"); } @@ -690,23 +770,28 @@ static OutputCtx *AlertPreludeInitCtx(ConfNode *conf) log_packet_header = ConfNodeLookupChildValue(conf, "log-packet-header"); ret = prelude_client_new(&client, prelude_profile_name); - if ( ret < 0 || ! client ) { + if ( unlikely(ret < 0 || client == NULL )) { prelude_perror(ret, "Unable to create a prelude client object"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } ret = prelude_client_set_flags(client, prelude_client_get_flags(client) | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER|PRELUDE_CLIENT_FLAGS_ASYNC_SEND); - if (ret < 0) { + if (unlikely(ret < 0)) { SCLogDebug("Unable to set asynchronous send and timer."); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); } - SetupAnalyzer(prelude_client_get_analyzer(client)); + ret = SetupAnalyzer(prelude_client_get_analyzer(client)); + if (ret < 0) { + SCLogDebug("Unable to setup prelude client analyzer."); + prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); + SCReturnPtr(NULL, "AlertPreludeCtx"); + } ret = prelude_client_start(client); - if (ret < 0) { + if (unlikely(ret < 0)) { prelude_perror(ret, "Unable to start prelude client"); prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); SCReturnPtr(NULL, "AlertPreludeCtx"); @@ -779,7 +864,7 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p SCEnter(); - if (apn == NULL || apn->ctx == NULL) { + if (unlikely(apn == NULL || apn->ctx == NULL)) { SCReturnInt(TM_ECODE_FAILED); } @@ -792,43 +877,43 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p /* XXX which one to add to this alert? Lets see how Snort solves this. * For now just take last alert. */ pa = &p->alerts.alerts[p->alerts.cnt-1]; - if (pa->s == NULL) + if (unlikely(pa->s == NULL)) goto err; ret = idmef_message_new(&idmef); - if ( ret < 0 ) + if (unlikely(ret < 0)) SCReturnInt(TM_ECODE_FAILED); ret = idmef_message_new_alert(idmef, &alert); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = idmef_alert_new_classification(alert, &class); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; if (pa->s->msg) { ret = idmef_classification_new_text(class, &str); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; prelude_string_set_ref(str, pa->s->msg); } ret = EventToImpact(pa, p, alert); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = EventToReference(pa, p, class); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = EventToSourceTarget(p, alert); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; ret = PacketToData(p, pa, alert, apn->ctx); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; if (PKT_IS_TCP(p) && (pa->flags & PACKET_ALERT_FLAG_STATE_MATCH)) { @@ -842,20 +927,20 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p PreludePrintStreamSegmentCallback, (void *)alert); } - if (ret < 0) + if (unlikely(ret < 0)) goto err; ret = idmef_alert_new_detect_time(alert, &time); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; idmef_time_set_from_timeval(time, &p->ts); ret = idmef_time_new_from_gettimeofday(&time); - if ( ret < 0 ) + if (unlikely(ret < 0)) goto err; idmef_alert_set_create_time(alert, time); - idmef_alert_set_analyzer(alert, idmef_analyzer_ref(prelude_client_get_analyzer(apn->ctx->client)), IDMEF_LIST_PREPEND); + idmef_alert_set_analyzer(alert, idmef_analyzer_ref(apn->analyzer), IDMEF_LIST_PREPEND); /* finally, send event */ prelude_client_send_idmef(apn->ctx->client, idmef); @@ -869,17 +954,10 @@ static int AlertPreludeLogger(ThreadVars *tv, void *thread_data, const Packet *p SCReturnInt(TM_ECODE_FAILED); } -void TmModuleAlertPreludeRegister (void) +void AlertPreludeRegister (void) { - tmm_modules[TMM_ALERTPRELUDE].name = "AlertPrelude"; - tmm_modules[TMM_ALERTPRELUDE].ThreadInit = AlertPreludeThreadInit; - tmm_modules[TMM_ALERTPRELUDE].Func = NULL; - tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; - tmm_modules[TMM_ALERTPRELUDE].cap_flags = 0; - tmm_modules[TMM_ALERTPRELUDE].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule("AlertPrelude", "alert-prelude", AlertPreludeInitCtx, - AlertPreludeLogger, AlertPreludeCondition); + OutputRegisterPacketModule(LOGGER_PRELUDE, "AlertPrelude", "alert-prelude", + AlertPreludeInitCtx, AlertPreludeLogger, AlertPreludeCondition, + AlertPreludeThreadInit, AlertPreludeThreadDeinit, NULL); } #endif /* PRELUDE */ - diff --git a/src/alert-prelude.h b/src/alert-prelude.h index 7a30e847ea1f..0f15961f091f 100644 --- a/src/alert-prelude.h +++ b/src/alert-prelude.h @@ -26,6 +26,6 @@ #ifndef __ALERT_PRELUDE_H__ #define __ALERT_PRELUDE_H__ -void TmModuleAlertPreludeRegister (void); +void AlertPreludeRegister(void); #endif /* __ALERT_PRELUDE_H__ */ diff --git a/src/alert-syslog.c b/src/alert-syslog.c index 13151dd99027..8de1d3a9c211 100644 --- a/src/alert-syslog.c +++ b/src/alert-syslog.c @@ -205,10 +205,9 @@ static TmEcode AlertSyslogIPv4(ThreadVars *tv, const Packet *p, void *data) if (p->alerts.cnt == 0) return TM_ECODE_OK; + /* Not sure if this mutex is needed around calls to syslog. */ SCMutexLock(&ast->file_ctx->fp_mutex); - ast->file_ctx->alerts += p->alerts.cnt; - for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { @@ -265,8 +264,6 @@ static TmEcode AlertSyslogIPv6(ThreadVars *tv, const Packet *p, void *data) SCMutexLock(&ast->file_ctx->fp_mutex); - ast->file_ctx->alerts += p->alerts.cnt; - for (i = 0; i < p->alerts.cnt; i++) { const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { @@ -328,7 +325,6 @@ static TmEcode AlertSyslogDecoderEvent(ThreadVars *tv, const Packet *p, void *da SCMutexLock(&ast->file_ctx->fp_mutex); - ast->file_ctx->alerts += p->alerts.cnt; char temp_buf_hdr[512]; char temp_buf_pkt[65] = ""; char temp_buf_tail[32]; @@ -371,22 +367,6 @@ static TmEcode AlertSyslogDecoderEvent(ThreadVars *tv, const Packet *p, void *da return TM_ECODE_OK; } -/** - * \brief Function to print the total alert while closing the engine - * - * \param tv Pointer to the output threadvars - * \param data Pointer to the AlertSyslogThread data - */ -static void AlertSyslogExitPrintStats(ThreadVars *tv, void *data) -{ - AlertSyslogThread *ast = (AlertSyslogThread *)data; - if (ast == NULL) { - return; - } - - SCLogInfo("(%s) Alerts %" PRIu64 "", tv->name, ast->file_ctx->alerts); -} - static int AlertSyslogCondition(ThreadVars *tv, const Packet *p) { return (p->alerts.cnt > 0 ? TRUE : FALSE); @@ -408,20 +388,11 @@ static int AlertSyslogLogger(ThreadVars *tv, void *thread_data, const Packet *p) #endif /* !OS_WIN32 */ /** \brief Function to register the AlertSyslog module */ -void TmModuleAlertSyslogRegister (void) +void AlertSyslogRegister (void) { #ifndef OS_WIN32 - tmm_modules[TMM_ALERTSYSLOG].name = MODULE_NAME; - tmm_modules[TMM_ALERTSYSLOG].ThreadInit = AlertSyslogThreadInit; - tmm_modules[TMM_ALERTSYSLOG].Func = NULL; - tmm_modules[TMM_ALERTSYSLOG].ThreadExitPrintStats = AlertSyslogExitPrintStats; - tmm_modules[TMM_ALERTSYSLOG].ThreadDeinit = AlertSyslogThreadDeinit; - tmm_modules[TMM_ALERTSYSLOG].RegisterTests = NULL; - tmm_modules[TMM_ALERTSYSLOG].cap_flags = 0; - tmm_modules[TMM_ALERTSYSLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "syslog", - AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition); - + OutputRegisterPacketModule(LOGGER_ALERT_SYSLOG, MODULE_NAME, "syslog", + AlertSyslogInitCtx, AlertSyslogLogger, AlertSyslogCondition, + AlertSyslogThreadInit, AlertSyslogThreadDeinit, NULL); #endif /* !OS_WIN32 */ } diff --git a/src/alert-syslog.h b/src/alert-syslog.h index 976a1122eff7..06890469fcfc 100644 --- a/src/alert-syslog.h +++ b/src/alert-syslog.h @@ -27,7 +27,7 @@ #ifndef __ALERT_SYSLOG_H__ #define __ALERT_SYSLOG_H__ -void TmModuleAlertSyslogRegister(void); +void AlertSyslogRegister(void); #endif /* __ALERT_SYSLOG_H__ */ diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index 9a0a280682c0..ac1fa7e29116 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -42,8 +42,6 @@ #include "alert-unified2-alert.h" #include "decode-ipv4.h" -#include "flow.h" - #include "host.h" #include "util-profiling.h" #include "decode.h" @@ -58,9 +56,9 @@ #include "app-layer-parser.h" #include "app-layer-htp.h" #include "app-layer.h" +#include "app-layer-htp-xff.h" #include "output.h" -#include "alert-unified2-alert.h" #include "util-privs.h" #include "stream.h" @@ -68,8 +66,6 @@ #include "util-optimize.h" -#include "util-memrchr.h" - #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif @@ -179,31 +175,19 @@ typedef struct AlertUnified2Packet_ { uint8_t packet_data[4]; /**< packet data */ } Unified2Packet; -/** XFF is disabled */ -#define UNIFIED2_ALERT_XFF_DISABLED 1 -/** XFF extra data mode */ -#define UNIFIED2_ALERT_XFF_EXTRADATA 2 -/** XFF overwrite mode */ -#define UNIFIED2_ALERT_XFF_OVERWRITE 4 /** Extracted XFF IP is v4 */ #define UNIFIED2_ALERT_XFF_IPV4 8 /** Extracted XFF IP is v4 */ #define UNIFIED2_ALERT_XFF_IPV6 16 -/** Default XFF header name */ -#define UNIFIED2_ALERT_XFF_DEFAULT "X-Forwarded-For" -/** Single XFF IP maximum length */ -#define UNIFIED2_ALERT_XFF_MAXLEN 46 -/** XFF header value minimal length */ -#define UNIFIED2_ALERT_XFF_CHAIN_MINLEN 7 -/** XFF header value maximum length */ -#define UNIFIED2_ALERT_XFF_CHAIN_MAXLEN 256 typedef struct Unified2AlertFileCtx_ { LogFileCtx *file_ctx; - uint8_t xff_mode; /**< XFF operation mode */ - char *xff_header; /**< XFF Header name */ + HttpXFFCfg *xff_cfg; + uint32_t flags; /**< flags for all alerts */ } Unified2AlertFileCtx; +#define UNIFIED2_ALERT_FLAGS_EMIT_PACKET (1 << 0) + /** * Unified2 thread vars * @@ -241,7 +225,7 @@ static int Unified2IPv4TypeAlert(ThreadVars *, const Packet *, void *); static int Unified2IPv6TypeAlert(ThreadVars *, const Packet *, void *); static int Unified2PacketTypeAlert(Unified2AlertThread *, const Packet *, uint32_t, int); void Unified2RegisterTests(void); -int Unified2AlertOpenFileCtx(LogFileCtx *, const char *); +static int Unified2AlertOpenFileCtx(LogFileCtx *, const char *, bool); static void Unified2AlertDeInitCtx(OutputCtx *); int Unified2Condition(ThreadVars *tv, const Packet *p); @@ -249,29 +233,20 @@ int Unified2Logger(ThreadVars *tv, void *data, const Packet *p); #define MODULE_NAME "Unified2Alert" -void TmModuleUnified2AlertRegister(void) +void Unified2AlertRegister(void) { - tmm_modules[TMM_ALERTUNIFIED2ALERT].name = MODULE_NAME; - tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadInit = Unified2AlertThreadInit; -// tmm_modules[TMM_ALERTUNIFIED2ALERT].Func = Unified2Alert; - tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadDeinit = Unified2AlertThreadDeinit; - tmm_modules[TMM_ALERTUNIFIED2ALERT].RegisterTests = Unified2RegisterTests; - tmm_modules[TMM_ALERTUNIFIED2ALERT].cap_flags = 0; - tmm_modules[TMM_ALERTUNIFIED2ALERT].flags = TM_FLAG_LOGAPI_TM; - - //OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx); - OutputRegisterPacketModule(MODULE_NAME, "unified2-alert", - Unified2AlertInitCtx, Unified2Logger, Unified2Condition); + OutputRegisterPacketModule(LOGGER_UNIFIED2, MODULE_NAME, "unified2-alert", + Unified2AlertInitCtx, Unified2Logger, Unified2Condition, + Unified2AlertThreadInit, Unified2AlertThreadDeinit, NULL); + Unified2RegisterTests(); } /** * \brief Function to close unified2 file * - * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param aun Unified2 thread variable. */ - -int Unified2AlertCloseFile(ThreadVars *t, Unified2AlertThread *aun) +static int Unified2AlertCloseFile(Unified2AlertThread *aun) { if (aun->unified2alert_ctx->file_ctx->fp != NULL) { fclose(aun->unified2alert_ctx->file_ctx->fp); @@ -284,21 +259,19 @@ int Unified2AlertCloseFile(ThreadVars *t, Unified2AlertThread *aun) /** * \brief Function to rotate unified2 file * - * \param t Thread Variable containing input/output queue, cpu affinity etc. * \param aun Unified2 thread variable. * \retval 0 on succces * \retval -1 on failure */ - -int Unified2AlertRotateFile(ThreadVars *t, Unified2AlertThread *aun) +static int Unified2AlertRotateFile(Unified2AlertThread *aun, bool truncate) { - if (Unified2AlertCloseFile(t,aun) < 0) { + if (Unified2AlertCloseFile(aun) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertCloseFile failed"); return -1; } - if (Unified2AlertOpenFileCtx(aun->unified2alert_ctx->file_ctx,aun->unified2alert_ctx-> - file_ctx->prefix) < 0) { + if (Unified2AlertOpenFileCtx(aun->unified2alert_ctx->file_ctx, + aun->unified2alert_ctx->file_ctx->prefix, truncate) < 0) { SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Error: Unified2AlertOpenFileCtx, open new log file failed"); return -1; @@ -328,85 +301,6 @@ static int Unified2Write(Unified2AlertThread *aun) return 1; } -static int GetXFFIPFromTx(const Packet *p, uint64_t tx_id, char *xff_header, char *dstbuf, int dstbuflen) -{ - uint8_t xff_chain[UNIFIED2_ALERT_XFF_CHAIN_MAXLEN]; - HtpState *htp_state = NULL; - htp_tx_t *tx = NULL; - uint64_t total_txs = 0; - - htp_state = (HtpState *)FlowGetAppState(p->flow); - - if (htp_state == NULL) { - SCLogDebug("no http state, XFF IP cannot be retrieved"); - return 0; - } - - total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); - if (tx_id >= total_txs) - return 0; - - tx = AppLayerParserGetTx(p->flow->proto, ALPROTO_HTTP, htp_state, tx_id); - if (tx == NULL) { - SCLogDebug("tx is NULL, XFF cannot be retrieved"); - return 0; - } - - htp_header_t *h_xff = NULL; - if (tx->request_headers != NULL) { - h_xff = htp_table_get_c(tx->request_headers, xff_header); - } - - if (h_xff != NULL && bstr_len(h_xff->value) >= UNIFIED2_ALERT_XFF_CHAIN_MINLEN && - bstr_len(h_xff->value) < UNIFIED2_ALERT_XFF_CHAIN_MAXLEN) { - - memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); - xff_chain[bstr_len(h_xff->value)]=0; - /** Check for chained IP's separated by ", ", we will get the last one */ - uint8_t *p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); - if (p_xff == NULL) { - p_xff = xff_chain; - } else { - p_xff++; - } - /** Sanity check on extracted IP for IPv4 and IPv6 */ - uint32_t ip[4]; - if ( inet_pton(AF_INET, (char *)p_xff, ip ) == 1 || - inet_pton(AF_INET6, (char *)p_xff, ip ) == 1 ) { - strlcpy(dstbuf, (char *)p_xff, dstbuflen); - return 1; // OK - } - } - return 0; -} - -/** - * \brief Function to return XFF IP if any... - * \retval 1 if the IP has been found and returned in dstbuf - * \retval 0 if the IP has not being found or error - */ -static int GetXFFIP(const Packet *p, char *xff_header, char *dstbuf, int dstbuflen) -{ - HtpState *htp_state = NULL; - uint64_t tx_id = 0; - uint64_t total_txs = 0; - - htp_state = (HtpState *)FlowGetAppState(p->flow); - if (htp_state == NULL) { - SCLogDebug("no http state, XFF IP cannot be retrieved"); - goto end; - } - - total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); - for (; tx_id < total_txs; tx_id++) { - if (GetXFFIPFromTx(p, tx_id, xff_header, dstbuf, dstbuflen) == 1) - return 1; - } - -end: - return 0; // Not found -} - int Unified2Condition(ThreadVars *tv, const Packet *p) { if (likely(p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG))) return FALSE; @@ -423,39 +317,40 @@ int Unified2Logger(ThreadVars *t, void *data, const Packet *p) { int ret = 0; Unified2AlertThread *aun = (Unified2AlertThread *)data; - aun->xff_flags = UNIFIED2_ALERT_XFF_DISABLED; + aun->xff_flags = XFF_DISABLED; + + HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; /* overwrite mode can only work per u2 block, not per individual * alert. So we'll look for an XFF record once */ - if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_OVERWRITE) && p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); + if ((xff_cfg->flags & XFF_OVERWRITE) && p->flow != NULL) { + char buffer[XFF_MAXLEN]; + int have_xff_ip = 0; if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); + } - if (GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN) == 1) { - /** Be sure that we have a nice zeroed buffer */ - memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + if (have_xff_ip) { + /** Be sure that we have a nice zeroed buffer */ + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - /** We can only have override mode if packet IP version matches - * the XFF IP version, otherwise fall-back to extra data */ - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - SCLogDebug("valid ipv4 xff, setting flags %s", buffer); - if (PKT_IS_IPV4(p)) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_OVERWRITE); - } else { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); - } - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - if (PKT_IS_IPV6(p)) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_OVERWRITE); - } else { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); - } + /** We can only have override mode if packet IP version matches + * the XFF IP version, otherwise fall-back to extra data */ + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + if (PKT_IS_IPV4(p)) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_OVERWRITE); + } else { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA); + } + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + if (PKT_IS_IPV6(p)) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_OVERWRITE); + } else { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA); } } } - FLOWLOCK_UNLOCK(p->flow); } if (PKT_IS_IPV4(p)) { @@ -538,7 +433,7 @@ static int Unified2ForgeFakeIPv6Header(FakeIPv6Hdr *fakehdr, const Packet *p, in /** * \brief Write a faked Packet in unified2 file for each stream segment. */ -static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, const uint8_t *buf, uint32_t buflen) { int ret = 1; Unified2AlertThread *aun = (Unified2AlertThread *)data; @@ -555,7 +450,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 aun->offset = 0; // If XFF is in extra data mode... - if (aun->xff_flags & UNIFIED2_ALERT_XFF_EXTRADATA) { + if (aun->xff_flags & XFF_EXTRADATA) { memset(dhdr, 0, sizeof(Unified2ExtraData)); if (aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4) { @@ -607,7 +502,6 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; uint32_t hdr_length = 0; - int datalink = p->datalink; memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); @@ -616,7 +510,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); - phdr->linktype = htonl(datalink); + phdr->linktype = htonl(p->datalink); phdr->event_id = aun->event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); @@ -625,7 +519,6 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (p->datalink != DLT_EN10MB) { /* We have raw data here */ phdr->linktype = htonl(DLT_RAW); - datalink = DLT_RAW; } aun->length += sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; @@ -639,8 +532,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; - datalink = DLT_EN10MB; - phdr->linktype = htonl(datalink); + phdr->linktype = htonl(DLT_EN10MB); aun->length += ethh_offset; if (aun->length > aun->datalen) { @@ -661,8 +553,9 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 goto error; } /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6); + if (p->flowflags & FLOW_PKT_TOCLIENT) { fakehdr.ip4h.s_ip_dst.s_addr = aun->xff_ip[0]; } else { @@ -681,8 +574,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; - datalink = DLT_EN10MB; - phdr->linktype = htonl(datalink); + phdr->linktype = htonl(DLT_EN10MB); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); @@ -703,7 +595,7 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 goto error; } /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4); if (p->flowflags & FLOW_PKT_TOCLIENT) { @@ -741,15 +633,15 @@ static int Unified2PrintStreamSegmentCallback(const Packet *p, void *data, uint8 if (PKT_IS_IPV6(p)) { FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr; - fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs, - (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); + fakehdr->tcph.th_sum = TCPV6Checksum(fakehdr->ip6h.s_ip6_addrs, + (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); } else { FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr; - fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs, - (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); - fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, - IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); + fakehdr->tcph.th_sum = TCPChecksum(fakehdr->ip4h.s_ip_addrs, + (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr), 0); + fakehdr->ip4h.ip_csum = IPV4Checksum((uint16_t *)&fakehdr->ip4h, + IPV4_GET_RAW_HLEN(&fakehdr->ip4h), 0); } /* write out */ @@ -789,6 +681,9 @@ static int Unified2PacketTypeAlert(Unified2AlertThread *aun, const Packet *p, ui { int ret = 0; + if (!(aun->unified2alert_ctx->flags & UNIFIED2_ALERT_FLAGS_EMIT_PACKET)) + return 1; + /* try stream logging first */ if (stream) { SCLogDebug("logging the state"); @@ -892,6 +787,7 @@ static int Unified2PacketTypeAlert(Unified2AlertThread *aun, const Packet *p, ui static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) { Unified2AlertThread *aun = (Unified2AlertThread *)data; + LogFileCtx *file_ctx = aun->unified2alert_ctx->file_ctx; Unified2AlertFileHeader hdr; AlertIPv6Unified2 *phdr; AlertIPv6Unified2 gphdr; @@ -923,7 +819,7 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) gphdr.src_ip = *(struct in6_addr*)GET_IPV6_SRC_ADDR(p); gphdr.dst_ip = *(struct in6_addr*)GET_IPV6_DST_ADDR(p); /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV4); if (p->flowflags & FLOW_PKT_TOCLIENT) { @@ -983,29 +879,29 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) if (unlikely(pa->s == NULL)) continue; - if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) && p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); - if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; - int have_xff_ip = 0; + HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; + if ((xff_cfg->flags & XFF_EXTRADATA) && p->flow != NULL) { + char buffer[XFF_MAXLEN]; + int have_xff_ip = 0; + + if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = GetXFFIPFromTx(p, pa->tx_id, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); } else { - have_xff_ip = GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } - if (have_xff_ip) { - memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - SCLogDebug("valid ipv4 xff, setting flag"); - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); - } + } + + if (have_xff_ip) { + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA); + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA); } } - FLOWLOCK_UNLOCK(p->flow); } /* reset length and offset */ @@ -1026,19 +922,20 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) phdr->classification_id = htonl(pa->s->class); phdr->priority_id = htonl(pa->s->prio); - SCMutexLock(&aun->unified2alert_ctx->file_ctx->fp_mutex); - if ((aun->unified2alert_ctx->file_ctx->size_current + length) > - aun->unified2alert_ctx->file_ctx->size_limit) { - if (Unified2AlertRotateFile(t,aun) < 0) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexLock(&file_ctx->fp_mutex); + + bool truncate = (file_ctx->size_current + length) > file_ctx->size_limit + ? true : false; + if (truncate || file_ctx->rotation_flag) { + if (Unified2AlertRotateFile(aun, truncate) < 0) { + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } + file_ctx->rotation_flag = 0; } if (Unified2Write(aun) != 1) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -1052,13 +949,11 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) ret = Unified2PacketTypeAlert(aun, p, phdr->event_id, stream); if (ret != 1) { SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno)); - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } fflush(aun->unified2alert_ctx->file_ctx->fp); - aun->unified2alert_ctx->file_ctx->alerts++; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); } return 0; @@ -1077,6 +972,7 @@ static int Unified2IPv6TypeAlert(ThreadVars *t, const Packet *p, void *data) static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) { Unified2AlertThread *aun = (Unified2AlertThread *)data; + LogFileCtx *file_ctx = aun->unified2alert_ctx->file_ctx; Unified2AlertFileHeader hdr; AlertIPv4Unified2 *phdr; AlertIPv4Unified2 gphdr; @@ -1108,7 +1004,7 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) gphdr.src_ip = p->ip4h->s_ip_src.s_addr; gphdr.dst_ip = p->ip4h->s_ip_dst.s_addr; /** If XFF is in overwrite mode... */ - if (aun->xff_flags & UNIFIED2_ALERT_XFF_OVERWRITE) { + if (aun->xff_flags & XFF_OVERWRITE) { BUG_ON(aun->xff_flags & UNIFIED2_ALERT_XFF_IPV6); if (p->flowflags & FLOW_PKT_TOCLIENT) { @@ -1158,30 +1054,29 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) if (unlikely(pa->s == NULL)) continue; - if ((aun->unified2alert_ctx->xff_mode & UNIFIED2_ALERT_XFF_EXTRADATA) && p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); - if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { - char buffer[UNIFIED2_ALERT_XFF_MAXLEN]; - int have_xff_ip = 0; + HttpXFFCfg *xff_cfg = aun->unified2alert_ctx->xff_cfg; + if ((xff_cfg->flags & XFF_EXTRADATA) && p->flow != NULL) { + char buffer[XFF_MAXLEN]; + int have_xff_ip = 0; + + if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { if (pa->flags & PACKET_ALERT_FLAG_TX) { - have_xff_ip = GetXFFIPFromTx(p, pa->tx_id, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); } else { - have_xff_ip = GetXFFIP(p, aun->unified2alert_ctx->xff_header, buffer, UNIFIED2_ALERT_XFF_MAXLEN); + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); } - if (have_xff_ip) { - SCLogDebug("buffer %s", buffer); - memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); - - if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { - SCLogDebug("valid ipv4 xff, setting flags %s", buffer); - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|UNIFIED2_ALERT_XFF_EXTRADATA); - } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { - aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|UNIFIED2_ALERT_XFF_EXTRADATA); - } + } + + if (have_xff_ip) { + memset(aun->xff_ip, 0, 4 * sizeof(uint32_t)); + + if (inet_pton(AF_INET, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV4|XFF_EXTRADATA); + } else if (inet_pton(AF_INET6, buffer, aun->xff_ip) == 1) { + aun->xff_flags = (UNIFIED2_ALERT_XFF_IPV6|XFF_EXTRADATA); } } - FLOWLOCK_UNLOCK(p->flow); } /* reset length and offset */ @@ -1203,20 +1098,20 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) phdr->priority_id = htonl(pa->s->prio); /* check and enforce the filesize limit */ - SCMutexLock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexLock(&file_ctx->fp_mutex); - if ((aun->unified2alert_ctx->file_ctx->size_current + length) > - aun->unified2alert_ctx->file_ctx->size_limit) { - if (Unified2AlertRotateFile(tv,aun) < 0) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + bool truncate = (file_ctx->size_current + length) > file_ctx->size_limit + ? true : false; + if (truncate || file_ctx->rotation_flag) { + if (Unified2AlertRotateFile(aun, truncate) < 0) { + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } + file_ctx->rotation_flag = 0; } if (Unified2Write(aun) != 1) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } @@ -1231,14 +1126,12 @@ static int Unified2IPv4TypeAlert (ThreadVars *tv, const Packet *p, void *data) (pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0) : 0; ret = Unified2PacketTypeAlert(aun, p, event_id, stream); if (ret != 1) { - aun->unified2alert_ctx->file_ctx->alerts += i; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); return -1; } fflush(aun->unified2alert_ctx->file_ctx->fp); - aun->unified2alert_ctx->file_ctx->alerts++; - SCMutexUnlock(&aun->unified2alert_ctx->file_ctx->fp_mutex); + SCMutexUnlock(&file_ctx->fp_mutex); } return 0; @@ -1262,7 +1155,7 @@ TmEcode Unified2AlertThreadInit(ThreadVars *t, void *initdata, void **data) memset(aun, 0, sizeof(Unified2AlertThread)); if(initdata == NULL) { - SCLogDebug("Error getting context for Unified2Alert. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for AlertUnified2. \"initdata\" argument NULL"); SCFree(aun); return TM_ECODE_FAILED; } @@ -1300,8 +1193,8 @@ TmEcode Unified2AlertThreadDeinit(ThreadVars *t, void *data) } if (!(aun->unified2alert_ctx->file_ctx->flags & LOGFILE_ALERTS_PRINTED)) { - SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts", - aun->unified2alert_ctx->file_ctx->alerts); + //SCLogInfo("Alert unified2 module wrote %"PRIu64" alerts", + // aun->unified2alert_ctx->file_ctx->alerts); /* Do not print it for each thread */ aun->unified2alert_ctx->file_ctx->flags |= LOGFILE_ALERTS_PRINTED; @@ -1331,7 +1224,8 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) int ret = 0; LogFileCtx* file_ctx = NULL; OutputCtx* output_ctx = NULL; - ConfNode *xff_node = NULL; + HttpXFFCfg *xff_cfg = NULL; + int nostamp = 0; file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { @@ -1385,59 +1279,64 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } } + + if (ConfGetChildValueBool(conf, "nostamp", &nostamp)) { + if (nostamp) { + SCLogConfig("Disabling unified2 timestamp."); + file_ctx->nostamp = true; + } + } + } + + uint32_t flags = UNIFIED2_ALERT_FLAGS_EMIT_PACKET; + if (conf != NULL) { + const char *payload = NULL; + payload = ConfNodeLookupChildValue(conf, "payload"); + if (payload) { + if (ConfValIsFalse(payload)) { + flags &= ~UNIFIED2_ALERT_FLAGS_EMIT_PACKET; + } else if (!ConfValIsTrue(payload)) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid payload: %s", payload); + exit(EXIT_FAILURE); + } + } } - ret = Unified2AlertOpenFileCtx(file_ctx, filename); + ret = Unified2AlertOpenFileCtx(file_ctx, filename, false); if (ret < 0) goto error; + /* Only register for file rotation if theout is non-timestamped. */ + if (nostamp) { + OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); + } + output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) goto error; + xff_cfg = SCMalloc(sizeof(HttpXFFCfg)); + if (unlikely(xff_cfg == NULL)) { + goto error; + } + memset(xff_cfg, 0x00, sizeof(HttpXFFCfg)); + + if (conf != NULL) { + HttpXFFGetCfg(conf, xff_cfg); + } + Unified2AlertFileCtx *unified2alert_ctx = SCMalloc(sizeof(Unified2AlertFileCtx)); if (unlikely(unified2alert_ctx == NULL)) { goto error; } memset(unified2alert_ctx, 0x00, sizeof(Unified2AlertFileCtx)); + unified2alert_ctx->file_ctx = file_ctx; + unified2alert_ctx->xff_cfg = xff_cfg; + unified2alert_ctx->flags = flags; output_ctx->data = unified2alert_ctx; - output_ctx->DeInit = Unified2AlertDeInitCtx; - if (conf != NULL) - xff_node = ConfNodeLookupChild(conf, "xff"); - - if (xff_node != NULL && ConfNodeChildValueIsTrue(xff_node, "enabled")) { - const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); - - if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { - unified2alert_ctx->xff_mode |= UNIFIED2_ALERT_XFF_OVERWRITE; - } else { - if (xff_mode == NULL) { - SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The unified2 output XFF mode hasn't been defined, falling back to extra-data mode"); - } - else if (strcasecmp(xff_mode, "extra-data") != 0) { - SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The unified2 output XFF mode %s is invalid, falling back to extra-data mode", - xff_mode); - } - unified2alert_ctx->xff_mode |= UNIFIED2_ALERT_XFF_EXTRADATA; - } - - const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); - - if (xff_header != NULL) { - unified2alert_ctx->xff_header = (char *) xff_header; - } else { - SCLogWarning(SC_WARN_XFF_INVALID_HEADER, "The unified2 output XFF header hasn't been defined, using the default %s", - UNIFIED2_ALERT_XFF_DEFAULT); - unified2alert_ctx->xff_header = UNIFIED2_ALERT_XFF_DEFAULT; - } - } - else { - unified2alert_ctx->xff_mode = UNIFIED2_ALERT_XFF_DISABLED; - } - SCLogInfo("Unified2-alert initialized: filename %s, limit %"PRIu64" MB", filename, file_ctx->size_limit / (1024*1024)); @@ -1446,6 +1345,9 @@ OutputCtx *Unified2AlertInitCtx(ConfNode *conf) return output_ctx; error: + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } if (output_ctx != NULL) { SCFree(output_ctx); } @@ -1462,6 +1364,10 @@ static void Unified2AlertDeInitCtx(OutputCtx *output_ctx) if (logfile_ctx != NULL) { LogFileFreeCtx(logfile_ctx); } + HttpXFFCfg *xff_cfg = unified2alert_ctx->xff_cfg; + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } SCFree(unified2alert_ctx); } SCFree(output_ctx); @@ -1473,7 +1379,8 @@ static void Unified2AlertDeInitCtx(OutputCtx *output_ctx) * \param prefix Prefix of the log file. * \return -1 if failure, 0 if succesful * */ -int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix) +static int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix, + bool truncate) { int ret = 0; char *filename = NULL; @@ -1502,9 +1409,17 @@ int Unified2AlertOpenFileCtx(LogFileCtx *file_ctx, const char *prefix) char *log_dir; log_dir = ConfigGetLogDirectory(); - snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec); + if (file_ctx->nostamp) { + snprintf(filename, PATH_MAX, "%s/%s", log_dir, prefix); + } else { + snprintf(filename, PATH_MAX, "%s/%s.%" PRIu32, log_dir, prefix, (uint32_t)ts.tv_sec); + } - file_ctx->fp = fopen(filename, "ab"); + if (truncate) { + file_ctx->fp = fopen(filename, "wb"); + } else { + file_ctx->fp = fopen(filename, "ab"); + } if (file_ctx->fp == NULL) { SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", filename, strerror(errno)); @@ -1557,10 +1472,10 @@ static int Unified2Test01(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv4_tcp)); FlowInitConfig(FLOW_QUIET); @@ -1648,10 +1563,10 @@ static int Unified2Test02(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv6_tcp)); FlowInitConfig(FLOW_QUIET); @@ -1745,10 +1660,10 @@ static int Unified2Test03(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_gre)); FlowInitConfig(FLOW_QUIET); @@ -1842,10 +1757,10 @@ static int Unified2Test04(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ppp)); FlowInitConfig(FLOW_QUIET); @@ -1930,10 +1845,10 @@ static int Unified2Test05(void) memset(&s, 0, sizeof(Signature)); p->alerts.cnt++; + s.id = 1; + s.gid = 1; + s.rev = 1; p->alerts.alerts[p->alerts.cnt-1].s = &s; - p->alerts.alerts[p->alerts.cnt-1].s->id = 1; - p->alerts.alerts[p->alerts.cnt-1].s->gid = 1; - p->alerts.alerts[p->alerts.cnt-1].s->rev = 1; SET_PKT_LEN(p, sizeof(raw_ipv4_tcp)); FlowInitConfig(FLOW_QUIET); @@ -2022,7 +1937,7 @@ static int Unified2TestRotate01(void) TimeSetIncrementTime(1); - ret = Unified2AlertRotateFile(&tv, data); + ret = Unified2AlertRotateFile(data, false); if (ret == -1) goto error; @@ -2052,13 +1967,13 @@ static int Unified2TestRotate01(void) */ void Unified2RegisterTests(void) { - PacketPoolInit(); #ifdef UNITTESTS - UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01, 1); - UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02, 1); - UtRegisterTest("Unified2Test03 -- GRE test", Unified2Test03, 1); - UtRegisterTest("Unified2Test04 -- PPP test", Unified2Test04, 1); - UtRegisterTest("Unified2Test05 -- Inline test", Unified2Test05, 1); - UtRegisterTest("Unified2TestRotate01 -- Rotate File", Unified2TestRotate01, 1); + UtRegisterTest("Unified2Test01 -- Ipv4 test", Unified2Test01); + UtRegisterTest("Unified2Test02 -- Ipv6 test", Unified2Test02); + UtRegisterTest("Unified2Test03 -- GRE test", Unified2Test03); + UtRegisterTest("Unified2Test04 -- PPP test", Unified2Test04); + UtRegisterTest("Unified2Test05 -- Inline test", Unified2Test05); + UtRegisterTest("Unified2TestRotate01 -- Rotate File", + Unified2TestRotate01); #endif /* UNITTESTS */ } diff --git a/src/alert-unified2-alert.h b/src/alert-unified2-alert.h index d4d3b2ec1536..ae068a1d4e89 100644 --- a/src/alert-unified2-alert.h +++ b/src/alert-unified2-alert.h @@ -43,7 +43,7 @@ #define UNIFIED2_EXTRADATA_TYPE_BLOB 1 #define UNIFIED2_EXTRADATA_TYPE_EXTRA_DATA 4 -void TmModuleUnified2AlertRegister(void); +void Unified2AlertRegister(void); OutputCtx *Unified2AlertInitCtx(ConfNode *); #endif /* __ALERT_UNIFIED2_ALERT_H__ */ diff --git a/src/app-layer-dcerpc-common.h b/src/app-layer-dcerpc-common.h index cdda563009d1..72fe4574fb44 100644 --- a/src/app-layer-dcerpc-common.h +++ b/src/app-layer-dcerpc-common.h @@ -145,6 +145,8 @@ typedef struct DCERPCUuidEntry_ { TAILQ_ENTRY(DCERPCUuidEntry_) next; } DCERPCUuidEntry; +typedef TAILQ_HEAD(DCERPCUuidEntryList_, DCERPCUuidEntry_) DCERPCUuidEntryList; + typedef struct DCERPCBindBindAck_ { uint8_t numctxitems; uint8_t numctxitemsleft; @@ -154,9 +156,9 @@ typedef struct DCERPCBindBindAck_ { uint16_t version; uint16_t versionminor; DCERPCUuidEntry *uuid_entry; - TAILQ_HEAD(, DCERPCUuidEntry_) uuid_list; + DCERPCUuidEntryList uuid_list; /* the interface uuids that the server has accepted */ - TAILQ_HEAD(, DCERPCUuidEntry_) accepted_uuid_list; + DCERPCUuidEntryList accepted_uuid_list; uint16_t uuid_internal_id; uint16_t secondaryaddrlen; uint16_t secondaryaddrlenleft; diff --git a/src/app-layer-dcerpc-udp.c b/src/app-layer-dcerpc-udp.c index c44bdbb370a3..7852a4b0bae1 100644 --- a/src/app-layer-dcerpc-udp.c +++ b/src/app-layer-dcerpc-udp.c @@ -1,5 +1,22 @@ /* * Copyright (c) 2009, 2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* \file * * \author Kirby Kuehl * @@ -36,21 +53,22 @@ #include "app-layer-dcerpc-udp.h" enum { - DCERPC_FIELD_NONE = 0, - DCERPC_PARSE_DCERPC_HEADER, - DCERPC_PARSE_DCERPC_BIND, - DCERPC_PARSE_DCERPC_BIND_ACK, - DCERPC_PARSE_DCERPC_REQUEST, - /* must be last */ - DCERPC_FIELD_MAX, + DCERPC_FIELD_NONE = 0, + DCERPC_PARSE_DCERPC_HEADER, + DCERPC_PARSE_DCERPC_BIND, + DCERPC_PARSE_DCERPC_BIND_ACK, + DCERPC_PARSE_DCERPC_REQUEST, + /* must be last */ + DCERPC_FIELD_MAX, }; +/** \internal + * \retval stub_len or 0 in case of error */ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, - AppLayerParserState *pstate, - uint8_t *input, uint32_t input_len) + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) { - SCEnter(); - DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; + SCEnter(); + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; uint8_t **stub_data_buffer = NULL; uint32_t *stub_data_buffer_len = NULL; uint8_t *stub_data_fresh = NULL; @@ -88,7 +106,7 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, SCFree(*stub_data_buffer); *stub_data_buffer = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - goto end; + SCReturnUInt(0); } *stub_data_buffer = ptmp; @@ -98,8 +116,8 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, /* length of the buffered stub */ *stub_data_buffer_len += stub_len; - sstate->dcerpc.fraglenleft -= stub_len; - sstate->dcerpc.bytesprocessed += stub_len; + sstate->dcerpc.fraglenleft -= stub_len; + sstate->dcerpc.bytesprocessed += stub_len; #ifdef DEBUG if (SCLogDebugEnabled()) { @@ -110,7 +128,6 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, } #endif -end: SCReturnUInt((uint32_t)stub_len); } @@ -121,673 +138,677 @@ static uint32_t FragmentDataParser(Flow *f, void *dcerpcudp_state, * fragmented packets. */ static int DCERPCUDPParseHeader(Flow *f, void *dcerpcudp_state, - AppLayerParserState *pstate, - uint8_t *input, uint32_t input_len) + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len) { - SCEnter(); - uint8_t *p = input; - DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; - if (input_len) { - switch (sstate->bytesprocessed) { - case 0: - // fallthrough - /* above statement to prevent coverity FPs from the switch - * fall through */ - if (input_len >= DCERPC_UDP_HDR_LEN) { - sstate->dcerpc.dcerpchdrudp.rpc_vers = *p; - if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { - SCLogDebug("DCERPC UDP Header did not validate"); - SCReturnInt(-1); - } - sstate->dcerpc.dcerpchdrudp.type = *(p + 1); - sstate->dcerpc.dcerpchdrudp.flags1 = *(p + 2); - sstate->dcerpc.dcerpchdrudp.flags2 = *(p + 3); - sstate->dcerpc.dcerpchdrudp.drep[0] = *(p + 4); - sstate->dcerpc.dcerpchdrudp.drep[1] = *(p + 5); - sstate->dcerpc.dcerpchdrudp.drep[2] = *(p + 6); - sstate->dcerpc.dcerpchdrudp.serial_hi = *(p + 7); - sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p + 8); - sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p + 9); - sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p + 10); - sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p + 11); - sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p + 12); - sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p + 13); - sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p + 14); - sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p + 15); - sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p + 16); - sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p + 17); - sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p + 18); - sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p + 19); - sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p + 20); - sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p + 21); - sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p + 22); - sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p + 23); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p + 24); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p + 25); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p + 26); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p + 27); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p + 28); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p + 29); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p + 30); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p + 31); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p + 32); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p + 33); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p + 34); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p + 35); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p + 36); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p + 37); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p + 38); - sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p + 39); - sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p + 40); - sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p + 41); - sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p + 42); - sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p + 43); - sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p + 44); - sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p + 45); - sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p + 46); - sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p + 47); - sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p + 48); - sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p + 49); - sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p + 50); - sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p + 51); - sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p + 52); - sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p + 53); - sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p + 54); - sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p + 55); - if (sstate->dcerpc.dcerpchdrudp.drep[0] == 0x10) { - sstate->dcerpc.dcerpchdrudp.server_boot = *(p + 56); - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 57) << 8; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 58) << 16; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 59) << 24; - sstate->dcerpc.dcerpchdrudp.if_vers = *(p + 60); - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 61) << 8; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 62) << 16; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 63) << 24; - sstate->dcerpc.dcerpchdrudp.seqnum = *(p + 64); - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 65) << 8; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 66) << 16; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 67) << 24; - sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68); - sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 8; - sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70); - sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71) << 8; - sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72); - sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73) << 8; - sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74); - sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75) << 8; - sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76); - sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77) << 8; - } else { - sstate->dcerpc.dcerpchdrudp.server_boot = *(p + 56) << 24; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 57) << 16; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 58) << 8; - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p + 59); - sstate->dcerpc.dcerpchdrudp.if_vers = *(p + 60) << 24; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 61) << 16; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 62) << 8; - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p + 63); - sstate->dcerpc.dcerpchdrudp.seqnum = *(p + 64) << 24; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 65) << 16; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 66) << 8; - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p + 67); - sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68) << 24; - sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 16; - sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70) << 8; - sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71); - sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72) << 8; - sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73); - sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74) << 8; - sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75); - sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76) << 8; - sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77); - } - sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; - sstate->dcerpc.dcerpchdrudp.auth_proto = *(p + 78); - sstate->dcerpc.dcerpchdrudp.serial_lo = *(p + 79); - sstate->bytesprocessed = DCERPC_UDP_HDR_LEN; - sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, - sizeof(DCERPCUuidEntry)); - if (sstate->uuid_entry == NULL) { - SCReturnUInt(-1); - } else { - memcpy(sstate->uuid_entry->uuid, - sstate->dcerpc.dcerpchdrudp.activityuuid, - sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); - TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, - next); + SCEnter(); + uint8_t *p = input; + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpcudp_state; + if (input_len) { + switch (sstate->bytesprocessed) { + case 0: + // fallthrough + /* above statement to prevent coverity FPs from the switch + * fall through */ + if (input_len >= DCERPC_UDP_HDR_LEN) { + sstate->dcerpc.dcerpchdrudp.rpc_vers = *p; + if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { + SCLogDebug("DCERPC UDP Header did not validate"); + SCReturnInt(-1); + } + sstate->dcerpc.dcerpchdrudp.type = *(p + 1); + sstate->dcerpc.dcerpchdrudp.flags1 = *(p + 2); + sstate->dcerpc.dcerpchdrudp.flags2 = *(p + 3); + sstate->dcerpc.dcerpchdrudp.drep[0] = *(p + 4); + sstate->dcerpc.dcerpchdrudp.drep[1] = *(p + 5); + sstate->dcerpc.dcerpchdrudp.drep[2] = *(p + 6); + sstate->dcerpc.dcerpchdrudp.serial_hi = *(p + 7); + sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p + 8); + sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p + 9); + sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p + 10); + sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p + 11); + sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p + 12); + sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p + 13); + sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p + 14); + sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p + 15); + sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p + 16); + sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p + 17); + sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p + 18); + sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p + 19); + sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p + 20); + sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p + 21); + sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p + 22); + sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p + 23); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p + 24); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p + 25); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p + 26); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p + 27); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p + 28); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p + 29); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p + 30); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p + 31); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p + 32); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p + 33); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p + 34); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p + 35); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p + 36); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p + 37); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p + 38); + sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p + 39); + sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p + 40); + sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p + 41); + sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p + 42); + sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p + 43); + sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p + 44); + sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p + 45); + sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p + 46); + sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p + 47); + sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p + 48); + sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p + 49); + sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p + 50); + sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p + 51); + sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p + 52); + sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p + 53); + sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p + 54); + sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p + 55); + if (sstate->dcerpc.dcerpchdrudp.drep[0] == 0x10) { + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56); + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60); + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64); + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67) << 24; + sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68); + sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 8; + sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70); + sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71) << 8; + sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72); + sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73) << 8; + sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74); + sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75) << 8; + sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76); + sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77) << 8; + } else { + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p + 56) << 24; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 57) << 16; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 58) << 8; + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p + 59); + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p + 60) << 24; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 61) << 16; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 62) << 8; + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p + 63); + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p + 64) << 24; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 65) << 16; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 66) << 8; + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p + 67); + sstate->dcerpc.dcerpchdrudp.opnum = *(p + 68) << 24; + sstate->dcerpc.dcerpchdrudp.opnum |= *(p + 69) << 16; + sstate->dcerpc.dcerpchdrudp.ihint = *(p + 70) << 8; + sstate->dcerpc.dcerpchdrudp.ihint |= *(p + 71); + sstate->dcerpc.dcerpchdrudp.ahint = *(p + 72) << 8; + sstate->dcerpc.dcerpchdrudp.ahint |= *(p + 73); + sstate->dcerpc.dcerpchdrudp.fraglen = *(p + 74) << 8; + sstate->dcerpc.dcerpchdrudp.fraglen |= *(p + 75); + sstate->dcerpc.dcerpchdrudp.fragnum = *(p + 76) << 8; + sstate->dcerpc.dcerpchdrudp.fragnum |= *(p + 77); + } + sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; + sstate->dcerpc.dcerpchdrudp.auth_proto = *(p + 78); + sstate->dcerpc.dcerpchdrudp.serial_lo = *(p + 79); + sstate->bytesprocessed = DCERPC_UDP_HDR_LEN; + sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, + sizeof(DCERPCUuidEntry)); + if (sstate->uuid_entry == NULL) { + SCReturnUInt(-1); + } else { + memcpy(sstate->uuid_entry->uuid, + sstate->dcerpc.dcerpchdrudp.activityuuid, + sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); + TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, + next); #ifdef UNITTESTS - if (RunmodeIsUnittests()) { - printUUID("DCERPC UDP", sstate->uuid_entry); + if (RunmodeIsUnittests()) { + printUUID("DCERPC UDP", sstate->uuid_entry); - } + } #endif - } - SCReturnUInt(80); - break; - } else { - sstate->dcerpc.dcerpchdrudp.rpc_vers = *(p++); - if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { - SCLogDebug("DCERPC UDP Header did not validate"); - SCReturnInt(-1); - } - if (!(--input_len)) - break; - /* We fall through to the next case if we still have input. - * Same applies for other cases as well */ - } - /* fall through */ - case 1: - sstate->dcerpc.dcerpchdrudp.type = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 2: - sstate->dcerpc.dcerpchdrudp.flags1 = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 3: - sstate->dcerpc.dcerpchdrudp.flags2 = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 4: - sstate->dcerpc.dcerpchdrudp.drep[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 5: - sstate->dcerpc.dcerpchdrudp.drep[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 6: - sstate->dcerpc.dcerpchdrudp.drep[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 7: - sstate->dcerpc.dcerpchdrudp.serial_hi = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 8: - sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 9: - sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 10: - sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 11: - sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 12: - sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 13: - sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 14: - sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 15: - sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 16: - sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 17: - sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 18: - sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 19: - sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 20: - sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 21: - sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 22: - sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 23: - sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 24: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 25: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 26: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 27: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 28: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 29: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 30: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 31: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 32: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 33: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 34: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 35: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 36: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 37: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 38: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 39: - sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 40: - sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 41: - sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 42: - sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 43: - sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 44: - sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 45: - sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 46: - sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 47: - sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 48: - sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 49: - sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 50: - sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 51: - sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 52: - sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 53: - sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 54: - sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 55: - sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 56: - sstate->dcerpc.dcerpchdrudp.server_boot = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 57: - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 58: - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 16; - if (!(--input_len)) - break; - /* fall through */ - case 59: - sstate->dcerpc.dcerpchdrudp.server_boot |= *(p++) << 24; - if (!(--input_len)) - break; - /* fall through */ - case 60: - sstate->dcerpc.dcerpchdrudp.if_vers = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 61: - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 62: - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 16; - if (!(--input_len)) - break; - /* fall through */ - case 63: - sstate->dcerpc.dcerpchdrudp.if_vers |= *(p++) << 24; - if (!(--input_len)) - break; - /* fall through */ - case 64: - sstate->dcerpc.dcerpchdrudp.seqnum = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 65: - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 66: - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 16; - if (!(--input_len)) - break; - /* fall through */ - case 67: - sstate->dcerpc.dcerpchdrudp.seqnum |= *(p++) << 24; - if (!(--input_len)) - break; - /* fall through */ - case 68: - sstate->dcerpc.dcerpchdrudp.opnum = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 69: - sstate->dcerpc.dcerpchdrudp.opnum |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 70: - sstate->dcerpc.dcerpchdrudp.ihint = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 71: - sstate->dcerpc.dcerpchdrudp.ihint |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 72: - sstate->dcerpc.dcerpchdrudp.ahint = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 73: - sstate->dcerpc.dcerpchdrudp.ahint |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 74: - sstate->dcerpc.dcerpchdrudp.fraglen = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 75: - sstate->dcerpc.dcerpchdrudp.fraglen |= *(p++) << 8; - if (!(--input_len)) - break; - /* fall through */ - case 76: - sstate->dcerpc.dcerpchdrudp.fragnum = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 77: - sstate->dcerpc.dcerpchdrudp.fragnum |= *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 78: - sstate->dcerpc.dcerpchdrudp.auth_proto = *(p++); - if (!(--input_len)) - break; - /* fall through */ - case 79: - sstate->dcerpc.dcerpchdrudp.serial_lo = *(p++); - if (sstate->dcerpc.dcerpchdrudp.drep[0] != 0x10) { - sstate->dcerpc.dcerpchdrudp.server_boot = SCByteSwap32(sstate->dcerpc.dcerpchdrudp.server_boot); - sstate->dcerpc.dcerpchdrudp.if_vers= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.if_vers); - sstate->dcerpc.dcerpchdrudp.seqnum= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.seqnum); - sstate->dcerpc.dcerpchdrudp.opnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.opnum); - sstate->dcerpc.dcerpchdrudp.ihint= SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ihint); - sstate->dcerpc.dcerpchdrudp.ahint = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ahint); - sstate->dcerpc.dcerpchdrudp.fraglen = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fraglen); - sstate->dcerpc.dcerpchdrudp.fragnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fragnum); - } - sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; - sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, - sizeof(DCERPCUuidEntry)); - if (sstate->uuid_entry == NULL) { - SCReturnUInt(-1); - } else { - memcpy(sstate->uuid_entry->uuid, - sstate->dcerpc.dcerpchdrudp.activityuuid, - sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); - TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, - next); + } + SCReturnUInt(80); + break; + } else { + sstate->dcerpc.dcerpchdrudp.rpc_vers = *(p++); + if (sstate->dcerpc.dcerpchdrudp.rpc_vers != 4) { + SCLogDebug("DCERPC UDP Header did not validate"); + SCReturnInt(-1); + } + if (!(--input_len)) + break; + /* We fall through to the next case if we still have input. + * Same applies for other cases as well */ + } + /* fall through */ + case 1: + sstate->dcerpc.dcerpchdrudp.type = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 2: + sstate->dcerpc.dcerpchdrudp.flags1 = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 3: + sstate->dcerpc.dcerpchdrudp.flags2 = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 4: + sstate->dcerpc.dcerpchdrudp.drep[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 5: + sstate->dcerpc.dcerpchdrudp.drep[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 6: + sstate->dcerpc.dcerpchdrudp.drep[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 7: + sstate->dcerpc.dcerpchdrudp.serial_hi = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 8: + sstate->dcerpc.dcerpchdrudp.objectuuid[3] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 9: + sstate->dcerpc.dcerpchdrudp.objectuuid[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 10: + sstate->dcerpc.dcerpchdrudp.objectuuid[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 11: + sstate->dcerpc.dcerpchdrudp.objectuuid[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 12: + sstate->dcerpc.dcerpchdrudp.objectuuid[5] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 13: + sstate->dcerpc.dcerpchdrudp.objectuuid[4] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 14: + sstate->dcerpc.dcerpchdrudp.objectuuid[7] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 15: + sstate->dcerpc.dcerpchdrudp.objectuuid[6] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 16: + sstate->dcerpc.dcerpchdrudp.objectuuid[8] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 17: + sstate->dcerpc.dcerpchdrudp.objectuuid[9] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 18: + sstate->dcerpc.dcerpchdrudp.objectuuid[10] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 19: + sstate->dcerpc.dcerpchdrudp.objectuuid[11] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 20: + sstate->dcerpc.dcerpchdrudp.objectuuid[12] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 21: + sstate->dcerpc.dcerpchdrudp.objectuuid[13] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 22: + sstate->dcerpc.dcerpchdrudp.objectuuid[14] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 23: + sstate->dcerpc.dcerpchdrudp.objectuuid[15] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 24: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[3] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 25: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 26: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 27: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 28: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[5] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 29: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[4] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 30: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[7] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 31: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[6] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 32: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[8] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 33: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[9] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 34: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[10] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 35: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[11] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 36: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[12] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 37: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[13] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 38: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[14] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 39: + sstate->dcerpc.dcerpchdrudp.interfaceuuid[15] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 40: + sstate->dcerpc.dcerpchdrudp.activityuuid[3] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 41: + sstate->dcerpc.dcerpchdrudp.activityuuid[2] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 42: + sstate->dcerpc.dcerpchdrudp.activityuuid[1] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 43: + sstate->dcerpc.dcerpchdrudp.activityuuid[0] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 44: + sstate->dcerpc.dcerpchdrudp.activityuuid[5] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 45: + sstate->dcerpc.dcerpchdrudp.activityuuid[4] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 46: + sstate->dcerpc.dcerpchdrudp.activityuuid[7] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 47: + sstate->dcerpc.dcerpchdrudp.activityuuid[6] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 48: + sstate->dcerpc.dcerpchdrudp.activityuuid[8] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 49: + sstate->dcerpc.dcerpchdrudp.activityuuid[9] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 50: + sstate->dcerpc.dcerpchdrudp.activityuuid[10] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 51: + sstate->dcerpc.dcerpchdrudp.activityuuid[11] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 52: + sstate->dcerpc.dcerpchdrudp.activityuuid[12] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 53: + sstate->dcerpc.dcerpchdrudp.activityuuid[13] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 54: + sstate->dcerpc.dcerpchdrudp.activityuuid[14] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 55: + sstate->dcerpc.dcerpchdrudp.activityuuid[15] = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 56: + sstate->dcerpc.dcerpchdrudp.server_boot = (uint32_t) *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 57: + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 58: + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 16; + if (!(--input_len)) + break; + /* fall through */ + case 59: + sstate->dcerpc.dcerpchdrudp.server_boot |= (uint32_t) *(p++) << 24; + if (!(--input_len)) + break; + /* fall through */ + case 60: + sstate->dcerpc.dcerpchdrudp.if_vers = (uint32_t) *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 61: + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 62: + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 16; + if (!(--input_len)) + break; + /* fall through */ + case 63: + sstate->dcerpc.dcerpchdrudp.if_vers |= (uint32_t) *(p++) << 24; + if (!(--input_len)) + break; + /* fall through */ + case 64: + sstate->dcerpc.dcerpchdrudp.seqnum = (uint32_t) *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 65: + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 66: + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 16; + if (!(--input_len)) + break; + /* fall through */ + case 67: + sstate->dcerpc.dcerpchdrudp.seqnum |= (uint32_t) *(p++) << 24; + if (!(--input_len)) + break; + /* fall through */ + case 68: + sstate->dcerpc.dcerpchdrudp.opnum = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 69: + sstate->dcerpc.dcerpchdrudp.opnum |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 70: + sstate->dcerpc.dcerpchdrudp.ihint = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 71: + sstate->dcerpc.dcerpchdrudp.ihint |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 72: + sstate->dcerpc.dcerpchdrudp.ahint = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 73: + sstate->dcerpc.dcerpchdrudp.ahint |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 74: + sstate->dcerpc.dcerpchdrudp.fraglen = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 75: + sstate->dcerpc.dcerpchdrudp.fraglen |= *(p++) << 8; + if (!(--input_len)) + break; + /* fall through */ + case 76: + sstate->dcerpc.dcerpchdrudp.fragnum = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 77: + sstate->dcerpc.dcerpchdrudp.fragnum |= *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 78: + sstate->dcerpc.dcerpchdrudp.auth_proto = *(p++); + if (!(--input_len)) + break; + /* fall through */ + case 79: + sstate->dcerpc.dcerpchdrudp.serial_lo = *(p++); + if (sstate->dcerpc.dcerpchdrudp.drep[0] != 0x10) { + sstate->dcerpc.dcerpchdrudp.server_boot = SCByteSwap32(sstate->dcerpc.dcerpchdrudp.server_boot); + sstate->dcerpc.dcerpchdrudp.if_vers= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.if_vers); + sstate->dcerpc.dcerpchdrudp.seqnum= SCByteSwap32(sstate->dcerpc.dcerpchdrudp.seqnum); + sstate->dcerpc.dcerpchdrudp.opnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.opnum); + sstate->dcerpc.dcerpchdrudp.ihint= SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ihint); + sstate->dcerpc.dcerpchdrudp.ahint = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.ahint); + sstate->dcerpc.dcerpchdrudp.fraglen = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fraglen); + sstate->dcerpc.dcerpchdrudp.fragnum = SCByteSwap16(sstate->dcerpc.dcerpchdrudp.fragnum); + } + sstate->fraglenleft = sstate->dcerpc.dcerpchdrudp.fraglen; + sstate->uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, + sizeof(DCERPCUuidEntry)); + if (sstate->uuid_entry == NULL) { + SCReturnUInt(-1); + } else { + memcpy(sstate->uuid_entry->uuid, + sstate->dcerpc.dcerpchdrudp.activityuuid, + sizeof(sstate->dcerpc.dcerpchdrudp.activityuuid)); + TAILQ_INSERT_HEAD(&sstate->uuid_list, sstate->uuid_entry, + next); #ifdef UNITTESTS - if (RunmodeIsUnittests()) { - printUUID("DCERPC UDP", sstate->uuid_entry); - } + if (RunmodeIsUnittests()) { + printUUID("DCERPC UDP", sstate->uuid_entry); + } #endif - } - --input_len; - break; - } - } - sstate->bytesprocessed += (p - input); - SCReturnInt((p - input)); + } + --input_len; + break; + } + } + sstate->bytesprocessed += (p - input); + SCReturnInt((p - input)); } static int DCERPCUDPParse(Flow *f, void *dcerpc_state, - AppLayerParserState *pstate, - uint8_t *input, uint32_t input_len, - void *local_data) + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, + void *local_data) { - uint32_t retval = 0; - uint32_t parsed = 0; - int hdrretval = 0; - SCEnter(); + uint32_t retval = 0; + uint32_t parsed = 0; + int hdrretval = 0; + SCEnter(); - DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; - while (sstate->bytesprocessed < DCERPC_UDP_HDR_LEN && input_len) { - hdrretval = DCERPCUDPParseHeader(f, dcerpc_state, pstate, input, - input_len); - if (hdrretval == -1 || hdrretval > (int32_t)input_len) { - sstate->bytesprocessed = 0; - SCReturnInt(hdrretval); - } else { - parsed += hdrretval; - input_len -= hdrretval; - } - } + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + + DCERPCUDPState *sstate = (DCERPCUDPState *) dcerpc_state; + while (sstate->bytesprocessed < DCERPC_UDP_HDR_LEN && input_len) { + hdrretval = DCERPCUDPParseHeader(f, dcerpc_state, pstate, input, + input_len); + if (hdrretval == -1 || hdrretval > (int32_t)input_len) { + sstate->bytesprocessed = 0; + SCReturnInt(hdrretval); + } else { + parsed += hdrretval; + input_len -= hdrretval; + } + } #if 0 - printf("Done with DCERPCUDPParseHeader bytesprocessed %u/%u left %u\n", - sstate->bytesprocessed, sstate->dcerpc.dcerpchdrudp.fraglen, input_len); - printf("\nDCERPC Version:\t%u\n", sstate->dcerpc.dcerpchdrudp.rpc_vers); - printf("DCERPC Type:\t%u\n", sstate->dcerpc.dcerpchdrudp.ptype); - printf("DCERPC Flags1:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags1); - printf("DCERPC Flags2:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags2); - printf("DCERPC Packed Drep:\t%02x %02x %02x\n", - sstate->dcerpc.dcerpchdrudp.drep[0], sstate->dcerpc.dcerpchdrudp.drep[1], - sstate->dcerpc.dcerpchdrudp.drep[2]); - printf("DCERPC Frag Length:\t0x%04x %u\n", sstate->dcerpc.dcerpchdrudp.fraglen, - sstate->dcerpc.dcerpchdrudp.fraglen); - printf("DCERPC Frag Number:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.fragnum); - printf("DCERPC OpNum:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.opnum); + printf("Done with DCERPCUDPParseHeader bytesprocessed %u/%u left %u\n", + sstate->bytesprocessed, sstate->dcerpc.dcerpchdrudp.fraglen, input_len); + printf("\nDCERPC Version:\t%u\n", sstate->dcerpc.dcerpchdrudp.rpc_vers); + printf("DCERPC Type:\t%u\n", sstate->dcerpc.dcerpchdrudp.ptype); + printf("DCERPC Flags1:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags1); + printf("DCERPC Flags2:\t0x%02x\n", sstate->dcerpc.dcerpchdrudp.flags2); + printf("DCERPC Packed Drep:\t%02x %02x %02x\n", + sstate->dcerpc.dcerpchdrudp.drep[0], sstate->dcerpc.dcerpchdrudp.drep[1], + sstate->dcerpc.dcerpchdrudp.drep[2]); + printf("DCERPC Frag Length:\t0x%04x %u\n", sstate->dcerpc.dcerpchdrudp.fraglen, + sstate->dcerpc.dcerpchdrudp.fraglen); + printf("DCERPC Frag Number:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.fragnum); + printf("DCERPC OpNum:\t0x%04x\n", sstate->dcerpc.dcerpchdrudp.opnum); #endif - while (sstate->bytesprocessed >= DCERPC_UDP_HDR_LEN - && sstate->bytesprocessed < sstate->dcerpc.dcerpchdrudp.fraglen - && input_len) { - retval = FragmentDataParser(f, dcerpc_state, pstate, input + parsed, - input_len); - if (retval || retval > input_len) { - parsed += retval; - input_len -= retval; - } else if (input_len) { - SCLogDebug("Error parsing DCERPC UDP Fragment Data"); - parsed -= input_len; - input_len = 0; - sstate->bytesprocessed = 0; - } - } + while (sstate->bytesprocessed >= DCERPC_UDP_HDR_LEN + && sstate->bytesprocessed < sstate->dcerpc.dcerpchdrudp.fraglen + && input_len) { + retval = FragmentDataParser(f, dcerpc_state, pstate, input + parsed, + input_len); + if (retval || retval > input_len) { + parsed += retval; + input_len -= retval; + } else if (input_len) { + SCLogDebug("Error parsing DCERPC UDP Fragment Data"); + parsed -= input_len; + input_len = 0; + sstate->bytesprocessed = 0; + } + } - if (sstate->bytesprocessed == sstate->dcerpc.dcerpchdrudp.fraglen) { - sstate->bytesprocessed = 0; - } - if (pstate == NULL) - SCReturnInt(-1); + if (sstate->bytesprocessed == sstate->dcerpc.dcerpchdrudp.fraglen) { + sstate->bytesprocessed = 0; + } + if (pstate == NULL) + SCReturnInt(-1); - SCReturnInt(1); + SCReturnInt(1); } static void *DCERPCUDPStateAlloc(void) { - void *s = SCMalloc(sizeof(DCERPCUDPState)); - if (unlikely(s == NULL)) - return NULL; + void *s = SCMalloc(sizeof(DCERPCUDPState)); + if (unlikely(s == NULL)) + return NULL; - memset(s, 0, sizeof(DCERPCUDPState)); - return s; + memset(s, 0, sizeof(DCERPCUDPState)); + return s; } static void DCERPCUDPStateFree(void *s) { - DCERPCUDPState *sstate = (DCERPCUDPState *) s; + DCERPCUDPState *sstate = (DCERPCUDPState *) s; - DCERPCUuidEntry *item; + DCERPCUuidEntry *item; - while ((item = TAILQ_FIRST(&sstate->uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->uuid_list, item, next); - SCFree(item); - } + while ((item = TAILQ_FIRST(&sstate->uuid_list))) { + //printUUID("Free", item); + TAILQ_REMOVE(&sstate->uuid_list, item, next); + SCFree(item); + } if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; @@ -804,7 +825,7 @@ static void DCERPCUDPStateFree(void *s) static int DCERPCUDPRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_DCERPC, - "|04 00|", 2, 0, STREAM_TOSERVER) < 0) + "|04 00|", 2, 0, STREAM_TOSERVER) < 0) { return -1; } @@ -822,21 +843,21 @@ void RegisterDCERPCUDPParsers(void) return; } else { SCLogInfo("Protocol detection and parser disabled for %s protocol.", - "dcerpc"); + "dcerpc"); return; } if (AppLayerParserConfParserEnabled("udp", "dcerpc")) { AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_DCERPC, STREAM_TOSERVER, - DCERPCUDPParse); + DCERPCUDPParse); AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_DCERPC, STREAM_TOCLIENT, - DCERPCUDPParse); + DCERPCUDPParse); AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_DCERPC, DCERPCUDPStateAlloc, - DCERPCUDPStateFree); + DCERPCUDPStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_UDP, ALPROTO_DCERPC, STREAM_TOSERVER); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" - "still on.", "dcerpc"); + "still on.", "dcerpc"); } #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_DCERPC, DCERPCUDPParserRegisterTests); @@ -852,257 +873,261 @@ void RegisterDCERPCUDPParsers(void) int DCERPCUDPParserTest01(void) { - int result = 1; - Flow f; - uint8_t dcerpcrequest[] = { - 0x04, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x3f, 0x98, 0xf0, 0x5c, 0xd9, 0x63, 0xcc, 0x46, - 0xc2, 0x74, 0x51, 0x6c, 0x8a, 0x53, 0x7d, 0x6f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x70, 0x05, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x58, 0xfd, - 0xcc, 0x45, 0x64, 0x49, 0xb0, 0x70, 0xdd, 0xae, - 0x74, 0x2c, 0x96, 0xd2, 0x60, 0x5e, 0x0d, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x70, 0x5e, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x7c, 0x5e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x80, 0x96, 0xf1, 0xf1, - 0x2a, 0x4d, 0xce, 0x11, 0xa6, 0x6a, 0x00, 0x20, - 0xaf, 0x6e, 0x72, 0xf4, 0x0c, 0x00, 0x00, 0x00, - 0x4d, 0x41, 0x52, 0x42, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0xf4, 0x0b, 0x00, - 0x10, 0x09, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, - 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, - 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, - 0xd8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0xc8, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, - 0xd8, 0x08, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc4, 0x28, 0xcd, 0x00, - 0x64, 0x29, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xab, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xa5, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xa6, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xa4, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xad, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0xaa, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x46, 0x07, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x50, 0x00, 0x00, 0x00, 0x4f, 0xb6, 0x88, 0x20, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x66, 0x00, - 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x0c, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x98, 0x93, - 0x98, 0x4f, 0xd2, 0x11, 0xa9, 0x3d, 0xbe, 0x57, - 0xb2, 0x00, 0x00, 0x00, 0x32, 0x00, 0x31, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x80, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, - 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x81, 0xc5, 0x17, 0x03, - 0x80, 0x0e, 0xe9, 0x4a, 0x99, 0x99, 0xf1, 0x8a, - 0x50, 0x6f, 0x7a, 0x85, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd8, 0xda, 0x0d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x2f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x46, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2e, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, - 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, - 0x68, 0x8b, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x31, 0x00, 0x31, 0x00, 0x9d, 0x13, 0x00, 0x01, - 0xcc, 0xe0, 0xfd, 0x7f, 0xcc, 0xe0, 0xfd, 0x7f, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - uint32_t requestlen = sizeof(dcerpcrequest); + int result = 1; + Flow f; + uint8_t dcerpcrequest[] = { + 0x04, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x3f, 0x98, 0xf0, 0x5c, 0xd9, 0x63, 0xcc, 0x46, + 0xc2, 0x74, 0x51, 0x6c, 0x8a, 0x53, 0x7d, 0x6f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x70, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x58, 0xfd, + 0xcc, 0x45, 0x64, 0x49, 0xb0, 0x70, 0xdd, 0xae, + 0x74, 0x2c, 0x96, 0xd2, 0x60, 0x5e, 0x0d, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x5e, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x7c, 0x5e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x80, 0x96, 0xf1, 0xf1, + 0x2a, 0x4d, 0xce, 0x11, 0xa6, 0x6a, 0x00, 0x20, + 0xaf, 0x6e, 0x72, 0xf4, 0x0c, 0x00, 0x00, 0x00, + 0x4d, 0x41, 0x52, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0xf4, 0x0b, 0x00, + 0x10, 0x09, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, + 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, + 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, + 0xd8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0xc8, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, + 0xd8, 0x08, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc4, 0x28, 0xcd, 0x00, + 0x64, 0x29, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xab, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xa5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xa6, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xa4, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xad, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xaa, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0x07, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x50, 0x00, 0x00, 0x00, 0x4f, 0xb6, 0x88, 0x20, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x66, 0x00, + 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x0c, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x98, 0x93, + 0x98, 0x4f, 0xd2, 0x11, 0xa9, 0x3d, 0xbe, 0x57, + 0xb2, 0x00, 0x00, 0x00, 0x32, 0x00, 0x31, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x80, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x81, 0xc5, 0x17, 0x03, + 0x80, 0x0e, 0xe9, 0x4a, 0x99, 0x99, 0xf1, 0x8a, + 0x50, 0x6f, 0x7a, 0x85, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd8, 0xda, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x2f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x46, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, + 0x68, 0x8b, 0x0b, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x9d, 0x13, 0x00, 0x01, + 0xcc, 0xe0, 0xfd, 0x7f, 0xcc, 0xe0, 0xfd, 0x7f, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + uint32_t requestlen = sizeof(dcerpcrequest); - TcpSession ssn; - DCERPCUuidEntry *uuid_entry; + TcpSession ssn; + DCERPCUuidEntry *uuid_entry; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; + f.protoctx = (void *)&ssn; f.proto = IPPROTO_UDP; f.protomap = FlowGetProtoMapping(f.proto); - StreamTcpInitConfig(TRUE); + StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); - if (r != 0) { - printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, + dcerpcrequest, + requestlen); + if (r != 0) { + printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); - DCERPCUDPState *dcerpc_state = f.alstate; - if (dcerpc_state == NULL) { - printf("no dcerpc state: "); - result = 0; - goto end; - } + DCERPCUDPState *dcerpc_state = f.alstate; + if (dcerpc_state == NULL) { + printf("no dcerpc state: "); + result = 0; + goto end; + } - if (dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers != 4) { - printf("expected dcerpc version 0x04, got 0x%02x : ", - dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers); - result = 0; - goto end; - } + if (dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers != 4) { + printf("expected dcerpc version 0x04, got 0x%02x : ", + dcerpc_state->dcerpc.dcerpchdrudp.rpc_vers); + result = 0; + goto end; + } - if (dcerpc_state->dcerpc.dcerpchdrudp.fraglen != 1392) { - printf("expected dcerpc fraglen 0x%02x , got 0x%02x : ", 1392, dcerpc_state->dcerpc.dcerpchdrudp.fraglen); - result = 0; - goto end; - } + if (dcerpc_state->dcerpc.dcerpchdrudp.fraglen != 1392) { + printf("expected dcerpc fraglen 0x%02x , got 0x%02x : ", 1392, dcerpc_state->dcerpc.dcerpchdrudp.fraglen); + result = 0; + goto end; + } - if (dcerpc_state->dcerpc.dcerpchdrudp.opnum != 4) { - printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 4, dcerpc_state->dcerpc.dcerpchdrudp.opnum); - result = 0; - goto end; - } + if (dcerpc_state->dcerpc.dcerpchdrudp.opnum != 4) { + printf("expected dcerpc opnum 0x%02x , got 0x%02x : ", 4, dcerpc_state->dcerpc.dcerpchdrudp.opnum); + result = 0; + goto end; + } - TAILQ_FOREACH(uuid_entry, &dcerpc_state->uuid_list, next) { - printUUID("REQUEST", uuid_entry); - } + TAILQ_FOREACH(uuid_entry, &dcerpc_state->uuid_list, next) { + printUUID("REQUEST", uuid_entry); + } end: - if (alp_tctx != NULL) + if (alp_tctx != NULL) { AppLayerParserThreadCtxFree(alp_tctx); - StreamTcpFreeConfig(TRUE); - return result; + } + StreamTcpFreeConfig(TRUE); + return result; } void DCERPCUDPParserRegisterTests(void) { - UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01, 1); + UtRegisterTest("DCERPCUDPParserTest01", DCERPCUDPParserTest01); } #endif diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 900c3269894c..38416a50d86d 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -77,6 +77,8 @@ enum { DCERPC_FIELD_MAX, }; +void DCERPCUuidListFree(DCERPCUuidEntryList *list); + /* \brief hexdump function from libdnet, used for debugging only */ void hexdump(/*Flow *f,*/ const void *buf, size_t len) { @@ -692,17 +694,14 @@ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32 dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); - if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Error allocating memory\n"); - exit(EXIT_FAILURE); + if (dcerpc->dcerpcbindbindack.uuid_entry != NULL) { + memcpy(dcerpc->dcerpcbindbindack.uuid_entry, + uuid_entry, + sizeof(DCERPCUuidEntry)); + TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, + dcerpc->dcerpcbindbindack.uuid_entry, + next); } - memcpy(dcerpc->dcerpcbindbindack.uuid_entry, - uuid_entry, - sizeof(DCERPCUuidEntry)); - TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, - dcerpc->dcerpcbindbindack.uuid_entry, - next); break; } } @@ -851,17 +850,14 @@ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32 dcerpc->dcerpcbindbindack.uuid_entry = (DCERPCUuidEntry *) SCCalloc(1, sizeof(DCERPCUuidEntry)); - if (dcerpc->dcerpcbindbindack.uuid_entry == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, - "Error allocating memory\n"); - exit(EXIT_FAILURE); + if (dcerpc->dcerpcbindbindack.uuid_entry != NULL) { + memcpy(dcerpc->dcerpcbindbindack.uuid_entry, + uuid_entry, + sizeof(DCERPCUuidEntry)); + TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, + dcerpc->dcerpcbindbindack.uuid_entry, + next); } - memcpy(dcerpc->dcerpcbindbindack.uuid_entry, - uuid_entry, - sizeof(DCERPCUuidEntry)); - TAILQ_INSERT_HEAD(&dcerpc->dcerpcbindbindack.accepted_uuid_list, - dcerpc->dcerpcbindbindack.uuid_entry, - next); break; } } @@ -881,28 +877,19 @@ static uint32_t DCERPCParseBINDACKCTXItem(DCERPC *dcerpc, uint8_t *input, uint32 static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); - DCERPCUuidEntry *item; uint8_t *p = input; if (input_len) { switch (dcerpc->bytesprocessed) { case 16: dcerpc->dcerpcbindbindack.numctxitems = 0; if (input_len >= 12) { - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, item, next); - SCFree(item); - } + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.uuid_list); if (dcerpc->dcerpchdr.type == BIND) { - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); - SCFree(item); - } - TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p + 8); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; - TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); dcerpc->bytesprocessed += 12; SCReturnUInt(12U); } else { @@ -955,21 +942,13 @@ static uint32_t DCERPCParseBIND(DCERPC *dcerpc, uint8_t *input, uint32_t input_l break; /* fall through */ case 24: - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.uuid_list, item, next); - SCFree(item); - } + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.uuid_list); if (dcerpc->dcerpchdr.type == BIND) { - while ((item = TAILQ_FIRST(&dcerpc->dcerpcbindbindack.accepted_uuid_list))) { - TAILQ_REMOVE(&dcerpc->dcerpcbindbindack.accepted_uuid_list, item, next); - SCFree(item); - } - TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.accepted_uuid_list); } dcerpc->dcerpcbindbindack.uuid_internal_id = 0; dcerpc->dcerpcbindbindack.numctxitems = *(p++); dcerpc->dcerpcbindbindack.numctxitemsleft = dcerpc->dcerpcbindbindack.numctxitems; - TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); if (!(--input_len)) break; /* fall through */ @@ -1189,6 +1168,8 @@ static uint32_t DCERPCParseREQUEST(DCERPC *dcerpc, uint8_t *input, uint32_t inpu SCReturnUInt((uint32_t)(p - input)); } +/** \internal + * \retval stub_len or 0 in case of error */ static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCEnter(); @@ -1248,7 +1229,7 @@ static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_le SCFree(*stub_data_buffer); *stub_data_buffer = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - goto end; + SCReturnUInt(0); } *stub_data_buffer = ptmp; @@ -1272,7 +1253,6 @@ static uint32_t StubDataParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_le } #endif -end: SCReturnUInt((uint32_t)stub_len); } @@ -1315,19 +1295,19 @@ static int DCERPCParseHeader(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) dcerpc->dcerpchdr.frag_length |= *(p + 9) << 8; dcerpc->dcerpchdr.auth_length = *(p + 10); dcerpc->dcerpchdr.auth_length |= *(p + 11) << 8; - dcerpc->dcerpchdr.call_id = *(p + 12) << 24; - dcerpc->dcerpchdr.call_id |= *(p + 13) << 16; - dcerpc->dcerpchdr.call_id |= *(p + 14) << 8; - dcerpc->dcerpchdr.call_id |= *(p + 15); + dcerpc->dcerpchdr.call_id = (uint32_t) *(p + 12) << 24; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 13) << 16; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 14) << 8; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 15); } else { dcerpc->dcerpchdr.frag_length = *(p + 8) << 8; dcerpc->dcerpchdr.frag_length |= *(p + 9); dcerpc->dcerpchdr.auth_length = *(p + 10) << 8; dcerpc->dcerpchdr.auth_length |= *(p + 11); - dcerpc->dcerpchdr.call_id = *(p + 12); - dcerpc->dcerpchdr.call_id |= *(p + 13) << 8; - dcerpc->dcerpchdr.call_id |= *(p + 14) << 16; - dcerpc->dcerpchdr.call_id |= *(p + 15) << 24; + dcerpc->dcerpchdr.call_id = (uint32_t) *(p + 12); + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 13) << 8; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 14) << 16; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p + 15) << 24; } dcerpc->bytesprocessed = DCERPC_HDR_LEN; SCReturnInt(16); @@ -1402,22 +1382,22 @@ static int DCERPCParseHeader(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) break; /* fall through */ case 12: - dcerpc->dcerpchdr.call_id = *(p++); + dcerpc->dcerpchdr.call_id = (uint32_t) *(p++); if (!(--input_len)) break; /* fall through */ case 13: - dcerpc->dcerpchdr.call_id |= *(p++) << 8; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p++) << 8; if (!(--input_len)) break; /* fall through */ case 14: - dcerpc->dcerpchdr.call_id |= *(p++) << 16; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p++) << 16; if (!(--input_len)) break; /* fall through */ case 15: - dcerpc->dcerpchdr.call_id |= *(p++) << 24; + dcerpc->dcerpchdr.call_id |= (uint32_t) *(p++) << 24; if (!(dcerpc->dcerpchdr.packed_drep[0] & 0x10)) { dcerpc->dcerpchdr.frag_length = SCByteSwap16(dcerpc->dcerpchdr.frag_length); dcerpc->dcerpchdr.auth_length = SCByteSwap16(dcerpc->dcerpchdr.auth_length); @@ -1573,7 +1553,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) (dcerpc->dcerpchdr.type == BIND) ? "BIND" : "ALTER_CONTEXT"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1599,7 +1581,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) //parsed -= input_len; SCLogDebug("Error Parsing CTX Item %u\n", parsed); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ dcerpc->dcerpcbindbindack.numctxitemsleft = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); @@ -1626,7 +1610,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1653,7 +1639,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) (dcerpc->dcerpchdr.type == BIND_ACK) ? "BIND_ACK" : "ALTER_CONTEXT_RESP"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1672,7 +1660,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing Secondary Address"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1699,7 +1689,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing DCERPC Padding"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1718,7 +1710,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing CTX Items"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1741,7 +1735,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing CTX Items"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ dcerpc->dcerpcbindbindack.numctxitemsleft = 0; DCERPCResetParsingState(dcerpc); SCReturnInt(0); @@ -1779,7 +1775,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1803,8 +1801,10 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) SCLogDebug("Error parsing DCERPC %s", (dcerpc->dcerpchdr.type == REQUEST) ? "REQUEST" : "RESPONSE"); parsed = 0; + (void)parsed; /* for scan-build */ dcerpc->padleft = 0; input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1820,7 +1820,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else if (input_len) { SCLogDebug("Error parsing DCERPC Stub Data"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1862,7 +1864,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1895,7 +1899,9 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) } else { SCLogDebug("Error Parsing DCERPC"); parsed = 0; + (void)parsed; /* for scan-build */ input_len = 0; + (void)input_len; /* for scan-build */ DCERPCResetParsingState(dcerpc); SCReturnInt(0); } @@ -1916,6 +1922,12 @@ static int DCERPCParse(Flow *f, void *dcerpc_state, int32_t retval = 0; DCERPCState *sstate = (DCERPCState *) dcerpc_state; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + if (sstate->dcerpc.bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { SCReturnInt(-1); } @@ -1951,53 +1963,116 @@ static int DCERPCParseResponse(Flow *f, void *dcerpc_state, local_data, 1); } +void DCERPCInit(DCERPC *dcerpc) +{ + dcerpc->transaction_id = 1; + + TAILQ_INIT(&dcerpc->dcerpcbindbindack.uuid_list); + TAILQ_INIT(&dcerpc->dcerpcbindbindack.accepted_uuid_list); +} + static void *DCERPCStateAlloc(void) { SCEnter(); - DCERPCState *s = SCMalloc(sizeof(DCERPCState)); + DCERPCState *s = SCCalloc(1, sizeof(DCERPCState)); if (unlikely(s == NULL)) { SCReturnPtr(NULL, "void"); } - memset(s, 0, sizeof(DCERPCState)); - s->dcerpc.transaction_id = 1; + DCERPCInit(&s->dcerpc); SCReturnPtr((void *)s, "void"); } -static void DCERPCStateFree(void *s) +void DCERPCUuidListFree(DCERPCUuidEntryList *list) { - DCERPCState *sstate = (DCERPCState *) s; - - DCERPCUuidEntry *item; + DCERPCUuidEntry *entry; - while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.uuid_list, item, next); - SCFree(item); + while ((entry = TAILQ_FIRST(list))) { + TAILQ_REMOVE(list, entry, next); + SCFree(entry); } +} - while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.accepted_uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.accepted_uuid_list, item, next); - SCFree(item); - } +void DCERPCCleanup(DCERPC *dcerpc) +{ + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.uuid_list); + DCERPCUuidListFree(&dcerpc->dcerpcbindbindack.accepted_uuid_list); - if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); - sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; + if (dcerpc->dcerpcrequest.stub_data_buffer != NULL) { + SCFree(dcerpc->dcerpcrequest.stub_data_buffer); + dcerpc->dcerpcrequest.stub_data_buffer = NULL; + dcerpc->dcerpcrequest.stub_data_buffer_len = 0; } - if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); - sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; + if (dcerpc->dcerpcresponse.stub_data_buffer != NULL) { + SCFree(dcerpc->dcerpcresponse.stub_data_buffer); + dcerpc->dcerpcresponse.stub_data_buffer = NULL; + dcerpc->dcerpcresponse.stub_data_buffer_len = 0; + } +} + +static void DCERPCStateFree(void *s) +{ + DCERPCState *sstate = (DCERPCState *) s; + + DCERPCCleanup(&sstate->dcerpc); + + if (sstate->de_state != NULL) { + DetectEngineStateFree(sstate->de_state); } SCFree(s); } +static int DCERPCStateHasTxDetectState(void *state) +{ + DCERPCState *dce_state = (DCERPCState *)state; + if (dce_state->de_state) + return 1; + return 0; +} + +static int DCERPCSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + DCERPCState *dce_state = (DCERPCState *)state; + dce_state->de_state = de_state; + return 0; +} + +static DetectEngineState *DCERPCGetTxDetectState(void *vtx) +{ + DCERPCState *dce_state = (DCERPCState *)vtx; + return dce_state->de_state; +} + +static void DCERPCStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *DCERPCGetTx(void *state, uint64_t tx_id) +{ + DCERPCState *dce_state = (DCERPCState *)state; + return dce_state; +} + +static uint64_t DCERPCGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int DCERPCGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +static int DCERPCGetAlstateProgress(void *tx, uint8_t direction) +{ + return 0; +} + static int DCERPCRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC, @@ -2036,6 +2111,21 @@ void RegisterDCERPCParsers(void) AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCStateAlloc, DCERPCStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_DCERPC, STREAM_TOSERVER); + + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCStateHasTxDetectState, + DCERPCGetTxDetectState, DCERPCSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DCERPC, DCERPCGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DCERPC, + DCERPCGetAlstateProgressCompletionStatus); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); @@ -2424,15 +2514,17 @@ int DCERPCParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcbind, bindlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpcbind, + bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -2460,15 +2552,16 @@ int DCERPCParserTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (dcerpc_state->dcerpc.dcerpchdr.type != BIND_ACK) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", BIND_ACK, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; @@ -2484,15 +2577,17 @@ int DCERPCParserTest01(void) printUUID("BIND_ACK", uuid_entry); } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_EOF, dcerpcrequest, requestlen); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_EOF, dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (dcerpc_state->dcerpc.dcerpchdr.type != REQUEST) { printf("expected dcerpc type 0x%02x , got 0x%02x : ", REQUEST, dcerpc_state->dcerpc.dcerpchdr.type); result = 0; @@ -2656,15 +2751,18 @@ int DCERPCParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, + dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -2856,15 +2954,18 @@ int DCERPCParserTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, dcerpcrequest, requestlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, + dcerpcrequest, + requestlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4305,16 +4406,16 @@ int DCERPCParserTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - bind1, bind1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4331,16 +4432,16 @@ int DCERPCParserTest05(void) m++; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind2, bind2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); item = NULL; m = 0; @@ -4480,16 +4581,16 @@ int DCERPCParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, - bind1, bind1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4503,16 +4604,16 @@ int DCERPCParserTest06(void) result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitems == 16); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.numctxitemsleft == 8); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind2, bind2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcbindbindack.ctxbytesprocessed == 0); @@ -4566,16 +4667,17 @@ int DCERPCParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, request1, + request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4589,32 +4691,32 @@ int DCERPCParserTest07(void) dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged = 1); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 38); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 14); result &= (dcerpc_state->dcerpc.pdu_fragged = 1); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request3, request3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -4658,16 +4760,17 @@ int DCERPCParserTest08(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - request, request_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, request, + request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4718,16 +4821,17 @@ int DCERPCParserTest09(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - request, request_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, request, + request_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4792,16 +4896,16 @@ int DCERPCParserTest10(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, - fault, fault_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, fault, fault_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4810,31 +4914,31 @@ int DCERPCParserTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 2); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -4893,16 +4997,16 @@ int DCERPCParserTest11(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -4916,30 +5020,30 @@ int DCERPCParserTest11(void) dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 2); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request3, request3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -4992,16 +5096,16 @@ int DCERPCParserTest12(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack1, bind_ack1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5013,16 +5117,16 @@ int DCERPCParserTest12(void) result &= (dcerpc_state->dcerpc.bytesprocessed == 24); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack2, bind_ack2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.pdu_fragged == 0); @@ -5045,7 +5149,7 @@ int DCERPCParserTest13(void) Flow f; int r = 0; - uint8_t bind[] = { + uint8_t bindbuf[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, @@ -5056,7 +5160,7 @@ int DCERPCParserTest13(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; - uint32_t bind_len = sizeof(bind); + uint32_t bindbuf_len = sizeof(bindbuf); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5070,16 +5174,16 @@ int DCERPCParserTest13(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind, bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bindbuf, bindbuf_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5130,7 +5234,7 @@ int DCERPCParserTest14(void) Flow f; int r = 0; - uint8_t bind[] = { + uint8_t bindbuf[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, @@ -5147,7 +5251,7 @@ int DCERPCParserTest14(void) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0xFF /* ka boom - endless loop */ }; - uint32_t bind_len = sizeof(bind); + uint32_t bindbuf_len = sizeof(bindbuf); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -5161,16 +5265,16 @@ int DCERPCParserTest14(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind, bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bindbuf, bindbuf_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5223,16 +5327,16 @@ int DCERPCParserTest15(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack, bind_ack_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5685,16 +5789,16 @@ int DCERPCParserTest16(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind1, bind1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind1, bind1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5703,16 +5807,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack1, bind_ack1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack1, bind_ack1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5735,16 +5839,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind2, bind2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind2, bind2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5755,16 +5859,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack2, bind_ack2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack2, bind_ack2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5787,16 +5891,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind3, bind3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bind3, bind3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5807,16 +5911,16 @@ int DCERPCParserTest16(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack3, bind_ack3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack3, bind_ack3_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5857,7 +5961,7 @@ int DCERPCParserTest17(void) Flow f; int r = 0; - uint8_t bind[] = { + uint8_t bindbuf[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, @@ -5868,7 +5972,7 @@ int DCERPCParserTest17(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; - uint32_t bind_len = sizeof(bind); + uint32_t bindbuf_len = sizeof(bindbuf); uint8_t bind_ack[] = { 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, @@ -5931,16 +6035,16 @@ int DCERPCParserTest17(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - bind, bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, bindbuf, bindbuf_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -5949,16 +6053,16 @@ int DCERPCParserTest17(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - bind_ack, bind_ack_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, bind_ack, bind_ack_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -5981,16 +6085,16 @@ int DCERPCParserTest17(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - alter_context, alter_context_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, alter_context, alter_context_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -6001,16 +6105,17 @@ int DCERPCParserTest17(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - alter_context_resp, alter_context_resp_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, alter_context_resp, + alter_context_resp_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); count = 0; TAILQ_FOREACH(item, &dcerpc_state->dcerpc.dcerpcbindbindack.accepted_uuid_list, next) { @@ -6076,16 +6181,16 @@ int DCERPCParserTest18(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -6098,16 +6203,16 @@ int DCERPCParserTest18(void) result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); result &= (dcerpc_state->dcerpc.pdu_fragged == 1); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result &= (dcerpc_state->dcerpc.bytesprocessed == 0); result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && @@ -6342,14 +6447,16 @@ int DCERPCParserTest19(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, dcerpcbind, bindlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpcbind, + bindlen); if (r != 0) { printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); DCERPCState *dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -6362,14 +6469,15 @@ int DCERPCParserTest19(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpcbindack, bindacklen); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpcbindack, bindacklen); if (r == 0) { printf("dce parser didn't return fail\n"); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: @@ -6385,25 +6493,25 @@ int DCERPCParserTest19(void) void DCERPCParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01, 1); - UtRegisterTest("DCERPCParserTest02", DCERPCParserTest02, 1); - UtRegisterTest("DCERPCParserTest03", DCERPCParserTest03, 1); - UtRegisterTest("DCERPCParserTest04", DCERPCParserTest04, 1); - UtRegisterTest("DCERPCParserTest05", DCERPCParserTest05, 1); - UtRegisterTest("DCERPCParserTest06", DCERPCParserTest06, 1); - UtRegisterTest("DCERPCParserTest07", DCERPCParserTest07, 1); - UtRegisterTest("DCERPCParserTest08", DCERPCParserTest08, 1); - UtRegisterTest("DCERPCParserTest09", DCERPCParserTest09, 1); - UtRegisterTest("DCERPCParserTest10", DCERPCParserTest10, 1); - UtRegisterTest("DCERPCParserTest11", DCERPCParserTest11, 1); - UtRegisterTest("DCERPCParserTest12", DCERPCParserTest12, 1); - UtRegisterTest("DCERPCParserTest13", DCERPCParserTest13, 1); - UtRegisterTest("DCERPCParserTest14", DCERPCParserTest14, 1); - UtRegisterTest("DCERPCParserTest15", DCERPCParserTest15, 1); - UtRegisterTest("DCERPCParserTest16", DCERPCParserTest16, 1); - UtRegisterTest("DCERPCParserTest17", DCERPCParserTest17, 1); - UtRegisterTest("DCERPCParserTest18", DCERPCParserTest18, 1); - UtRegisterTest("DCERPCParserTest19", DCERPCParserTest19, 1); + UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01); + UtRegisterTest("DCERPCParserTest02", DCERPCParserTest02); + UtRegisterTest("DCERPCParserTest03", DCERPCParserTest03); + UtRegisterTest("DCERPCParserTest04", DCERPCParserTest04); + UtRegisterTest("DCERPCParserTest05", DCERPCParserTest05); + UtRegisterTest("DCERPCParserTest06", DCERPCParserTest06); + UtRegisterTest("DCERPCParserTest07", DCERPCParserTest07); + UtRegisterTest("DCERPCParserTest08", DCERPCParserTest08); + UtRegisterTest("DCERPCParserTest09", DCERPCParserTest09); + UtRegisterTest("DCERPCParserTest10", DCERPCParserTest10); + UtRegisterTest("DCERPCParserTest11", DCERPCParserTest11); + UtRegisterTest("DCERPCParserTest12", DCERPCParserTest12); + UtRegisterTest("DCERPCParserTest13", DCERPCParserTest13); + UtRegisterTest("DCERPCParserTest14", DCERPCParserTest14); + UtRegisterTest("DCERPCParserTest15", DCERPCParserTest15); + UtRegisterTest("DCERPCParserTest16", DCERPCParserTest16); + UtRegisterTest("DCERPCParserTest17", DCERPCParserTest17); + UtRegisterTest("DCERPCParserTest18", DCERPCParserTest18); + UtRegisterTest("DCERPCParserTest19", DCERPCParserTest19); #endif /* UNITTESTS */ return; diff --git a/src/app-layer-dcerpc.h b/src/app-layer-dcerpc.h index 4781f0d1ae07..5a8410c761a8 100644 --- a/src/app-layer-dcerpc.h +++ b/src/app-layer-dcerpc.h @@ -34,8 +34,11 @@ typedef struct DCERPCState_ { DCERPC dcerpc; uint8_t data_needed_for_dir; + DetectEngineState *de_state; } DCERPCState; +void DCERPCInit(DCERPC *dcerpc); +void DCERPCCleanup(DCERPC *dcerpc); void RegisterDCERPCParsers(void); void DCERPCParserTests(void); void DCERPCParserRegisterTests(void); diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index b5b380cdbb22..338d6e8149bd 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -75,8 +75,12 @@ typedef struct AppLayerProtoDetectProbingParserElement_ { uint32_t min_depth; /* the max length of data after which this parser won't be invoked */ uint32_t max_depth; - /* the probing parser function */ - ProbingParserFPtr ProbingParser; + + /* the to_server probing parser function */ + ProbingParserFPtr ProbingParserTs; + + /* the to_client probing parser function */ + ProbingParserFPtr ProbingParserTc; struct AppLayerProtoDetectProbingParserElement_ *next; } AppLayerProtoDetectProbingParserElement; @@ -106,6 +110,7 @@ typedef struct AppLayerProtoDetectProbingParser_ { typedef struct AppLayerProtoDetectPMSignature_ { AppProto alproto; + SigIntId id; /* \todo Change this into a non-pointer */ DetectContentData *cd; struct AppLayerProtoDetectPMSignature_ *next; @@ -124,6 +129,7 @@ typedef struct AppLayerProtoDetectPMCtx_ { /* \todo we don't need this except at setup time. Get rid of it. */ PatIntId max_pat_id; + SigIntId max_sig_id; } AppLayerProtoDetectPMCtx; typedef struct AppLayerProtoDetectCtxIpproto_ { @@ -140,6 +146,9 @@ typedef struct AppLayerProtoDetectCtx_ { * implemented if needed. Waste of space otherwise. */ AppLayerProtoDetectCtxIpproto ctx_ipp[FLOW_PROTO_DEFAULT]; + /* Global SPM thread context prototype. */ + SpmGlobalThreadCtx *spm_global_thread_ctx; + AppLayerProtoDetectProbingParser *ctx_pp; /* Indicates the protocols that have registered themselves @@ -152,9 +161,10 @@ typedef struct AppLayerProtoDetectCtx_ { * \brief The app layer protocol detection thread context. */ struct AppLayerProtoDetectThreadCtx_ { - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; /* The value 2 is for direction(0 - toserver, 1 - toclient). */ MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2]; + SpmThreadCtx *spm_thread_ctx; }; /* The global app layer proto detection context. */ @@ -165,6 +175,7 @@ static AppLayerProtoDetectCtx alpd_ctx; /** \internal * \brief Handle SPM search for Signature */ static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s, + AppLayerProtoDetectThreadCtx *tctx, uint8_t *buf, uint16_t buflen, uint8_t ipproto) { @@ -189,10 +200,7 @@ static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMS SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")", s->cd->offset, s->cd->depth); - if (s->cd->flags & DETECT_CONTENT_NOCASE) - found = BoyerMooreNocase(s->cd->content, s->cd->content_len, sbuf, sbuflen, s->cd->bm_ctx); - else - found = BoyerMoore(s->cd->content, s->cd->content_len, sbuf, sbuflen, s->cd->bm_ctx); + found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, sbuf, sbuflen); if (found != NULL) proto = s->alproto; @@ -254,11 +262,11 @@ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx /* loop through unique pattern id's. Can't use search_cnt here, * as that contains all matches, tctx->pmq.pattern_id_array_cnt * contains only *unique* matches. */ - for (cnt = 0; cnt < tctx->pmq.pattern_id_array_cnt; cnt++) { - const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.pattern_id_array[cnt]]; + for (cnt = 0; cnt < tctx->pmq.rule_id_array_cnt; cnt++) { + const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]]; while (s != NULL) { AppProto proto = AppLayerProtoDetectPMMatchSignature(s, - buf, searchlen, ipproto); + tctx, buf, searchlen, ipproto); /* store each unique proto once */ if (proto != ALPROTO_UNKNOWN && @@ -391,7 +399,11 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, continue; } - alproto = pe->ProbingParser(buf, buflen, NULL); + if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { + alproto = pe->ProbingParserTs(buf, buflen, NULL); + } else if (pe->ProbingParserTc != NULL) { + alproto = pe->ProbingParserTc(buf, buflen, NULL); + } if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) goto end; if (alproto == ALPROTO_FAILED || @@ -408,7 +420,11 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, continue; } - alproto = pe->ProbingParser(buf, buflen, NULL); + if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) { + alproto = pe->ProbingParserTs(buf, buflen, NULL); + } else if (pe->ProbingParserTc != NULL) { + alproto = pe->ProbingParserTc(buf, buflen, NULL); + } if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) goto end; if (alproto == ALPROTO_FAILED || @@ -425,8 +441,6 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, mask = pp_port_dp->alproto_mask; else if (pp_port_sp) mask = pp_port_sp->alproto_mask; - else - mask = 0; if (alproto_masks[0] == mask) { FLOW_SET_PP_DONE(f, direction); @@ -575,9 +589,7 @@ static AppLayerProtoDetectProbingParserElement * AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, uint16_t port, uint16_t min_depth, - uint16_t max_depth, - uint16_t (*AppLayerProtoDetectProbingParser) - (uint8_t *input, uint32_t input_len, uint32_t *offset)) + uint16_t max_depth) { AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc(); @@ -586,7 +598,6 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, pe->alproto_mask = AppLayerProtoDetectProbingParserGetMask(alproto); pe->min_depth = min_depth; pe->max_depth = max_depth; - pe->ProbingParser = AppLayerProtoDetectProbingParser; pe->next = NULL; if (max_depth != 0 && min_depth >= max_depth) { @@ -599,11 +610,6 @@ AppLayerProtoDetectProbingParserElementCreate(AppProto alproto, "the probing parser. Invalid alproto - %d", alproto); goto error; } - if (AppLayerProtoDetectProbingParser == NULL) { - SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " - "register the probing parser. Probing parser func NULL"); - goto error; - } SCReturnPtr(pe, "AppLayerProtoDetectProbingParserElement"); error: @@ -623,7 +629,8 @@ AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParse new_pe->alproto_mask = pe->alproto_mask; new_pe->min_depth = pe->min_depth; new_pe->max_depth = pe->max_depth; - new_pe->ProbingParser = pe->ProbingParser; + new_pe->ProbingParserTs = pe->ProbingParserTs; + new_pe->ProbingParserTc = pe->ProbingParserTc; new_pe->next = NULL; SCReturnPtr(new_pe, "AppLayerProtoDetectProbingParserElement"); @@ -645,7 +652,7 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp else if (pp->ipproto == IPPROTO_UDP) printf("IPProto: UDP\n"); else - printf("IPProto: %"PRIu16"\n", pp->ipproto); + printf("IPProto: %"PRIu8"\n", pp->ipproto); pp_port = pp->port; for ( ; pp_port != NULL; pp_port = pp_port->next) { @@ -685,6 +692,14 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_IRC\n"); else if (pp_pe->alproto == ALPROTO_DNS) printf(" alproto: ALPROTO_DNS\n"); + else if (pp_pe->alproto == ALPROTO_MODBUS) + printf(" alproto: ALPROTO_MODBUS\n"); + else if (pp_pe->alproto == ALPROTO_ENIP) + printf(" alproto: ALPROTO_ENIP\n"); + else if (pp_pe->alproto == ALPROTO_TEMPLATE) + printf(" alproto: ALPROTO_TEMPLATE\n"); + else if (pp_pe->alproto == ALPROTO_DNP3) + printf(" alproto: ALPROTO_DNP3\n"); else printf("impossible\n"); @@ -734,6 +749,14 @@ void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp printf(" alproto: ALPROTO_IRC\n"); else if (pp_pe->alproto == ALPROTO_DNS) printf(" alproto: ALPROTO_DNS\n"); + else if (pp_pe->alproto == ALPROTO_MODBUS) + printf(" alproto: ALPROTO_MODBUS\n"); + else if (pp_pe->alproto == ALPROTO_ENIP) + printf(" alproto: ALPROTO_ENIP\n"); + else if (pp_pe->alproto == ALPROTO_TEMPLATE) + printf(" alproto: ALPROTO_TEMPLATE\n"); + else if (pp_pe->alproto == ALPROTO_DNP3) + printf(" alproto: ALPROTO_DNP3\n"); else printf("impossible\n"); @@ -840,7 +863,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, - ProbingParserFPtr ProbingParser) + ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2) { SCEnter(); @@ -930,7 +954,7 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing while (curr_pe != NULL) { if (curr_pe->alproto == alproto) { SCLogError(SC_ERR_ALPARSER, "Duplicate pp registered - " - "ipproto - %"PRIu16" Port - %"PRIu16" " + "ipproto - %"PRIu8" Port - %"PRIu16" " "App Protocol - NULL, App Protocol(ID) - " "%"PRIu16" min_depth - %"PRIu16" " "max_dept - %"PRIu16".", @@ -944,13 +968,14 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementCreate(alproto, curr_port->port, - min_depth, max_depth, - ProbingParser); + min_depth, max_depth); if (new_pe == NULL) goto error; curr_pe = new_pe; AppLayerProtoDetectProbingParserElement **head_pe; if (direction & STREAM_TOSERVER) { + curr_pe->ProbingParserTs = ProbingParser1; + curr_pe->ProbingParserTc = ProbingParser2; if (curr_port->dp == NULL) curr_port->dp_max_depth = new_pe->max_depth; if (new_pe->max_depth == 0) @@ -962,6 +987,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port->alproto_mask |= new_pe->alproto_mask; head_pe = &curr_port->dp; } else { + curr_pe->ProbingParserTs = ProbingParser2; + curr_pe->ProbingParserTc = ProbingParser1; if (curr_port->sp == NULL) curr_port->sp_max_depth = new_pe->max_depth; if (new_pe->max_depth == 0) @@ -1019,8 +1046,6 @@ static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto, SCEnter(); const AppLayerProtoDetectPMSignature *s = NULL; - int pat_id, max_pat_id; - int i, j; uint8_t ipproto; @@ -1028,15 +1053,12 @@ static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto, ipproto = FlowGetReverseProtoMapping(i); for (j = 0; j < 2; j++) { AppLayerProtoDetectPMCtx *pm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j]; - max_pat_id = pm_ctx->max_pat_id; - - for (pat_id = 0; pat_id < max_pat_id; pat_id++) { - s = pm_ctx->map[pat_id]; - while (s != NULL) { - if (s->alproto == alproto) - ipprotos[ipproto / 8] |= 1 << (ipproto % 8); - s = s->next; - } + + SigIntId x; + for (x = 0; x < pm_ctx->max_sig_id;x++) { + s = pm_ctx->map[x]; + if (s->alproto == alproto) + ipprotos[ipproto / 8] |= 1 << (ipproto % 8); } } } @@ -1064,7 +1086,6 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) PatIntId max_id = 0; TempContainer *struct_offset = NULL; uint8_t *content_offset = NULL; - TempContainer *dup = NULL; int ret = 0; if (ctx->head == NULL) @@ -1073,6 +1094,7 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) for (s = ctx->head; s != NULL; s = s->next) { struct_total_size += sizeof(TempContainer); content_total_size += s->cd->content_len; + ctx->max_sig_id++; } ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size)); @@ -1082,21 +1104,21 @@ static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx) struct_offset = (TempContainer *)ahb; content_offset = ahb + struct_total_size; for (s = ctx->head; s != NULL; s = s->next) { - dup = (TempContainer *)ahb; + TempContainer *tcdup = (TempContainer *)ahb; content = s->cd->content; content_len = s->cd->content_len; - for (; dup != struct_offset; dup++) { - if (dup->content_len != content_len || - SCMemcmp(dup->content, content, dup->content_len) != 0) + for (; tcdup != struct_offset; tcdup++) { + if (tcdup->content_len != content_len || + SCMemcmp(tcdup->content, content, tcdup->content_len) != 0) { continue; } break; } - if (dup != struct_offset) { - s->cd->id = dup->id; + if (tcdup != struct_offset) { + s->cd->id = tcdup->id; continue; } @@ -1126,54 +1148,40 @@ static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx) SCEnter(); int ret = 0; - PatIntId max_pat_id = 0, tmp_pat_id; AppLayerProtoDetectPMSignature *s, *next_s; int mpm_ret; + SigIntId id = 0; - max_pat_id = ctx->max_pat_id; - - ctx->map = SCMalloc((max_pat_id) * sizeof(AppLayerProtoDetectPMSignature *)); + ctx->map = SCMalloc(ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *)); if (ctx->map == NULL) goto error; - memset(ctx->map, 0, (max_pat_id) * sizeof(AppLayerProtoDetectPMSignature *)); + memset(ctx->map, 0, ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *)); - /* add an array indexed by pattern id to look up the sig */ - for (s = ctx->head; s != NULL;) { + /* add an array indexed by rule id to look up the sig */ + for (s = ctx->head; s != NULL; ) { next_s = s->next; - s->next = ctx->map[s->cd->id]; - ctx->map[s->cd->id] = s; - s = next_s; - } - ctx->head = NULL; + s->id = id++; + SCLogDebug("s->id %u", s->id); - - for (tmp_pat_id = 0; tmp_pat_id < max_pat_id; tmp_pat_id++) { - s = NULL; - for (s = ctx->map[tmp_pat_id]; s != NULL; s = s->next) { - if (s->cd->flags & DETECT_CONTENT_NOCASE) { - break; - } - } - /* if s != NULL now, it's CI. If NULL, CS */ - - if (s != NULL) { + if (s->cd->flags & DETECT_CONTENT_NOCASE) { mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx, s->cd->content, s->cd->content_len, - 0, 0, tmp_pat_id, 0, 0); + 0, 0, s->cd->id, s->id, 0); if (mpm_ret < 0) goto error; } else { - s = ctx->map[tmp_pat_id]; - if (s == NULL) - goto error; - mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx, s->cd->content, s->cd->content_len, - 0, 0, tmp_pat_id, 0, 0); + 0, 0, s->cd->id, s->id, 0); if (mpm_ret < 0) goto error; } + + ctx->map[s->id] = s; + s->next = NULL; + s = next_s; } + ctx->head = NULL; goto end; error: @@ -1248,13 +1256,20 @@ static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alprot DetectContentData *cd; int ret = 0; - cd = DetectContentParseEncloseQuotes(pattern); + cd = DetectContentParseEncloseQuotes(alpd_ctx.spm_global_thread_ctx, + pattern); if (cd == NULL) goto error; cd->depth = depth; cd->offset = offset; if (!is_cs) { - BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); + /* Rebuild as nocase */ + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, + alpd_ctx.spm_global_thread_ctx); + if (cd->spm_ctx == NULL) { + goto error; + } cd->flags |= DETECT_CONTENT_NOCASE; } if (depth < cd->content_len) @@ -1309,7 +1324,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto, direction); end: - SCReturnCT(alproto, "AppProto"); + SCReturnUInt(alproto); } static void AppLayerProtoDetectFreeProbingParsers(AppLayerProtoDetectProbingParser *pp) @@ -1348,7 +1363,7 @@ int AppLayerProtoDetectPrepareState(void) if (AppLayerProtoDetectPMSetContentIDs(ctx_pm) < 0) goto error; - if (ctx_pm->max_pat_id == 0) + if (ctx_pm->max_sig_id == 0) continue; if (AppLayerProtoDetectPMMapSignatures(ctx_pm) < 0) @@ -1382,12 +1397,13 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, - ProbingParserFPtr ProbingParser) + ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2) { SCEnter(); DetectPort *head = NULL; - DetectPortParse(&head, portstr); + DetectPortParse(NULL,&head, portstr); DetectPort *temp_dp = head; while (temp_dp != NULL) { uint32_t port = temp_dp->port; @@ -1400,7 +1416,8 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, alproto, min_depth, max_depth, direction, - ProbingParser); + ProbingParser1, + ProbingParser2); } temp_dp = temp_dp->next; } @@ -1414,7 +1431,8 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, - ProbingParserFPtr ProbingParser) + ProbingParserFPtr ProbingParserTs, + ProbingParserFPtr ProbingParserTc) { SCEnter(); @@ -1461,7 +1479,7 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, alproto, min_depth, max_depth, STREAM_TOSERVER, /* to indicate dp */ - ProbingParser); + ProbingParserTs, ProbingParserTc); } /* detect by source port of flow */ @@ -1475,7 +1493,7 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, alproto, min_depth, max_depth, STREAM_TOCLIENT, /* to indicate sp */ - ProbingParser); + ProbingParserTc, ProbingParserTs); } @@ -1526,9 +1544,24 @@ int AppLayerProtoDetectSetup(void) memset(&alpd_ctx, 0, sizeof(alpd_ctx)); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + uint16_t mpm_matcher = PatternMatchDefaultMatcher(); + +#ifdef __SC_CUDA_SUPPORT__ + /* CUDA won't work here, so fall back to AC */ + if (mpm_matcher == MPM_AC_CUDA) + mpm_matcher = mpm_default_matcher; +#endif + + alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + if (alpd_ctx.spm_global_thread_ctx == NULL) { + SCLogError(SC_ERR_FATAL, "Unable to alloc SpmGlobalThreadCtx."); + exit(EXIT_FAILURE); + } + for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { for (j = 0; j < 2; j++) { - MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, MPM_AC); + MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, mpm_matcher); } } SCReturnInt(0); @@ -1545,23 +1578,21 @@ int AppLayerProtoDetectDeSetup(void) int dir = 0; PatIntId id = 0; AppLayerProtoDetectPMCtx *pm_ctx = NULL; - AppLayerProtoDetectPMSignature *sig = NULL, *next_sig = NULL; + AppLayerProtoDetectPMSignature *sig = NULL; for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) { for (dir = 0; dir < 2; dir++) { pm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir]; - mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(pm_ctx->mpm_ctx.ctx); - for (id = 0; id < pm_ctx->max_pat_id; id++) { + mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(&pm_ctx->mpm_ctx); + for (id = 0; id < pm_ctx->max_sig_id; id++) { sig = pm_ctx->map[id]; - while (sig != NULL) { - next_sig = sig->next; - AppLayerProtoDetectPMFreeSignature(sig); - sig = next_sig; - } + AppLayerProtoDetectPMFreeSignature(sig); } } } + SpmDestroyGlobalThreadCtx(alpd_ctx.spm_global_thread_ctx); + AppLayerProtoDetectFreeProbingParsers(alpd_ctx.ctx_pp); SCReturnInt(0); @@ -1593,6 +1624,9 @@ int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, ConfNode *node; int r; +#ifdef AFLFUZZ_APPLAYER + goto enabled; +#endif if (RunmodeIsUnittests()) goto enabled; @@ -1626,17 +1660,20 @@ int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, } } - if (strcasecmp(node->val, "yes") == 0) { - goto enabled; - } else if (strcasecmp(node->val, "no") == 0) { - goto disabled; - } else if (strcasecmp(node->val, "detection-only") == 0) { - goto enabled; - } else { - SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); - exit(EXIT_FAILURE); + if (node->val) { + if (ConfValIsTrue(node->val)) { + goto enabled; + } else if (ConfValIsFalse(node->val)) { + goto disabled; + } else if (strcasecmp(node->val, "detection-only") == 0) { + goto enabled; + } } + /* Invalid or null value. */ + SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); + exit(EXIT_FAILURE); + disabled: enabled = 0; enabled: @@ -1672,17 +1709,22 @@ AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void) memset(alpd_tctx, 0, sizeof(*alpd_tctx)); /* Get the max pat id for all the mpm ctxs. */ - if (PmqSetup(&alpd_tctx->pmq, max_pat_id) < 0) + if (PmqSetup(&alpd_tctx->pmq) < 0) goto error; for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { for (j = 0; j < 2; j++) { mpm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx; mpm_tctx = &alpd_tctx->mpm_tctx[i][j]; - mpm_table[mpm_ctx->mpm_type].InitThreadCtx(mpm_ctx, mpm_tctx, 0); + mpm_table[mpm_ctx->mpm_type].InitThreadCtx(mpm_ctx, mpm_tctx); } } + alpd_tctx->spm_thread_ctx = SpmMakeThreadCtx(alpd_ctx.spm_global_thread_ctx); + if (alpd_tctx->spm_thread_ctx == NULL) { + goto error; + } + goto end; error: if (alpd_tctx != NULL) @@ -1708,6 +1750,9 @@ void AppLayerProtoDetectDestroyCtxThread(AppLayerProtoDetectThreadCtx *alpd_tctx } } PmqFree(&alpd_tctx->pmq); + if (alpd_tctx->spm_thread_ctx != NULL) { + SpmDestroyThreadCtx(alpd_tctx->spm_thread_ctx); + } SCFree(alpd_tctx); SCReturn; @@ -1729,19 +1774,17 @@ AppProto AppLayerProtoDetectGetProtoByName(char *alproto_name) { SCEnter(); - AppProto a = ALPROTO_UNKNOWN; - + AppProto a; for (a = 0; a < ALPROTO_MAX; a++) { if (alpd_ctx.alproto_names[a] != NULL && strlen(alpd_ctx.alproto_names[a]) == strlen(alproto_name) && (SCMemcmp(alpd_ctx.alproto_names[a], alproto_name, strlen(alproto_name)) == 0)) { - goto end; + SCReturnCT(a, "AppProto"); } } - end: - SCReturnCT(a, "AppProto"); + SCReturnCT(ALPROTO_UNKNOWN, "AppProto"); } char *AppLayerProtoDetectGetProtoName(AppProto alproto) @@ -2950,57 +2993,57 @@ static int AppLayerProtoDetectTest15(void) ALPROTO_HTTP, 5, 8, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 0, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_FTP, 7, 15, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); result = 1; AppLayerProtoDetectPPRegister(IPPROTO_UDP, @@ -3008,7 +3051,7 @@ static int AppLayerProtoDetectTest15(void) ALPROTO_IMAP, 12, 23, STREAM_TOSERVER, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); /* toclient */ AppLayerProtoDetectPPRegister(IPPROTO_TCP, @@ -3016,74 +3059,74 @@ static int AppLayerProtoDetectTest15(void) ALPROTO_JABBER, 12, 23, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_IRC, 12, 14, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "85", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_TLS, 12, 18, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP, 5, 8, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "81", ALPROTO_DCERPC, 9, 10, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "90", ALPROTO_FTP, 7, 15, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_SMB, 5, 6, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_UDP, "85", ALPROTO_IMAP, 12, 23, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "0", ALPROTO_SMTP, 12, 17, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_FTP, 7, 10, STREAM_TOCLIENT, - ProbingParserDummyForTesting); + ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPTestDataElement element_ts_80[] = { { "http", ALPROTO_HTTP, 80, 1 << ALPROTO_HTTP, 5, 8 }, @@ -3306,7 +3349,6 @@ static int AppLayerProtoDetectTest16(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " @@ -3319,14 +3361,15 @@ static int AppLayerProtoDetectTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3400,7 +3443,6 @@ static int AppLayerProtoDetectTest17(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " @@ -3413,14 +3455,15 @@ static int AppLayerProtoDetectTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3496,7 +3539,6 @@ static int AppLayerProtoDetectTest18(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ftp any any -> any any " @@ -3509,14 +3551,15 @@ static int AppLayerProtoDetectTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -3588,7 +3631,6 @@ static int AppLayerProtoDetectTest19(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any " @@ -3601,14 +3643,15 @@ static int AppLayerProtoDetectTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_FTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_FTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); @@ -3691,7 +3734,6 @@ static int AppLayerProtoDetectTest20(void) ssn.toserver_smsg_head = stream_msg; ssn.toserver_smsg_tail = stream_msg; - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " @@ -3704,14 +3746,15 @@ static int AppLayerProtoDetectTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); @@ -3744,26 +3787,26 @@ void AppLayerProtoDetectUnittestsRegister(void) { SCEnter(); - UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01, 1); - UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02, 1); - UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03, 1); - UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04, 1); - UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05, 1); - UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06, 1); - UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07, 1); - UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08, 1); - UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09, 1); - UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10, 1); - UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11, 1); - UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12, 1); - UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13, 1); - UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14, 1); - UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15, 1); - UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16, 1); - UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17, 1); - UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18, 1); - UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19, 1); - UtRegisterTest("AppLayerProtoDetectTest20", AppLayerProtoDetectTest20, 1); + UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01); + UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02); + UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03); + UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04); + UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05); + UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06); + UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07); + UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08); + UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09); + UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10); + UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11); + UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12); + UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13); + UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14); + UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15); + UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16); + UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17); + UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18); + UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19); + UtRegisterTest("AppLayerProtoDetectTest20", AppLayerProtoDetectTest20); SCReturn; } diff --git a/src/app-layer-detect-proto.h b/src/app-layer-detect-proto.h index 81b75fe392be..591ccbf5f843 100644 --- a/src/app-layer-detect-proto.h +++ b/src/app-layer-detect-proto.h @@ -65,7 +65,8 @@ void AppLayerProtoDetectPPRegister(uint8_t ipproto, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, - ProbingParserFPtr ProbingParser); + ProbingParserFPtr ProbingParser1, + ProbingParserFPtr ProbingParser2); /** * \retval bool 0 if no config was found, 1 if config was found */ @@ -74,7 +75,8 @@ int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, - ProbingParserFPtr ProbingParser); + ProbingParserFPtr ProbingParserTs, + ProbingParserFPtr ProbingParserTc); /***** PM registration *****/ diff --git a/src/app-layer-dnp3-objects.c b/src/app-layer-dnp3-objects.c new file mode 100644 index 000000000000..6c1a1d296cf7 --- /dev/null +++ b/src/app-layer-dnp3-objects.c @@ -0,0 +1,9154 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jason Ish + * + * This file contains the DNP3 object decoders. + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +void DNP3FreeObjectPoint(int group, int variation, void *point); + +#if 0 +static void DNP3HexDump(uint8_t *data, int len) +{ + for (int i = 0; i < len; i++) { + printf("%02x ", data[i]); + } +} +#endif + +/** + * \brief Allocate a list for DNP3 points. + */ +DNP3PointList *DNP3PointListAlloc(void) +{ + DNP3PointList *items = SCCalloc(1, sizeof(*items)); + if (unlikely(items == NULL)) { + return NULL; + } + TAILQ_INIT(items); + return items; +} + +/** + * \brief Free a DNP3PointList. + */ +void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *list) +{ + DNP3Point *point; + while ((point = TAILQ_FIRST(list)) != NULL) { + TAILQ_REMOVE(list, point, next); + if (point->data != NULL) { + DNP3FreeObjectPoint(group, variation, point->data); + } + SCFree(point); + } + SCFree(list); +} + +/** + * \brief Read an uint8_t from a buffer. + * + * Reads a uint8_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint8(const uint8_t **buf, uint32_t *len, uint8_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = *(uint8_t *)(*buf); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an uint16_t from a buffer. + * + * Reads an uint16_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint16(const uint8_t **buf, uint32_t *len, uint16_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = DNP3_SWAP16(*(uint16_t *)(*buf)); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an unsigned 24 bit integer from a buffer. + * + * Reads an an unsigned 24 bit integer from a buffer advancing the + * pointer and decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint24(const uint8_t **buf, uint32_t *len, uint32_t *out) +{ + if (*len < (int)(sizeof(uint8_t) * 3)) { + return 0; + } + +#if __BYTE_ORDER__ == __BIG_ENDIAN + *out = ((uint32_t)(*buf)[0] << 16) | ((uint32_t)(*buf)[1] << 8) | + (uint32_t)(*buf)[2]; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | + ((uint64_t)(*buf)[2] << 16); +#endif + + *buf += 3; + *len -= 3; + + return 1; +} + +/** + * \brief Read an uint32_t from a buffer. + * + * Reads an uint32_t from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint32(const uint8_t **buf, uint32_t *len, uint32_t *out) +{ + if (*len < (int)sizeof(*out)) { + return 0; + } + *out = DNP3_SWAP32(*(uint32_t *)(*buf)); + *buf += sizeof(*out); + *len -= sizeof(*out); + return 1; +} + +/** + * \brief Read an unsigned 48 bit integer from a buffer. + * + * Reads an an unsigned 48 bit integer from a buffer advancing the + * pointer and decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadUint48(const uint8_t **buf, uint32_t *len, uint64_t *out) +{ + if (*len < (int)(sizeof(uint8_t) * 6)) { + return 0; + } + +#if __BYTE_ORDER__ == __BIG_ENDIAN + *out = ((uint64_t)(*buf)[0] << 40) | ((uint64_t)(*buf)[1] << 32) | + ((uint64_t)(*buf)[2] << 24) | ((uint64_t)(*buf)[3] << 16) | + ((uint64_t)(*buf)[4] << 8) | (uint64_t)(*buf)[5]; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + *out = ((uint64_t)(*buf)[0]) | ((uint64_t)(*buf)[1] << 8) | + ((uint64_t)(*buf)[2] << 16) | ((uint64_t)(*buf)[3] << 24) | + ((uint64_t)(*buf)[4] << 32) | ((uint64_t)(*buf)[5] << 40); +#endif + + *buf += 6; + *len -= 6; + + return 1; +} + +/** + * \brief Read a 32 bit float from a buffer. + * + * Reads an 32 bit float from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadFloat32(const uint8_t **buf, uint32_t *len, float *out) +{ + if (*len < 4) { + return 0; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *((uint8_t *)out + 0) = (*buf)[0]; + *((uint8_t *)out + 1) = (*buf)[1]; + *((uint8_t *)out + 2) = (*buf)[2]; + *((uint8_t *)out + 3) = (*buf)[3]; +#else + *((uint8_t *)out + 3) = (*buf)[0]; + *((uint8_t *)out + 2) = (*buf)[1]; + *((uint8_t *)out + 1) = (*buf)[2]; + *((uint8_t *)out + 0) = (*buf)[3]; +#endif + *len -= 4; + *buf += 4; + + return 1; +} + +/** + * \brief Read a 64 bit float from a buffer. + * + * Reads an 64 bit float from a buffer advancing the pointer and + * decrementing the length. + * + * \param buf A pointer to the buffer to read from. + * \param len A pointer to the buffer length. + * \param out A pointer to where the value will be stored. + * + * \retval Returns 1 if there was enough space in the buffer to read from, + * otherwise 0 is returned. + */ +static int DNP3ReadFloat64(const uint8_t **buf, uint32_t *len, double *out) +{ + if (*len < 8) { + return 0; + } + +#if __BYTE_ORDER == __LITTLE_ENDIAN + *((uint8_t *)out + 0) = (*buf)[0]; + *((uint8_t *)out + 1) = (*buf)[1]; + *((uint8_t *)out + 2) = (*buf)[2]; + *((uint8_t *)out + 3) = (*buf)[3]; + *((uint8_t *)out + 4) = (*buf)[4]; + *((uint8_t *)out + 5) = (*buf)[5]; + *((uint8_t *)out + 6) = (*buf)[6]; + *((uint8_t *)out + 7) = (*buf)[7]; +#else + *((uint8_t *)out + 7) = (*buf)[0]; + *((uint8_t *)out + 6) = (*buf)[1]; + *((uint8_t *)out + 5) = (*buf)[2]; + *((uint8_t *)out + 4) = (*buf)[3]; + *((uint8_t *)out + 3) = (*buf)[4]; + *((uint8_t *)out + 2) = (*buf)[5]; + *((uint8_t *)out + 1) = (*buf)[6]; + *((uint8_t *)out + 0) = (*buf)[7]; +#endif + *len -= 8; + *buf += 8; + + return 1; +} + +/** + * \brief Get the prefix value and advance the buffer. + */ +static int DNP3ReadPrefix( + const uint8_t **buf, uint32_t *len, uint8_t prefix_code, uint32_t *out) +{ + uint8_t prefix_len = 0; + + switch (prefix_code) { + case 0x01: + case 0x04: + prefix_len = 1; + break; + case 0x02: + case 0x05: + prefix_len = 2; + break; + case 0x03: + case 0x06: + prefix_len = 4; + default: + break; + } + + if (*len < (uint32_t)prefix_len) { + return 0; + } + + switch (prefix_len) { + case sizeof(uint32_t): + if (!DNP3ReadUint32(buf, len, out)) { + return 0; + } + break; + case sizeof(uint16_t): { + /* Temp value for strict-aliasing. */ + uint16_t val = 0; + if (!DNP3ReadUint16(buf, len, &val)) { + return 0; + } + *out = val; + break; + } + case sizeof(uint8_t): { + /* Temp value for strict-aliasing. */ + uint8_t val = 0; + if (!DNP3ReadUint8(buf, len, &val)) { + return 0; + } + *out = val; + break; + } + default: + *out = 0; + break; + } + + return 1; +} + +/** + * \brief Add an object to a DNP3PointList. + * + * \retval 1 if successfull, 0 on failure. + */ +static int DNP3AddPoint(DNP3PointList *list, void *object, uint32_t point_index, + uint8_t prefix_code, uint32_t prefix) +{ + DNP3Point *point = SCCalloc(1, sizeof(*point)); + if (unlikely(point == NULL)) { + return 0; + } + TAILQ_INSERT_TAIL(list, point, next); + point->data = object; + point->prefix = prefix; + point->index = point_index; + switch (prefix_code) { + case 0x00: + break; + case 0x01: + case 0x02: + case 0x03: + point->index = prefix; + break; + case 0x04: + case 0x05: + case 0x06: + point->size = prefix; + break; + default: + break; + } + + return 1; +} + +/* START GENERATED CODE */ + +/* Code generated by: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +static int DNP3DecodeObjectG1V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG1V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG1V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG1V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG2V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->state)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG2V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG2V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG2V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->reserved = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG3V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG3V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 2) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x3; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG3V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG3V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG4V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG4V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG4V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG4V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->chatter_filter = (octet >> 5) & 0x1; + object->state = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint16(buf, len, &object->relative_time_ms)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG10V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG10V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG10V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG10V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG11V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG11V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG11V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG11V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->reserved1 = (octet >> 6) & 0x1; + object->state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG12V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->op_type = (octet >> 0) & 0xf; + object->qu = (octet >> 4) & 0x1; + object->cr = (octet >> 5) & 0x1; + object->tcc = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint8(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->ontime)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->offtime)) { + goto error; + } + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG12V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->op_type = (octet >> 0) & 0xf; + object->qu = (octet >> 4) & 0x1; + object->cr = (octet >> 5) & 0x1; + object->tcc = (octet >> 6) & 0x3; + } + if (!DNP3ReadUint8(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->ontime)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->offtime)) { + goto error; + } + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG12V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG12V3 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->point = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG13V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG13V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->commanded_state = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG13V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG13V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->commanded_state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG20V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG20V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V9(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V9 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V10(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V10 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V11(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V11 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG21V12(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG21V12 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG22V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG22V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG23V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG23V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->rollover = (octet >> 5) & 0x1; + object->reserved0 = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->count)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG30V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG30V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG31V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG31V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG32V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG32V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG33V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG33V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG34V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG34V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG34V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG34V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat32(buf, len, &object->deadband_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG40V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG40V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG41V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG41V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->control_status)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG42V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG42V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->over_range = (octet >> 5) & 0x1; + object->reference_err = (octet >> 6) & 0x1; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat32(buf, len, &object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG43V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG43V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->status_code = (octet >> 0) & 0x7f; + object->reserved0 = (octet >> 7) & 0x1; + } + if (!DNP3ReadFloat64(buf, len, &object->commanded_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->interval)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG50V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG50V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->interval_count)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->interval_units)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG51V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG51V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG51V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG51V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG52V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG52V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->delay_secs)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG52V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG52V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->delay_ms)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->filetype_code)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->attribute_code)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->start_record)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->end_record)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permission)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->owner_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->group_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->file_function_code)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + if (object->filename_size > 0) { + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + if (!DNP3ReadUint16(buf, len, &object->data_size)) { + goto error; + } + if (object->data_size > 0) { + memcpy(object->data, *buf, object->data_size); + *buf += object->data_size; + *len -= object->data_size; + } + object->data[object->data_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->username_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->password_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->password_size)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { + goto error; + } + if (object->username_size > 0) { + memcpy(object->username, *buf, object->username_size); + *buf += object->username_size; + *len -= object->username_size; + } + object->username[object->username_size] = '\0'; + if (object->password_size > 0) { + memcpy(object->password, *buf, object->password_size); + *buf += object->password_size; + *len -= object->password_size; + } + object->password[object->password_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permissions)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->authentication_key)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->operational_mode)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (object->filename_size > 0) { + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->maximum_block_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + object->optional_text_len = prefix - (offset - *len); + if (object->optional_text_len > 0) { + memcpy(object->optional_text, *buf, object->optional_text_len); + *buf += object->optional_text_len; + *len -= object->optional_text_len; + } + object->optional_text[object->optional_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->block_number)) { + goto error; + } + object->file_data_len = prefix - (offset - *len); + if (object->file_data_len > 0) { + memcpy(object->file_data, *buf, object->file_data_len); + *buf += object->file_data_len; + *len -= object->file_data_len; + } + object->file_data[object->file_data_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (!DNP3PrefixIsSize(prefix_code)) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->file_handle)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->block_number)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->status_code)) { + goto error; + } + object->optional_text_len = prefix - (offset - *len); + if (object->optional_text_len > 0) { + memcpy(object->optional_text, *buf, object->optional_text_len); + *buf += object->optional_text_len; + *len -= object->optional_text_len; + } + object->optional_text[object->optional_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->filename_offset)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->filename_size)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->file_type)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->file_size)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->created_timestamp)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->permissions)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->request_id)) { + goto error; + } + if (object->filename_size > 0) { + memcpy(object->filename, *buf, object->filename_size); + *buf += object->filename_size; + *len -= object->filename_size; + } + object->filename[object->filename_size] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG70V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG70V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->file_specification_len = prefix - (offset - *len); + if (object->file_specification_len > 0) { + memcpy(object->file_specification, *buf, object->file_specification_len); + *buf += object->file_specification_len; + *len -= object->file_specification_len; + } + object->file_specification[object->file_specification_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG80V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG80V1 *object = NULL; + int bytes = (count / 8) + 1; + uint32_t prefix = 0; + int point_index = start; + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + for (int i = 0; i < bytes; i++) { + + uint8_t octet; + + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + + for (int j = 0; j < 8 && count; j = j + 1) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + object->state = (octet >> j) & 0x1; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + count--; + point_index++; + } + + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + return 0; +} + +static int DNP3DecodeObjectG81V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG81V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->fill_percentage = (octet >> 0) & 0x7f; + object->overflow_state = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint8(buf, len, &object->group)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->variation)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG83V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG83V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (*len < 4) { + goto error; + } + memcpy(object->vendor_code, *buf, 4); + object->vendor_code[4] = '\0'; + *buf += 4; + *len -= 4; + if (!DNP3ReadUint16(buf, len, &object->object_id)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->length)) { + goto error; + } + if (object->length > 0) { + if (*len < object->length) { + /* Not enough data. */ + goto error; + } + object->data_objects = SCCalloc(1, object->length); + if (unlikely(object->data_objects == NULL)) { + goto error; + } + memcpy(object->data_objects, *buf, object->length); + *buf += object->length; + *len -= object->length; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG86V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG86V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->rd = (octet >> 0) & 0x1; + object->wr = (octet >> 1) & 0x1; + object->st = (octet >> 2) & 0x1; + object->ev = (octet >> 3) & 0x1; + object->df = (octet >> 4) & 0x1; + object->padding0 = (octet >> 5) & 0x1; + object->padding1 = (octet >> 6) & 0x1; + object->padding2 = (octet >> 7) & 0x1; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG102V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG102V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->mal)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->reason)) { + goto error; + } + object->challenge_data_len = prefix - (offset - *len); + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + object->mac_value_len = prefix - (offset - *len); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V3(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V3 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->csq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V4(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V4 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V5(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V5 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->key_wrap_alg)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->key_status)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->mal)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { + goto error; + } + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + object->mac_value_len = prefix - (offset - *len); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V6(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V6 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint24(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + object->wrapped_key_data_len = prefix - (offset - *len); + if (object->wrapped_key_data_len > 0) { + if (*len < object->wrapped_key_data_len) { + /* Not enough data. */ + goto error; + } + object->wrapped_key_data = SCCalloc(1, object->wrapped_key_data_len); + if (unlikely(object->wrapped_key_data == NULL)) { + goto error; + } + memcpy(object->wrapped_key_data, *buf, object->wrapped_key_data_len); + *buf += object->wrapped_key_data_len; + *len -= object->wrapped_key_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V7(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V7 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint32(buf, len, &object->sequence_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->usr)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->error_code)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->time_of_error)) { + goto error; + } + object->error_text_len = prefix - (offset - *len); + if (object->error_text_len > 0) { + memcpy(object->error_text, *buf, object->error_text_len); + *buf += object->error_text_len; + *len -= object->error_text_len; + } + object->error_text[object->error_text_len] = '\0'; + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V8(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V8 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->certificate_type)) { + goto error; + } + object->certificate_len = prefix - (offset - *len); + if (object->certificate_len > 0) { + if (*len < object->certificate_len) { + /* Not enough data. */ + goto error; + } + object->certificate = SCCalloc(1, object->certificate_len); + if (unlikely(object->certificate == NULL)) { + goto error; + } + memcpy(object->certificate, *buf, object->certificate_len); + *buf += object->certificate_len; + *len -= object->certificate_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V9(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V9 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->mac_value_len = prefix - (offset - *len); + if (object->mac_value_len > 0) { + if (*len < object->mac_value_len) { + /* Not enough data. */ + goto error; + } + object->mac_value = SCCalloc(1, object->mac_value_len); + if (unlikely(object->mac_value == NULL)) { + goto error; + } + memcpy(object->mac_value, *buf, object->mac_value_len); + *buf += object->mac_value_len; + *len -= object->mac_value_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V10(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V10 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint8(buf, len, &object->operation)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->scs)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_role)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_role_expiry_interval)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_public_key_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->certification_data_len)) { + goto error; + } + if (object->username_len > 0) { + memcpy(object->username, *buf, object->username_len); + *buf += object->username_len; + *len -= object->username_len; + } + object->username[object->username_len] = '\0'; + if (object->user_public_key_len > 0) { + if (*len < object->user_public_key_len) { + /* Not enough data. */ + goto error; + } + object->user_public_key = SCCalloc(1, object->user_public_key_len); + if (unlikely(object->user_public_key == NULL)) { + goto error; + } + memcpy(object->user_public_key, *buf, object->user_public_key_len); + *buf += object->user_public_key_len; + *len -= object->user_public_key_len; + } + if (object->certification_data_len > 0) { + if (*len < object->certification_data_len) { + /* Not enough data. */ + goto error; + } + object->certification_data = SCCalloc(1, object->certification_data_len); + if (unlikely(object->certification_data == NULL)) { + goto error; + } + memcpy(object->certification_data, *buf, object->certification_data_len); + *buf += object->certification_data_len; + *len -= object->certification_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V11(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V11 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint8(buf, len, &object->key_change_method)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->username_len)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->master_challenge_data_len)) { + goto error; + } + if (object->username_len > 0) { + memcpy(object->username, *buf, object->username_len); + *buf += object->username_len; + *len -= object->username_len; + } + object->username[object->username_len] = '\0'; + if (object->master_challenge_data_len > 0) { + if (*len < object->master_challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->master_challenge_data = SCCalloc(1, object->master_challenge_data_len); + if (unlikely(object->master_challenge_data == NULL)) { + goto error; + } + memcpy(object->master_challenge_data, *buf, object->master_challenge_data_len); + *buf += object->master_challenge_data_len; + *len -= object->master_challenge_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V12(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V12 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->challenge_data_len)) { + goto error; + } + if (object->challenge_data_len > 0) { + if (*len < object->challenge_data_len) { + /* Not enough data. */ + goto error; + } + object->challenge_data = SCCalloc(1, object->challenge_data_len); + if (unlikely(object->challenge_data == NULL)) { + goto error; + } + memcpy(object->challenge_data, *buf, object->challenge_data_len); + *buf += object->challenge_data_len; + *len -= object->challenge_data_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V13(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V13 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + if (!DNP3ReadUint32(buf, len, &object->ksq)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->user_number)) { + goto error; + } + if (!DNP3ReadUint16(buf, len, &object->encrypted_update_key_len)) { + goto error; + } + if (object->encrypted_update_key_len > 0) { + if (*len < object->encrypted_update_key_len) { + /* Not enough data. */ + goto error; + } + object->encrypted_update_key_data = SCCalloc(1, object->encrypted_update_key_len); + if (unlikely(object->encrypted_update_key_data == NULL)) { + goto error; + } + memcpy(object->encrypted_update_key_data, *buf, object->encrypted_update_key_len); + *buf += object->encrypted_update_key_len; + *len -= object->encrypted_update_key_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V14(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V14 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->digital_signature_len = prefix - (offset - *len); + if (object->digital_signature_len > 0) { + if (*len < object->digital_signature_len) { + /* Not enough data. */ + goto error; + } + object->digital_signature = SCCalloc(1, object->digital_signature_len); + if (unlikely(object->digital_signature == NULL)) { + goto error; + } + memcpy(object->digital_signature, *buf, object->digital_signature_len); + *buf += object->digital_signature_len; + *len -= object->digital_signature_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG120V15(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG120V15 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + uint32_t offset; + + if (prefix_code != 5) { + goto error; + } + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + offset = *len; + + object->mac_len = prefix - (offset - *len); + if (object->mac_len > 0) { + if (*len < object->mac_len) { + /* Not enough data. */ + goto error; + } + object->mac = SCCalloc(1, object->mac_len); + if (unlikely(object->mac == NULL)) { + goto error; + } + memcpy(object->mac, *buf, object->mac_len); + *buf += object->mac_len; + *len -= object->mac_len; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG121V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG121V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG122V1(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG122V1 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + +static int DNP3DecodeObjectG122V2(const uint8_t **buf, uint32_t *len, + uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *points) +{ + DNP3ObjectG122V2 *object = NULL; + uint32_t prefix = 0; + uint32_t point_index = start; + + while (count--) { + + object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + goto error; + } + + if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) { + goto error; + } + + { + uint8_t octet; + if (!DNP3ReadUint8(buf, len, &octet)) { + goto error; + } + object->online = (octet >> 0) & 0x1; + object->restart = (octet >> 1) & 0x1; + object->comm_lost = (octet >> 2) & 0x1; + object->remote_forced = (octet >> 3) & 0x1; + object->local_forced = (octet >> 4) & 0x1; + object->reserved0 = (octet >> 5) & 0x1; + object->discontinuity = (octet >> 6) & 0x1; + object->reserved1 = (octet >> 7) & 0x1; + } + if (!DNP3ReadUint16(buf, len, &object->association_id)) { + goto error; + } + if (!DNP3ReadUint32(buf, len, &object->count_value)) { + goto error; + } + if (!DNP3ReadUint48(buf, len, &object->timestamp)) { + goto error; + } + + if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) { + goto error; + } + + object = NULL; + point_index++; + } + + return 1; +error: + if (object != NULL) { + SCFree(object); + } + + return 0; +} + + +void DNP3FreeObjectPoint(int group, int variation, void *point) +{ + switch(DNP3_OBJECT_CODE(group, variation)) { + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *object = (DNP3ObjectG83V1 *) point; + if (object->data_objects != NULL) { + SCFree(object->data_objects); + } + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *object = (DNP3ObjectG120V1 *) point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *object = (DNP3ObjectG120V2 *) point; + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *object = (DNP3ObjectG120V5 *) point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *object = (DNP3ObjectG120V6 *) point; + if (object->wrapped_key_data != NULL) { + SCFree(object->wrapped_key_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *object = (DNP3ObjectG120V8 *) point; + if (object->certificate != NULL) { + SCFree(object->certificate); + } + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *object = (DNP3ObjectG120V9 *) point; + if (object->mac_value != NULL) { + SCFree(object->mac_value); + } + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *object = (DNP3ObjectG120V10 *) point; + if (object->user_public_key != NULL) { + SCFree(object->user_public_key); + } + if (object->certification_data != NULL) { + SCFree(object->certification_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *object = (DNP3ObjectG120V11 *) point; + if (object->master_challenge_data != NULL) { + SCFree(object->master_challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *object = (DNP3ObjectG120V12 *) point; + if (object->challenge_data != NULL) { + SCFree(object->challenge_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *object = (DNP3ObjectG120V13 *) point; + if (object->encrypted_update_key_data != NULL) { + SCFree(object->encrypted_update_key_data); + } + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *object = (DNP3ObjectG120V14 *) point; + if (object->digital_signature != NULL) { + SCFree(object->digital_signature); + } + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *object = (DNP3ObjectG120V15 *) point; + if (object->mac != NULL) { + SCFree(object->mac); + } + break; + } + default: + break; + } + SCFree(point); +} + +/** + * \brief Decode a DNP3 object. + * + * \retval 0 on success. On failure a positive integer corresponding + * to a DNP3 application layer event will be returned. + */ +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, + uint32_t *len, uint8_t prefix_code, uint32_t start, + uint32_t count, DNP3PointList *points) +{ + int rc = 0; + + switch (DNP3_OBJECT_CODE(group, variation)) { + case DNP3_OBJECT_CODE(1, 1): + rc = DNP3DecodeObjectG1V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(1, 2): + rc = DNP3DecodeObjectG1V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(2, 1): + rc = DNP3DecodeObjectG2V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(2, 2): + rc = DNP3DecodeObjectG2V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(2, 3): + rc = DNP3DecodeObjectG2V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(3, 1): + rc = DNP3DecodeObjectG3V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(3, 2): + rc = DNP3DecodeObjectG3V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(4, 1): + rc = DNP3DecodeObjectG4V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(4, 2): + rc = DNP3DecodeObjectG4V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(4, 3): + rc = DNP3DecodeObjectG4V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(10, 1): + rc = DNP3DecodeObjectG10V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(10, 2): + rc = DNP3DecodeObjectG10V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(11, 1): + rc = DNP3DecodeObjectG11V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(11, 2): + rc = DNP3DecodeObjectG11V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(12, 1): + rc = DNP3DecodeObjectG12V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(12, 2): + rc = DNP3DecodeObjectG12V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(12, 3): + rc = DNP3DecodeObjectG12V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(13, 1): + rc = DNP3DecodeObjectG13V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(13, 2): + rc = DNP3DecodeObjectG13V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 1): + rc = DNP3DecodeObjectG20V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 2): + rc = DNP3DecodeObjectG20V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 3): + rc = DNP3DecodeObjectG20V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 4): + rc = DNP3DecodeObjectG20V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 5): + rc = DNP3DecodeObjectG20V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 6): + rc = DNP3DecodeObjectG20V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 7): + rc = DNP3DecodeObjectG20V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(20, 8): + rc = DNP3DecodeObjectG20V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 1): + rc = DNP3DecodeObjectG21V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 2): + rc = DNP3DecodeObjectG21V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 3): + rc = DNP3DecodeObjectG21V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 4): + rc = DNP3DecodeObjectG21V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 5): + rc = DNP3DecodeObjectG21V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 6): + rc = DNP3DecodeObjectG21V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 7): + rc = DNP3DecodeObjectG21V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 8): + rc = DNP3DecodeObjectG21V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 9): + rc = DNP3DecodeObjectG21V9(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 10): + rc = DNP3DecodeObjectG21V10(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 11): + rc = DNP3DecodeObjectG21V11(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(21, 12): + rc = DNP3DecodeObjectG21V12(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 1): + rc = DNP3DecodeObjectG22V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 2): + rc = DNP3DecodeObjectG22V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 3): + rc = DNP3DecodeObjectG22V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 4): + rc = DNP3DecodeObjectG22V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 5): + rc = DNP3DecodeObjectG22V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 6): + rc = DNP3DecodeObjectG22V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 7): + rc = DNP3DecodeObjectG22V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(22, 8): + rc = DNP3DecodeObjectG22V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 1): + rc = DNP3DecodeObjectG23V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 2): + rc = DNP3DecodeObjectG23V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 3): + rc = DNP3DecodeObjectG23V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 4): + rc = DNP3DecodeObjectG23V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 5): + rc = DNP3DecodeObjectG23V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 6): + rc = DNP3DecodeObjectG23V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 7): + rc = DNP3DecodeObjectG23V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(23, 8): + rc = DNP3DecodeObjectG23V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 1): + rc = DNP3DecodeObjectG30V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 2): + rc = DNP3DecodeObjectG30V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 3): + rc = DNP3DecodeObjectG30V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 4): + rc = DNP3DecodeObjectG30V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 5): + rc = DNP3DecodeObjectG30V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(30, 6): + rc = DNP3DecodeObjectG30V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 1): + rc = DNP3DecodeObjectG31V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 2): + rc = DNP3DecodeObjectG31V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 3): + rc = DNP3DecodeObjectG31V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 4): + rc = DNP3DecodeObjectG31V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 5): + rc = DNP3DecodeObjectG31V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 6): + rc = DNP3DecodeObjectG31V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 7): + rc = DNP3DecodeObjectG31V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(31, 8): + rc = DNP3DecodeObjectG31V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 1): + rc = DNP3DecodeObjectG32V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 2): + rc = DNP3DecodeObjectG32V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 3): + rc = DNP3DecodeObjectG32V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 4): + rc = DNP3DecodeObjectG32V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 5): + rc = DNP3DecodeObjectG32V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 6): + rc = DNP3DecodeObjectG32V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 7): + rc = DNP3DecodeObjectG32V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(32, 8): + rc = DNP3DecodeObjectG32V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 1): + rc = DNP3DecodeObjectG33V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 2): + rc = DNP3DecodeObjectG33V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 3): + rc = DNP3DecodeObjectG33V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 4): + rc = DNP3DecodeObjectG33V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 5): + rc = DNP3DecodeObjectG33V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 6): + rc = DNP3DecodeObjectG33V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 7): + rc = DNP3DecodeObjectG33V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(33, 8): + rc = DNP3DecodeObjectG33V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(34, 1): + rc = DNP3DecodeObjectG34V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(34, 2): + rc = DNP3DecodeObjectG34V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(34, 3): + rc = DNP3DecodeObjectG34V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 1): + rc = DNP3DecodeObjectG40V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 2): + rc = DNP3DecodeObjectG40V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 3): + rc = DNP3DecodeObjectG40V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(40, 4): + rc = DNP3DecodeObjectG40V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 1): + rc = DNP3DecodeObjectG41V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 2): + rc = DNP3DecodeObjectG41V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 3): + rc = DNP3DecodeObjectG41V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(41, 4): + rc = DNP3DecodeObjectG41V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 1): + rc = DNP3DecodeObjectG42V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 2): + rc = DNP3DecodeObjectG42V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 3): + rc = DNP3DecodeObjectG42V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 4): + rc = DNP3DecodeObjectG42V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 5): + rc = DNP3DecodeObjectG42V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 6): + rc = DNP3DecodeObjectG42V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 7): + rc = DNP3DecodeObjectG42V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(42, 8): + rc = DNP3DecodeObjectG42V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 1): + rc = DNP3DecodeObjectG43V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 2): + rc = DNP3DecodeObjectG43V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 3): + rc = DNP3DecodeObjectG43V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 4): + rc = DNP3DecodeObjectG43V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 5): + rc = DNP3DecodeObjectG43V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 6): + rc = DNP3DecodeObjectG43V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 7): + rc = DNP3DecodeObjectG43V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(43, 8): + rc = DNP3DecodeObjectG43V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 1): + rc = DNP3DecodeObjectG50V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 2): + rc = DNP3DecodeObjectG50V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 3): + rc = DNP3DecodeObjectG50V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(50, 4): + rc = DNP3DecodeObjectG50V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(51, 1): + rc = DNP3DecodeObjectG51V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(51, 2): + rc = DNP3DecodeObjectG51V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(52, 1): + rc = DNP3DecodeObjectG52V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(52, 2): + rc = DNP3DecodeObjectG52V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 1): + rc = DNP3DecodeObjectG70V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 2): + rc = DNP3DecodeObjectG70V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 3): + rc = DNP3DecodeObjectG70V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 4): + rc = DNP3DecodeObjectG70V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 5): + rc = DNP3DecodeObjectG70V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 6): + rc = DNP3DecodeObjectG70V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 7): + rc = DNP3DecodeObjectG70V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(70, 8): + rc = DNP3DecodeObjectG70V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(80, 1): + rc = DNP3DecodeObjectG80V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(81, 1): + rc = DNP3DecodeObjectG81V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(83, 1): + rc = DNP3DecodeObjectG83V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(86, 2): + rc = DNP3DecodeObjectG86V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(102, 1): + rc = DNP3DecodeObjectG102V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 1): + rc = DNP3DecodeObjectG120V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 2): + rc = DNP3DecodeObjectG120V2(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 3): + rc = DNP3DecodeObjectG120V3(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 4): + rc = DNP3DecodeObjectG120V4(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 5): + rc = DNP3DecodeObjectG120V5(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 6): + rc = DNP3DecodeObjectG120V6(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 7): + rc = DNP3DecodeObjectG120V7(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 8): + rc = DNP3DecodeObjectG120V8(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 9): + rc = DNP3DecodeObjectG120V9(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 10): + rc = DNP3DecodeObjectG120V10(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 11): + rc = DNP3DecodeObjectG120V11(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 12): + rc = DNP3DecodeObjectG120V12(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 13): + rc = DNP3DecodeObjectG120V13(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 14): + rc = DNP3DecodeObjectG120V14(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(120, 15): + rc = DNP3DecodeObjectG120V15(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(121, 1): + rc = DNP3DecodeObjectG121V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(122, 1): + rc = DNP3DecodeObjectG122V1(buf, len, prefix_code, start, count, + points); + break; + case DNP3_OBJECT_CODE(122, 2): + rc = DNP3DecodeObjectG122V2(buf, len, prefix_code, start, count, + points); + break; + default: + return DNP3_DECODER_EVENT_UNKNOWN_OBJECT; + } + + return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED; +} + +/* END GENERATED CODE */ diff --git a/src/app-layer-dnp3-objects.h b/src/app-layer-dnp3-objects.h new file mode 100644 index 000000000000..e292f012758b --- /dev/null +++ b/src/app-layer-dnp3-objects.h @@ -0,0 +1,1464 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jason Ish + * + * This file contains the types (definitions) of the DNP3 objects. + */ + +#ifndef __APP_LAYER_DNP3_OBJECTS_H__ +#define __APP_LAYER_DNP3_OBJECTS_H__ + +#define DNP3_OBJECT_CODE(group, variation) (group << 8 | variation) + +/* START GENERATED CODE */ + +/* Code generated by: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +typedef struct DNP3ObjectG1V1_ { + uint8_t state; +} DNP3ObjectG1V1; + +typedef struct DNP3ObjectG1V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t reserved:1; + uint8_t state:1; +} DNP3ObjectG1V2; + +typedef struct DNP3ObjectG2V1_ { + uint8_t state; +} DNP3ObjectG2V1; + +typedef struct DNP3ObjectG2V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t reserved:1; + uint8_t state:1; + uint64_t timestamp; +} DNP3ObjectG2V2; + +typedef struct DNP3ObjectG2V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t reserved:1; + uint8_t state:1; + uint16_t timestamp; +} DNP3ObjectG2V3; + +typedef struct DNP3ObjectG3V1_ { + uint8_t state; +} DNP3ObjectG3V1; + +typedef struct DNP3ObjectG3V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; +} DNP3ObjectG3V2; + +typedef struct DNP3ObjectG4V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; +} DNP3ObjectG4V1; + +typedef struct DNP3ObjectG4V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; + uint64_t timestamp; +} DNP3ObjectG4V2; + +typedef struct DNP3ObjectG4V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t chatter_filter:1; + uint8_t state:2; + uint16_t relative_time_ms; +} DNP3ObjectG4V3; + +typedef struct DNP3ObjectG10V1_ { + uint8_t state; +} DNP3ObjectG10V1; + +typedef struct DNP3ObjectG10V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint8_t state:1; +} DNP3ObjectG10V2; + +typedef struct DNP3ObjectG11V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint8_t state:1; +} DNP3ObjectG11V1; + +typedef struct DNP3ObjectG11V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint8_t state:1; + uint64_t timestamp; +} DNP3ObjectG11V2; + +typedef struct DNP3ObjectG12V1_ { + uint8_t op_type:4; + uint8_t qu:1; + uint8_t cr:1; + uint8_t tcc:2; + uint8_t count; + uint32_t ontime; + uint32_t offtime; + uint8_t status_code:7; + uint8_t reserved:1; +} DNP3ObjectG12V1; + +typedef struct DNP3ObjectG12V2_ { + uint8_t op_type:4; + uint8_t qu:1; + uint8_t cr:1; + uint8_t tcc:2; + uint8_t count; + uint32_t ontime; + uint32_t offtime; + uint8_t status_code:7; + uint8_t reserved:1; +} DNP3ObjectG12V2; + +typedef struct DNP3ObjectG12V3_ { + uint8_t point; +} DNP3ObjectG12V3; + +typedef struct DNP3ObjectG13V1_ { + uint8_t status_code:7; + uint8_t commanded_state:1; +} DNP3ObjectG13V1; + +typedef struct DNP3ObjectG13V2_ { + uint8_t status_code:7; + uint8_t commanded_state:1; + uint64_t timestamp; +} DNP3ObjectG13V2; + +typedef struct DNP3ObjectG20V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG20V1; + +typedef struct DNP3ObjectG20V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; +} DNP3ObjectG20V2; + +typedef struct DNP3ObjectG20V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG20V3; + +typedef struct DNP3ObjectG20V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG20V4; + +typedef struct DNP3ObjectG20V5_ { + uint32_t count; +} DNP3ObjectG20V5; + +typedef struct DNP3ObjectG20V6_ { + uint16_t count; +} DNP3ObjectG20V6; + +typedef struct DNP3ObjectG20V7_ { + uint32_t count; +} DNP3ObjectG20V7; + +typedef struct DNP3ObjectG20V8_ { + uint16_t count; +} DNP3ObjectG20V8; + +typedef struct DNP3ObjectG21V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG21V1; + +typedef struct DNP3ObjectG21V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; +} DNP3ObjectG21V2; + +typedef struct DNP3ObjectG21V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG21V3; + +typedef struct DNP3ObjectG21V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG21V4; + +typedef struct DNP3ObjectG21V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG21V5; + +typedef struct DNP3ObjectG21V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG21V6; + +typedef struct DNP3ObjectG21V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG21V7; + +typedef struct DNP3ObjectG21V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG21V8; + +typedef struct DNP3ObjectG21V9_ { + uint32_t count; +} DNP3ObjectG21V9; + +typedef struct DNP3ObjectG21V10_ { + uint16_t count; +} DNP3ObjectG21V10; + +typedef struct DNP3ObjectG21V11_ { + uint32_t count; +} DNP3ObjectG21V11; + +typedef struct DNP3ObjectG21V12_ { + uint16_t count; +} DNP3ObjectG21V12; + +typedef struct DNP3ObjectG22V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG22V1; + +typedef struct DNP3ObjectG22V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; +} DNP3ObjectG22V2; + +typedef struct DNP3ObjectG22V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG22V3; + +typedef struct DNP3ObjectG22V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG22V4; + +typedef struct DNP3ObjectG22V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG22V5; + +typedef struct DNP3ObjectG22V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG22V6; + +typedef struct DNP3ObjectG22V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG22V7; + +typedef struct DNP3ObjectG22V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG22V8; + +typedef struct DNP3ObjectG23V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; +} DNP3ObjectG23V1; + +typedef struct DNP3ObjectG23V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG23V2; + +typedef struct DNP3ObjectG23V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; +} DNP3ObjectG23V3; + +typedef struct DNP3ObjectG23V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; +} DNP3ObjectG23V4; + +typedef struct DNP3ObjectG23V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG23V5; + +typedef struct DNP3ObjectG23V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t discontinuity:1; + uint8_t reserved0:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG23V6; + +typedef struct DNP3ObjectG23V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint32_t count; + uint64_t timestamp; +} DNP3ObjectG23V7; + +typedef struct DNP3ObjectG23V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t rollover:1; + uint8_t reserved0:1; + uint8_t reserved1:1; + uint16_t count; + uint64_t timestamp; +} DNP3ObjectG23V8; + +typedef struct DNP3ObjectG30V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG30V1; + +typedef struct DNP3ObjectG30V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG30V2; + +typedef struct DNP3ObjectG30V3_ { + int32_t value; +} DNP3ObjectG30V3; + +typedef struct DNP3ObjectG30V4_ { + int16_t value; +} DNP3ObjectG30V4; + +typedef struct DNP3ObjectG30V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG30V5; + +typedef struct DNP3ObjectG30V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG30V6; + +typedef struct DNP3ObjectG31V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG31V1; + +typedef struct DNP3ObjectG31V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG31V2; + +typedef struct DNP3ObjectG31V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG31V3; + +typedef struct DNP3ObjectG31V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG31V4; + +typedef struct DNP3ObjectG31V5_ { + int32_t value; +} DNP3ObjectG31V5; + +typedef struct DNP3ObjectG31V6_ { + int16_t value; +} DNP3ObjectG31V6; + +typedef struct DNP3ObjectG31V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG31V7; + +typedef struct DNP3ObjectG31V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG31V8; + +typedef struct DNP3ObjectG32V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG32V1; + +typedef struct DNP3ObjectG32V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG32V2; + +typedef struct DNP3ObjectG32V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG32V3; + +typedef struct DNP3ObjectG32V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG32V4; + +typedef struct DNP3ObjectG32V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG32V5; + +typedef struct DNP3ObjectG32V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG32V6; + +typedef struct DNP3ObjectG32V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; + uint64_t timestamp; +} DNP3ObjectG32V7; + +typedef struct DNP3ObjectG32V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; + uint64_t timestamp; +} DNP3ObjectG32V8; + +typedef struct DNP3ObjectG33V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG33V1; + +typedef struct DNP3ObjectG33V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG33V2; + +typedef struct DNP3ObjectG33V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG33V3; + +typedef struct DNP3ObjectG33V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG33V4; + +typedef struct DNP3ObjectG33V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG33V5; + +typedef struct DNP3ObjectG33V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG33V6; + +typedef struct DNP3ObjectG33V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; + uint64_t timestamp; +} DNP3ObjectG33V7; + +typedef struct DNP3ObjectG33V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; + uint64_t timestamp; +} DNP3ObjectG33V8; + +typedef struct DNP3ObjectG34V1_ { + uint16_t deadband_value; +} DNP3ObjectG34V1; + +typedef struct DNP3ObjectG34V2_ { + uint32_t deadband_value; +} DNP3ObjectG34V2; + +typedef struct DNP3ObjectG34V3_ { + float deadband_value; +} DNP3ObjectG34V3; + +typedef struct DNP3ObjectG40V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG40V1; + +typedef struct DNP3ObjectG40V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG40V2; + +typedef struct DNP3ObjectG40V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG40V3; + +typedef struct DNP3ObjectG40V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG40V4; + +typedef struct DNP3ObjectG41V1_ { + int32_t value; + uint8_t control_status; +} DNP3ObjectG41V1; + +typedef struct DNP3ObjectG41V2_ { + int16_t value; + uint8_t control_status; +} DNP3ObjectG41V2; + +typedef struct DNP3ObjectG41V3_ { + float value; + uint8_t control_status; +} DNP3ObjectG41V3; + +typedef struct DNP3ObjectG41V4_ { + double value; + uint8_t control_status; +} DNP3ObjectG41V4; + +typedef struct DNP3ObjectG42V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; +} DNP3ObjectG42V1; + +typedef struct DNP3ObjectG42V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; +} DNP3ObjectG42V2; + +typedef struct DNP3ObjectG42V3_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int32_t value; + uint64_t timestamp; +} DNP3ObjectG42V3; + +typedef struct DNP3ObjectG42V4_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + int16_t value; + uint64_t timestamp; +} DNP3ObjectG42V4; + +typedef struct DNP3ObjectG42V5_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; +} DNP3ObjectG42V5; + +typedef struct DNP3ObjectG42V6_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; +} DNP3ObjectG42V6; + +typedef struct DNP3ObjectG42V7_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + float value; + uint64_t timestamp; +} DNP3ObjectG42V7; + +typedef struct DNP3ObjectG42V8_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t over_range:1; + uint8_t reference_err:1; + uint8_t reserved0:1; + double value; + uint64_t timestamp; +} DNP3ObjectG42V8; + +typedef struct DNP3ObjectG43V1_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int32_t commanded_value; +} DNP3ObjectG43V1; + +typedef struct DNP3ObjectG43V2_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int16_t commanded_value; +} DNP3ObjectG43V2; + +typedef struct DNP3ObjectG43V3_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int32_t commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V3; + +typedef struct DNP3ObjectG43V4_ { + uint8_t status_code:7; + uint8_t reserved0:1; + int16_t commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V4; + +typedef struct DNP3ObjectG43V5_ { + uint8_t status_code:7; + uint8_t reserved0:1; + float commanded_value; +} DNP3ObjectG43V5; + +typedef struct DNP3ObjectG43V6_ { + uint8_t status_code:7; + uint8_t reserved0:1; + double commanded_value; +} DNP3ObjectG43V6; + +typedef struct DNP3ObjectG43V7_ { + uint8_t status_code:7; + uint8_t reserved0:1; + float commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V7; + +typedef struct DNP3ObjectG43V8_ { + uint8_t status_code:7; + uint8_t reserved0:1; + double commanded_value; + uint64_t timestamp; +} DNP3ObjectG43V8; + +typedef struct DNP3ObjectG50V1_ { + uint64_t timestamp; +} DNP3ObjectG50V1; + +typedef struct DNP3ObjectG50V2_ { + uint64_t timestamp; + uint32_t interval; +} DNP3ObjectG50V2; + +typedef struct DNP3ObjectG50V3_ { + uint64_t timestamp; +} DNP3ObjectG50V3; + +typedef struct DNP3ObjectG50V4_ { + uint64_t timestamp; + uint32_t interval_count; + uint8_t interval_units; +} DNP3ObjectG50V4; + +typedef struct DNP3ObjectG51V1_ { + uint64_t timestamp; +} DNP3ObjectG51V1; + +typedef struct DNP3ObjectG51V2_ { + uint64_t timestamp; +} DNP3ObjectG51V2; + +typedef struct DNP3ObjectG52V1_ { + uint16_t delay_secs; +} DNP3ObjectG52V1; + +typedef struct DNP3ObjectG52V2_ { + uint16_t delay_ms; +} DNP3ObjectG52V2; + +typedef struct DNP3ObjectG70V1_ { + uint16_t filename_size; + uint8_t filetype_code; + uint8_t attribute_code; + uint16_t start_record; + uint16_t end_record; + uint32_t file_size; + uint64_t created_timestamp; + uint16_t permission; + uint32_t file_id; + uint32_t owner_id; + uint32_t group_id; + uint8_t file_function_code; + uint8_t status_code; + char filename[65535]; + uint16_t data_size; + char data[65535]; +} DNP3ObjectG70V1; + +typedef struct DNP3ObjectG70V2_ { + uint16_t username_offset; + uint16_t username_size; + uint16_t password_offset; + uint16_t password_size; + uint32_t authentication_key; + char username[65535]; + char password[65535]; +} DNP3ObjectG70V2; + +typedef struct DNP3ObjectG70V3_ { + uint16_t filename_offset; + uint16_t filename_size; + uint64_t created; + uint16_t permissions; + uint32_t authentication_key; + uint32_t file_size; + uint16_t operational_mode; + uint16_t maximum_block_size; + uint16_t request_id; + char filename[65535]; +} DNP3ObjectG70V3; + +typedef struct DNP3ObjectG70V4_ { + uint32_t file_handle; + uint32_t file_size; + uint16_t maximum_block_size; + uint16_t request_id; + uint8_t status_code; + char optional_text[255]; + uint8_t optional_text_len; +} DNP3ObjectG70V4; + +typedef struct DNP3ObjectG70V5_ { + uint32_t file_handle; + uint32_t block_number; + char file_data[255]; + uint8_t file_data_len; +} DNP3ObjectG70V5; + +typedef struct DNP3ObjectG70V6_ { + uint32_t file_handle; + uint32_t block_number; + uint8_t status_code; + char optional_text[255]; + uint8_t optional_text_len; +} DNP3ObjectG70V6; + +typedef struct DNP3ObjectG70V7_ { + uint16_t filename_offset; + uint16_t filename_size; + uint16_t file_type; + uint32_t file_size; + uint64_t created_timestamp; + uint16_t permissions; + uint16_t request_id; + char filename[65535]; +} DNP3ObjectG70V7; + +typedef struct DNP3ObjectG70V8_ { + char file_specification[65535]; + uint16_t file_specification_len; +} DNP3ObjectG70V8; + +typedef struct DNP3ObjectG80V1_ { + uint8_t state; +} DNP3ObjectG80V1; + +typedef struct DNP3ObjectG81V1_ { + uint8_t fill_percentage:7; + uint8_t overflow_state:1; + uint8_t group; + uint8_t variation; +} DNP3ObjectG81V1; + +typedef struct DNP3ObjectG83V1_ { + char vendor_code[5]; + uint16_t object_id; + uint16_t length; + uint8_t *data_objects; +} DNP3ObjectG83V1; + +typedef struct DNP3ObjectG86V2_ { + uint8_t rd:1; + uint8_t wr:1; + uint8_t st:1; + uint8_t ev:1; + uint8_t df:1; + uint8_t padding0:1; + uint8_t padding1:1; + uint8_t padding2:1; +} DNP3ObjectG86V2; + +typedef struct DNP3ObjectG102V1_ { + uint8_t value; +} DNP3ObjectG102V1; + +typedef struct DNP3ObjectG120V1_ { + uint32_t csq; + uint16_t usr; + uint8_t mal; + uint8_t reason; + uint8_t *challenge_data; + uint16_t challenge_data_len; +} DNP3ObjectG120V1; + +typedef struct DNP3ObjectG120V2_ { + uint32_t csq; + uint16_t usr; + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V2; + +typedef struct DNP3ObjectG120V3_ { + uint32_t csq; + uint16_t user_number; +} DNP3ObjectG120V3; + +typedef struct DNP3ObjectG120V4_ { + uint16_t user_number; +} DNP3ObjectG120V4; + +typedef struct DNP3ObjectG120V5_ { + uint32_t ksq; + uint16_t user_number; + uint8_t key_wrap_alg; + uint8_t key_status; + uint8_t mal; + uint16_t challenge_data_len; + uint8_t *challenge_data; + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V5; + +typedef struct DNP3ObjectG120V6_ { + uint32_t ksq; + uint16_t usr; + uint8_t *wrapped_key_data; + uint16_t wrapped_key_data_len; +} DNP3ObjectG120V6; + +typedef struct DNP3ObjectG120V7_ { + uint32_t sequence_number; + uint16_t usr; + uint16_t association_id; + uint8_t error_code; + uint64_t time_of_error; + char error_text[65535]; + uint16_t error_text_len; +} DNP3ObjectG120V7; + +typedef struct DNP3ObjectG120V8_ { + uint8_t key_change_method; + uint8_t certificate_type; + uint8_t *certificate; + uint16_t certificate_len; +} DNP3ObjectG120V8; + +typedef struct DNP3ObjectG120V9_ { + uint8_t *mac_value; + uint16_t mac_value_len; +} DNP3ObjectG120V9; + +typedef struct DNP3ObjectG120V10_ { + uint8_t key_change_method; + uint8_t operation; + uint32_t scs; + uint16_t user_role; + uint16_t user_role_expiry_interval; + uint16_t username_len; + uint16_t user_public_key_len; + uint16_t certification_data_len; + char username[65535]; + uint8_t *user_public_key; + uint8_t *certification_data; +} DNP3ObjectG120V10; + +typedef struct DNP3ObjectG120V11_ { + uint8_t key_change_method; + uint16_t username_len; + uint16_t master_challenge_data_len; + char username[65535]; + uint8_t *master_challenge_data; +} DNP3ObjectG120V11; + +typedef struct DNP3ObjectG120V12_ { + uint32_t ksq; + uint16_t user_number; + uint16_t challenge_data_len; + uint8_t *challenge_data; +} DNP3ObjectG120V12; + +typedef struct DNP3ObjectG120V13_ { + uint32_t ksq; + uint16_t user_number; + uint16_t encrypted_update_key_len; + uint8_t *encrypted_update_key_data; +} DNP3ObjectG120V13; + +typedef struct DNP3ObjectG120V14_ { + uint8_t *digital_signature; + uint16_t digital_signature_len; +} DNP3ObjectG120V14; + +typedef struct DNP3ObjectG120V15_ { + uint8_t *mac; + uint32_t mac_len; +} DNP3ObjectG120V15; + +typedef struct DNP3ObjectG121V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t association_id; + uint32_t count_value; +} DNP3ObjectG121V1; + +typedef struct DNP3ObjectG122V1_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t association_id; + uint32_t count_value; +} DNP3ObjectG122V1; + +typedef struct DNP3ObjectG122V2_ { + uint8_t online:1; + uint8_t restart:1; + uint8_t comm_lost:1; + uint8_t remote_forced:1; + uint8_t local_forced:1; + uint8_t reserved0:1; + uint8_t discontinuity:1; + uint8_t reserved1:1; + uint16_t association_id; + uint32_t count_value; + uint64_t timestamp; +} DNP3ObjectG122V2; + +/* END GENERATED CODE */ + +int DNP3DecodeObject(int group, int variation, const uint8_t **buf, + uint32_t *len, uint8_t prefix_code, uint32_t start, uint32_t count, + DNP3PointList *); +DNP3PointList *DNP3PointListAlloc(void); +void DNP3FreeObjectPointList(int group, int variation, DNP3PointList *); + +#endif /* __APP_LAYER_DNP3_OBJECTS_H__ */ diff --git a/src/app-layer-dnp3.c b/src/app-layer-dnp3.c new file mode 100644 index 000000000000..4d2efa165f3a --- /dev/null +++ b/src/app-layer-dnp3.c @@ -0,0 +1,2658 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "util-byte.h" +#include "util-unittest.h" +#include "util-hashlist.h" + +#include "util-print.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-detect-proto.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +/* For hexdump(). */ +#include "app-layer-dcerpc-common.h" + +/* Default number of unreplied requests to be considered a flood. */ +#define DNP3_DEFAULT_REQ_FLOOD_COUNT 500 + +#define DNP3_DEFAULT_PORT "20000" + +/* Expected values for the start bytes. */ +#define DNP3_START_BYTE0 0x05 +#define DNP3_START_BYTE1 0x64 + +/* Minimum length for a DNP3 frame. */ +#define DNP3_MIN_LEN 5 + +/* Length of each CRC. */ +#define DNP3_CRC_LEN 2 + +/* DNP3 block size. After the link header a CRC is inserted after + * after 16 bytes of data. */ +#define DNP3_BLOCK_SIZE 16 + +/* Maximum transport layer sequence number. */ +#define DNP3_MAX_TRAN_SEQNO 64 + +/* Maximum application layer sequence number. */ +#define DNP3_MAX_APP_SEQNO 16 + +/* The number of bytes in the header that are counted as part of the + * header length field. */ +#define DNP3_LINK_HDR_LEN 5 + +/* Link function codes. */ +enum { + DNP3_LINK_FC_CONFIRMED_USER_DATA = 3, + DNP3_LINK_FC_UNCONFIRMED_USER_DATA +}; + +/* Reserved addresses. */ +#define DNP3_RESERVED_ADDR_MIN 0xfff0 +#define DNP3_RESERVED_ADDR_MAX 0xfffb + +/* Source addresses must be < 0xfff0. */ +#define DNP3_SRC_ADDR_MAX 0xfff0 + +#define DNP3_OBJ_TIME_SIZE 6 /* AKA UINT48. */ +#define DNP3_OBJ_G12_V1_SIZE 11 +#define DNP3_OBJ_G12_V2_SIZE 11 +#define DNP3_OBJ_G12_V3_SIZE 1 + +/* Extract the prefix code from the object qualifier. */ +#define DNP3_OBJ_PREFIX(x) ((x >> 4) & 0x7) + +/* Extract the range code from the object qualifier. */ +#define DNP3_OBJ_RANGE(x) (x & 0xf) + +/* Decoder event map. */ +SCEnumCharMap dnp3_decoder_event_table[] = { + {"FLOODED", DNP3_DECODER_EVENT_FLOODED}, + {"LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL}, + {"BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC}, + {"BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC}, + {"MALFORMED", DNP3_DECODER_EVENT_MALFORMED}, + {"UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT}, + {NULL, -1}, +}; + +/* Some DNP3 servers start with a banner. */ +static const char banner[] = "DNP3"; + +/* Calculate the next transport sequence number. */ +#define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO) + +/* Calculate the next application sequence number. */ +#define NEXT_APP_SEQNO(current) ((current + 1) % DNP3_MAX_APP_SEQNO) + +/* CRC table generated by pycrc - http://github.com/tpircher/pycrc. + * - Polynomial: 0x3d65. */ +static const uint16_t crc_table[256] = { + 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a, + 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13, + 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1, + 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78, + 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35, + 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc, + 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e, + 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7, + 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4, + 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d, + 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af, + 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26, + 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b, + 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2, + 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00, + 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489, + 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526, + 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf, + 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d, + 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4, + 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89, + 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300, + 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2, + 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b, + 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678, + 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1, + 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413, + 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a, + 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7, + 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e, + 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc, + 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235 +}; + +/** + * \brief Compute the CRC for a buffer. + * + * \param buf Buffer to create CRC from. + * \param len Length of buffer (number of bytes to use for CRC). + + */ +static uint16_t DNP3ComputeCRC(const uint8_t *buf, uint32_t len) +{ + const uint8_t *byte = buf; + uint16_t crc = 0; + int idx; + + while (len--) { + idx = (crc ^ *byte) & 0xff; + crc = (crc_table[idx] ^ (crc >> 8)) & 0xffff; + byte++; + } + + return ~crc & 0xffff; +} + +/** + * \brief Check the CRC of a block. + * + * \param block The block of data with CRC to be checked. + * \param len The size of the data block. + * + * \retval 1 if CRC is OK, otherwise 0. + */ +static int DNP3CheckCRC(const uint8_t *block, uint32_t len) +{ + uint32_t crc_offset; + uint16_t crc; + + /* Need at least one byte plus the CRC. */ + if (len < DNP3_CRC_LEN + 1) { + return 0; + } + + crc_offset = len - DNP3_CRC_LEN; + crc = DNP3ComputeCRC(block, len - DNP3_CRC_LEN); + if (((crc & 0xff) == block[crc_offset]) && + ((crc >> 8) == block[crc_offset + 1])) { + return 1; + } + + return 0; +} + +/** + * \brief Check the CRC of the link header. + * + * \param header Point to the link header. + * + * \retval 1 if header CRC is OK, otherwise 0. + */ +static int DNP3CheckLinkHeaderCRC(const DNP3LinkHeader *header) +{ + return DNP3CheckCRC((uint8_t *)header, sizeof(DNP3LinkHeader)); +} + +/** + * \brief Check user data CRCs. + * + * \param data Pointer to user data. + * \param len Length of user data. + * + * \retval 1 if CRCs are OK, otherwise 0. + */ +static int DNP3CheckUserDataCRCs(const uint8_t *data, uint32_t len) +{ + uint32_t offset = 0; + uint32_t block_size; + + while (offset < len) { + if (len - offset >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; + } + else { + block_size = len - offset; + } + + if (!DNP3CheckCRC(data + offset, block_size)) { + /* Once failed, may as well return immediately. */ + return 0; + } + + offset += block_size; + } + + return 1; +} + +/** + * \brief Check the DNP3 frame start bytes. + * + * \retval 1 if valid, 0 if not. + */ +static int DNP3CheckStartBytes(const DNP3LinkHeader *header) +{ + return header->start_byte0 == DNP3_START_BYTE0 && + header->start_byte1 == DNP3_START_BYTE1; +} + +/** + * \brief Check if a frame contains a banner. + * + * Some servers (outstations) appear to send back a banner that fails + * the normal frame checks. So first check for a banner. + * + * \retval 1 if a banner is found, 0 if not. + */ +static int DNP3ContainsBanner(const uint8_t *input, uint32_t len) +{ + return memmem(input, len, banner, strlen(banner)) != NULL; +} + +/** + * \brief DNP3 probing parser. + */ +static uint16_t DNP3ProbingParser(uint8_t *input, uint32_t len, + uint32_t *offset) +{ + DNP3LinkHeader *hdr = (DNP3LinkHeader *)input; + + /* Check that we have the minimum amount of bytes. */ + if (len < sizeof(DNP3LinkHeader)) { + SCLogDebug("Length too small to be a DNP3 header."); + return ALPROTO_UNKNOWN; + } + + /* May be a banner. */ + if (DNP3ContainsBanner(input, len)) { + SCLogDebug("Packet contains a DNP3 banner."); + goto end; + } + + /* Verify start value (from AN2013-004b). */ + if (!DNP3CheckStartBytes(hdr)) { + SCLogDebug("Invalid start bytes."); + return ALPROTO_FAILED; + } + + /* Verify minimum length. */ + if (hdr->len < DNP3_MIN_LEN) { + SCLogDebug("Packet too small to be a valid DNP3 fragment."); + return ALPROTO_FAILED; + } + +end: + SCLogDebug("Detected DNP3."); + return ALPROTO_DNP3; +} + +/** + * \brief Caculate the length of the transport layer with CRCs removed. + * + * \param input_len The length of the transport layer buffer. + * + * \retval The length of the buffer after CRCs are removed. + */ +static int DNP3CalculateTransportLengthWithoutCRCs(uint32_t input_len) +{ + /* Too small. */ + if (input_len < DNP3_CRC_LEN) { + return -1; + } + + /* Get the number of complete blocks. */ + int blocks = input_len / (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); + + /* And the number of bytes in the last block. */ + int rem = input_len - (blocks * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + if (rem) { + if (rem < DNP3_CRC_LEN) { + return -1; + } + return (blocks * DNP3_BLOCK_SIZE) + (rem - DNP3_CRC_LEN); + } + else { + return (blocks * DNP3_BLOCK_SIZE); + } +} + +/** + * \brief Reassemble the application layer by stripping the CRCs. + * + * Remove the CRCs from the user data blocks. The output is the user + * data with the CRCs removed as well as the transport header removed, + * but the input data still needs to include the transport header as + * its part of the first user data block. + * + * If the output length passed in is non-null, the new input data will + * be appended, and the output length pointer incremented as needed. + * + * \param input Input buffer starting at the transport header (which + * will be removed from the output). + * \param input_len Length of the input buffer. + * \param output Pointer to output buffer (may be realloc'd). + * \param output_len Pointer to output length. + * + * \retval 1 if reassembly was successful, otherwise 0. + */ +static int DNP3ReassembleApplicationLayer(const uint8_t *input, + uint32_t input_len, uint8_t **output, uint32_t *output_len) +{ + int len = DNP3CalculateTransportLengthWithoutCRCs(input_len); + + if (len <= 0) { + return 0; + } + + /* Remove one byte for the transport header and make sure we have + * at least one byte of user data. */ + if (--len < 1) { + return 0; + } + + if (*output == NULL) { + *output = SCCalloc(1, len); + if (unlikely(*output == NULL)) { + return 0; + } + } + else { + uint8_t *ptr = SCRealloc(*output, (size_t)(*output_len + len)); + if (unlikely(ptr == NULL)) { + return 0; + } + *output = ptr; + } + + int offset = 0, block_size; + while ((uint32_t)offset < input_len) { + if (input_len - offset > DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE + DNP3_CRC_LEN; + } + else { + block_size = input_len - offset; + } + + /* If handling the first block (offset is 0), trim off the + * first byte which is the transport header, and not part of + * the application data. */ + if (offset == 0) { + offset++; + block_size--; + } + + /* Need at least 3 bytes to continue. One for application + * data, and 2 for the CRC. If not, return failure for + * malformed frame. */ + if (block_size < DNP3_CRC_LEN + 1) { + SCLogDebug("Not enough data to continue."); + return 0; + } + + /* Make sure there is enough space to write into. */ + if (block_size - DNP3_CRC_LEN > len) { + SCLogDebug("Not enough data to continue."); + return 0; + } + + memcpy(*output + *output_len, input + offset, + block_size - DNP3_CRC_LEN); + *output_len += block_size - DNP3_CRC_LEN; + offset += block_size; + len -= block_size - DNP3_CRC_LEN; + } + + return 1; +} + +/** + * \brief Allocate a DNP3 state object. + * + * The DNP3 state object represents a single DNP3 TCP session. + */ +static void *DNP3StateAlloc(void) +{ + SCEnter(); + DNP3State *dnp3; + + dnp3 = (DNP3State *)SCCalloc(1, sizeof(DNP3State)); + if (unlikely(dnp3 == NULL)) { + return NULL; + } + TAILQ_INIT(&dnp3->tx_list); + + SCReturnPtr(dnp3, "void"); +} + +/** + * \brief Set a DNP3 application layer event. + * + * Sets an event on the current transaction object. + */ +static void DNP3SetEvent(DNP3State *dnp3, uint8_t event) +{ + if (dnp3 && dnp3->curr) { + AppLayerDecoderEventsSetEventRaw(&dnp3->curr->decoder_events, event); + dnp3->events++; + } + else { + SCLogWarning(SC_ERR_ALPARSER, + "Fail set set event, state or txn was NULL."); + } +} + +/** + * \brief Set a DNP3 application layer event on a transaction. + */ +static void DNP3SetEventTx(DNP3Transaction *tx, uint8_t event) +{ + AppLayerDecoderEventsSetEventRaw(&tx->decoder_events, event); + tx->dnp3->events++; +} + +/** + * \brief Allocation a DNP3 transaction. + */ +static DNP3Transaction *DNP3TxAlloc(DNP3State *dnp3) +{ + DNP3Transaction *tx = SCCalloc(1, sizeof(DNP3Transaction)); + if (unlikely(tx == NULL)) { + return NULL; + } + dnp3->transaction_max++; + dnp3->unreplied++; + dnp3->curr = tx; + tx->dnp3 = dnp3; + tx->tx_num = dnp3->transaction_max; + TAILQ_INIT(&tx->request_objects); + TAILQ_INIT(&tx->response_objects); + TAILQ_INSERT_TAIL(&dnp3->tx_list, tx, next); + + /* Check for flood state. */ + if (dnp3->unreplied > DNP3_DEFAULT_REQ_FLOOD_COUNT) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_FLOODED); + dnp3->flooded = 1; + } + + return tx; +} + +/** + * \brief Calculate the length of a link frame with CRCs. + * + * This is required as the length parameter in the DNP3 header does not + * include the added CRCs. + * + * \param length The length from the DNP3 link header. + * + * \retval The length of the frame with CRCs included or 0 if the length isn't + * long enough to be a valid DNP3 frame. + */ +static uint32_t DNP3CalculateLinkLength(uint8_t length) +{ + uint32_t frame_len = 0; + int rem; + + /* Fail early if the length is less than the minimum size. */ + if (length < DNP3_LINK_HDR_LEN) { + return 0; + } + + /* Subtract the 5 bytes of the header that are included in the + * length. */ + length -= DNP3_LINK_HDR_LEN; + + rem = length % DNP3_BLOCK_SIZE; + frame_len = (length / DNP3_BLOCK_SIZE) * (DNP3_BLOCK_SIZE + DNP3_CRC_LEN); + if (rem) { + frame_len += rem + DNP3_CRC_LEN; + } + + return frame_len + sizeof(DNP3LinkHeader); +} + +/** + * \brief Check if the link function code specifies user data. + * + * \param header Point to link header. + * + * \retval 1 if frame contains user data, otherwise 0. + */ +static int DNP3IsUserData(const DNP3LinkHeader *header) +{ + switch (DNP3_LINK_FC(header->control)) { + case DNP3_LINK_FC_CONFIRMED_USER_DATA: + case DNP3_LINK_FC_UNCONFIRMED_USER_DATA: + return 1; + default: + return 0; + } +} + +/** + * \brief Check if the frame has user data. + * + * Check if the DNP3 frame actually has user data by checking if data + * exists after the headers. + * + * \retval 1 if user data exists, otherwise 0. + */ +static int DNP3HasUserData(const DNP3LinkHeader *header) +{ + if (DNP3_LINK_DIR(header->control)) { + return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + + sizeof(DNP3ApplicationHeader); + } + else { + return header->len >= DNP3_LINK_HDR_LEN + sizeof(DNP3TransportHeader) + + sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); + } +} + +/** + * \brief Reset a DNP3Buffer. + */ +static void DNP3BufferReset(DNP3Buffer *buffer) +{ + buffer->offset = 0; + buffer->len = 0; +} + +/** + * \brief Add data to a DNP3 buffer, enlarging the buffer if required. + * + * \param buffer Buffer to add data data. + * \param data Data to be added to buffer. + * \param len Size of data to be added to buffer. + * + * \param 1 if data was added successful, otherwise 0. + */ +static int DNP3BufferAdd(DNP3Buffer *buffer, const uint8_t *data, uint32_t len) +{ + if (buffer->size == 0) { + buffer->buffer = SCCalloc(1, len); + if (unlikely(buffer->buffer == NULL)) { + return 0; + } + buffer->size = len; + } + else if (buffer->len + len > buffer->size) { + uint8_t *tmp = SCRealloc(buffer->buffer, buffer->len + len); + if (unlikely(tmp == NULL)) { + return 0; + } + buffer->buffer = tmp; + buffer->size = buffer->len + len; + } + memcpy(buffer->buffer + buffer->len, data, len); + buffer->len += len; + + return 1; +} + +/** + * \brief Trim a DNP3 buffer. + * + * Trimming a buffer moves the data in the buffer up to the front of + * the buffer freeing up room at the end for more incoming data. + * + * \param buffer The buffer to trim. + */ +static void DNP3BufferTrim(DNP3Buffer *buffer) +{ + if (buffer->offset == buffer->len) { + DNP3BufferReset(buffer); + } + else if (buffer->offset > 0) { + memmove(buffer->buffer, buffer->buffer + buffer->offset, + buffer->len - buffer->offset); + buffer->len = buffer->len - buffer->offset; + buffer->offset = 0; + } +} + +/** + * \brief Free a DNP3 object. + */ +static void DNP3ObjectFree(DNP3Object *object) +{ + if (object->points != NULL) { + DNP3FreeObjectPointList(object->group, object->variation, + object->points); + } + SCFree(object); +} + +/** + * \breif Allocate a DNP3 object. + */ +static DNP3Object *DNP3ObjectAlloc(void) +{ + DNP3Object *object = SCCalloc(1, sizeof(*object)); + if (unlikely(object == NULL)) { + return NULL; + } + object->points = DNP3PointListAlloc(); + if (object->points == NULL) { + DNP3ObjectFree(object); + return NULL; + } + return object; +} + +/** + * \brief Decode DNP3 application objects. + * + * This function decoded known DNP3 application objects. As the + * protocol isn't self describing, we can only decode the buffer while + * the application objects are known. As soon as an unknown + * group/variation is hit, we must stop processing. + * + * \param buf the input buffer + * \param len length of the input buffer + * \param objects pointer to list where decoded objects will be stored. + * + * \retval 1 if all objects decoded, 0 if all objects could not be decoded ( + * unknown group/variations) + */ +static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf, + uint32_t len, DNP3ObjectList *objects) +{ + int retval = 0; + + if (buf == NULL || len == 0) { + return 1; + } + + while (len) { + uint32_t offset = 0; + + if (len < sizeof(DNP3ObjHeader)) { + goto done; + } + DNP3ObjHeader *header = (DNP3ObjHeader *)buf; + offset += sizeof(DNP3ObjHeader); + + DNP3Object *object = DNP3ObjectAlloc(); + if (unlikely(object == NULL)) { + goto done; + } + TAILQ_INSERT_TAIL(objects, object, next); + + object->group = header->group; + object->variation = header->variation; + object->qualifier = header->qualifier; + object->prefix_code = DNP3_OBJ_PREFIX(header->qualifier); + object->range_code = DNP3_OBJ_RANGE(header->qualifier); + + /* IEEE 1815-2012, Table 4-5. */ + switch (object->range_code) { + case 0x00: + case 0x03: { + /* 1 octet start and stop indexes OR 1 octet start and + * stop virtual addresses. */ + if (offset + (sizeof(uint8_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = buf[offset++]; + object->stop = buf[offset++]; + object->count = object->stop - object->start + 1; + break; + } + case 0x01: + case 0x04: { + /* 2 octet start and stop indexes OR 2 octect start + * and stop virtual addresses. */ + if (offset + (sizeof(uint16_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + object->stop = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + object->count = object->stop - object->start + 1; + break; + } + case 0x02: + case 0x05: { + /* 4 octet start and stop indexes OR 4 octect start + * and stop virtual addresses. */ + if (offset + (sizeof(uint32_t) * 2) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->start = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + object->stop = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + object->count = object->stop - object->start + 1; + break; + } + case 0x06: + /* No range field. */ + object->count = 0; + break; + case 0x07: + /* 1 octet count of objects. */ + if (offset + sizeof(uint8_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = buf[offset]; + offset += sizeof(uint8_t); + break; + case 0x08: { + /* 2 octet count of objects. */ + if (offset + sizeof(uint16_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = DNP3_SWAP16(*(uint16_t *)(buf + offset)); + offset += sizeof(uint16_t); + break; + } + case 0x09: { + /* 4 octet count of objects. */ + if (offset + sizeof(uint32_t) > len) { + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = DNP3_SWAP32(*(uint32_t *)(buf + offset)); + offset += sizeof(uint32_t); + break; + } + case 0x0b: { + if (offset + sizeof(uint8_t) > len) { + /* Not enough data. */ + SCLogDebug("Not enough data."); + goto not_enough_data; + } + object->count = *(uint8_t *)(buf + offset); + offset += sizeof(uint8_t); + break; + } + default: + SCLogDebug("Range code 0x%02x is reserved.", + object->range_code); + goto done; + } + + buf += offset; + len -= offset; + + if (object->variation == 0 || object->count == 0) { + goto next; + } + + int event = DNP3DecodeObject(header->group, header->variation, &buf, + &len, object->prefix_code, object->start, object->count, + object->points); + if (event) { + DNP3SetEventTx(tx, DNP3_DECODER_EVENT_UNKNOWN_OBJECT); + goto done; + } + + next: + continue; + } + + /* All objects were decoded. */ + retval = 1; + +not_enough_data: +done: + return retval; +} + +/** + * \brief Handle DNP3 request user data. + * + * \param dnp3 the current DNP3State + * \param input pointer to the DNP3 frame (starting with link header) + * \param input_len length of the input frame + */ +static void DNP3HandleUserDataRequest(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + DNP3LinkHeader *lh; + DNP3TransportHeader th; + DNP3ApplicationHeader *ah; + DNP3Transaction *tx = NULL, *ttx; + + lh = (DNP3LinkHeader *)input; + + if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader))) { + return; + } + + th = input[sizeof(DNP3LinkHeader)]; + + if (!DNP3_TH_FIR(th)) { + TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { + if (ttx->request_lh.src == lh->src && + ttx->request_lh.dst == lh->dst && + ttx->has_request && + !ttx->request_done && + NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->request_th)) == DNP3_TH_SEQ(th)) + { + tx = ttx; + break; + } + } + + if (tx == NULL) { + return; + } + + /* Update the saved transport header so subsequent segments + * will be matched to this sequence number. */ + tx->response_th = th; + } + else { + ah = (DNP3ApplicationHeader *)(input + sizeof(DNP3LinkHeader) + + sizeof(DNP3TransportHeader)); + + /* Ignore confirms - for now. */ + if (ah->function_code == DNP3_APP_FC_CONFIRM) { + return; + } + + /* Create a transaction. */ + tx = DNP3TxAlloc(dnp3); + if (unlikely(tx == NULL)) { + return; + } + tx->request_lh = *lh; + tx->request_th = th; + tx->request_ah = *ah; + tx->has_request = 1; + + } + + if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader), + &tx->request_buffer, &tx->request_buffer_len)) { + + /* Malformed, set event and mark as done. */ + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); + tx->request_done = 1; + return; + } + + /* If this is not the final segment, just return. */ + if (!DNP3_TH_FIN(th)) { + return; + } + + tx->request_done = 1; + + /* Some function codes do not expect a reply. */ + switch (tx->request_ah.function_code) { + case DNP3_APP_FC_CONFIRM: + case DNP3_APP_FC_DIR_OPERATE_NR: + case DNP3_APP_FC_FREEZE_NR: + case DNP3_APP_FC_FREEZE_CLEAR_NR: + case DNP3_APP_FC_FREEZE_AT_TIME_NR: + case DNP3_APP_FC_AUTH_REQ_NR: + tx->response_done = 1; + default: + break; + } + + if (DNP3DecodeApplicationObjects( + tx, tx->request_buffer + sizeof(DNP3ApplicationHeader), + tx->request_buffer_len - sizeof(DNP3ApplicationHeader), + &tx->request_objects)) { + tx->request_complete = 1; + } +} + +static void DNP3HandleUserDataResponse(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + DNP3LinkHeader *lh; + DNP3TransportHeader th; + DNP3ApplicationHeader *ah; + DNP3InternalInd *iin; + DNP3Transaction *tx = NULL, *ttx; + uint32_t offset = 0; + + lh = (DNP3LinkHeader *)input; + offset += sizeof(DNP3LinkHeader); + + if (!DNP3CheckUserDataCRCs(input + offset, input_len - offset)) { + return; + } + + th = input[offset++]; + + if (!DNP3_TH_FIR(th)) { + TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { + if (ttx->response_lh.src == lh->src && + ttx->response_lh.dst == lh->dst && + ttx->has_response && !ttx->response_done && + NEXT_TH_SEQNO(DNP3_TH_SEQ(ttx->response_th)) == DNP3_TH_SEQ(th)) + { + tx = ttx; + break; + } + } + + if (tx == NULL) { + return; + } + + /* Replace the transport header in the transaction with this + * one in case there are more frames. */ + tx->response_th = th; + } + else { + ah = (DNP3ApplicationHeader *)(input + offset); + offset += sizeof(DNP3ApplicationHeader); + iin = (DNP3InternalInd *)(input + offset); + + if (ah->function_code == DNP3_APP_FC_UNSOLICITED_RESP) { + tx = DNP3TxAlloc(dnp3); + if (unlikely(tx == NULL)) { + return; + } + + /* There is no request associated with an unsolicited + * response, so mark the request done as far as + * transaction state handling is concerned. */ + tx->request_done = 1; + } + else { + /* Find transaction. */ + TAILQ_FOREACH(ttx, &dnp3->tx_list, next) { + if (ttx->has_request && + ttx->request_done && + ttx->request_lh.src == lh->dst && + ttx->request_lh.dst == lh->src && + !ttx->has_response && + !ttx->response_done && + DNP3_APP_SEQ(ttx->request_ah.control) == DNP3_APP_SEQ(ah->control)) { + tx = ttx; + break; + } + } + if (tx == NULL) { + return; + } + } + + tx->has_response = 1; + tx->response_lh = *lh; + tx->response_th = th; + tx->response_ah = *ah; + tx->response_iin = *iin; + } + + if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), + input_len - sizeof(DNP3LinkHeader), + &tx->response_buffer, &tx->response_buffer_len)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); + return; + } + + if (!DNP3_TH_FIN(th)) { + return; + } + + tx->response_done = 1; + + offset = sizeof(DNP3ApplicationHeader) + sizeof(DNP3InternalInd); + if (DNP3DecodeApplicationObjects(tx, tx->response_buffer + offset, + tx->response_buffer_len - offset, + &tx->response_objects)) { + tx->response_complete = 1; + } +} + +/** + * \brief Decode the DNP3 request link layer. + * + * \retval number of bytes processed or -1 if the data stream does not look + * like DNP3. + */ +static int DNP3HandleRequestLinkLayer(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint32_t processed = 0; + + while (input_len) { + + /* Need at least enough bytes for a DNP3 header. */ + if (input_len < sizeof(DNP3LinkHeader)) { + break; + } + + DNP3LinkHeader *header = (DNP3LinkHeader *)input; + + if (!DNP3CheckStartBytes(header)) { + goto error; + } + + if (!DNP3CheckLinkHeaderCRC(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); + goto error; + } + + uint32_t frame_len = DNP3CalculateLinkLength(header->len); + if (frame_len == 0) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + if (input_len < frame_len) { + /* Insufficient data, just break - will wait for more data. */ + break; + } + + /* Ignore non-user data for now. */ + if (!DNP3IsUserData(header)) { + goto next; + } + + /* Make sure the header length is large enough for transport and + * application headers. */ + if (!DNP3HasUserData(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto next; + } + + if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), + frame_len - sizeof(DNP3LinkHeader))) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); + goto next; + } + + DNP3HandleUserDataRequest(dnp3, input, frame_len); + + next: + /* Advance the input buffer. */ + input += frame_len; + input_len -= frame_len; + processed += frame_len; + } + + SCReturnInt(processed); +error: + /* Error out. Should only happen if this doesn't look like a DNP3 + * frame. */ + SCReturnInt(-1); +} + +/** + * \brief Handle incoming request data. + * + * The actual request PDU parsing is done in + * DNP3HandleRequestLinkLayer. This function takes care of buffering TCP + * date if a segment does not contain a complete frame (or contains + * multiple frames, but not the complete final frame). + */ +static int DNP3ParseRequest(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)state; + DNP3Buffer *buffer = &dnp3->request_buffer; + int processed = 0; + + if (input_len == 0) { + SCReturnInt(1); + } + + if (buffer->len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory to buffer " + "DNP3 request data"); + goto error; + } + processed = DNP3HandleRequestLinkLayer(dnp3, + buffer->buffer + buffer->offset, + buffer->len - buffer->offset); + if (processed < 0) { + goto error; + } + buffer->offset += processed; + DNP3BufferTrim(buffer); + } + else { + processed = DNP3HandleRequestLinkLayer(dnp3, input, input_len); + if (processed < 0) { + SCLogDebug("Failed to process request link layer."); + goto error; + } + + input += processed; + input_len -= processed; + + /* Not all data was processed, buffer it. */ + if (input_len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory to buffer DNP3 request data"); + goto error; + } + } + } + + SCReturnInt(1); + +error: + /* Reset the buffer. */ + DNP3BufferReset(buffer); + SCReturnInt(-1); +} + +/** + * \brief Decode the DNP3 response link layer. + * + * \retval number of bytes processed or -1 if the data stream does not + * like look DNP3. + */ +static int DNP3HandleResponseLinkLayer(DNP3State *dnp3, const uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint32_t processed = 0; + + while (input_len) { + + /* Need at least enough bytes for a DNP3 header. */ + if (input_len < sizeof(DNP3LinkHeader)) { + break; + } + + DNP3LinkHeader *header = (DNP3LinkHeader *)input; + + if (!DNP3CheckStartBytes(header)) { + goto error; + } + + if (!DNP3CheckLinkHeaderCRC(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); + goto error; + } + + /* Calculate the number of bytes needed to for this frame. */ + uint32_t frame_len = DNP3CalculateLinkLength(header->len); + if (frame_len == 0) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + if (input_len < frame_len) { + /* Insufficient data, just break - will wait for more data. */ + break; + } + + /* Only handle user data frames for now. */ + if (!DNP3IsUserData(header)) { + goto next; + } + + /* Make sure the header length is large enough for transport and + * application headers. */ + if (!DNP3HasUserData(header)) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); + goto error; + } + + if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), + frame_len - sizeof(DNP3LinkHeader))) { + DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); + goto next; + } + + DNP3HandleUserDataResponse(dnp3, input, frame_len); + + next: + /* Advance the input buffer. */ + input += frame_len; + input_len -= frame_len; + processed += frame_len; + } + + SCReturnInt(processed); +error: + /* Error out. Should only happen if the data stream no longer + * looks like DNP3. */ + SCReturnInt(-1); +} + +/** + * \brief Parse incoming data. + * + * This is the entry function for DNP3 application layer data. Its + * main responsibility is buffering incoming data that cannot be + * processed. + * + * See DNP3ParseResponsePDUs for DNP3 frame handling. + */ +static int DNP3ParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)state; + DNP3Buffer *buffer = &dnp3->response_buffer; + int processed; + + if (buffer->len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory to buffer " + "DNP3 response data"); + goto error; + } + processed = DNP3HandleResponseLinkLayer(dnp3, + buffer->buffer + buffer->offset, + buffer->len - buffer->offset); + if (processed < 0) { + goto error; + } + buffer->offset += processed; + DNP3BufferTrim(buffer); + } + else { + + /* Check if this is a banner, ignore if it is. */ + if (DNP3ContainsBanner(input, input_len)) { + goto done; + } + + processed = DNP3HandleResponseLinkLayer(dnp3, input, input_len); + if (processed < 0) { + goto error; + } + input += processed; + input_len -= processed; + + /* Not all data was processed, buffer it. */ + if (input_len) { + if (!DNP3BufferAdd(buffer, input, input_len)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory to buffer DNP3 response data"); + goto error; + } + } + } + +done: + SCReturnInt(1); + +error: + /* An error occurred while processing DNP3 frames. Dump the + * buffer as we can't be assured that they are valid anymore. */ + DNP3BufferReset(buffer); + SCReturnInt(-1); +} + +static AppLayerDecoderEvents *DNP3GetEvents(void *state, uint64_t tx_id) +{ + DNP3State *dnp3 = state; + DNP3Transaction *tx; + uint64_t tx_num = tx_id + 1; + + if (dnp3->curr && dnp3->curr->tx_num == tx_num) { + return dnp3->curr->decoder_events; + } + + TAILQ_FOREACH(tx, &dnp3->tx_list, next) { + if (tx->tx_num == tx_num) { + return tx->decoder_events; + } + } + + return NULL; +} + +static int DNP3HasEvents(void *state) +{ + SCEnter(); + uint16_t events = (((DNP3State *)state)->events); + SCReturnInt((events > 0)); +} + +static void *DNP3GetTx(void *alstate, uint64_t tx_id) +{ + SCEnter(); + DNP3State *dnp3 = (DNP3State *)alstate; + DNP3Transaction *tx = NULL; + uint64_t tx_num = tx_id + 1; + + if (dnp3->curr && dnp3->curr->tx_num == (tx_num)) { + SCReturnPtr(dnp3->curr, "void"); + } + + TAILQ_FOREACH(tx, &dnp3->tx_list, next) { + if (tx_num != tx->tx_num) { + continue; + } + SCReturnPtr(tx, "void"); + } + + SCReturnPtr(NULL, "void"); +} + +static uint64_t DNP3GetTxCnt(void *state) +{ + SCEnter(); + uint64_t count = ((uint64_t)((DNP3State *)state)->transaction_max); + SCReturnUInt(count); +} + +/** + * \brief Free all the objects in a DNP3ObjectList. + */ +static void DNP3TxFreeObjectList(DNP3ObjectList *objects) +{ + DNP3Object *object; + + while ((object = TAILQ_FIRST(objects)) != NULL) { + TAILQ_REMOVE(objects, object, next); + DNP3ObjectFree(object); + } +} + +/** + * \brief Free a DNP3 transaction. + */ +static void DNP3TxFree(DNP3Transaction *tx) +{ + SCEnter(); + + if (tx->request_buffer != NULL) { + SCFree(tx->request_buffer); + } + + if (tx->response_buffer != NULL) { + SCFree(tx->response_buffer); + } + + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + if (tx->de_state != NULL) { + DetectEngineStateFree(tx->de_state); + } + + DNP3TxFreeObjectList(&tx->request_objects); + DNP3TxFreeObjectList(&tx->response_objects); + + SCFree(tx); + SCReturn; +} + +/** + * \brief Free a transaction by ID on a specific DNP3 state. + * + * This function is called by the app-layer to free a transaction on a + * specific DNP3 state object. + */ +static void DNP3StateTxFree(void *state, uint64_t tx_id) +{ + SCEnter(); + DNP3State *dnp3 = state; + DNP3Transaction *tx = NULL, *ttx; + uint64_t tx_num = tx_id + 1; + + TAILQ_FOREACH_SAFE(tx, &dnp3->tx_list, next, ttx) { + + if (tx->tx_num != tx_num) { + continue; + } + + if (tx == dnp3->curr) { + dnp3->curr = NULL; + } + + if (tx->decoder_events != NULL) { + if (tx->decoder_events->cnt <= dnp3->events) { + dnp3->events -= tx->decoder_events->cnt; + } + else { + dnp3->events = 0; + } + } + dnp3->unreplied--; + + /* Check flood state. */ + if (dnp3->flooded && dnp3->unreplied < DNP3_DEFAULT_REQ_FLOOD_COUNT) { + dnp3->flooded = 0; + } + + TAILQ_REMOVE(&dnp3->tx_list, tx, next); + DNP3TxFree(tx); + break; + } + + SCReturn; +} + +/** + * \brief Free a DNP3 state. + */ +static void DNP3StateFree(void *state) +{ + SCEnter(); + DNP3State *dnp3 = state; + DNP3Transaction *tx; + if (state != NULL) { + while ((tx = TAILQ_FIRST(&dnp3->tx_list)) != NULL) { + TAILQ_REMOVE(&dnp3->tx_list, tx, next); + DNP3TxFree(tx); + } + if (dnp3->request_buffer.buffer != NULL) { + SCFree(dnp3->request_buffer.buffer); + } + if (dnp3->response_buffer.buffer != NULL) { + SCFree(dnp3->response_buffer.buffer); + } + SCFree(dnp3); + } + SCReturn; +} + +/** + * \brief Called by the app-layer to get the state progress. + */ +static int DNP3GetAlstateProgress(void *tx, uint8_t direction) +{ + DNP3Transaction *dnp3tx = (DNP3Transaction *)tx; + DNP3State *dnp3 = dnp3tx->dnp3; + int retval = 0; + + /* If flooded, "ack" old transactions. */ + if (dnp3->flooded && (dnp3->transaction_max - + dnp3tx->tx_num >= DNP3_DEFAULT_REQ_FLOOD_COUNT)) { + SCLogDebug("flooded: returning tx as done."); + SCReturnInt(1); + } + + if (direction & STREAM_TOCLIENT && dnp3tx->response_done) { + retval = 1; + } + else if (direction & STREAM_TOSERVER && dnp3tx->request_done) { + retval = 1; + } + + SCReturnInt(retval); +} + +/** + * \brief App-layer support. + */ +static int DNP3GetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +/** + * \brief App-layer support. + */ +static int DNP3StateGetEventInfo(const char *event_name, int *event_id, + AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, dnp3_decoder_event_table); + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "Event \"%s\" not present in " + "the DNP3 enum event map table.", event_name); + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +/** + * \brief App-layer support. + */ +static DetectEngineState *DNP3GetTxDetectState(void *vtx) +{ + DNP3Transaction *tx = vtx; + return tx->de_state; +} + +/** + * \brief App-layer support. + */ +static int DNP3SetTxDetectState(void *state, void *vtx, DetectEngineState *s) +{ + DNP3Transaction *tx = vtx; + tx->de_state = s; + return 0; +} + +static void DNP3SetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + DNP3Transaction *tx = (DNP3Transaction *)vtx; + tx->logged |= logger; +} + +static int DNP3GetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + DNP3Transaction *tx = (DNP3Transaction *)vtx; + if (tx->logged & logger) { + return 1; + } + + return 0; +} + +/** + * \brief Check if the prefix code is a size prefix. + * + * \retval 1 if the prefix_code specifies a size prefix, 0 if not. + */ +int DNP3PrefixIsSize(uint8_t prefix_code) +{ + switch (prefix_code) { + case 0x04: + case 0x05: + case 0x06: + return 1; + break; + default: + return 0; + } +} + +/** + * \brief Register the DNP3 application protocol parser. + */ +void RegisterDNP3Parsers(void) +{ + SCEnter(); + + char *proto_name = "dnp3"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) + { + AppLayerProtoDetectRegisterProtocol(ALPROTO_DNP3, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, DNP3_DEFAULT_PORT, + ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), STREAM_TOSERVER, + DNP3ProbingParser, NULL); + } + else { + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_DNP3, 0, sizeof(DNP3LinkHeader), + DNP3ProbingParser, NULL)) { +#ifndef AFLFUZZ_APPLAYER + return; +#endif + } + } + + } + else { + SCLogConfig("Protocol detection and parser disabled for DNP3."); + SCReturn; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) + { + SCLogConfig("Registering DNP3/tcp parsers."); + + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOSERVER, + DNP3ParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNP3, STREAM_TOCLIENT, + DNP3ParseResponse); + + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DNP3, + DNP3StateAlloc, DNP3StateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3GetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3HasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNP3, NULL, + DNP3GetTxDetectState, DNP3SetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNP3, DNP3GetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3StateTxFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNP3, + DNP3GetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNP3, + DNP3GetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNP3, + DNP3StateGetEventInfo); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_DNP3, + DNP3GetTxLogged, DNP3SetTxLogged); + } + else { + SCLogConfig("Parser disabled for protocol %s. " + "Protocol detection still on.", proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNP3, + DNP3ParserRegisterTests); +#endif + + SCReturn; +} + +#ifdef UNITTESTS + +#include "flow-util.h" +#include "stream-tcp.h" + +/** + * \brief Utility function to fix CRCs when mangling a frame. + */ +static void DNP3FixCrc(uint8_t *data, uint32_t len) +{ + uint32_t block_size; + + while (len) { + if (len >= DNP3_BLOCK_SIZE + DNP3_CRC_LEN) { + block_size = DNP3_BLOCK_SIZE; + } else { + block_size = len - DNP3_CRC_LEN; + } + uint16_t crc = DNP3ComputeCRC(data, block_size); + data[block_size + 1] = (crc >> 8) & 0xff; + data[block_size] = crc & 0xff; + data += block_size + DNP3_CRC_LEN; + len -= block_size + DNP3_CRC_LEN; + } +} + +/** + * \test Test CRC checking on partial and full blocks. + */ +static int DNP3ParserTestCheckCRC(void) +{ + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer - segment 1. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, + + /* Application layer - segment 2. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + /* Check link header CRC. */ + FAIL_IF(!DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); + + /* Check first application layer segment. */ + FAIL_IF(!DNP3CheckCRC(request + sizeof(DNP3LinkHeader), + DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + /* Change a byte in link header, should fail now. */ + request[2]++; + FAIL_IF(DNP3CheckCRC(request, sizeof(DNP3LinkHeader))); + + /* Change a byte in the first application segment, should fail + * now. */ + request[sizeof(DNP3LinkHeader) + 3]++; + FAIL_IF(DNP3CheckCRC(request + sizeof(DNP3LinkHeader), + DNP3_BLOCK_SIZE + DNP3_CRC_LEN)); + + PASS; +} + +/** + * \test Test validation of all CRCs in user data. + */ +static int DNP3CheckUserDataCRCsTest(void) +{ + /* Multi-block data with valid CRCs. */ + uint8_t data_valid[] = { + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0xff, 0xff, /* CRC. */ + }; + FAIL_IF(!DNP3CheckUserDataCRCs(data_valid, sizeof(data_valid))); + + /* Multi-block data with one non-crc byte altered. */ + uint8_t data_invalid[] = { + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x01, /* Invalid byte. */ + 0xff, 0xff, /* CRC. */ + }; + FAIL_IF(DNP3CheckUserDataCRCs(data_invalid, sizeof(data_invalid))); + + /* 1 byte - need at least 3. */ + uint8_t one_byte_nocrc[] = { 0x01 }; + FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc, sizeof(one_byte_nocrc))); + + /* 2 bytes - need at least 3. */ + uint8_t two_byte_nocrc[] = { 0x01, 0x02 }; + FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc, sizeof(two_byte_nocrc))); + + /* 3 bytes, valid CRC. */ + uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 }; + *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC( + three_bytes_good_crc, 1); + FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc, + sizeof(three_bytes_good_crc))); + + PASS; +} + +/** + * \test Test the link layer length calculation. + * + * Test the calculation that converts the link provided in the DNP3 + * header to the actual length of the frame. That is the length with + * CRCs as the length in the header does not include CRCs. + */ +static int DNP3CalculateLinkLengthTest(void) +{ + /* These are invalid. */ + FAIL_IF(DNP3CalculateLinkLength(0) != 0); + FAIL_IF(DNP3CalculateLinkLength(1) != 0); + FAIL_IF(DNP3CalculateLinkLength(2) != 0); + FAIL_IF(DNP3CalculateLinkLength(3) != 0); + FAIL_IF(DNP3CalculateLinkLength(4) != 0); + + /* This is the minimum size. */ + FAIL_IF(DNP3CalculateLinkLength(5) != 10); + + /* 1 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(21) != 28); + + /* 2 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(37) != 46); + + /* 2 full user data blocks, plus one more byte. */ + /* 2 full user data blocks of data. */ + FAIL_IF(DNP3CalculateLinkLength(38) != 49); + + /* The maximum size. */ + FAIL_IF(DNP3CalculateLinkLength(255) != 292); + + PASS; +} + +/** + * \test The conversion of length with CRCs to the length without + * CRCs. + */ +static int DNP3CalculateTransportLengthWithoutCRCsTest(void) +{ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15); + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16); + + /* 19 bytes is not enough for a second block. */ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1); + + /* 20 bytes really isn't enough either, but is large enough to + * satisfy the CRC on the second block. */ + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16); + + FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17); + + PASS; +} + +/** + * \test Test the validation of the link header CRC. + */ +static int DNP3ParserCheckLinkHeaderCRC(void) +{ + /* DNP3 frame with valid headers and CRCs. */ + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + DNP3LinkHeader *header = (DNP3LinkHeader *)request; + FAIL_IF(!DNP3CheckLinkHeaderCRC(header)); + + /* Alter a byte in the header. */ + request[4] = 0; + FAIL_IF(DNP3CheckLinkHeaderCRC(header)); + + PASS; +} + +/** + * \test Test removal of CRCs from user data. + */ +static int DNP3ReassembleApplicationLayerTest01(void) +{ + uint32_t reassembled_len = 0; + uint8_t *output = NULL; + + uint8_t payload[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00, 0x00, 0x00, + 0x00, + 0xff, 0xff, /* CRC. */ + }; + + uint8_t expected[] = { + 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + /* CRC removed. */ + 0x00, 0x00, 0x00, 0x00, + 0x00 + /* CRC removed. */ + }; + + /* Valid frame. */ + FAIL_IF(!DNP3ReassembleApplicationLayer(payload, + sizeof(payload), &output, &reassembled_len)); + FAIL_IF(output == NULL); + FAIL_IF(reassembled_len != sizeof(expected)); + FAIL_IF(memcmp(expected, output, reassembled_len)); + SCFree(output); + + /* 1 byte, invalid. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output, + &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 2 bytes, invalid. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output, + &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 3 bytes, minimum - but that would only be the transport header + * which isn't included in the output. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output, + &reassembled_len)); + FAIL_IF(output != NULL); + FAIL_IF(reassembled_len != 0); + + /* 4 bytes is the minimum to get any reassembled data. */ + reassembled_len = 0; + output = NULL; + FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output, + &reassembled_len)); + FAIL_IF(output == NULL); + FAIL_IF(reassembled_len != 1); + + /* Last block too short (by 1 byte) for data + CRC. */ + uint8_t short_payload1[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, 0x00 + }; + reassembled_len = 0; + FAIL_IF(DNP3ReassembleApplicationLayer(short_payload1, + sizeof(short_payload1), &output, &reassembled_len)); + + /* Last block too short (by 2 bytes) for data + CRC. */ + uint8_t short_payload2[] = { + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0xff, 0xc9, 0x05, 0x0c, + 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x72, 0xef, /* CRC. */ + + 0x00, + }; + reassembled_len = 0; + FAIL_IF(DNP3ReassembleApplicationLayer(short_payload2, + sizeof(short_payload2), &output, &reassembled_len)); + + PASS; +} + +/** + * \test Test the probing parser. + */ +static int DNP3ProbingParserTest(void) +{ + uint8_t pkt[] = { + 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00, + 0xbd, 0x71 + }; + + /* Valid frame. */ + FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_DNP3); + + /* Send too little bytes. */ + FAIL_IF(DNP3ProbingParser(pkt, sizeof(DNP3LinkHeader) - 1, NULL) != ALPROTO_UNKNOWN); + + /* Bad start bytes. */ + pkt[0] = 0x06; + FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_FAILED); + + /* Restore start byte. */ + pkt[0] = 0x05; + + /* Set the length to a value less than the minimum length of 5. */ + pkt[2] = 0x03; + FAIL_IF(DNP3ProbingParser(pkt, sizeof(pkt), NULL) != ALPROTO_FAILED); + + /* Send a banner. */ + char mybanner[] = "Welcome to DNP3 SCADA."; + FAIL_IF(DNP3ProbingParser((uint8_t *)mybanner, sizeof(mybanner), NULL) != ALPROTO_DNP3); + + PASS; +} + +/** + * \test Test a basic request/response. + */ +int DNP3ParserTestRequestResponse(void) +{ + DNP3State *state = NULL; + + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + uint8_t response[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff + }; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(DNP3HasEvents(state)); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer == NULL); + FAIL_IF(tx->request_buffer_len != 20); + FAIL_IF(tx->request_ah.function_code != DNP3_APP_FC_DIR_OPERATE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response, sizeof(response))); + SCMutexUnlock(&flow.m); + FAIL_IF(DNP3GetTx(state, 0) != tx); + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_buffer == NULL); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test an unsolicited response from an outstation. + * + * This is kind of like a request initiated from the "server". + */ +static int DNP3ParserTestUnsolicitedResponseConfirm(void) +{ + DNP3State *state = NULL; + + /* Unsolicited response with confirm bit set. */ + uint8_t response[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, + 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9 + }; + + /* Confirm. */ + uint8_t confirm[] = { + 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00, + 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a, + 0x3d + }; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response, sizeof(response))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(DNP3HasEvents(state)); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer != NULL); + FAIL_IF(tx->response_buffer == NULL); + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_ah.function_code != DNP3_APP_FC_UNSOLICITED_RESP); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, confirm, sizeof(confirm))); + SCMutexUnlock(&flow.m); + FAIL_IF(DNP3GetTx(state, 0) != tx); + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_buffer == NULL); + /* FAIL_IF(tx->iin1 != 0 || tx->iin2 != 0); */ + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test flood state. + */ +int DNP3ParserTestFlooded(void) +{ + DNP3State *state = NULL; + + uint8_t request[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(DNP3HasEvents(state)); + + DNP3Transaction *tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer == NULL); + FAIL_IF(tx->request_buffer_len != 20); + /* FAIL_IF(tx->app_function_code != DNP3_APP_FC_DIR_OPERATE); */ + FAIL_IF(tx->response_done); + + for (int i = 0; i < DNP3_DEFAULT_REQ_FLOOD_COUNT - 1; i++) { + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + } + FAIL_IF(state->flooded); + FAIL_IF(DNP3GetAlstateProgress(tx, 0)); + + /* One more request should trip us into flooded state. */ + SCMutexLock(&flow.m); + FAIL_IF(AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request))); + SCMutexUnlock(&flow.m); + FAIL_IF(!state->flooded); + + /* Progress for the oldest tx should return 1. */ + FAIL_IF(!DNP3GetAlstateProgress(tx, 0)); + + /* But progress for the current state should still return 0. */ + FAIL_IF(DNP3GetAlstateProgress(state->curr, 0)); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test parsing of partial frames. + * + * As DNP3 operates over TCP, it is possible that a partial DNP3 frame + * is received. Test that the partial frame will be buffered until the + * remainder is seen. + */ +static int DNP3ParserTestPartialFrame(void) +{ + DNP3State *state = NULL; + DNP3Transaction *tx; + int r; + + uint8_t request_partial1[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + }; + + uint8_t request_partial2[] = { + /* Remainder of application layer. */ + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff + }; + + uint8_t response_partial1[] = { + /* DNP3 start. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + }; + + uint8_t response_partial2[] = { + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff + }; + + /* Boiler plate for app layer setup. */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + StreamTcpInitConfig(TRUE); + + /* Pass in the first partial frame. */ + + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request_partial1, sizeof(request_partial1)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* Frame should just be buffered, but not yet processed. */ + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(state->request_buffer.len != sizeof(request_partial1)); + FAIL_IF(state->request_buffer.offset != 0); + FAIL_IF(memcmp(state->request_buffer.buffer, request_partial1, + sizeof(request_partial1))); + + /* There should not be a transaction yet. */ + FAIL_IF(state->transaction_max != 0); + FAIL_IF(DNP3GetTx(state, 0) != NULL); + + /* Send the second partial. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOSERVER, request_partial2, sizeof(request_partial2)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* The second partial completed the frame, the buffer should now + * be clear. */ + FAIL_IF(state->request_buffer.len != 0); + FAIL_IF(state->request_buffer.offset != 0); + + /* Should now have a complete transaction. */ + tx = DNP3GetTx(state, 0); + FAIL_IF(tx == NULL); + FAIL_IF(tx->tx_num != 1); + FAIL_IF(tx != state->curr); + FAIL_IF(tx->request_buffer == NULL); + FAIL_IF(tx->request_buffer_len != 20); + FAIL_IF(tx->request_ah.function_code != DNP3_APP_FC_DIR_OPERATE); + + /* Send partial response. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response_partial1, sizeof(response_partial1)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + FAIL_IF(state->response_buffer.len != sizeof(response_partial1)); + FAIL_IF(state->response_buffer.offset != 0); + FAIL_IF(tx->response_done); + + /* Send rest of response. */ + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, response_partial2, sizeof(response_partial2)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + /* Buffer should now be empty. */ + FAIL_IF(state->response_buffer.len != 0); + FAIL_IF(state->response_buffer.offset != 0); + + /* Transaction should be replied to now. */ + FAIL_IF(!tx->response_done); + FAIL_IF(tx->response_buffer == NULL); + FAIL_IF(tx->response_buffer_len == 0); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test multiple DNP3 frames in one TCP read. + */ +static int DNP3ParserTestMultiFrame(void) +{ + DNP3State *state = NULL; + + /* Unsolicited response 1. */ + uint8_t unsol_response1[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8, + 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9, + }; + + /* Unsolicited response 2. */ + uint8_t unsol_response2[] = { + 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00, + 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02, + 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8, + 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9, + }; + + uint8_t combined[sizeof(unsol_response1) + sizeof(unsol_response2)]; + memcpy(combined, unsol_response1, sizeof(unsol_response1)); + memcpy(combined + sizeof(unsol_response1), unsol_response2, + sizeof(unsol_response2)); + + /* Setup. */ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow flow; + TcpSession ssn; + int r; + memset(&flow, 0, sizeof(flow)); + memset(&ssn, 0, sizeof(ssn)); + flow.protoctx = (void *)&ssn; + flow.proto = IPPROTO_TCP; + StreamTcpInitConfig(TRUE); + + SCMutexLock(&flow.m); + r = AppLayerParserParse(NULL, alp_tctx, &flow, ALPROTO_DNP3, + STREAM_TOCLIENT, combined, sizeof(combined)); + SCMutexUnlock(&flow.m); + FAIL_IF(r != 0); + + state = flow.alstate; + FAIL_IF(state == NULL); + FAIL_IF(state->transaction_max != 2); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&flow); + DNP3StateFree(state); + PASS; +} + +/** + * \test Test the parsing of a request PDU. + * + * The PDU under test contains a single read request object: + * - Group: 1 + * - Variation: 0 + * - Count: 0 + */ +static int DNP3ParserTestParsePDU01(void) +{ + /* Frame to be tested. This frame is a DNP3 request with one read + * request data object, group 1, variation 0. */ + const uint8_t pkt[] = { + 0x05, 0x64, + 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f, + 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e + }; + + DNP3State *dnp3state = DNP3StateAlloc(); + int pdus = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(pdus < 1); + DNP3Transaction *dnp3tx = DNP3GetTx(dnp3state, 0); + FAIL_IF_NULL(dnp3tx); + FAIL_IF(!dnp3tx->has_request); + FAIL_IF(TAILQ_EMPTY(&dnp3tx->request_objects)); + DNP3Object *object = TAILQ_FIRST(&dnp3tx->request_objects); + FAIL_IF(object->group != 1 || object->variation != 0); + FAIL_IF(object->count != 0); + + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \test Test the decode of a DNP3 fragment with a single 70:3 object. + */ +static int DNP3ParserDecodeG70V3Test(void) +{ + const uint8_t pkt[] = { + 0x05, 0x64, + 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee, + 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55, + 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, + 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, + 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, + 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, + 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, + 0xc4, 0x8b + }; + + DNP3State *dnp3state = DNP3StateAlloc(); + FAIL_IF_NULL(dnp3state); + int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(bytes != sizeof(pkt)); + FAIL_IF(DNP3HasEvents(dnp3state)); + DNP3Transaction *tx = DNP3GetTx(dnp3state, 0); + FAIL_IF_NULL(tx); + FAIL_IF_NOT(tx->has_request); + DNP3Object *obj = TAILQ_FIRST(&tx->request_objects); + FAIL_IF_NULL(obj); + FAIL_IF_NOT(obj->group == 70); + FAIL_IF_NOT(obj->variation == 3); + FAIL_IF_NOT(obj->prefix_code == 0x5); + FAIL_IF_NOT(obj->range_code == 0xb); + FAIL_IF_NOT(obj->count == 1); + DNP3Point *point = TAILQ_FIRST(obj->points); + FAIL_IF_NULL(point); + FAIL_IF_NOT(point->prefix == 85); + FAIL_IF_NOT(point->size == 85); + FAIL_IF_NULL(point->data); + DNP3ObjectG70V3 *data = point->data; + FAIL_IF_NOT(strcmp( + data->filename, + "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0); + DNP3StateFree(dnp3state); + PASS; +} + +/** + * \brief Test that an alert is raised on an unknown object. + */ +static int DNP3ParserUnknownEventAlertTest(void) +{ + /* Valid DNP3 frame with 70:3 object. */ + uint8_t pkt[] = { + 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, + 0xc7, 0xee, + + 0xc7, 0xc9, 0x1b, + + /* Object and variation. Originally 70:3, now 70:99, an + * unknown object. */ + 0x46, 0x63, + + 0x5b, 0x01, 0x55, + 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43, + 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44, + 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c, + 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d, + 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c, + 0xc4, 0x8b + }; + + DNP3FixCrc(pkt + 10, sizeof(pkt) - 10); + + DNP3State *dnp3state = DNP3StateAlloc(); + FAIL_IF_NULL(dnp3state); + int bytes = DNP3HandleRequestLinkLayer(dnp3state, pkt, sizeof(pkt)); + FAIL_IF(bytes != sizeof(pkt)); + + /* Should have an event now. */ + FAIL_IF_NOT(DNP3HasEvents(dnp3state)); + + DNP3StateFree(dnp3state); + PASS; +} + +#endif + +void DNP3ParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC); + UtRegisterTest("DNP3ParserCheckLinkHeaderCRC", + DNP3ParserCheckLinkHeaderCRC); + UtRegisterTest("DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest); + UtRegisterTest("DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest); + UtRegisterTest("DNP3CalculateTransportLengthWithoutCRCsTest", + DNP3CalculateTransportLengthWithoutCRCsTest); + UtRegisterTest("DNP3ReassembleApplicationLayerTest01", + DNP3ReassembleApplicationLayerTest01); + UtRegisterTest("DNP3ProbingParserTest", DNP3ProbingParserTest); + UtRegisterTest("DNP3ParserTestRequestResponse", + DNP3ParserTestRequestResponse); + UtRegisterTest("DNP3ParserTestUnsolicitedResponseConfirm", + DNP3ParserTestUnsolicitedResponseConfirm); + UtRegisterTest("DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame); + UtRegisterTest("DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame); + UtRegisterTest("DNP3ParserTestFlooded", DNP3ParserTestFlooded); + UtRegisterTest("DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01); + UtRegisterTest("DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test); + UtRegisterTest("DNP3ParserUnknownEventAlertTest", + DNP3ParserUnknownEventAlertTest); +#endif +} diff --git a/src/app-layer-dnp3.h b/src/app-layer-dnp3.h new file mode 100644 index 000000000000..13cebc7478eb --- /dev/null +++ b/src/app-layer-dnp3.h @@ -0,0 +1,277 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __APP_LAYER_DNP3_H__ +#define __APP_LAYER_DNP3_H__ + +#include "detect-engine-state.h" +#include "util-hashlist.h" +#include "util-byte.h" + +/** + * The maximum size of a DNP3 link PDU. + */ +#define DNP3_MAX_LINK_PDU_LEN 292 + +/* DNP3 application request function codes. */ +#define DNP3_APP_FC_CONFIRM 0x00 +#define DNP3_APP_FC_READ 0x01 +#define DNP3_APP_FC_WRITE 0x02 +#define DNP3_APP_FC_SELECT 0x03 +#define DNP3_APP_FC_OPERATE 0x04 +#define DNP3_APP_FC_DIR_OPERATE 0x05 +#define DNP3_APP_FC_DIR_OPERATE_NR 0x06 +#define DNP3_APP_FC_FREEZE 0x07 +#define DNP3_APP_FC_FREEZE_NR 0x08 +#define DNP3_APP_FC_FREEZE_CLEAR 0x09 +#define DNP3_APP_FC_FREEZE_CLEAR_NR 0x0a +#define DNP3_APP_FC_FREEZE_AT_TIME 0x0b +#define DNP3_APP_FC_FREEZE_AT_TIME_NR 0x0c +#define DNP3_APP_FC_COLD_RESTART 0x0d +#define DNP3_APP_FC_WARM_RESTART 0x0e +#define DNP3_APP_FC_INITIALIZE_DATA 0x0f +#define DNP3_APP_FC_INITIALIZE_APPLICATION 0x10 +#define DNP3_APP_FC_START_APPLICATION 0x11 +#define DNP3_APP_FC_STOP_APPLICATION 0x12 +#define DNP3_APP_FC_SAVE_CONFIGURATION 0x13 +#define DNP3_APP_FC_ENABLE_UNSOLICITED 0x14 +#define DNP3_APP_FC_DISABLE_UNSOLICTED 0x15 +#define DNP3_APP_FC_ASSIGN_CLASS 0x16 +#define DNP3_APP_FC_DELAY_MEASUREMENT 0x17 +#define DNP3_APP_FC_RECORD_CURRENT_TIME 0x18 +#define DNP3_APP_FC_OPEN_TIME 0x19 +#define DNP3_APP_FC_CLOSE_FILE 0x1a +#define DNP3_APP_FC_DELETE_FILE 0x1b +#define DNP3_APP_FC_GET_FILE_INFO 0x1c +#define DNP3_APP_FC_AUTHENTICATE_FILE 0x1d +#define DNP3_APP_FC_ABORT_FILE 0x1e +#define DNP3_APP_FC_ACTIVATE_CONFIG 0x1f +#define DNP3_APP_FC_AUTH_REQ 0x20 +#define DNP3_APP_FC_AUTH_REQ_NR 0x21 + +/* DNP3 application response function codes. */ +#define DNP3_APP_FC_RESPONSE 0x81 +#define DNP3_APP_FC_UNSOLICITED_RESP 0x82 +#define DNP3_APP_FC_AUTH_RESP 0x83 + +/* Extract fields from the link control octet. */ +#define DNP3_LINK_DIR(control) (control & 0x80) +#define DNP3_LINK_PRI(control) (control & 0x40) +#define DNP3_LINK_FCB(control) (control & 0x20) +#define DNP3_LINK_FCV(control) (control & 0x10) +#define DNP3_LINK_FC(control) (control & 0x0f) + +/* Extract fields from transport layer header octet. */ +#define DNP3_TH_FIN(x) (x & 0x80) +#define DNP3_TH_FIR(x) (x & 0x40) +#define DNP3_TH_SEQ(x) (x & 0x3f) + +/* Extract fields from the application control octet. */ +#define DNP3_APP_FIR(x) (x & 0x80) +#define DNP3_APP_FIN(x) (x & 0x40) +#define DNP3_APP_CON(x) (x & 0x20) +#define DNP3_APP_UNS(x) (x & 0x10) +#define DNP3_APP_SEQ(x) (x & 0x0f) + +/* DNP3 values are stored in little endian on the wire, so swapping will be + * needed on big endian architectures. */ +#if __BYTE_ORDER == __BIG_ENDIAN +#define DNP3_SWAP16(x) SCByteSwap16(x) +#define DNP3_SWAP32(x) SCByteSwap32(x) +#define DNP3_SWAP64(x) SCByteSwap64(x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define DNP3_SWAP16(x) x +#define DNP3_SWAP32(x) x +#define DNP3_SWAP64(x) x +#endif + +/* DNP3 decoder events. */ +enum { + DNP3_DECODER_EVENT_FLOODED = 1, + DNP3_DECODER_EVENT_LEN_TOO_SMALL, + DNP3_DECODER_EVENT_BAD_LINK_CRC, + DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC, + DNP3_DECODER_EVENT_MALFORMED, + DNP3_DECODER_EVENT_UNKNOWN_OBJECT, +}; + +/** + * \brief DNP3 link header. + */ +typedef struct DNP3LinkHeader_ { + uint8_t start_byte0; /**< First check byte. */ + uint8_t start_byte1; /**< Second check byte. */ + uint8_t len; /**< Length of PDU without CRCs. */ + uint8_t control; /**< Control flags. */ + uint16_t dst; /**< DNP3 destination address. */ + uint16_t src; /**< DNP3 source address. */ + uint16_t crc; /**< Link header CRC. */ +} __attribute__((__packed__)) DNP3LinkHeader; + +/** + * \brief DNP3 transport header. + */ +typedef uint8_t DNP3TransportHeader; + +/** + * \brief DNP3 application header. + */ +typedef struct DNP3ApplicationHeader_ { + uint8_t control; /**< Control flags. */ + uint8_t function_code; /**< Application function code. */ +} __attribute__((__packed__)) DNP3ApplicationHeader; + +/** + * \brief DNP3 internal indicators. + * + * Part of the application header for responses only. + */ +typedef struct DNP3InternalInd_ { + uint8_t iin1; + uint8_t iin2; +} __attribute__((__packed__)) DNP3InternalInd; + +/** + * \brief A struct used for buffering incoming data prior to reassembly. + */ +typedef struct DNP3Buffer_ { + uint8_t *buffer; + size_t size; + int len; + int offset; +} DNP3Buffer; + +/** + * \brief DNP3 application object header. + */ +typedef struct DNP3ObjHeader_ { + uint8_t group; + uint8_t variation; + uint8_t qualifier; +} __attribute__((packed)) DNP3ObjHeader; + +/** + * \brief DNP3 object point. + * + * Each DNP3 object can have 0 or more points representing the values + * of the object. + */ +typedef struct DNP3Point_ { + uint32_t prefix; /**< Prefix value for point. */ + uint32_t index; /**< Index of point. If the object is prefixed + * with an index then this will be that + * value. Otherwise this is the place the point + * was in the list of points (starting at 0). */ + uint32_t size; /**< Size of point if the object prefix was a + * size. */ + void *data; /**< Data for this point. */ + TAILQ_ENTRY(DNP3Point_) next; +} DNP3Point; + +typedef TAILQ_HEAD(DNP3PointList_, DNP3Point_) DNP3PointList; + +/** + * \brief Struct to hold the list of decoded objects. + */ +typedef struct DNP3Object_ { + uint8_t group; + uint8_t variation; + uint8_t qualifier; + uint8_t prefix_code; + uint8_t range_code; + uint32_t start; + uint32_t stop; + uint32_t count; + DNP3PointList *points; /**< List of points for this object. */ + + TAILQ_ENTRY(DNP3Object_) next; +} DNP3Object; + +typedef TAILQ_HEAD(DNP3ObjectList_, DNP3Object_) DNP3ObjectList; + +/** + * \brief DNP3 transaction. + */ +typedef struct DNP3Transaction_ { + uint64_t tx_num; /**< Internal transaction ID. */ + uint32_t logged; /**< Flags indicating which loggers have logged this tx. */ + + struct DNP3State_ *dnp3; + + uint8_t has_request; + uint8_t request_done; + DNP3LinkHeader request_lh; + DNP3TransportHeader request_th; + DNP3ApplicationHeader request_ah; + uint8_t *request_buffer; /**< Reassembled request + * buffer. */ + uint32_t request_buffer_len; + uint8_t request_complete; /**< Was the decode + * complete. It will not be + * complete if we hit objects + * we do not know. */ + DNP3ObjectList request_objects; + + uint8_t has_response; + uint8_t response_done; + DNP3LinkHeader response_lh; + DNP3TransportHeader response_th; + DNP3ApplicationHeader response_ah; + DNP3InternalInd response_iin; + uint8_t *response_buffer; /**< Reassembed response + * buffer. */ + uint32_t response_buffer_len; + uint8_t response_complete; /**< Was the decode + * complete. It will not be + * complete if we hit objects + * we do not know. */ + DNP3ObjectList response_objects; + + AppLayerDecoderEvents *decoder_events; /**< Per transcation + * decoder events. */ + DetectEngineState *de_state; + + TAILQ_ENTRY(DNP3Transaction_) next; +} DNP3Transaction; + +TAILQ_HEAD(TxListHead, DNP3Transaction_); + +/** + * \brief Per flow DNP3 state. + */ +typedef struct DNP3State_ { + TAILQ_HEAD(, DNP3Transaction_) tx_list; + DNP3Transaction *curr; /**< Current transaction. */ + uint64_t transaction_max; + uint16_t events; + uint32_t unreplied; /**< Number of unreplied requests. */ + uint8_t flooded; /**< Flag indicating flood. */ + + DNP3Buffer request_buffer; /**< Request buffer for buffering + * incomplete request PDUs received + * over TCP. */ + DNP3Buffer response_buffer; /**< Response buffer for buffering + * incomplete response PDUs received + * over TCP. */ + +} DNP3State; + +void RegisterDNP3Parsers(void); +void DNP3ParserRegisterTests(void); +int DNP3PrefixIsSize(uint8_t); + +#endif /* __APP_LAYER_DNP3_H__ */ diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 5f8e0be13326..c9f7eb334595 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -103,12 +103,22 @@ int DNSCheckMemcap(uint32_t want, DNSState *state) return 0; } -void DNSMemcapGetCounters(uint64_t *memuse, uint64_t *memcap_state, - uint64_t *memcap_global) +uint64_t DNSMemcapGetMemuseCounter(void) { - *memuse = SC_ATOMIC_GET(dns_memuse); - *memcap_state = SC_ATOMIC_GET(dns_memcap_state); - *memcap_global = SC_ATOMIC_GET(dns_memcap_global); + uint64_t x = SC_ATOMIC_GET(dns_memuse); + return x; +} + +uint64_t DNSMemcapGetMemcapStateCounter(void) +{ + uint64_t x = SC_ATOMIC_GET(dns_memcap_state); + return x; +} + +uint64_t DNSMemcapGetMemcapGlobalCounter(void) +{ + uint64_t x = SC_ATOMIC_GET(dns_memcap_global); + return x; } SCEnumCharMap dns_decoder_event_table[ ] = { @@ -173,15 +183,31 @@ void *DNSGetTx(void *alstate, uint64_t tx_id) DNSState *dns_state = (DNSState *)alstate; DNSTransaction *tx = NULL; + /* fast track: try the current tx */ if (dns_state->curr && dns_state->curr->tx_num == tx_id + 1) return dns_state->curr; + /* fast track: + * if the prev tx_id is equal to the stored tx ptr, we can + * use this shortcut to get to the next. */ + if (dns_state->iter) { + if (tx_id == dns_state->iter->tx_num) { + tx = TAILQ_NEXT(dns_state->iter, next); + if (tx && tx->tx_num == tx_id + 1) { + dns_state->iter = tx; + return tx; + } + } + } + + /* no luck with the fast tracks, do the full list walk */ TAILQ_FOREACH(tx, &dns_state->tx_list, next) { SCLogDebug("tx->tx_num %u, tx_id %"PRIu64, tx->tx_num, (tx_id+1)); if ((tx_id+1) != tx->tx_num) continue; SCLogDebug("returning tx %p", tx); + dns_state->iter = tx; return tx; } @@ -197,17 +223,37 @@ uint64_t DNSGetTxCnt(void *alstate) int DNSGetAlstateProgress(void *tx, uint8_t direction) { DNSTransaction *dns_tx = (DNSTransaction *)tx; - if (direction == 1) - return dns_tx->replied|dns_tx->reply_lost; + if (direction & STREAM_TOCLIENT) { + /* response side of the tx is done if we parsed a reply + * or if we tagged this tx as 'reply lost'. */ + return (dns_tx->replied|dns_tx->reply_lost) ? 1 : 0; + } else { - /* toserver/query is complete if we have stored a query */ - return (TAILQ_FIRST(&dns_tx->query_list) != NULL); + /* tx is only created if we have a complete request, + * or if we lost the request. Either way, if we have + * a tx it we consider the request complete. */ + return 1; } } +void DNSSetTxLogged(void *alstate, void *tx, uint32_t logger) +{ + DNSTransaction *dns_tx = (DNSTransaction *)tx; + dns_tx->logged |= logger; +} + +int DNSGetTxLogged(void *alstate, void *tx, uint32_t logger) +{ + DNSTransaction *dns_tx = (DNSTransaction *)tx; + if (dns_tx->logged & logger) + return 1; + + return 0; +} + /** \brief get value for 'complete' status in DNS * - * For DNS we use a simple bool. + * For DNS we use a simple bool. 1 means done. */ int DNSGetAlstateProgressCompletionStatus(uint8_t direction) { @@ -277,6 +323,15 @@ static void DNSTransactionFree(DNSTransaction *tx, DNSState *state) AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + if (tx->de_state != NULL) { + DetectEngineStateFree(tx->de_state); + BUG_ON(state->tx_with_detect_state_cnt == 0); + state->tx_with_detect_state_cnt--; + } + + if (state->iter == tx) + state->iter = NULL; + DNSDecrMemcap(sizeof(DNSTransaction), state); SCFree(tx); SCReturn; @@ -337,6 +392,9 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16 TAILQ_FOREACH(tx, &dns_state->tx_list, next) { if (tx->tx_id == tx_id) { return tx; + } else if ((dns_state->transaction_max - tx->tx_num) > + (dns_state->window - 1U)) { + tx->reply_lost = 1; } } } @@ -344,6 +402,27 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16 return NULL; } +int DNSStateHasTxDetectState(void *alstate) +{ + DNSState *state = (DNSState *)alstate; + return (state->tx_with_detect_state_cnt > 0); +} + +DetectEngineState *DNSGetTxDetectState(void *vtx) +{ + DNSTransaction *tx = (DNSTransaction *)vtx; + return tx->de_state; +} + +int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s) +{ + DNSState *state = (DNSState *)alstate; + DNSTransaction *tx = (DNSTransaction *)vtx; + state->tx_with_detect_state_cnt++; + tx->de_state = s; + return 0; +} + void *DNSStateAlloc(void) { void *s = SCMalloc(sizeof(DNSState)); @@ -378,6 +457,8 @@ void DNSStateFree(void *s) SCFree(dns_state->buffer); } + BUG_ON(dns_state->tx_with_detect_state_cnt > 0); + DNSDecrMemcap(sizeof(DNSState), dns_state); BUG_ON(dns_state->memuse > 0); SCFree(s); @@ -476,19 +557,11 @@ void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16 return; } - /* see if the last tx is unreplied */ - if (dns_state->curr != tx && dns_state->curr != NULL && - dns_state->curr->replied == 0) - { - dns_state->curr->reply_lost = 1; - dns_state->unreplied_cnt++; - - /* check flood limit */ - if (dns_config.request_flood != 0 && - dns_state->unreplied_cnt > dns_config.request_flood) { - DNSSetEvent(dns_state, DNS_DECODER_EVENT_FLOODED); - dns_state->givenup = 1; - } + /* check flood limit */ + if (dns_config.request_flood != 0 && + dns_state->unreplied_cnt > dns_config.request_flood) { + DNSSetEvent(dns_state, DNS_DECODER_EVENT_FLOODED); + dns_state->givenup = 1; } if (tx == NULL) { @@ -501,6 +574,7 @@ void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16 dns_state->curr = tx; tx->tx_num = dns_state->transaction_max; SCLogDebug("new tx %u with internal id %u", tx->tx_id, tx->tx_num); + dns_state->unreplied_cnt++; } if (DNSCheckMemcap((sizeof(DNSQueryEntry) + fqdn_len), dns_state) < 0) @@ -531,6 +605,7 @@ void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t * return; TAILQ_INSERT_TAIL(&dns_state->tx_list, tx, next); dns_state->curr = tx; + dns_state->transaction_max++; tx->tx_num = dns_state->transaction_max; } @@ -567,9 +642,6 @@ void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t * /* mark tx is as replied so we can log it */ tx->replied = 1; - - /* reset unreplied counter */ - dns_state->unreplied_cnt = 0; } /** \internal @@ -593,7 +665,7 @@ void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t * static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const uint32_t input_len, const uint16_t offset, uint8_t *fqdn, const size_t fqdn_size) { - if (input + input_len < input + offset + 1) { + if (offset >= input_len) { SCLogDebug("input buffer too small for domain of len %u", offset); goto insufficient_data; } @@ -609,13 +681,18 @@ static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const ui SCReturnUInt(6U); } + if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { + SCLogDebug("input buffer too small"); + goto insufficient_data; + } + while (length != 0) { int cnt = 0; while (length & 0xc0) { - uint16_t offset = ((length & 0x3f) << 8) + *(qdata+1); - qdata = (const uint8_t *)input + offset; + uint16_t off = ((length & 0x3f) << 8) + *(qdata+1); + qdata = (const uint8_t *)input + off; - if (input + input_len < qdata + 1) { + if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) { SCLogDebug("input buffer too small"); goto insufficient_data; } @@ -647,8 +724,12 @@ static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const ui } qdata += length; - if (input + input_len < qdata + 1) { - SCLogDebug("input buffer too small for len field"); + /* if we're at the end of the input data, we're done */ + if ((uint64_t)((qdata + 1) - input) == (uint64_t)input_len) { + break; + } + else if ((uint64_t)((qdata + 1) - input) > (uint64_t)input_len) { + SCLogDebug("input buffer too small"); goto insufficient_data; } @@ -725,10 +806,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((fqdn_len = DNSResponseGetNameByOffset(input, input_len, data - input, fqdn, sizeof(fqdn))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } //PrintRawDataFp(stdout, fqdn, fqdn_len); @@ -743,10 +821,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((fqdn_len = DNSResponseGetNameByOffset(input, input_len, offset, fqdn, sizeof(fqdn))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } //PrintRawDataFp(stdout, fqdn, fqdn_len); @@ -759,22 +834,23 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } const DNSAnswerHeader *head = (DNSAnswerHeader *)data; - switch (ntohs(head->type)) { - case DNS_RECORD_TYPE_A: - case DNS_RECORD_TYPE_AAAA: - case DNS_RECORD_TYPE_CNAME: - { - data += sizeof(DNSAnswerHeader); + const uint16_t datalen = ntohs(head->len); - SCLogDebug("head->len %u", ntohs(head->len)); + data += sizeof(DNSAnswerHeader); - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } - SCLogDebug("TTL %u", ntohl(head->ttl)); + SCLogDebug("head->len %u", ntohs(head->len)); + + if (input + input_len < data + ntohs(head->len)) { + SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); + goto insufficient_data; + } + + SCLogDebug("TTL %u", ntohl(head->ttl)); - if (ntohs(head->type) == DNS_RECORD_TYPE_A && ntohs(head->len) == 4) { + switch (ntohs(head->type)) { + case DNS_RECORD_TYPE_A: + { + if (datalen == 0 || datalen == 4) { //PrintRawDataFp(stdout, data, ntohs(head->len)); //char a[16]; //PrintInet(AF_INET, (const void *)data, a, sizeof(a)); @@ -782,65 +858,56 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - data, 4, ntohs(dns_header->tx_id)); - } else if (ntohs(head->type) == DNS_RECORD_TYPE_AAAA && ntohs(head->len) == 16) { + data, datalen, ntohs(dns_header->tx_id)); + } else { + SCLogDebug("invalid length for A response data: %u", ntohs(head->len)); + goto bad_data; + } + + data += datalen; + break; + } + case DNS_RECORD_TYPE_AAAA: + { + if (datalen == 0 || datalen == 16) { //char a[46]; //PrintInet(AF_INET6, (const void *)data, a, sizeof(a)); //SCLogInfo("AAAA %s TTL %u", a, ntohl(head->ttl)); DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - data, 16, ntohs(dns_header->tx_id)); - } else if (ntohs(head->type) == DNS_RECORD_TYPE_CNAME) { - uint8_t cname[DNS_MAX_SIZE]; - uint16_t cname_len = 0; - - if ((cname_len = DNSResponseGetNameByOffset(input, input_len, - data - input, cname, sizeof(cname))) == 0) - { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif - goto insufficient_data; - } - - DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, - ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - cname, cname_len, ntohs(dns_header->tx_id)); + data, datalen, ntohs(dns_header->tx_id)); + } else { + SCLogDebug("invalid length for AAAA response data: %u", ntohs(head->len)); + goto bad_data; } - data += ntohs(head->len); + data += datalen; break; } case DNS_RECORD_TYPE_MX: + case DNS_RECORD_TYPE_CNAME: + case DNS_RECORD_TYPE_PTR: { - data += sizeof(DNSAnswerHeader); + uint8_t name[DNS_MAX_SIZE]; + uint16_t name_len = 0; + uint8_t skip = 0; - SCLogDebug("head->len %u", ntohs(head->len)); - - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; + if (ntohs(head->type) == DNS_RECORD_TYPE_MX) { + // Skip the preference header + skip = 2; } - SCLogDebug("TTL %u", ntohl(head->ttl)); - - uint8_t mxname[DNS_MAX_SIZE]; - uint16_t mxname_len = 0; - - if ((mxname_len = DNSResponseGetNameByOffset(input, input_len, - data - input + 2, mxname, sizeof(mxname))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + if ((name_len = DNSResponseGetNameByOffset(input, input_len, + data - input + skip, name, sizeof(name))) == 0) + { + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), - mxname, mxname_len, ntohs(dns_header->tx_id)); + name, name_len, ntohs(dns_header->tx_id)); data += ntohs(head->len); break; @@ -848,25 +915,13 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ case DNS_RECORD_TYPE_NS: case DNS_RECORD_TYPE_SOA: { - data += sizeof(DNSAnswerHeader); - - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } - - SCLogDebug("TTL %u", ntohl(head->ttl)); - uint8_t pname[DNS_MAX_SIZE]; uint16_t pname_len = 0; if ((pname_len = DNSResponseGetNameByOffset(input, input_len, data - input, pname, sizeof(pname))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } @@ -882,10 +937,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ if ((pmail_len = DNSResponseGetNameByOffset(input, input_len, sdata - input, pmail, sizeof(pmail))) == 0) { -#if DEBUG - PrintRawDataFp(stdout, (uint8_t *)input, input_len); - BUG_ON(1); -#endif + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); goto insufficient_data; } SCLogDebug("pmail_len %u", pmail_len); @@ -925,55 +977,62 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_ } case DNS_RECORD_TYPE_TXT: { - data += sizeof(DNSAnswerHeader); + uint16_t txtdatalen = datalen; - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; + if (txtdatalen == 0) { + DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA); + goto bad_data; } - uint16_t datalen = ntohs(head->len); uint8_t txtlen = *data; const uint8_t *tdata = data + 1; do { //PrintRawDataFp(stdout, (uint8_t*)tdata, txtlen); - if (txtlen > datalen) + if (txtlen >= txtdatalen) goto bad_data; DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), (uint8_t*)tdata, (uint16_t)txtlen, ntohs(dns_header->tx_id)); - datalen -= txtlen; + txtdatalen -= txtlen; tdata += txtlen; txtlen = *tdata; tdata++; - datalen--; + txtdatalen--; - SCLogDebug("datalen %u, txtlen %u", datalen, txtlen); - } while (datalen > 1); + SCLogDebug("datalen %u, txtlen %u", txtdatalen, txtlen); + } while (txtdatalen > 1); - data += ntohs(head->len); + data += datalen; break; } - default: /* unsupported record */ + case DNS_RECORD_TYPE_SSHFP: { - data += sizeof(DNSAnswerHeader); + /* data here should be: + * [1 byte algo][1 byte type][var bytes fingerprint] + * As we currently can't store each of those in the state, + * we just store the raw data an let the output/detect + * code figure out what to do with it. */ - if (input + input_len < data + ntohs(head->len)) { - SCLogDebug("input buffer too small for data of len %u", ntohs(head->len)); - goto insufficient_data; - } + DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len, + ntohs(head->type), ntohs(head->class), ntohl(head->ttl), + data, ntohs(head->len), ntohs(dns_header->tx_id)); + data += datalen; + break; + } + default: /* unsupported record */ + { DNSStoreAnswerInState(dns_state, list, NULL, 0, ntohs(head->type), ntohs(head->class), ntohl(head->ttl), NULL, 0, ntohs(dns_header->tx_id)); //PrintRawDataFp(stdout, data, ntohs(head->len)); - data += ntohs(head->len); + data += datalen; break; } } @@ -995,23 +1054,29 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_AAAA: snprintf(str, str_size, "AAAA"); break; - case DNS_RECORD_TYPE_TXT: - snprintf(str, str_size, "TXT"); - break; case DNS_RECORD_TYPE_CNAME: snprintf(str, str_size, "CNAME"); break; - case DNS_RECORD_TYPE_SOA: - snprintf(str, str_size, "SOA"); + case DNS_RECORD_TYPE_TXT: + snprintf(str, str_size, "TXT"); break; case DNS_RECORD_TYPE_MX: snprintf(str, str_size, "MX"); break; + case DNS_RECORD_TYPE_SOA: + snprintf(str, str_size, "SOA"); + break; case DNS_RECORD_TYPE_PTR: snprintf(str, str_size, "PTR"); break; - case DNS_RECORD_TYPE_ANY: - snprintf(str, str_size, "ANY"); + case DNS_RECORD_TYPE_SIG: + snprintf(str, str_size, "SIG"); + break; + case DNS_RECORD_TYPE_KEY: + snprintf(str, str_size, "KEY"); + break; + case DNS_RECORD_TYPE_WKS: + snprintf(str, str_size, "WKS"); break; case DNS_RECORD_TYPE_TKEY: snprintf(str, str_size, "TKEY"); @@ -1019,25 +1084,207 @@ void DNSCreateTypeString(uint16_t type, char *str, size_t str_size) case DNS_RECORD_TYPE_TSIG: snprintf(str, str_size, "TSIG"); break; + case DNS_RECORD_TYPE_ANY: + snprintf(str, str_size, "ANY"); + break; + case DNS_RECORD_TYPE_RRSIG: + snprintf(str, str_size, "RRSIG"); + break; + case DNS_RECORD_TYPE_NSEC: + snprintf(str, str_size, "NSEC"); + break; + case DNS_RECORD_TYPE_DNSKEY: + snprintf(str, str_size, "DNSKEY"); + break; + case DNS_RECORD_TYPE_HINFO: + snprintf(str, str_size, "HINFO"); + break; + case DNS_RECORD_TYPE_MINFO: + snprintf(str, str_size, "MINFO"); + break; + case DNS_RECORD_TYPE_RP: + snprintf(str, str_size, "RP"); + break; + case DNS_RECORD_TYPE_AFSDB: + snprintf(str, str_size, "AFSDB"); + break; + case DNS_RECORD_TYPE_X25: + snprintf(str, str_size, "X25"); + break; + case DNS_RECORD_TYPE_ISDN: + snprintf(str, str_size, "ISDN"); + break; + case DNS_RECORD_TYPE_RT: + snprintf(str, str_size, "RT"); + break; + case DNS_RECORD_TYPE_NSAP: + snprintf(str, str_size, "NSAP"); + break; + case DNS_RECORD_TYPE_NSAPPTR: + snprintf(str, str_size, "NSAPPTR"); + break; + case DNS_RECORD_TYPE_PX: + snprintf(str, str_size, "PX"); + break; + case DNS_RECORD_TYPE_GPOS: + snprintf(str, str_size, "GPOS"); + break; + case DNS_RECORD_TYPE_LOC: + snprintf(str, str_size, "LOC"); + break; case DNS_RECORD_TYPE_SRV: snprintf(str, str_size, "SRV"); break; + case DNS_RECORD_TYPE_ATMA: + snprintf(str, str_size, "ATMA"); + break; case DNS_RECORD_TYPE_NAPTR: snprintf(str, str_size, "NAPTR"); break; + case DNS_RECORD_TYPE_KX: + snprintf(str, str_size, "KX"); + break; + case DNS_RECORD_TYPE_CERT: + snprintf(str, str_size, "CERT"); + break; + case DNS_RECORD_TYPE_A6: + snprintf(str, str_size, "A6"); + break; + case DNS_RECORD_TYPE_DNAME: + snprintf(str, str_size, "DNAME"); + break; + case DNS_RECORD_TYPE_OPT: + snprintf(str, str_size, "OPT"); + break; + case DNS_RECORD_TYPE_APL: + snprintf(str, str_size, "APL"); + break; case DNS_RECORD_TYPE_DS: snprintf(str, str_size, "DS"); break; - case DNS_RECORD_TYPE_RRSIG: - snprintf(str, str_size, "RRSIG"); + case DNS_RECORD_TYPE_SSHFP: + snprintf(str, str_size, "SSHFP"); break; - case DNS_RECORD_TYPE_NSEC: - snprintf(str, str_size, "NSEC"); + case DNS_RECORD_TYPE_IPSECKEY: + snprintf(str, str_size, "IPSECKEY"); + break; + case DNS_RECORD_TYPE_DHCID: + snprintf(str, str_size, "DHCID"); break; case DNS_RECORD_TYPE_NSEC3: snprintf(str, str_size, "NSEC3"); break; + case DNS_RECORD_TYPE_NSEC3PARAM: + snprintf(str, str_size, "NSEC3PARAM"); + break; + case DNS_RECORD_TYPE_TLSA: + snprintf(str, str_size, "TLSA"); + break; + case DNS_RECORD_TYPE_HIP: + snprintf(str, str_size, "HIP"); + break; + case DNS_RECORD_TYPE_CDS: + snprintf(str, str_size, "CDS"); + break; + case DNS_RECORD_TYPE_CDNSKEY: + snprintf(str, str_size, "CDNSKEY"); + break; + case DNS_RECORD_TYPE_MAILA: + snprintf(str, str_size, "MAILA"); + break; + case DNS_RECORD_TYPE_URI: + snprintf(str, str_size, "URI"); + break; + case DNS_RECORD_TYPE_MB: + snprintf(str, str_size, "MB"); + break; + case DNS_RECORD_TYPE_MG: + snprintf(str, str_size, "MG"); + break; + case DNS_RECORD_TYPE_MR: + snprintf(str, str_size, "MR"); + break; + case DNS_RECORD_TYPE_NULL: + snprintf(str, str_size, "NULL"); + break; + case DNS_RECORD_TYPE_SPF: + snprintf(str, str_size, "SPF"); + break; + case DNS_RECORD_TYPE_NXT: + snprintf(str, str_size, "NXT"); + break; + case DNS_RECORD_TYPE_MD: + snprintf(str, str_size, "MD"); + break; + case DNS_RECORD_TYPE_MF: + snprintf(str, str_size, "MF"); + break; default: snprintf(str, str_size, "%04x/%u", type, type); } } + +void DNSCreateRcodeString(uint8_t rcode, char *str, size_t str_size) +{ + switch (rcode) { + case DNS_RCODE_NOERROR: + snprintf(str, str_size, "NOERROR"); + break; + case DNS_RCODE_FORMERR: + snprintf(str, str_size, "FORMERR"); + break; + case DNS_RCODE_SERVFAIL: + snprintf(str, str_size, "SERVFAIL"); + break; + case DNS_RCODE_NXDOMAIN: + snprintf(str, str_size, "NXDOMAIN"); + break; + case DNS_RCODE_NOTIMP: + snprintf(str, str_size, "NOTIMP"); + break; + case DNS_RCODE_REFUSED: + snprintf(str, str_size, "REFUSED"); + break; + case DNS_RCODE_YXDOMAIN: + snprintf(str, str_size, "YXDOMAIN"); + break; + case DNS_RCODE_YXRRSET: + snprintf(str, str_size, "YXRRSET"); + break; + case DNS_RCODE_NXRRSET: + snprintf(str, str_size, "NXRRSET"); + break; + case DNS_RCODE_NOTAUTH: + snprintf(str, str_size, "NOTAUTH"); + break; + case DNS_RCODE_NOTZONE: + snprintf(str, str_size, "NOTZONE"); + break; + /* these are the same, need more logic */ + case DNS_RCODE_BADVERS: + //case DNS_RCODE_BADSIG: + snprintf(str, str_size, "BADVERS/BADSIG"); + break; + case DNS_RCODE_BADKEY: + snprintf(str, str_size, "BADKEY"); + break; + case DNS_RCODE_BADTIME: + snprintf(str, str_size, "BADTIME"); + break; + case DNS_RCODE_BADMODE: + snprintf(str, str_size, "BADMODE"); + break; + case DNS_RCODE_BADNAME: + snprintf(str, str_size, "BADNAME"); + break; + case DNS_RCODE_BADALG: + snprintf(str, str_size, "BADALG"); + break; + case DNS_RCODE_BADTRUNC: + snprintf(str, str_size, "BADTRUNC"); + break; + default: + SCLogDebug("could not map DNS rcode to name, bug!"); + snprintf(str, str_size, "%04x/%u", rcode, rcode); + } +} diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index ab2d8ef11835..bc20907f6f48 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -32,33 +32,87 @@ #define DNS_MAX_SIZE 256 -#define DNS_RECORD_TYPE_A 1 -#define DNS_RECORD_TYPE_NS 2 -#define DNS_RECORD_TYPE_CNAME 5 -#define DNS_RECORD_TYPE_SOA 6 - -#define DNS_RECORD_TYPE_PTR 12 -#define DNS_RECORD_TYPE_MX 15 -#define DNS_RECORD_TYPE_TXT 16 - -#define DNS_RECORD_TYPE_AAAA 28 - -#define DNS_RECORD_TYPE_SRV 33 - -#define DNS_RECORD_TYPE_NAPTR 35 - -#define DNS_RECORD_TYPE_DS 43 - -#define DNS_RECORD_TYPE_RRSIG 46 -#define DNS_RECORD_TYPE_NSEC 47 - -#define DNS_RECORD_TYPE_NSEC3 50 - -#define DNS_RECORD_TYPE_TKEY 249 -#define DNS_RECORD_TYPE_TSIG 250 - -#define DNS_RECORD_TYPE_ANY 255 +#define DNS_RECORD_TYPE_A 1 +#define DNS_RECORD_TYPE_NS 2 +#define DNS_RECORD_TYPE_MD 3 // Obsolete +#define DNS_RECORD_TYPE_MF 4 // Obsolete +#define DNS_RECORD_TYPE_CNAME 5 +#define DNS_RECORD_TYPE_SOA 6 +#define DNS_RECORD_TYPE_MB 7 // Experimental +#define DNS_RECORD_TYPE_MG 8 // Experimental +#define DNS_RECORD_TYPE_MR 9 // Experimental +#define DNS_RECORD_TYPE_NULL 10 // Experimental +#define DNS_RECORD_TYPE_WKS 11 +#define DNS_RECORD_TYPE_PTR 12 +#define DNS_RECORD_TYPE_HINFO 13 +#define DNS_RECORD_TYPE_MINFO 14 +#define DNS_RECORD_TYPE_MX 15 +#define DNS_RECORD_TYPE_TXT 16 +#define DNS_RECORD_TYPE_RP 17 +#define DNS_RECORD_TYPE_AFSDB 18 +#define DNS_RECORD_TYPE_X25 19 +#define DNS_RECORD_TYPE_ISDN 20 +#define DNS_RECORD_TYPE_RT 21 +#define DNS_RECORD_TYPE_NSAP 22 +#define DNS_RECORD_TYPE_NSAPPTR 23 +#define DNS_RECORD_TYPE_SIG 24 +#define DNS_RECORD_TYPE_KEY 25 +#define DNS_RECORD_TYPE_PX 26 +#define DNS_RECORD_TYPE_GPOS 27 +#define DNS_RECORD_TYPE_AAAA 28 +#define DNS_RECORD_TYPE_LOC 29 +#define DNS_RECORD_TYPE_NXT 30 // Obosolete +#define DNS_RECORD_TYPE_SRV 33 +#define DNS_RECORD_TYPE_ATMA 34 +#define DNS_RECORD_TYPE_NAPTR 35 +#define DNS_RECORD_TYPE_KX 36 +#define DNS_RECORD_TYPE_CERT 37 +#define DNS_RECORD_TYPE_A6 38 // Obsolete +#define DNS_RECORD_TYPE_DNAME 39 +#define DNS_RECORD_TYPE_OPT 41 +#define DNS_RECORD_TYPE_APL 42 +#define DNS_RECORD_TYPE_DS 43 +#define DNS_RECORD_TYPE_SSHFP 44 +#define DNS_RECORD_TYPE_IPSECKEY 45 +#define DNS_RECORD_TYPE_RRSIG 46 +#define DNS_RECORD_TYPE_NSEC 47 +#define DNS_RECORD_TYPE_DNSKEY 48 +#define DNS_RECORD_TYPE_DHCID 49 +#define DNS_RECORD_TYPE_NSEC3 50 +#define DNS_RECORD_TYPE_NSEC3PARAM 51 +#define DNS_RECORD_TYPE_TLSA 52 +#define DNS_RECORD_TYPE_HIP 55 +#define DNS_RECORD_TYPE_CDS 59 +#define DNS_RECORD_TYPE_CDNSKEY 60 +#define DNS_RECORD_TYPE_SPF 99 // Obsolete +#define DNS_RECORD_TYPE_TKEY 249 +#define DNS_RECORD_TYPE_TSIG 250 +#define DNS_RECORD_TYPE_MAILA 254 // Obsolete +#define DNS_RECORD_TYPE_ANY 255 +#define DNS_RECORD_TYPE_URI 256 + +#define DNS_RCODE_NOERROR 0 +#define DNS_RCODE_FORMERR 1 +#define DNS_RCODE_SERVFAIL 2 +#define DNS_RCODE_NXDOMAIN 3 +#define DNS_RCODE_NOTIMP 4 +#define DNS_RCODE_REFUSED 5 +#define DNS_RCODE_YXDOMAIN 6 +#define DNS_RCODE_YXRRSET 7 +#define DNS_RCODE_NXRRSET 8 +#define DNS_RCODE_NOTAUTH 9 +#define DNS_RCODE_NOTZONE 10 +// Support for OPT RR from RFC6891 will be needed to +// parse RCODE values over 15 +#define DNS_RCODE_BADVERS 16 +#define DNS_RCODE_BADSIG 16 +#define DNS_RCODE_BADKEY 17 +#define DNS_RCODE_BADTIME 18 +#define DNS_RCODE_BADMODE 19 +#define DNS_RCODE_BADNAME 20 +#define DNS_RCODE_BADALG 21 +#define DNS_RCODE_BADTRUNC 22 enum { DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE, @@ -136,10 +190,11 @@ typedef struct DNSAnswerEntry_ { typedef struct DNSTransaction_ { uint16_t tx_num; /**< internal: id */ uint16_t tx_id; /**< transaction id */ + uint32_t logged; /**< flags for loggers done logging */ uint8_t replied; /**< bool indicating request is replied to. */ uint8_t reply_lost; - uint8_t no_such_name; /**< server said "no such name" */ + uint8_t rcode; /**< response code (e.g. "no error" / "no such name") */ uint8_t recursion_desired; /**< server said "recursion desired" */ TAILQ_HEAD(, DNSQueryEntry_) query_list; /**< list for query/queries */ @@ -149,16 +204,27 @@ typedef struct DNSTransaction_ { AppLayerDecoderEvents *decoder_events; /**< per tx events */ TAILQ_ENTRY(DNSTransaction_) next; + DetectEngineState *de_state; } DNSTransaction; /** \brief Per flow DNS state container */ typedef struct DNSState_ { TAILQ_HEAD(, DNSTransaction_) tx_list; /**< transaction list */ DNSTransaction *curr; /**< ptr to current tx */ + DNSTransaction *iter; uint64_t transaction_max; uint32_t unreplied_cnt; /**< number of unreplied requests in a row */ uint32_t memuse; /**< state memuse, for comparing with state-memcap settings */ + uint64_t tx_with_detect_state_cnt; + + struct timeval last_req; /**< Timestamp of last request. */ + struct timeval last_resp; /**< Timestamp of last response. */ + + uint16_t window; /**< Window of allowed unreplied + * requests. Set by the maximum + * number of subsequent requests + * without a response. */ uint16_t events; uint16_t givenup; @@ -180,8 +246,9 @@ void DNSConfigSetGlobalMemcap(uint64_t value); void DNSIncrMemcap(uint32_t size, DNSState *state); void DNSDecrMemcap(uint32_t size, DNSState *state); int DNSCheckMemcap(uint32_t want, DNSState *state); -void DNSMemcapGetCounters(uint64_t *memuse, uint64_t *memcap_state, - uint64_t *memcap_global); +uint64_t DNSMemcapGetMemuseCounter(void); +uint64_t DNSMemcapGetMemcapStateCounter(void); +uint64_t DNSMemcapGetMemcapGlobalCounter(void); void RegisterDNSParsers(void); void DNSParserTests(void); @@ -193,12 +260,18 @@ void DNSAppLayerRegisterGetEventInfo(uint8_t ipproto, AppProto alproto); void *DNSGetTx(void *alstate, uint64_t tx_id); uint64_t DNSGetTxCnt(void *alstate); +void DNSSetTxLogged(void *alstate, void *tx, uint32_t logger); +int DNSGetTxLogged(void *alstate, void *tx, uint32_t logger); int DNSGetAlstateProgress(void *tx, uint8_t direction); int DNSGetAlstateProgressCompletionStatus(uint8_t direction); void DNSStateTransactionFree(void *state, uint64_t tx_id); DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id); +int DNSStateHasTxDetectState(void *alstate); +DetectEngineState *DNSGetTxDetectState(void *vtx); +int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s); + void DNSSetEvent(DNSState *s, uint8_t e); void *DNSStateAlloc(void); void DNSStateFree(void *s); @@ -223,5 +296,6 @@ uint16_t DNSUdpResponseGetNameByOffset(const uint8_t * const input, const uint32 const uint16_t offset, uint8_t *fqdn, const size_t fqdn_size); void DNSCreateTypeString(uint16_t type, char *str, size_t str_size); +void DNSCreateRcodeString(uint8_t rcode, char *str, size_t str_size); #endif /* __APP_LAYER_DNS_COMMON_H__ */ diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 6b46a5a1dcb2..4296a49c15f5 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -141,7 +141,7 @@ static int DNSTCPRequestParseProbe(uint8_t *input, uint32_t input_len) data += sizeof(DNSQueryTrailer); } - SCReturnInt(1); + SCReturnInt(1); insufficient_data: SCReturnInt(0); bad_data: @@ -196,6 +196,14 @@ static int DNSRequestParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu //PrintRawDataFp(stdout, (uint8_t*)data, input_len - (data - input)); + if (dns_state != NULL) { + if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) { + if (dns_state->window <= dns_state->unreplied_cnt) { + dns_state->window++; + } + } + } + for (q = 0; q < ntohs(dns_header->questions); q++) { uint8_t fqdn[DNS_MAX_SIZE]; uint16_t fqdn_offset = 0; @@ -262,7 +270,7 @@ static int DNSRequestParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu } } - SCReturnInt(1); + SCReturnInt(1); bad_data: insufficient_data: SCReturnInt(-1); @@ -277,15 +285,19 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, uint8_t *input, uint32_t input_len, void *local_data) { - DNSState *dns_state = (DNSState *)dstate; + DNSState *dns_state = (DNSState *)dstate; SCLogDebug("starting %u", input_len); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_TCP) SCReturnInt(-1); /* probably a rst/fin sending an eof */ - if (input_len == 0) { + if (input == NULL || input_len == 0) { goto insufficient_data; } @@ -317,8 +329,8 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, goto bad_data; /* treat the rest of the data as a (potential) new record */ - input += ntohs(dns_tcp_header->len); - input_len -= ntohs(dns_tcp_header->len); + input += (2 + ntohs(dns_tcp_header->len)); + input_len -= (2 + ntohs(dns_tcp_header->len)); goto next_record; } else { /* not enough data, store record length and buffer */ @@ -351,7 +363,11 @@ static int DNSTCPRequestParse(Flow *f, void *dstate, goto bad_data; } - SCReturnInt(1); + if (f != NULL) { + dns_state->last_req = f->lastts; + } + + SCReturnInt(1); insufficient_data: SCReturnInt(-1); bad_data: @@ -373,6 +389,8 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu if (!found) { SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE"); DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE); + } else if (dns_state->unreplied_cnt > 0) { + dns_state->unreplied_cnt--; } uint16_t q; @@ -447,11 +465,15 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu } } - /* see if this is a "no such name" error */ - if (ntohs(dns_header->flags) & 0x0003) { - SCLogDebug("no such name"); + /* parse rcode, e.g. "noerror" or "nxdomain" */ + uint8_t rcode = ntohs(dns_header->flags) & 0x0F; + if (rcode <= DNS_RCODE_NOTZONE) { + SCLogDebug("rcode %u", rcode); if (tx != NULL) - tx->no_such_name = 1; + tx->rcode = rcode; + } else { + /* this is not invalid, rcodes can be user defined */ + SCLogDebug("unexpected DNS rcode %u", rcode); } if (ntohs(dns_header->flags) & 0x0080) { @@ -464,7 +486,7 @@ static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *inpu tx->replied = 1; } - SCReturnInt(1); + SCReturnInt(1); bad_data: insufficient_data: SCReturnInt(-1); @@ -484,14 +506,18 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, uint8_t *input, uint32_t input_len, void *local_data) { - DNSState *dns_state = (DNSState *)dstate; + DNSState *dns_state = (DNSState *)dstate; + + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_TCP) SCReturnInt(-1); /* probably a rst/fin sending an eof */ - if (input_len == 0) { + if (input == NULL || input_len == 0) { goto insufficient_data; } @@ -509,7 +535,9 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input; SCLogDebug("DNS %p", dns_tcp_header); - if (ntohs(dns_tcp_header->len) == (input_len-2)) { + if (ntohs(dns_tcp_header->len) == 0) { + goto bad_data; + } else if (ntohs(dns_tcp_header->len) == (input_len-2)) { /* we have all data, so process w/o buffering */ if (DNSReponseParseData(f, dns_state, input+2, input_len-2) < 0) goto bad_data; @@ -520,8 +548,8 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, goto bad_data; /* treat the rest of the data as a (potential) new record */ - input += ntohs(dns_tcp_header->len); - input_len -= ntohs(dns_tcp_header->len); + input += (2 + ntohs(dns_tcp_header->len)); + input_len -= (2 + ntohs(dns_tcp_header->len)); goto next_record; } else { /* not enough data, store record length and buffer */ @@ -553,7 +581,12 @@ static int DNSTCPResponseParse(Flow *f, void *dstate, if (r < 0) goto bad_data; } - SCReturnInt(1); + + if (f != NULL) { + dns_state->last_req = f->lastts; + } + + SCReturnInt(1); insufficient_data: SCReturnInt(-1); bad_data: @@ -594,6 +627,28 @@ static uint16_t DNSTcpProbingParser(uint8_t *input, uint32_t ilen, uint32_t *off return ALPROTO_DNS; } +/** + * \brief Probing parser for TCP DNS responses. + * + * This is a minimal parser that just checks that the input contains enough + * data for a TCP DNS response. + */ +static uint16_t DNSTcpProbeResponse(uint8_t *input, uint32_t len, + uint32_t *offset) +{ + if (len == 0 || len < sizeof(DNSTcpHeader)) { + return ALPROTO_UNKNOWN; + } + + DNSTcpHeader *dns_header = (DNSTcpHeader *)input; + + if (ntohs(dns_header->len) < sizeof(DNSHeader)) { + return ALPROTO_FAILED; + } + + return ALPROTO_DNS; +} + void RegisterDNSTCPParsers(void) { char *proto_name = "dns"; @@ -608,12 +663,13 @@ void RegisterDNSTCPParsers(void) ALPROTO_DNS, 0, sizeof(DNSTcpHeader), STREAM_TOSERVER, - DNSTcpProbingParser); + DNSTcpProbingParser, NULL); } else { int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_DNS, 0, sizeof(DNSTcpHeader), - DNSTcpProbingParser); + DNSTcpProbingParser, + DNSTcpProbeResponse); /* if we have no config, we enable the default port 53 */ if (!have_cfg) { SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS TCP config found, " @@ -621,7 +677,8 @@ void RegisterDNSTCPParsers(void) "port 53."); AppLayerProtoDetectPPRegister(IPPROTO_TCP, "53", ALPROTO_DNS, 0, sizeof(DNSTcpHeader), - STREAM_TOSERVER, DNSTcpProbingParser); + STREAM_TOSERVER, DNSTcpProbingParser, + DNSTcpProbeResponse); } } } else { @@ -642,12 +699,17 @@ void RegisterDNSTCPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSHasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS, + DNSStateHasTxDetectState, + DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxCnt); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxLogged, + DNSSetTxLogged); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetAlstateProgress); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_DNS, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS, DNSGetAlstateProgressCompletionStatus); DNSAppLayerRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNS); } else { @@ -655,13 +717,131 @@ void RegisterDNSTCPParsers(void) "still on.", proto_name); } +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNS, + DNSTCPParserRegisterTests); +#endif + return; } /* UNITTESTS */ #ifdef UNITTESTS + +#include "util-unittest-helper.h" + +static int DNSTCPParserTestMultiRecord(void) +{ + /* This is a buffer containing 20 DNS requests each prefixed by + * the request length for transport over TCP. It was generated with Scapy, + * where each request is: + * DNS(id=i, rd=1, qd=DNSQR(qname="%d.google.com" % i, qtype="A")) + * where i is 0 to 19. + */ + uint8_t req[] = { + 0x00, 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x04, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x34, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x06, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x36, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x08, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1e, 0x00, 0x09, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x39, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1f, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, + 0x30, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x1f, 0x00, 0x0b, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x31, 0x31, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0c, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x31, 0x32, 0x06, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0d, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x31, 0x33, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0e, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x31, 0x34, 0x06, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x31, 0x35, 0x06, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, + 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, + 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x36, 0x06, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x1f, 0x00, 0x11, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x37, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x1f, 0x00, 0x12, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, + 0x38, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x1f, 0x00, 0x13, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x31, 0x39, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, + 0x00, 0x01 + }; + size_t reqlen = sizeof(req); + + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_TCP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + FAIL_IF_NOT(DNSTCPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF(state->transaction_max != 20); + + UTHFreeFlow(f); + PASS; +} + void DNSTCPParserRegisterTests(void) { -// UtRegisterTest("DNSTCPParserTest01", DNSTCPParserTest01, 1); + UtRegisterTest("DNSTCPParserTestMultiRecord", DNSTCPParserTestMultiRecord); } -#endif + +#endif /* UNITTESTS */ diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index feeb7de1c7dc..83d1834ce6f1 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -62,11 +62,15 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, SCLogDebug("starting %u", input_len); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_UDP) SCReturnInt(-1); - if (input_len == 0 || input_len < sizeof(DNSHeader)) { + if (input == NULL || input_len == 0 || input_len < sizeof(DNSHeader)) { SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader)); goto insufficient_data; } @@ -77,6 +81,14 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, if (DNSValidateRequestHeader(dns_state, dns_header) < 0) goto bad_data; + if (dns_state != NULL) { + if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) { + if (dns_state->window <= dns_state->unreplied_cnt) { + dns_state->window++; + } + } + } + uint16_t q; const uint8_t *data = input + sizeof(DNSHeader); for (q = 0; q < ntohs(dns_header->questions); q++) { @@ -147,7 +159,11 @@ static int DNSUDPRequestParse(Flow *f, void *dstate, } } - SCReturnInt(1); + if (dns_state != NULL && f != NULL) { + dns_state->last_req = f->lastts; + } + + SCReturnInt(1); bad_data: insufficient_data: SCReturnInt(-1); @@ -164,15 +180,19 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, uint8_t *input, uint32_t input_len, void *local_data) { - DNSState *dns_state = (DNSState *)dstate; + DNSState *dns_state = (DNSState *)dstate; SCLogDebug("starting %u", input_len); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + /** \todo remove this when PP is fixed to enforce ipproto */ if (f != NULL && f->proto != IPPROTO_UDP) SCReturnInt(-1); - if (input_len == 0 || input_len < sizeof(DNSHeader)) { + if (input == NULL || input_len == 0 || input_len < sizeof(DNSHeader)) { SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader)); goto insufficient_data; } @@ -188,6 +208,8 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, if (!found) { SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE"); DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE); + } else if (dns_state->unreplied_cnt > 0) { + dns_state->unreplied_cnt--; } if (DNSValidateResponseHeader(dns_state, dns_header) < 0) @@ -269,23 +291,32 @@ static int DNSUDPResponseParse(Flow *f, void *dstate, } } - /* see if this is a "no such name" error */ - if (ntohs(dns_header->flags) & 0x0003) { - SCLogDebug("no such name"); - if (tx != NULL) - tx->no_such_name = 1; + /* if we previously didn't have a tx, it could have been created by the + * above code, so lets check again */ + if (tx == NULL) { + tx = DNSTransactionFindByTxId(dns_state, ntohs(dns_header->tx_id)); } + if (tx != NULL) { + /* parse rcode, e.g. "noerror" or "nxdomain" */ + uint8_t rcode = ntohs(dns_header->flags) & 0x0F; + if (rcode <= DNS_RCODE_NOTZONE) { + SCLogDebug("rcode %u", rcode); + tx->rcode = rcode; + } else { + /* this is not invalid, rcodes can be user defined */ + SCLogDebug("unexpected DNS rcode %u", rcode); + } - if (ntohs(dns_header->flags) & 0x0080) { - SCLogDebug("recursion desired"); - if (tx != NULL) + if (ntohs(dns_header->flags) & 0x0080) { + SCLogDebug("recursion desired"); tx->recursion_desired = 1; - } + } - if (tx != NULL) { tx->replied = 1; } - + if (f != NULL) { + dns_state->last_resp = f->lastts; + } SCReturnInt(1); bad_data: @@ -322,7 +353,7 @@ static void DNSUDPConfigure(void) request_flood = value; } } - SCLogInfo("DNS request flood protection level: %u", request_flood); + SCLogConfig("DNS request flood protection level: %u", request_flood); DNSConfigSetRequestFlood(request_flood); p = ConfGetNode("app-layer.protocols.dns.state-memcap"); @@ -334,7 +365,7 @@ static void DNSUDPConfigure(void) state_memcap = value; } } - SCLogInfo("DNS per flow memcap (state-memcap): %u", state_memcap); + SCLogConfig("DNS per flow memcap (state-memcap): %u", state_memcap); DNSConfigSetStateMemcap(state_memcap); p = ConfGetNode("app-layer.protocols.dns.global-memcap"); @@ -346,7 +377,7 @@ static void DNSUDPConfigure(void) global_memcap = value; } } - SCLogInfo("DNS global memcap: %"PRIu64, global_memcap); + SCLogConfig("DNS global memcap: %"PRIu64, global_memcap); DNSConfigSetGlobalMemcap(global_memcap); } @@ -364,20 +395,23 @@ void RegisterDNSUDPParsers(void) ALPROTO_DNS, 0, sizeof(DNSHeader), STREAM_TOSERVER, - DNSUdpProbingParser); + DNSUdpProbingParser, + NULL); } else { int have_cfg = AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, proto_name, ALPROTO_DNS, 0, sizeof(DNSHeader), - DNSUdpProbingParser); + DNSUdpProbingParser, NULL); /* if we have no config, we enable the default port 53 */ if (!have_cfg) { +#ifndef AFLFUZZ_APPLAYER SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS UDP config found, " "enabling DNS detection on " "port 53."); +#endif AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS, 0, sizeof(DNSHeader), - STREAM_TOSERVER, DNSUdpProbingParser); + STREAM_TOSERVER, DNSUdpProbingParser, NULL); } } } else { @@ -398,14 +432,19 @@ void RegisterDNSUDPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSHasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS, + DNSStateHasTxDetectState, + DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS, DNSGetTx); AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_DNS, DNSGetTxCnt); + AppLayerParserRegisterLoggerFuncs(IPPROTO_UDP, ALPROTO_DNS, DNSGetTxLogged, + DNSSetTxLogged); AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetAlstateProgress); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_UDP, ALPROTO_DNS, + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS, DNSGetAlstateProgressCompletionStatus); DNSAppLayerRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_DNS); @@ -426,7 +465,6 @@ void RegisterDNSUDPParsers(void) static int DNSUDPParserTest01 (void) { - int result = 0; /* query: abcdefghijk.com * TTL: 86400 * serial 20130422 refresh 28800 retry 7200 exp 604800 min ttl 86400 @@ -446,25 +484,19 @@ static int DNSUDPParserTest01 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } static int DNSUDPParserTest02 (void) { - int result = 0; uint8_t buf[] = { 0x6D,0x08,0x84,0x80,0x00,0x01,0x00,0x08,0x00,0x00,0x00,0x01,0x03,0x57,0x57,0x57, 0x04,0x54,0x54,0x54,0x54,0x03,0x56,0x56,0x56,0x03,0x63,0x6F,0x6D,0x02,0x79,0x79, @@ -481,25 +513,19 @@ static int DNSUDPParserTest02 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } static int DNSUDPParserTest03 (void) { - int result = 0; uint8_t buf[] = { 0x6F,0xB4,0x84,0x80,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x03,0x57,0x57,0x77, 0x0B,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x03,0x55,0x55,0x55, @@ -516,26 +542,20 @@ static int DNSUDPParserTest03 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } /** \test TXT records in answer */ static int DNSUDPParserTest04 (void) { - int result = 0; uint8_t buf[] = { 0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41, 0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72, @@ -554,26 +574,20 @@ static int DNSUDPParserTest04 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != 1) - goto end; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL)); - result = 1; -end: UTHFreeFlow(f); - return (result); + PASS; } /** \test TXT records in answer, bad txtlen */ static int DNSUDPParserTest05 (void) { - int result = 0; uint8_t buf[] = { 0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41, 0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72, @@ -592,29 +606,256 @@ static int DNSUDPParserTest05 (void) Flow *f = NULL; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->proto = IPPROTO_UDP; f->alproto = ALPROTO_DNS; f->alstate = DNSStateAlloc(); - int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL); - if (r != -1) - goto end; + FAIL_IF(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL) != -1); + + UTHFreeFlow(f); + PASS; +} + +/** + * \test Test subsequent requests before response. + * + * This test sends 2 DNS requests on the same state then sends the response + * to the first request checking that it is seen and associated with the + * transaction. + */ +static int DNSUDPParserTestDelayedResponse(void) +{ + /* DNS request: + * - Flags: 0x0100 Standard query + * - A www.google.com + */ + uint8_t req[] = { + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + }; + size_t reqlen = sizeof(req); + + /* DNS response: + * - Flags: 0x8180 Standard query response, no error + * - www.google.com A 24.244.4.56 + * - www.google.com A 24.244.4.54 + * - www.google.com A 24.244.4.57 + * - www.google.com A 24.244.4.55 + * - www.google.com A 24.244.4.52 + * - www.google.com A 24.244.4.53 + * - www.google.com A 24.244.4.58 + * - www.google.com A 24.244.4.59 + */ + uint8_t res[] = { + 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a + }; + size_t reslen = sizeof(res); + + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_UDP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + /* Send to requests with an incrementing tx id. */ + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + req[1] = 0x02; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + + /* Send response to the first request. */ + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL)); + DNSTransaction *tx = TAILQ_FIRST(&state->tx_list); + FAIL_IF_NULL(tx); + FAIL_IF_NOT(tx->replied); + + /* Also free's state. */ + UTHFreeFlow(f); + + PASS; +} + +/** + * \test Test entering the flood/givenup state. + */ +static int DNSUDPParserTestFlood(void) +{ + /* DNS request: + * - Flags: 0x0100 Standard query + * - A www.google.com + */ + uint8_t req[] = { + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + }; + size_t reqlen = sizeof(req); + + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_UDP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + uint16_t txid; + for (txid = 1; txid <= DNS_CONFIG_DEFAULT_REQUEST_FLOOD + 1; txid++) { + req[0] = (txid >> 8) & 0xff; + req[1] = txid & 0xff; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF(state->givenup); + } + + /* With one more request we should enter a flooded state. */ + txid++; + req[0] = (txid >> 8) & 0xff; + req[1] = txid & 0xff; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF(!state->givenup); - result = 1; -end: + /* Also free's state. */ UTHFreeFlow(f); - return (result); + + PASS; } +static int DNSUDPParserTestLostResponse(void) +{ + /* DNS request: + * - Flags: 0x0100 Standard query + * - A www.google.com + */ + uint8_t req[] = { + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + }; + size_t reqlen = sizeof(req); + + uint8_t res[] = { + 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, + 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, + 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37, + 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a + }; + size_t reslen = sizeof(res); + + DNSTransaction *tx; + DNSState *state = DNSStateAlloc(); + FAIL_IF_NULL(state); + Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53); + FAIL_IF_NULL(f); + f->proto = IPPROTO_UDP; + f->alproto = ALPROTO_DNS; + f->alstate = state; + + /* First request. */ + req[1] = 0x01; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->transaction_max == 1); + FAIL_IF_NOT(state->unreplied_cnt == 1); + FAIL_IF_NOT(state->window == 1); + + /* Second request. */ + req[1] = 0x02; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->transaction_max == 2); + FAIL_IF_NOT(state->unreplied_cnt == 2); + FAIL_IF_NOT(state->window == 2); + + /* Third request. */ + req[1] = 0x03; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->transaction_max == 3); + FAIL_IF_NOT(state->unreplied_cnt == 3); + FAIL_IF_NOT(state->window == 3); + + /* Now respond to the second. */ + res[1] = 0x02; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL)); + FAIL_IF_NOT(state->unreplied_cnt == 2); + FAIL_IF_NOT(state->window == 3); + tx = TAILQ_FIRST(&state->tx_list); + FAIL_IF_NULL(tx); + FAIL_IF(tx->replied); + FAIL_IF(tx->reply_lost); + + /* Send a 4th request. */ + req[1] = 0x04; + FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL)); + FAIL_IF_NOT(state->unreplied_cnt == 3); + FAIL_IF(state->window != 3); + FAIL_IF_NOT(state->transaction_max == 4); + + /* Response to the third request. */ + res[1] = 0x03; + FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL)); + FAIL_IF_NOT(state->unreplied_cnt == 2); + FAIL_IF_NOT(state->window == 3); + tx = TAILQ_FIRST(&state->tx_list); + FAIL_IF_NULL(tx); + FAIL_IF(tx->replied); + FAIL_IF(!tx->reply_lost); + + /* Also free's state. */ + UTHFreeFlow(f); + + PASS; +} void DNSUDPParserRegisterTests(void) { - UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01, 1); - UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02, 1); - UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03, 1); - UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04, 1); - UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05, 1); + UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01); + UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02); + UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03); + UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04); + UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05); + UtRegisterTest("DNSUDPParserTestFlood", DNSUDPParserTestFlood); + UtRegisterTest("DNSUDPParserTestDelayedResponse", + DNSUDPParserTestDelayedResponse); + UtRegisterTest("DNSUDPParserTestLostResponse", + DNSUDPParserTestLostResponse); } #endif diff --git a/src/app-layer-enip-common.c b/src/app-layer-enip-common.c new file mode 100644 index 000000000000..3af826814562 --- /dev/null +++ b/src/app-layer-enip-common.c @@ -0,0 +1,947 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + * + * App-layer parser for ENIP protocol common code + * + */ + +#include "suricata-common.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "util-byte.h" +#include "pkt-var.h" +#include "util-profiling.h" + +#include "app-layer-enip-common.h" + +/** + * \brief Extract 8 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint8(uint8_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint8_t))) + { + SCLogDebug("ENIPExtractUint8: Parsing beyond payload length"); + return 0; + } + + *res = *(input + *offset); + *offset += sizeof(uint8_t); + return 1; +} + +/** + * \brief Extract 16 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint16(uint16_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint16_t))) + { + SCLogDebug("ENIPExtractUint16: Parsing beyond payload length"); + return 0; + } + + ByteExtractUint16(res, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + *offset)); + *offset += sizeof(uint16_t); + return 1; +} + +/** + * \brief Extract 32 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint32(uint32_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint32_t))) + { + SCLogDebug("ENIPExtractUint32: Parsing beyond payload length"); + return 0; + } + + ByteExtractUint32(res, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), + (const uint8_t *) (input + *offset)); + *offset += sizeof(uint32_t); + return 1; +} + +/** + * \brief Extract 64 bits and move up the offset + * @param res + * @param input + * @param offset + */ +int ENIPExtractUint64(uint64_t *res, uint8_t *input, uint16_t *offset, uint32_t input_len) +{ + + if (*offset > (input_len - sizeof(uint64_t))) + { + SCLogDebug("ENIPExtractUint64: Parsing beyond payload length"); + return 0; + } + + ByteExtractUint64(res, BYTE_LITTLE_ENDIAN, sizeof(uint64_t), + (const uint8_t *) (input + *offset)); + *offset += sizeof(uint64_t); + return 1; +} + + +/** + * \brief Create service entry, add to transaction + * @param tx Transaction + * @return service entry + */ +static CIPServiceEntry *CIPServiceAlloc(ENIPTransaction *tx) +{ + + CIPServiceEntry *svc = (CIPServiceEntry *) SCCalloc(1, + sizeof(CIPServiceEntry)); + if (unlikely(svc == NULL)) + return NULL; + + memset(svc, 0x00, sizeof(CIPServiceEntry)); + + TAILQ_INIT(&svc->segment_list); + TAILQ_INIT(&svc->attrib_list); + + TAILQ_INSERT_TAIL(&tx->service_list, svc, next); + tx->service_count++; + return svc; + +} + + +/** + * \brief Delete service entry + */ + +void CIPServiceFree(void *s) +{ + SCEnter(); + if (s) + { + CIPServiceEntry *svc = (CIPServiceEntry *) s; + + SegmentEntry *seg = NULL; + while ((seg = TAILQ_FIRST(&svc->segment_list))) + { + TAILQ_REMOVE(&svc->segment_list, seg, next); + SCFree(seg); + } + + AttributeEntry *attr = NULL; + while ((attr = TAILQ_FIRST(&svc->attrib_list))) + { + TAILQ_REMOVE(&svc->attrib_list, attr, next); + SCFree(attr); + } + + SCFree(s); + } + SCReturn; +} + + + +/** + * \brief Decode ENIP Encapsulation Header + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeENIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data) +{ + int ret = 1; + + uint16_t offset = 0; //byte offset + + //Decode Encapsulation Header + uint16_t cmd; + uint16_t len; + uint32_t session; + uint32_t status; + uint64_t context; + uint32_t option; + if (ENIPExtractUint16(&cmd, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&len, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&session, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&status, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint64(&context, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&option, input, &offset, input_len) != 1) + { + return 0; + } + + enip_data->header.command = cmd; + enip_data->header.length = len; + enip_data->header.session = session; + enip_data->header.status = status; + enip_data->header.context = context; + enip_data->header.option = option; + + switch (enip_data->header.command) + { + case NOP: + SCLogDebug("DecodeENIP - NOP"); + break; + case LIST_SERVICES: + SCLogDebug("DecodeENIP - LIST_SERVICES"); + break; + case LIST_IDENTITY: + SCLogDebug("DecodeENIP - LIST_IDENTITY"); + break; + case LIST_INTERFACES: + SCLogDebug("DecodeENIP - LIST_INTERFACES"); + break; + case REGISTER_SESSION: + SCLogDebug("DecodeENIP - REGISTER_SESSION"); + break; + case UNREGISTER_SESSION: + SCLogDebug("DecodeENIP - UNREGISTER_SESSION"); + break; + case SEND_RR_DATA: + SCLogDebug( + "DecodeENIP - SEND_RR_DATA - parse Common Packet Format"); + ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, + offset); + break; + case SEND_UNIT_DATA: + SCLogDebug( + "DecodeENIP - SEND UNIT DATA - parse Common Packet Format"); + ret = DecodeCommonPacketFormatPDU(input, input_len, enip_data, + offset); + break; + case INDICATE_STATUS: + SCLogDebug("DecodeENIP - INDICATE_STATUS"); + break; + case CANCEL: + SCLogDebug("DecodeENIP - CANCEL"); + break; + default: + SCLogDebug("DecodeENIP - UNSUPPORTED COMMAND 0x%x", + enip_data->header.command); + } + + return ret; +} + + +/** + * \brief Decode Common Packet Format + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCommonPacketFormatPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + + if (enip_data->header.length < sizeof(ENIPEncapDataHdr)) + { + SCLogDebug("DecodeCommonPacketFormat: Malformed ENIP packet"); + return 0; + } + + uint32_t handle; + uint16_t timeout; + uint16_t count; + if (ENIPExtractUint32(&handle, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&timeout, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&count, input, &offset, input_len) != 1) + { + return 0; + } + enip_data->encap_data_header.interface_handle = handle; + enip_data->encap_data_header.timeout = timeout; + enip_data->encap_data_header.item_count = count; + + uint16_t address_type; + uint16_t address_length; //length of connection id in bytes + uint32_t address_connectionid = 0; + uint32_t address_sequence = 0; + + if (ENIPExtractUint16(&address_type, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&address_length, input, &offset, input_len) != 1) + { + return 0; + } + + //depending on addr type, get connection id, sequence if needed. Can also use addr length too? + if (address_type == CONNECTION_BASED) + { //get 4 byte connection id + if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) + { + return 0; + } + } else if (address_type == SEQUENCE_ADDR_ITEM) + { // get 4 byte connection id and 4 byte sequence + if (ENIPExtractUint32(&address_connectionid, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint32(&address_sequence, input, &offset, input_len) != 1) + { + return 0; + } + } + + enip_data->encap_addr_item.type = address_type; + enip_data->encap_addr_item.length = address_length; + enip_data->encap_addr_item.conn_id = address_connectionid; + enip_data->encap_addr_item.sequence_num = address_sequence; + + uint16_t data_type; + uint16_t data_length; //length of data in bytes + uint16_t data_sequence_count; + + if (ENIPExtractUint16(&data_type, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&data_length, input, &offset, input_len) != 1) + { + return 0; + } + + enip_data->encap_data_item.type = data_type; + enip_data->encap_data_item.length = data_length; + + if (enip_data->encap_data_item.type == CONNECTED_DATA_ITEM) + { //connected data items have seq number + if (ENIPExtractUint16(&data_sequence_count, input, &offset, input_len) != 1) + { + return 0; + } + enip_data->encap_data_item.sequence_count = data_sequence_count; + } + + switch (enip_data->encap_data_item.type) + { + case CONNECTED_DATA_ITEM: + SCLogDebug( + "DecodeCommonPacketFormat - CONNECTED DATA ITEM - parse CIP"); + DecodeCIPPDU(input, input_len, enip_data, offset); + break; + case UNCONNECTED_DATA_ITEM: + SCLogDebug("DecodeCommonPacketFormat - UNCONNECTED DATA ITEM"); + DecodeCIPPDU(input, input_len, enip_data, offset); + break; + default: + SCLogDebug("DecodeCommonPacketFormat - UNKNOWN TYPE 0x%x", + enip_data->encap_data_item.type); + return 0; + } + + return 1; +} + +/** + * \brief Decode CIP packet + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ + +int DecodeCIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length == 0) + { + SCLogDebug("DecodeCIP: No CIP Data"); + return 0; + } + + if (offset > (input_len - sizeof(uint8_t))) + { + SCLogDebug("DecodeCIP: Parsing beyond payload length"); + return 0; + } + + uint8_t service = 0; + service = *(input + offset); + + //SCLogDebug("CIP Service 0x%x", service); + + //use service code first bit to determine request/response, no need to save or push offset + if (service >> 7) + { + ret = DecodeCIPResponsePDU(input, input_len, enip_data, offset); + } else + { + ret = DecodeCIPRequestPDU(input, input_len, enip_data, offset); + } + + return ret; +} + + + +/** + * \brief Decode CIP Request + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length < sizeof(CIPReqHdr)) + { + SCLogDebug("DecodeCIPRequest - Malformed CIP Data"); + return 0; + } + + uint8_t service; //<-----CIP SERVICE + uint8_t path_size; + + if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint8(&path_size, input, &offset, input_len) != 1) + { + return 0; + } + + if (service > MAX_CIP_SERVICE) + { // service codes of value 0x80 or greater are not permitted because in the CIP protocol the highest order bit is used to flag request(0)/response(1) + SCLogDebug("DecodeCIPRequest - INVALID CIP SERVICE 0x%x", service); + return 0; + } + + //reached maximum number of services + if (enip_data->service_count > 32) + { + SCLogDebug("DecodeCIPRequest: Maximum services reached"); + return 0; + } + + //save CIP data + CIPServiceEntry *node = CIPServiceAlloc(enip_data); + if (node == NULL) + { + SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); + return 0; + } + node->direction = 0; + node->service = service; + node->request.path_size = path_size; + node->request.path_offset = offset; + // SCLogDebug("DecodeCIPRequestPDU: service 0x%x size %d", node->service, + // node->request.path_size); + + DecodeCIPRequestPathPDU(input, input_len, node, offset); + + offset += path_size * sizeof(uint16_t); //move offset past pathsize + + //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action + switch (service) + { + case CIP_RESERVED: + SCLogDebug("DecodeCIPRequest - CIP_RESERVED"); + break; + case CIP_GET_ATTR_ALL: + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_ALL"); + break; + case CIP_GET_ATTR_LIST: + SCLogDebug("DecodeCIPRequest - CIP_GET_ATTR_LIST"); + break; + case CIP_SET_ATTR_LIST: + SCLogDebug("DecodeCIPRequest - CIP_SET_ATTR_LIST"); + break; + case CIP_RESET: + SCLogDebug("DecodeCIPRequest - CIP_RESET"); + break; + case CIP_START: + SCLogDebug("DecodeCIPRequest - CIP_START"); + break; + case CIP_STOP: + SCLogDebug("DecodeCIPRequest - CIP_STOP"); + break; + case CIP_CREATE: + SCLogDebug("DecodeCIPRequest - CIP_CREATE"); + break; + case CIP_DELETE: + SCLogDebug("DecodeCIPRequest - CIP_DELETE"); + break; + case CIP_MSP: + SCLogDebug("DecodeCIPRequest - CIP_MSP"); + DecodeCIPRequestMSPPDU(input, input_len, enip_data, offset); + break; + case CIP_APPLY_ATTR: + SCLogDebug("DecodeCIPRequest - CIP_APPLY_ATTR"); + break; + case CIP_KICK_TIMER: + SCLogDebug("DecodeCIPRequest - CIP_KICK_TIMER"); + break; + case CIP_OPEN_CONNECTION: + SCLogDebug("DecodeCIPRequest - CIP_OPEN_CONNECTION"); + break; + case CIP_CHANGE_START: + SCLogDebug("DecodeCIPRequest - CIP_CHANGE_START"); + break; + case CIP_GET_STATUS: + SCLogDebug("DecodeCIPRequest - CIP_GET_STATUS"); + break; + default: + SCLogDebug("DecodeCIPRequest - CIP SERVICE 0x%x", service); + } + + return ret; +} + + +/** + * \brief Deocde CIP Request Path + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @param cipserviced the cip service rule + * @return 1 Packet matches + * @return 0 Packet not match + */ +int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, + CIPServiceEntry *node, uint16_t offset) +{ + //SCLogDebug("DecodeCIPRequestPath: service 0x%x size %d length %d", + // node->service, node->request.path_size, input_len); + + if (node->request.path_size < 1) + { + //SCLogDebug("DecodeCIPRequestPath: empty path or CIP Response"); + return 0; + } + + int bytes_remain = node->request.path_size; + + uint8_t segment; + uint8_t reserved; //unused byte reserved by ODVA + + //8 bit fields + uint8_t req_path_class8; + uint8_t req_path_instance8; + uint8_t req_path_attr8; + + //16 bit fields + uint16_t req_path_class16; + uint16_t req_path_instance16; + + uint16_t class = 0; + + SegmentEntry *seg = NULL; + + while (bytes_remain > 0) + { + if (ENIPExtractUint8(&segment, input, &offset, input_len) != 1) + { + return 0; + } + switch (segment) + { //assume order is class then instance. Can have multiple + case PATH_CLASS_8BIT: + if (ENIPExtractUint8(&req_path_class8, input, &offset, input_len) != 1) + { + return 0; + } + class = (uint16_t) req_path_class8; + SCLogDebug("DecodeCIPRequestPathPDU: 8bit class 0x%x", class); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + + bytes_remain--; + break; + case PATH_INSTANCE_8BIT: + if (ENIPExtractUint8(&req_path_instance8, input, &offset, input_len) != 1) + { + return 0; + } + //skip instance, don't need to store + bytes_remain--; + break; + case PATH_ATTR_8BIT: //single attribute + if (ENIPExtractUint8(&req_path_attr8, input, &offset, input_len) != 1) + { + return 0; + } + //uint16_t attrib = (uint16_t) req_path_attr8; + //SCLogDebug("DecodeCIPRequestPath: 8bit attr 0x%x", attrib); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + + bytes_remain--; + break; + case PATH_CLASS_16BIT: + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) //skip reserved + { + return 0; + } + if (ENIPExtractUint16(&req_path_class16, input, &offset, input_len) != 1) + { + return 0; + } + class = req_path_class16; + SCLogDebug("DecodeCIPRequestPath: 16bit class 0x%x", class); + + seg = SCMalloc(sizeof(SegmentEntry)); + if (unlikely(seg == NULL)) + return 0; + seg->segment = segment; + seg->value = class; + TAILQ_INSERT_TAIL(&node->segment_list, seg, next); + if (bytes_remain >= 2) + { + bytes_remain = bytes_remain - 2; + } else + { + bytes_remain = 0; + } + break; + case PATH_INSTANCE_16BIT: + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) // skip reserved + { + return 0; + } + if (ENIPExtractUint16(&req_path_instance16, input, &offset, input_len) != 1) + { + return 0; + } + //skip instance, don't need to store + if (bytes_remain >= 2) + { + bytes_remain = bytes_remain - 2; + } else + { + bytes_remain = 0; + } + break; + default: + SCLogDebug( + "DecodeCIPRequestPath: UNKNOWN SEGMENT 0x%x service 0x%x", + segment, node->service); + return 0; + } + } + + if ((node->service == CIP_SET_ATTR_LIST) || (node->service + == CIP_GET_ATTR_LIST)) + { + uint16_t attr_list_count; + uint16_t attribute; + //parse get/set attribute list + + if (ENIPExtractUint16(&attr_list_count, input, &offset, input_len) != 1) + { + return 0; + } + SCLogDebug("DecodeCIPRequestPathPDU: attribute list count %d", + attr_list_count); + for (int i = 0; i < attr_list_count; i++) + { + if (ENIPExtractUint16(&attribute, input, &offset, input_len) != 1) + { + return 0; + } + SCLogDebug("DecodeCIPRequestPathPDU: attribute %d", attribute); + //save attrs + AttributeEntry *attr = SCMalloc(sizeof(AttributeEntry)); + if (unlikely(attr == NULL)) + return 0; + attr->attribute = attribute; + TAILQ_INSERT_TAIL(&node->attrib_list, attr, next); + + } + } + + return 1; +} + +/** + * \brief Decode CIP Response + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (enip_data->encap_data_item.length < sizeof(CIPRespHdr)) + { + SCLogDebug("DecodeCIPResponse - Malformed CIP Data"); + return 0; + } + + uint8_t service; //<----CIP SERVICE + uint8_t reserved; //unused byte reserved by ODVA + uint16_t status; + + if (ENIPExtractUint8(&service, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint8(&reserved, input, &offset, input_len) != 1) + { + return 0; + } + if (ENIPExtractUint16(&status, input, &offset, input_len) != 1) + { + return 0; + } + + //SCLogDebug("DecodeCIPResponse: service 0x%x",service); + service &= 0x7f; //strip off top bit to get service code. Responses have first bit as 1 + + SCLogDebug("CIP service 0x%x status 0x%x", service, status); + + //reached maximum number of services + if (enip_data->service_count > 32) + { + SCLogDebug("DecodeCIPRequest: Maximum services reached"); + return 0; + } + + //save CIP data + CIPServiceEntry *node = CIPServiceAlloc(enip_data); + if (node == NULL) + { + SCLogDebug("DecodeCIPRequest: Unable to create CIP service"); + return 0; + } + node->direction = 1; + node->service = service; + node->response.status = status; + + SCLogDebug("DecodeCIPResponsePDU: service 0x%x size %d", node->service, + node->request.path_size); + + //list of CIP services is large and can be vendor specific, store CIP service anyways and let the rule decide the action + switch (service) + { + case CIP_RESERVED: + SCLogDebug("DecodeCIPResponse - CIP_RESERVED"); + break; + case CIP_GET_ATTR_ALL: + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_ALL"); + break; + case CIP_GET_ATTR_LIST: + SCLogDebug("DecodeCIPResponse - CIP_GET_ATTR_LIST"); + break; + case CIP_SET_ATTR_LIST: + SCLogDebug("DecodeCIPResponse - CIP_SET_ATTR_LIST"); + break; + case CIP_RESET: + SCLogDebug("DecodeCIPResponse - CIP_RESET"); + break; + case CIP_START: + SCLogDebug("DecodeCIPResponse - CIP_START"); + break; + case CIP_STOP: + SCLogDebug("DecodeCIPResponse - CIP_STOP"); + break; + case CIP_CREATE: + SCLogDebug("DecodeCIPResponse - CIP_CREATE"); + break; + case CIP_DELETE: + SCLogDebug("DecodeCIPResponse - CIP_DELETE"); + break; + case CIP_MSP: + SCLogDebug("DecodeCIPResponse - CIP_MSP"); + DecodeCIPResponseMSPPDU(input, input_len, enip_data, offset); + break; + case CIP_APPLY_ATTR: + SCLogDebug("DecodeCIPResponse - CIP_APPLY_ATTR"); + break; + case CIP_KICK_TIMER: + SCLogDebug("DecodeCIPResponse - CIP_KICK_TIMER"); + break; + case CIP_OPEN_CONNECTION: + SCLogDebug("DecodeCIPResponse - CIP_OPEN_CONNECTION"); + break; + case CIP_CHANGE_START: + SCLogDebug("DecodeCIPResponse - CIP_CHANGE_START"); + break; + case CIP_GET_STATUS: + SCLogDebug("DecodeCIPResponse - CIP_GET_STATUS"); + break; + default: + SCLogDebug("DecodeCIPResponse - CIP SERVICE 0x%x", service); + } + + return ret; +} + + +/** + * \brief Decode CIP Request Multi Service Packet + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + if (offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); + return 0; + } + //use temp_offset just to grab the service offset, don't want to use and push offset + uint16_t temp_offset = offset; + uint16_t num_services; + ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("DecodeCIPRequestMSP number of services %d",num_services); + + for (int svc = 1; svc < num_services + 1; svc++) + { + if (temp_offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPRequestMSPPDU: Parsing beyond payload length"); + return 0; + } + + uint16_t svc_offset; //read set of service offsets + ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("parseCIPRequestMSP service %d offset %d",svc, svc_offset); + + DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset + } + + return ret; +} + + + +/** + * \brief Decode CIP Response MultiService Packet. + * @param input, input_len data stream + * @param enip_data stores data from Packet + * @param offset current point in the packet + * @return 1 Packet ok + * @return 0 Packet has errors + */ +int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset) +{ + int ret = 1; + + if (offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPResponseMSPPDU: Parsing beyond payload length"); + return 0; + } + //use temp_offset just to grab the service offset, don't want to use and push offset + uint16_t temp_offset = offset; + uint16_t num_services; + ByteExtractUint16(&num_services, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("DecodeCIPResponseMSP number of services %d", num_services); + + for (int svc = 0; svc < num_services; svc++) + { + if (temp_offset >= (input_len - sizeof(uint16_t))) + { + SCLogDebug("DecodeCIPResponseMSP: Parsing beyond payload length"); + return 0; + } + + uint16_t svc_offset; //read set of service offsets + ByteExtractUint16(&svc_offset, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), + (const uint8_t *) (input + temp_offset)); + temp_offset += sizeof(uint16_t); + //SCLogDebug("parseCIPResponseMSP service %d offset %d", svc, svc_offset); + + DecodeCIPPDU(input, input_len, enip_data, offset + svc_offset); //parse CIP at found offset + } + + return ret; +} diff --git a/src/app-layer-enip-common.h b/src/app-layer-enip-common.h new file mode 100644 index 000000000000..dec1f0510a9c --- /dev/null +++ b/src/app-layer-enip-common.h @@ -0,0 +1,250 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + */ + +#ifndef __APP_LAYER_ENIP_COMMON_H__ +#define __APP_LAYER_ENIP_COMMON_H__ + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "flow.h" +#include "queue.h" + +#define MAX_ENIP_CMD 65535 + +// EtherNet/IP commands +#define NOP 0x0000 +#define LIST_SERVICES 0x0004 +#define LIST_IDENTITY 0x0063 +#define LIST_INTERFACES 0x0064 +#define REGISTER_SESSION 0x0065 +#define UNREGISTER_SESSION 0x0066 +#define SEND_RR_DATA 0x006F +#define SEND_UNIT_DATA 0x0070 +#define INDICATE_STATUS 0x0072 +#define CANCEL 0x0073 + +//Common Packet Format Types +#define NULL_ADDR 0x0000 +#define CONNECTION_BASED 0x00a1 +#define CONNECTED_DATA_ITEM 0x00b1 +#define UNCONNECTED_DATA_ITEM 0x00b2 +#define SEQUENCE_ADDR_ITEM 0xB002 + +//status codes +#define SUCCESS 0x0000 +#define INVALID_CMD 0x0001 +#define NO_RESOURCES 0x0002 +#define INCORRECT_DATA 0x0003 +#define INVALID_SESSION 0x0064 +#define INVALID_LENGTH 0x0065 +#define UNSUPPORTED_PROT_REV 0x0069 + +#define MAX_CIP_SERVICE 127 +#define MAX_CIP_CLASS 65535 +#define MAX_CIP_ATTRIBUTE 65535 + +// CIP service codes +#define CIP_RESERVED 0x00 +#define CIP_GET_ATTR_ALL 0x01 +#define CIP_GET_ATTR_LIST 0x03 +#define CIP_SET_ATTR_LIST 0x04 +#define CIP_RESET 0x05 +#define CIP_START 0x06 +#define CIP_STOP 0x07 +#define CIP_CREATE 0x08 +#define CIP_DELETE 0x09 +#define CIP_MSP 0x0a +#define CIP_APPLY_ATTR 0x0d +#define CIP_GET_ATTR_SINGLE 0x0e +#define CIP_SET_ATTR_SINGLE 0x10 +#define CIP_KICK_TIMER 0x4b +#define CIP_OPEN_CONNECTION 0x4c +#define CIP_CHANGE_START 0x4f +#define CIP_GET_STATUS 0x50 + +//PATH sizing codes +#define PATH_CLASS_8BIT 0x20 +#define PATH_CLASS_16BIT 0x21 +#define PATH_INSTANCE_8BIT 0x24 +#define PATH_INSTANCE_16BIT 0x25 +#define PATH_ATTR_8BIT 0x30 +#define PATH_ATTR_16BIT 0x31 //possible value + +/** + * ENIP encapsulation header + */ +typedef struct ENIPEncapHdr_ +{ + uint64_t context; + uint32_t session; + uint32_t status; + uint32_t option; + uint16_t command; + uint16_t length; +} ENIPEncapHdr; + +/** + * ENIP encapsulation data header + */ +typedef struct ENIPEncapDataHdr_ +{ + uint32_t interface_handle; + uint16_t timeout; + uint16_t item_count; +} ENIPEncapDataHdr; + +/** + * ENIP encapsulation address item + */ +typedef struct ENIPEncapAddresItem_ +{ + uint16_t type; + uint16_t length; + uint16_t conn_id; + uint16_t sequence_num; +} ENIPEncapAddresItem; + +/** + * ENIP encapsulation data item + */ +typedef struct ENIPEncapDataItem_ +{ + uint16_t type; + uint16_t length; + uint16_t sequence_count; +} ENIPEncapDataItem; + +/** + * CIP Request Header + */ +typedef struct CIPReqHdr_ +{ + uint8_t service; + uint8_t path_size; +} CIPReqHdr; + +/** + * CIP Response Header + */ +typedef struct CIPRespHdr_ +{ + uint8_t service; + uint8_t pad; + uint8_t status; + uint8_t status_size; +} CIPRespHdr; + +typedef struct SegmentEntry_ +{ + uint16_t segment; /**< segment type */ + uint16_t value; /**< segment value (class or attribute) */ + + TAILQ_ENTRY(SegmentEntry_) next; +} SegmentEntry; + +typedef struct AttributeEntry_ +{ + uint16_t attribute; /**< segment class */ + + TAILQ_ENTRY(AttributeEntry_) next; +} AttributeEntry; + +typedef struct CIPServiceEntry_ +{ + uint8_t service; /**< cip service */ + uint8_t direction; + union + { + struct + { + uint8_t path_size; /**< cip path size */ + uint16_t path_offset; /**< offset to cip path */ + } request; + struct + { + uint8_t status; + } response; + }; + + TAILQ_HEAD(, SegmentEntry_) segment_list; /**< list for CIP segment */ + TAILQ_HEAD(, AttributeEntry_) attrib_list; /**< list for CIP segment */ + + TAILQ_ENTRY(CIPServiceEntry_) next; +} CIPServiceEntry; + +typedef struct ENIPTransaction_ +{ + struct ENIPState_ *enip; + uint16_t tx_num; /**< internal: id */ + uint16_t tx_id; /**< transaction id */ + uint16_t service_count; + + ENIPEncapHdr header; /**< encapsulation header */ + ENIPEncapDataHdr encap_data_header; /**< encapsulation data header */ + ENIPEncapAddresItem encap_addr_item; /**< encapsulated address item */ + ENIPEncapDataItem encap_data_item; /**< encapsulated data item */ + + TAILQ_HEAD(, CIPServiceEntry_) service_list; /**< list for CIP */ + + AppLayerDecoderEvents *decoder_events; /**< per tx events */ + + TAILQ_ENTRY(ENIPTransaction_) next; + DetectEngineState *de_state; +} ENIPTransaction; + +/** \brief Per flow ENIP state container */ +typedef struct ENIPState_ +{ + TAILQ_HEAD(, ENIPTransaction_) tx_list; /**< transaction list */ + ENIPTransaction *curr; /**< ptr to current tx */ + ENIPTransaction *iter; + uint64_t transaction_max; + uint64_t tx_with_detect_state_cnt; + + uint16_t events; + uint16_t givenup; + + /* used by TCP only */ + uint16_t offset; + uint16_t record_len; + uint8_t *buffer; +} ENIPState; + +int DecodeENIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data); +int DecodeCommonPacketFormatPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPRequestPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPResponsePDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPRequestPathPDU(uint8_t *input, uint32_t input_len, + CIPServiceEntry *node, uint16_t offset); +int DecodeCIPRequestMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); +int DecodeCIPResponseMSPPDU(uint8_t *input, uint32_t input_len, + ENIPTransaction *enip_data, uint16_t offset); + +#endif /* __APP_LAYER_ENIP_COMMON_H__ */ diff --git a/src/app-layer-enip.c b/src/app-layer-enip.c new file mode 100644 index 000000000000..d6218fa22f92 --- /dev/null +++ b/src/app-layer-enip.c @@ -0,0 +1,598 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + * + * App-layer parser for ENIP protocol + * + */ + +#include "suricata-common.h" + +#include "util-debug.h" +#include "util-byte.h" +#include "util-enum.h" +#include "util-mem.h" +#include "util-misc.h" + +#include "stream.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-enip.h" +#include "app-layer-enip-common.h" + +#include "app-layer-detect-proto.h" + +#include "conf.h" +#include "decode.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "util-byte.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "pkt-var.h" +#include "util-profiling.h" + + +SCEnumCharMap enip_decoder_event_table[ ] = { + { NULL, -1 }, +}; + +/** \brief get value for 'complete' status in ENIP + * + * For ENIP we use a simple bool. + */ +int ENIPGetAlstateProgress(void *tx, uint8_t direction) +{ + return 1; +} + +/** \brief get value for 'complete' status in ENIP + * + * For ENIP we use a simple bool. + */ +int ENIPGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +DetectEngineState *ENIPGetTxDetectState(void *vtx) +{ + ENIPTransaction *tx = (ENIPTransaction *)vtx; + return tx->de_state; +} + +int ENIPSetTxDetectState(void *state, void *vtx, DetectEngineState *s) +{ + ENIPTransaction *tx = (ENIPTransaction *)vtx; + tx->de_state = s; + return 0; +} + +void *ENIPGetTx(void *alstate, uint64_t tx_id) { + ENIPState *enip = (ENIPState *) alstate; + ENIPTransaction *tx = NULL; + + if (enip->curr && enip->curr->tx_num == tx_id + 1) + return enip->curr; + + TAILQ_FOREACH(tx, &enip->tx_list, next) { + if (tx->tx_num != (tx_id+1)) + continue; + + SCLogDebug("returning tx %p", tx); + return tx; + } + + return NULL; +} + +uint64_t ENIPGetTxCnt(void *alstate) { + return ((uint64_t) ((ENIPState *) alstate)->transaction_max); +} + +AppLayerDecoderEvents *ENIPGetEvents(void *state, uint64_t id) { + ENIPState *enip = (ENIPState *) state; + ENIPTransaction *tx; + + if (enip->curr && enip->curr->tx_num == (id + 1)) + return enip->curr->decoder_events; + + TAILQ_FOREACH(tx, &enip->tx_list, next) { + if (tx->tx_num == (id+1)) + return tx->decoder_events; + } + + return NULL; +} + +int ENIPHasEvents(void *state) { + return (((ENIPState *) state)->events > 0); +} + +int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) { + *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table); + + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "enip's enum map table.", event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +/** \brief Allocate enip state + * + * return state + */ +void *ENIPStateAlloc(void) +{ + SCLogDebug("ENIPStateAlloc"); + void *s = SCMalloc(sizeof(ENIPState)); + if (unlikely(s == NULL)) + return NULL; + + memset(s, 0, sizeof(ENIPState)); + + ENIPState *enip_state = (ENIPState *) s; + + TAILQ_INIT(&enip_state->tx_list); + return s; +} + +/** \internal + * \brief Free a ENIP TX + * \param tx ENIP TX to free */ +static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state) +{ + SCEnter(); + SCLogDebug("ENIPTransactionFree"); + CIPServiceEntry *svc = NULL; + while ((svc = TAILQ_FIRST(&tx->service_list))) + { + TAILQ_REMOVE(&tx->service_list, svc, next); + + SegmentEntry *seg = NULL; + while ((seg = TAILQ_FIRST(&svc->segment_list))) + { + TAILQ_REMOVE(&svc->segment_list, seg, next); + SCFree(seg); + } + + AttributeEntry *attr = NULL; + while ((attr = TAILQ_FIRST(&svc->attrib_list))) + { + TAILQ_REMOVE(&svc->attrib_list, attr, next); + SCFree(attr); + } + + SCFree(svc); + } + + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + if (tx->de_state != NULL) + { + DetectEngineStateFree(tx->de_state); + + state->tx_with_detect_state_cnt--; + } + + if (state->iter == tx) + state->iter = NULL; + + SCFree(tx); + SCReturn; +} + +/** \brief Free enip state + * + */ +void ENIPStateFree(void *s) +{ + SCEnter(); + SCLogDebug("ENIPStateFree"); + if (s) + { + ENIPState *enip_state = (ENIPState *) s; + + ENIPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&enip_state->tx_list))) + { + TAILQ_REMOVE(&enip_state->tx_list, tx, next); + ENIPTransactionFree(tx, enip_state); + } + + if (enip_state->buffer != NULL) + { + SCFree(enip_state->buffer); + } + + SCFree(s); + } + SCReturn; +} + +/** \internal + * \brief Allocate a ENIP TX + * \retval tx or NULL */ +static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state) +{ + SCLogDebug("ENIPStateTransactionAlloc"); + ENIPTransaction *tx = (ENIPTransaction *) SCCalloc(1, + sizeof(ENIPTransaction)); + if (unlikely(tx == NULL)) + return NULL; + + state->curr = tx; + state->transaction_max++; + + memset(tx, 0x00, sizeof(ENIPTransaction)); + TAILQ_INIT(&tx->service_list); + + tx->enip = state; + tx->tx_num = state->transaction_max; + tx->service_count = 0; + + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + + return tx; +} + +/** + * \brief enip transaction cleanup callback + */ +void ENIPStateTransactionFree(void *state, uint64_t tx_id) +{ + SCEnter(); + SCLogDebug("ENIPStateTransactionFree"); + ENIPState *enip_state = state; + ENIPTransaction *tx = NULL; + TAILQ_FOREACH(tx, &enip_state->tx_list, next) + { + + if ((tx_id+1) < tx->tx_num) + break; + else if ((tx_id+1) > tx->tx_num) + continue; + + if (tx == enip_state->curr) + enip_state->curr = NULL; + + if (tx->decoder_events != NULL) + { + if (tx->decoder_events->cnt <= enip_state->events) + enip_state->events -= tx->decoder_events->cnt; + else + enip_state->events = 0; + } + + TAILQ_REMOVE(&enip_state->tx_list, tx, next); + ENIPTransactionFree(tx, state); + break; + } + SCReturn; +} + +/** \internal + * + * \brief This function is called to retrieve a ENIP + * + * \param state ENIP state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int ENIPParse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + SCEnter(); + ENIPState *enip = (ENIPState *) state; + ENIPTransaction *tx; + + if (input == NULL && AppLayerParserStateIssetFlag(pstate, + APP_LAYER_PARSER_EOF)) + { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) + { + SCReturnInt(-1); + } + + while (input_len > 0) + { + tx = ENIPTransactionAlloc(enip); + if (tx == NULL) + SCReturnInt(0); + + SCLogDebug("ENIPParse input len %d", input_len); + DecodeENIPPDU(input, input_len, tx); + uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr); + SCLogDebug("ENIPParse packet len %d", pkt_len); + if (pkt_len > input_len) + { + SCLogDebug("Invalid packet length"); + break; + } + + input += pkt_len; + input_len -= pkt_len; + //SCLogDebug("remaining %d", input_len); + + if (input_len < sizeof(ENIPEncapHdr)) + { + //SCLogDebug("Not enough data"); //not enough data for ENIP + break; + } + } + + return 1; +} + + + +static uint16_t ENIPProbingParser(uint8_t *input, uint32_t input_len, + uint32_t *offset) +{ + // SCLogDebug("ENIPProbingParser %d", input_len); + if (input_len < sizeof(ENIPEncapHdr)) + { + SCLogDebug("length too small to be a ENIP header"); + return ALPROTO_UNKNOWN; + } + + return ALPROTO_ENIP; +} + +/** + * \brief Function to register the ENIP protocol parsers and other functions + */ +void RegisterENIPUDPParsers(void) +{ + SCEnter(); + char *proto_name = "enip"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) + { + AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); + + if (RunmodeIsUnittests()) + { + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); + + } else + { + if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, + proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), + ENIPProbingParser, ENIPProbingParser)) + { + SCLogDebug( + "no ENIP UDP config found enabling ENIP detection on port 44818."); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", + ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, + ENIPProbingParser, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", + ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, + ENIPProbingParser, NULL); + } + } + + } else + { + SCLogConfig("Protocol detection and parser disabled for %s protocol.", + proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) + { + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, + STREAM_TOSERVER, ENIPParse); + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, + STREAM_TOCLIENT, ENIPParse); + + AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_ENIP, + ENIPStateAlloc, ENIPStateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPHasEvents); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_ENIP, NULL, + ENIPGetTxDetectState, ENIPSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_ENIP, ENIPGetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_UDP, + ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); + + } else + { + SCLogInfo( + "Parsed disabled for %s protocol. Protocol detection" "still on.", + proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_ENIP, ENIPParserRegisterTests); +#endif + + SCReturn; +} + +/** + * \brief Function to register the ENIP protocol parsers and other functions + */ +void RegisterENIPTCPParsers(void) +{ + SCEnter(); + char *proto_name = "enip"; + + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) + { + AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name); + + if (RunmodeIsUnittests()) + { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, + 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL); + + } else + { + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), + ENIPProbingParser, ENIPProbingParser)) + { +#ifndef AFLFUZZ_APPLAYER + return; +#endif + } + } + + } else + { + SCLogDebug("Protocol detection and parser disabled for %s protocol.", + proto_name); + return; + } + + if (AppLayerParserConfParserEnabled("tcp", proto_name)) + { + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, + STREAM_TOSERVER, ENIPParse); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, + STREAM_TOCLIENT, ENIPParse); + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_ENIP, + ENIPStateAlloc, ENIPStateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPHasEvents); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_ENIP, NULL, + ENIPGetTxDetectState, ENIPSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_ENIP, ENIPGetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, + ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT); + } else + { + SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.", + proto_name); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_ENIP, ENIPParserRegisterTests); +#endif + + SCReturn; +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "app-layer-parser.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00, + /* Length */ 0x00, 0x00, + /* Session */ 0x00, 0x00, 0x00, 0x00, + /* Status */ 0x00, 0x00, 0x00, 0x00, + /* Delay*/ 0x00, + /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00}; + +/** + * \brief Test if ENIP Packet matches signature + */ +int ALDecodeENIPTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER, + listIdentity, sizeof(listIdentity)); + FAIL_IF(r != 0); + + ENIPState *enip_state = f.alstate; + FAIL_IF_NULL(enip_state); + + ENIPTransaction *tx = ENIPGetTx(enip_state, 0); + FAIL_IF_NULL(tx); + + FAIL_IF(tx->header.command != 99); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + + PASS; +} + +#endif /* UNITTESTS */ + +void ENIPParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer-enip.h b/src/app-layer-enip.h new file mode 100644 index 000000000000..d31cfb3aad0b --- /dev/null +++ b/src/app-layer-enip.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + */ + +#ifndef __APP_LAYER_ENIP_H__ +#define __APP_LAYER_ENIP_H__ + +#include "decode.h" +#include "detect-engine-state.h" +#include "queue.h" + +void RegisterENIPUDPParsers(void); +void RegisterENIPTCPParsers(void); +void ENIPParserRegisterTests(void); + +#endif /* __APP_LAYER_ENIP_H__ */ diff --git a/src/app-layer-events.h b/src/app-layer-events.h index 11dfb9e60daa..0261a26f9265 100644 --- a/src/app-layer-events.h +++ b/src/app-layer-events.h @@ -50,8 +50,7 @@ enum { /* the event types for app events */ typedef enum AppLayerEventType_ { - APP_LAYER_EVENT_TYPE_GENERAL = 1, - APP_LAYER_EVENT_TYPE_TRANSACTION, + APP_LAYER_EVENT_TYPE_TRANSACTION = 1, APP_LAYER_EVENT_TYPE_PACKET, } AppLayerEventType; diff --git a/src/app-layer-ftp.c b/src/app-layer-ftp.c index b4a4d6f8e8bd..7bdd40436934 100644 --- a/src/app-layer-ftp.c +++ b/src/app-layer-ftp.c @@ -219,6 +219,12 @@ static int FTPParseRequest(Flow *f, void *ftp_state, FtpState *state = (FtpState *)ftp_state; void *ptmp; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + state->input = input; state->input_len = input_len; /* toserver stream */ @@ -297,6 +303,13 @@ static void FTPStateFree(void *s) SCFree(fstate->line_state[0].db); if (fstate->line_state[1].db) SCFree(fstate->line_state[1].db); + + //AppLayerDecoderEventsFreeEvents(&s->decoder_events); + + if (fstate->de_state != NULL) { + DetectEngineStateFree(fstate->de_state); + } + SCFree(s); #ifdef DEBUG SCMutexLock(&ftp_state_mem_lock); @@ -306,6 +319,64 @@ static void FTPStateFree(void *s) #endif } +static int FTPStateHasTxDetectState(void *state) +{ + FtpState *ssh_state = (FtpState *)state; + if (ssh_state->de_state) + return 1; + return 0; +} + +static int FTPSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + FtpState *ssh_state = (FtpState *)state; + ssh_state->de_state = de_state; + return 0; +} + +static DetectEngineState *FTPGetTxDetectState(void *vtx) +{ + FtpState *ssh_state = (FtpState *)vtx; + return ssh_state->de_state; +} + +static void FTPStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *FTPGetTx(void *state, uint64_t tx_id) +{ + FtpState *ssh_state = (FtpState *)state; + return ssh_state; +} + +static uint64_t FTPGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int FTPGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return FTP_STATE_FINISHED; +} + +static int FTPGetAlstateProgress(void *tx, uint8_t direction) +{ + FtpState *ftp_state = (FtpState *)tx; + + if (direction == STREAM_TOSERVER && + ftp_state->command == FTP_COMMAND_PORT) { + return FTP_STATE_PORT_DONE; + } + + /* TODO: figure out further progress handling */ + + return FTP_STATE_IN_PROGRESS; +} + + static int FTPRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_FTP, @@ -345,6 +416,20 @@ void RegisterFTPParsers(void) FTPParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER | STREAM_TOCLIENT); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateHasTxDetectState, + FTPGetTxDetectState, FTPSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_FTP, + FTPGetAlstateProgressCompletionStatus); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); @@ -386,15 +471,16 @@ int FTPParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf, ftplen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -433,40 +519,46 @@ int FTPParserTest03(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_START, ftpbuf1, + ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf3, ftplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_EOF, ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -507,15 +599,18 @@ int FTPParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, ftpbuf1, ftplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + ftpbuf1, + ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -559,25 +654,28 @@ int FTPParserTest07(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_START, ftpbuf1, ftplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_START, ftpbuf1, + ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER|STREAM_EOF, ftpbuf2, ftplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER | STREAM_EOF, ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -629,15 +727,16 @@ int FTPParserTest10(void) else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, flags, &ftpbuf1[u], 1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, flags, + &ftpbuf1[u], 1); if (r != 0) { SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); } FtpState *ftp_state = f.alstate; @@ -665,11 +764,11 @@ int FTPParserTest10(void) void FTPParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FTPParserTest01", FTPParserTest01, 1); - UtRegisterTest("FTPParserTest03", FTPParserTest03, 1); - UtRegisterTest("FTPParserTest06", FTPParserTest06, 1); - UtRegisterTest("FTPParserTest07", FTPParserTest07, 1); - UtRegisterTest("FTPParserTest10", FTPParserTest10, 1); + UtRegisterTest("FTPParserTest01", FTPParserTest01); + UtRegisterTest("FTPParserTest03", FTPParserTest03); + UtRegisterTest("FTPParserTest06", FTPParserTest06); + UtRegisterTest("FTPParserTest07", FTPParserTest07); + UtRegisterTest("FTPParserTest10", FTPParserTest10); #endif /* UNITTESTS */ } diff --git a/src/app-layer-ftp.h b/src/app-layer-ftp.h index 4a001290d554..de93f5f77398 100644 --- a/src/app-layer-ftp.h +++ b/src/app-layer-ftp.h @@ -24,6 +24,12 @@ #ifndef __APP_LAYER_FTP_H__ #define __APP_LAYER_FTP_H__ +enum { + FTP_STATE_IN_PROGRESS, + FTP_STATE_PORT_DONE, + FTP_STATE_FINISHED, +}; + typedef enum { FTP_COMMAND_UNKNOWN = 0, FTP_COMMAND_ABOR, @@ -123,6 +129,11 @@ typedef struct FtpState_ { uint32_t port_line_len; uint32_t port_line_size; uint8_t *port_line; + + /* specifies which loggers are done logging */ + uint32_t logged; + + DetectEngineState *de_state; } FtpState; void RegisterFTPParsers(void); diff --git a/src/app-layer-htp-body.c b/src/app-layer-htp-body.c index 393336a40de3..3520182a6395 100644 --- a/src/app-layer-htp-body.c +++ b/src/app-layer-htp-body.c @@ -47,7 +47,6 @@ #include "util-spm.h" #include "util-debug.h" -#include "app-layer-htp.h" #include "app-layer-htp-file.h" #include "util-time.h" @@ -63,6 +62,9 @@ #include "util-memcmp.h" +static StreamingBufferConfig default_cfg = { + 0, 0, 3072, HTPMalloc, HTPCalloc, HTPRealloc, HTPFree }; + /** * \brief Append a chunk of body to the HtpBody struct * @@ -73,7 +75,8 @@ * \retval 0 ok * \retval -1 error */ -int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32_t len) +int HtpBodyAppendChunk(const HTPCfgDir *hcfg, HtpBody *body, + const uint8_t *data, uint32_t len) { SCEnter(); @@ -83,59 +86,35 @@ int HtpBodyAppendChunk(HtpTxUserData *htud, HtpBody *body, uint8_t *data, uint32 SCReturnInt(0); } - if (body->first == NULL) { - /* New chunk */ - bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); - if (bd == NULL) - goto error; - - bd->len = len; - bd->stream_offset = 0; - bd->next = NULL; - bd->logged = 0; - - bd->data = HTPMalloc(len); - if (bd->data == NULL) { - goto error; - } - memcpy(bd->data, data, len); + if (body->sb == NULL) { + const StreamingBufferConfig *cfg = hcfg ? &hcfg->sbcfg : &default_cfg; + body->sb = StreamingBufferInit(cfg); + if (body->sb == NULL) + SCReturnInt(-1); + } - body->first = body->last = bd; + /* New chunk */ + bd = (HtpBodyChunk *)HTPCalloc(1, sizeof(HtpBodyChunk)); + if (bd == NULL) { + SCReturnInt(-1); + } - body->content_len_so_far = len; - } else { - bd = (HtpBodyChunk *)HTPMalloc(sizeof(HtpBodyChunk)); - if (bd == NULL) - goto error; - - bd->len = len; - bd->stream_offset = body->content_len_so_far; - bd->next = NULL; - bd->logged = 0; - - bd->data = HTPMalloc(len); - if (bd->data == NULL) { - goto error; - } - memcpy(bd->data, data, len); + if (StreamingBufferAppend(body->sb, &bd->sbseg, data, len) != 0) { + HTPFree(bd, sizeof(HtpBodyChunk)); + SCReturnInt(-1); + } + if (body->first == NULL) { + body->first = body->last = bd; + } else { body->last->next = bd; body->last = bd; - - body->content_len_so_far += len; } - SCLogDebug("Body %p; data %p, len %"PRIu32, body, bd->data, (uint32_t)bd->len); + body->content_len_so_far += len; - SCReturnInt(0); + SCLogDebug("body %p", body); -error: - if (bd != NULL) { - if (bd->data != NULL) { - HTPFree(bd->data, bd->len); - } - HTPFree(bd, sizeof(HtpBodyChunk)); - } - SCReturnInt(-1); + SCReturnInt(0); } /** @@ -155,9 +134,12 @@ void HtpBodyPrint(HtpBody *body) SCLogDebug("--- Start body chunks at %p ---", body); printf("--- Start body chunks at %p ---\n", body); for (cur = body->first; cur != NULL; cur = cur->next) { - SCLogDebug("Body %p; data %p, len %"PRIu32, body, cur->data, (uint32_t)cur->len); - printf("Body %p; data %p, len %"PRIu32"\n", body, cur->data, (uint32_t)cur->len); - PrintRawDataFp(stdout, (uint8_t*)cur->data, cur->len); + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &cur->sbseg, &data, &data_len); + SCLogDebug("Body %p; data %p, len %"PRIu32, body, data, data_len); + printf("Body %p; data %p, len %"PRIu32"\n", body, data, data_len); + PrintRawDataFp(stdout, data, data_len); } SCLogDebug("--- End body chunks at %p ---", body); } @@ -172,11 +154,7 @@ void HtpBodyFree(HtpBody *body) { SCEnter(); - if (body->first == NULL) - return; - - SCLogDebug("Removing chunks of Body %p; data %p, len %"PRIu32, body, - body->last->data, (uint32_t)body->last->len); + SCLogDebug("removing chunks of body %p", body); HtpBodyChunk *cur = NULL; HtpBodyChunk *prev = NULL; @@ -184,22 +162,24 @@ void HtpBodyFree(HtpBody *body) prev = body->first; while (prev != NULL) { cur = prev->next; - if (prev->data != NULL) - HTPFree(prev->data, prev->len); HTPFree(prev, sizeof(HtpBodyChunk)); prev = cur; } body->first = body->last = NULL; + + StreamingBufferFree(body->sb); } /** * \brief Free request body chunks that are already fully parsed. * - * \param htud pointer to the HtpTxUserData holding the body + * \param state htp_state, with reference to our config + * \param body the body to prune + * \param direction STREAM_TOSERVER (request), STREAM_TOCLIENT (response) * * \retval none */ -void HtpBodyPrune(HtpBody *body) +void HtpBodyPrune(HtpState *state, HtpBody *body, int direction) { SCEnter(); @@ -211,18 +191,48 @@ void HtpBodyPrune(HtpBody *body) SCReturn; } - SCLogDebug("Pruning chunks of Body %p; data %p, len %"PRIu32, body, - body->last->data, (uint32_t)body->last->len); + /* get the configured inspect sizes. Default to response values */ + uint32_t min_size = state->cfg->response.inspect_min_size; + uint32_t window = state->cfg->response.inspect_window; + + if (direction == STREAM_TOSERVER) { + min_size = state->cfg->request.inspect_min_size; + window = state->cfg->request.inspect_window; + } + + uint64_t max_window = ((min_size > window) ? min_size : window); + uint64_t in_flight = body->content_len_so_far - body->body_inspected; + + /* Special case. If body_inspected is not being updated, we make sure that + * we prune the body. We allow for some extra size/room as we may be called + * multiple times on uninspected body chunk additions if a large block of + * data was ack'd at once. Want to avoid pruning before inspection. */ + if (in_flight > (max_window * 3)) { + body->body_inspected = body->content_len_so_far - max_window; + } else if (body->body_inspected < max_window) { + SCReturn; + } + + uint64_t left_edge = body->body_inspected; + if (left_edge <= min_size || left_edge <= window) + left_edge = 0; + if (left_edge) + left_edge -= window; + + if (left_edge) { + SCLogDebug("sliding body to offset %"PRIu64, left_edge); + StreamingBufferSlideToOffset(body->sb, left_edge); + } + + SCLogDebug("pruning chunks of body %p", body); HtpBodyChunk *cur = body->first; while (cur != NULL) { HtpBodyChunk *next = cur->next; + SCLogDebug("cur %p", cur); - SCLogDebug("cur->stream_offset %"PRIu64" + cur->len %u = %"PRIu64", " - "body->body_parsed %"PRIu64, cur->stream_offset, cur->len, - cur->stream_offset + cur->len, body->body_parsed); - - if (cur->stream_offset >= body->body_inspected) { + if (!StreamingBufferSegmentIsBeforeWindow(body->sb, &cur->sbseg)) { + SCLogDebug("not removed"); break; } @@ -231,12 +241,10 @@ void HtpBodyPrune(HtpBody *body) body->last = next; } - if (cur->data != NULL) { - HTPFree(cur->data, cur->len); - } HTPFree(cur, sizeof(HtpBodyChunk)); cur = next; + SCLogDebug("removed"); } SCReturn; diff --git a/src/app-layer-htp-body.h b/src/app-layer-htp-body.h index 82d92a486042..637eb07d61d1 100644 --- a/src/app-layer-htp-body.h +++ b/src/app-layer-htp-body.h @@ -28,9 +28,9 @@ #ifndef __APP_LAYER_HTP_BODY_H__ #define __APP_LAYER_HTP_BODY_H__ -int HtpBodyAppendChunk(HtpTxUserData *, HtpBody *, uint8_t *, uint32_t); +int HtpBodyAppendChunk(const HTPCfgDir *, HtpBody *, const uint8_t *, uint32_t); void HtpBodyPrint(HtpBody *); void HtpBodyFree(HtpBody *); -void HtpBodyPrune(HtpBody *); +void HtpBodyPrune(HtpState *, HtpBody *, int); #endif /* __APP_LAYER_HTP_BODY_H__ */ diff --git a/src/app-layer-htp-file.c b/src/app-layer-htp-file.c index d8659f338e04..520f734c0350 100644 --- a/src/app-layer-htp-file.c +++ b/src/app-layer-htp-file.c @@ -46,7 +46,6 @@ #include "util-spm.h" #include "util-debug.h" -#include "app-layer-htp.h" #include "util-time.h" #include "util-unittest.h" @@ -76,13 +75,15 @@ * \retval -1 error * \retval -2 not handling files on this flow */ -int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, - uint8_t *data, uint32_t data_len, uint16_t txid, uint8_t direction) +int HTPFileOpen(HtpState *s, const uint8_t *filename, uint16_t filename_len, + const uint8_t *data, uint32_t data_len, + uint64_t txid, uint8_t direction) { int retval = 0; - uint8_t flags = 0; + uint16_t flags = 0; FileContainer *files = NULL; FileContainer *files_opposite = NULL; + const StreamingBufferConfig *sbcfg = NULL; SCLogDebug("data %p data_len %"PRIu32, data, data_len); @@ -102,24 +103,18 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, files = s->files_tc; files_opposite = s->files_ts; + flags = FileFlowToFlags(s->f, STREAM_TOCLIENT); + if ((s->flags & HTP_FLAG_STORE_FILES_TS) || ((s->flags & HTP_FLAG_STORE_FILES_TX_TS) && txid == s->store_tx_id)) { flags |= FILE_STORE; + flags &= ~FILE_NOSTORE; + } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TC)) { + flags |= FILE_NOSTORE; } - if (s->f->flags & FLOW_FILE_NO_MAGIC_TC) { - SCLogDebug("no magic for this flow in toclient direction, so none for this file"); - flags |= FILE_NOMAGIC; - } - - if (s->f->flags & FLOW_FILE_NO_MD5_TC) { - SCLogDebug("no md5 for this flow in toclient direction, so none for this file"); - flags |= FILE_NOMD5; - } + sbcfg = &s->cfg->response.sbcfg; - if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TC)) { - flags |= FILE_NOSTORE; - } } else { if (s->files_ts == NULL) { s->files_ts = FileContainerAlloc(); @@ -132,23 +127,16 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, files = s->files_ts; files_opposite = s->files_tc; + flags = FileFlowToFlags(s->f, STREAM_TOSERVER); if ((s->flags & HTP_FLAG_STORE_FILES_TC) || ((s->flags & HTP_FLAG_STORE_FILES_TX_TC) && txid == s->store_tx_id)) { flags |= FILE_STORE; - } - if (s->f->flags & FLOW_FILE_NO_MAGIC_TS) { - SCLogDebug("no magic for this flow in toserver direction, so none for this file"); - flags |= FILE_NOMAGIC; - } - - if (s->f->flags & FLOW_FILE_NO_MD5_TS) { - SCLogDebug("no md5 for this flow in toserver direction, so none for this file"); - flags |= FILE_NOMD5; - } - - if (!(flags & FILE_STORE) && (s->f->flags & FLOW_FILE_NO_STORE_TS)) { + flags &= ~FILE_NOSTORE; + } else if (!(flags & FILE_STORE) && (s->f->file_flags & FLOWFILE_NO_STORE_TS)) { flags |= FILE_NOSTORE; } + + sbcfg = &s->cfg->request.sbcfg; } /* if the previous file is in the same txid, we reset the file part of the @@ -176,7 +164,7 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, } } - if (FileOpenFile(files, filename, filename_len, + if (FileOpenFile(files, sbcfg, filename, filename_len, data, data_len, flags) == NULL) { retval = -1; @@ -201,7 +189,7 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len, * \retval -1 error * \retval -2 file doesn't need storing */ -int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len, +int HTPFileStoreChunk(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t direction) { SCEnter(); @@ -255,7 +243,7 @@ int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len, * \retval -1 error * \retval -2 not storing files on this flow/tx */ -int HTPFileClose(HtpState *s, uint8_t *data, uint32_t data_len, +int HTPFileClose(HtpState *s, const uint8_t *data, uint32_t data_len, uint8_t flags, uint8_t direction) { SCEnter(); @@ -325,26 +313,29 @@ static int HTPFileParserTest01(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -417,48 +408,53 @@ static int HTPFileParserTest02(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -541,70 +537,77 @@ static int HTPFileParserTest03(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -629,8 +632,12 @@ static int HTPFileParserTest03(void) goto end; } - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("filedata len not 11 but %u: ", http_state->files_ts->head->chunks_head->len); + if (http_state->files_ts->head == NULL || + FileDataSize(http_state->files_ts->head) != 11) + { + if (http_state->files_ts->head != NULL) + printf("filedata len not 11 but %"PRIu64": ", + FileDataSize(http_state->files_ts->head)); goto end; } @@ -692,70 +699,77 @@ static int HTPFileParserTest04(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 5 size %u <<<<\n", httplen5); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 6 size %u <<<<\n", httplen6); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -829,26 +843,29 @@ static int HTPFileParserTest05(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -879,31 +896,18 @@ static int HTPFileParserTest05(void) if (http_state->files_ts->head->next != http_state->files_ts->tail) goto end; - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("filecontent", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->head->sb, + (uint8_t *)"filecontent", 11) != 1) + { goto end; } - if (http_state->files_ts->tail->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->tail->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len); + if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } - if (memcmp("FILECONTENT", http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len) != 0) { - goto end; - } result = 1; end: if (alp_tctx != NULL) @@ -954,26 +958,29 @@ static int HTPFileParserTest06(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1004,31 +1011,18 @@ static int HTPFileParserTest06(void) if (http_state->files_ts->head->next != http_state->files_ts->tail) goto end; - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("filecontent", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->head->sb, + (uint8_t *)"filecontent", 11) != 1) + { goto end; } - if (http_state->files_ts->tail->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->tail->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len); + if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } - if (memcmp("FILECONTENT", http_state->files_ts->tail->chunks_head->data, - http_state->files_ts->tail->chunks_head->len) != 0) { - goto end; - } result = 1; end: if (alp_tctx != NULL) @@ -1068,26 +1062,29 @@ static int HTPFileParserTest07(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 size %u <<<<\n", httplen1); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1113,16 +1110,9 @@ static int HTPFileParserTest07(void) goto end; } - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->tail->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } @@ -1169,26 +1159,29 @@ static int HTPFileParserTest08(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1197,14 +1190,14 @@ static int HTPFileParserTest08(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->cnt != 2) { printf("expected 2 events: "); @@ -1265,48 +1258,53 @@ static int HTPFileParserTest09(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1315,14 +1313,14 @@ static int HTPFileParserTest09(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->cnt != 1) { printf("expected 1 event: "); @@ -1381,48 +1379,53 @@ static int HTPFileParserTest10(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1431,14 +1434,14 @@ static int HTPFileParserTest10(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); result = 1; end: @@ -1520,44 +1523,49 @@ static int HTPFileParserTest11(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 3 size %u <<<<\n", httplen3); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 4 size %u <<<<\n", httplen4); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { @@ -1565,14 +1573,14 @@ static int HTPFileParserTest11(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, http_state, 0); if (tx == NULL) { @@ -1591,16 +1599,9 @@ static int HTPFileParserTest11(void) goto end; } - if (http_state->files_ts->head->chunks_head->len != 11) { - printf("expected 11 but file is %u bytes instead: ", - http_state->files_ts->head->chunks_head->len); - PrintRawDataFp(stdout, http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len); - goto end; - } - - if (memcmp("FILECONTENT", http_state->files_ts->head->chunks_head->data, - http_state->files_ts->head->chunks_head->len) != 0) { + if (StreamingBufferCompareRawData(http_state->files_ts->head->sb, + (uint8_t *)"FILECONTENT", 11) != 1) + { goto end; } @@ -1620,16 +1621,16 @@ static int HTPFileParserTest11(void) void HTPFileParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01, 1); - UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02, 1); - UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03, 1); - UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04, 1); - UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05, 1); - UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06, 1); - UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07, 1); - UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08, 1); - UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09, 1); - UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10, 1); - UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11, 1); + UtRegisterTest("HTPFileParserTest01", HTPFileParserTest01); + UtRegisterTest("HTPFileParserTest02", HTPFileParserTest02); + UtRegisterTest("HTPFileParserTest03", HTPFileParserTest03); + UtRegisterTest("HTPFileParserTest04", HTPFileParserTest04); + UtRegisterTest("HTPFileParserTest05", HTPFileParserTest05); + UtRegisterTest("HTPFileParserTest06", HTPFileParserTest06); + UtRegisterTest("HTPFileParserTest07", HTPFileParserTest07); + UtRegisterTest("HTPFileParserTest08", HTPFileParserTest08); + UtRegisterTest("HTPFileParserTest09", HTPFileParserTest09); + UtRegisterTest("HTPFileParserTest10", HTPFileParserTest10); + UtRegisterTest("HTPFileParserTest11", HTPFileParserTest11); #endif /* UNITTESTS */ } diff --git a/src/app-layer-htp-file.h b/src/app-layer-htp-file.h index d70794eaa573..1f0bfb60556f 100644 --- a/src/app-layer-htp-file.h +++ b/src/app-layer-htp-file.h @@ -25,9 +25,9 @@ #ifndef __APP_LAYER_HTP_FILE_H__ #define __APP_LAYER_HTP_FILE_H__ -int HTPFileOpen(HtpState *, uint8_t *, uint16_t, uint8_t *, uint32_t, uint16_t, uint8_t); -int HTPFileStoreChunk(HtpState *, uint8_t *, uint32_t, uint8_t); -int HTPFileClose(HtpState *, uint8_t *, uint32_t, uint8_t, uint8_t); +int HTPFileOpen(HtpState *, const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint64_t, uint8_t); +int HTPFileStoreChunk(HtpState *, const uint8_t *, uint32_t, uint8_t); +int HTPFileClose(HtpState *, const uint8_t *, uint32_t, uint8_t, uint8_t); void HTPFileParserRegisterTests(void); diff --git a/src/app-layer-htp-libhtp.c b/src/app-layer-htp-libhtp.c index fbe2df54f846..69d862208d5f 100644 --- a/src/app-layer-htp-libhtp.c +++ b/src/app-layer-htp-libhtp.c @@ -201,11 +201,13 @@ bstr *SCHTPGenerateNormalizedUri(htp_tx_t *tx, htp_uri_t *uri, int uri_include_a if (uri->query != NULL) { bstr *query = bstr_dup(uri->query); - uint64_t flags = 0; - htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); - bstr_add_c_noex(r, "?"); - bstr_add_noex(r, query); - bstr_free(query); + if (query) { + uint64_t flags = 0; + htp_urldecode_inplace(tx->cfg, HTP_DECODER_URLENCODED, query, &flags); + bstr_add_c_noex(r, "?"); + bstr_add_noex(r, query); + bstr_free(query); + } } if (uri->fragment != NULL) { diff --git a/src/app-layer-htp-mem.c b/src/app-layer-htp-mem.c index 8d5e9f0e8b17..c9caefa2dffe 100644 --- a/src/app-layer-htp-mem.c +++ b/src/app-layer-htp-mem.c @@ -78,14 +78,18 @@ void HTPDecrMemuse(uint64_t size) return; } -void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt) +uint64_t HTPMemuseGlobalCounter(void) { uint64_t tmpval = SC_ATOMIC_GET(htp_memuse); - SCPerfCounterSetUI64(trt->counter_htp_memuse, tv->sc_perf_pca, tmpval); - tmpval = SC_ATOMIC_GET(htp_memcap); - SCPerfCounterSetUI64(trt->counter_htp_memcap, tv->sc_perf_pca, tmpval); - return; + return tmpval; } + +uint64_t HTPMemcapGlobalCounter(void) +{ + uint64_t tmpval = SC_ATOMIC_GET(htp_memcap); + return tmpval; +} + /** * \brief Check if alloc'ing "size" would mean we're over memcap * @@ -117,6 +121,23 @@ void *HTPMalloc(size_t size) return ptr; } +void *HTPCalloc(size_t n, size_t size) +{ + void *ptr = NULL; + + if (HTPCheckMemcap((uint32_t)(n * size)) == 0) + return NULL; + + ptr = SCCalloc(n, size); + + if (unlikely(ptr == NULL)) + return NULL; + + HTPIncrMemuse((uint64_t)(n * size)); + + return ptr; +} + void *HTPRealloc(void *ptr, size_t orig_size, size_t size) { void *rptr = NULL; diff --git a/src/app-layer-htp-mem.h b/src/app-layer-htp-mem.h index 54b21f5d27d5..1039c32ce611 100644 --- a/src/app-layer-htp-mem.h +++ b/src/app-layer-htp-mem.h @@ -19,8 +19,9 @@ void HTPParseMemcap(); void *HTPMalloc(size_t size); +void *HTPCalloc(size_t n, size_t size); void *HTPRealloc(void *ptr, size_t orig_size, size_t size); void HTPFree(void *ptr, size_t size); - -void HTPMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *trt); +uint64_t HTPMemuseGlobalCounter(void); +uint64_t HTPMemcapGlobalCounter(void); diff --git a/src/app-layer-htp-xff.c b/src/app-layer-htp-xff.c new file mode 100644 index 000000000000..8ba6637e9a1a --- /dev/null +++ b/src/app-layer-htp-xff.c @@ -0,0 +1,364 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Ignacio Sanchez + * \author Duarte Silva + */ + +#include "suricata-common.h" +#include "conf.h" + +#include "app-layer-parser.h" +#include "app-layer-htp.h" +#include "app-layer-htp-xff.h" + +#include "util-misc.h" +#include "util-memrchr.h" +#include "util-unittest.h" + +/** XFF header value minimal length */ +#define XFF_CHAIN_MINLEN 7 +/** XFF header value maximum length */ +#define XFF_CHAIN_MAXLEN 256 +/** Default XFF header name */ +#define XFF_DEFAULT "X-Forwarded-For" + +/** \internal + * \brief parse XFF string + * \param input input string, might be modified + * \param output output buffer + * \param output_size size of output buffer + * \retval bool 1 ok, 0 fail + */ +static int ParseXFFString(char *input, char *output, int output_size) +{ + size_t len = strlen(input); + if (len == 0) + return 0; + + if (input[0] == '[') { + char *end = strchr(input, ']'); + if (end == NULL) // malformed, not closed + return 0; + + if (end != input+(len - 1)) { + SCLogDebug("data after closing bracket"); + // if we ever want to parse the port, we can do it here + } + + /* done, lets wrap up */ + input++; // skip past [ + *end = '\0'; // overwrite ], ignore anything after + + } else { + /* lets see if the xff string ends in a port */ + int c = 0; + int d = 0; + char *p = input; + while (*p != '\0') { + if (*p == ':') + c++; + if (*p == '.') + d++; + p++; + } + /* 3 dots: ipv4, one ':' port */ + if (d == 3 && c == 1) { + SCLogDebug("XFF w port %s", input); + char *x = strchr(input, ':'); + if (x) { + *x = '\0'; + SCLogDebug("XFF w/o port %s", input); + // if we ever want to parse the port, we can do it here + } + } + } + + SCLogDebug("XFF %s", input); + + /** Sanity check on extracted IP for IPv4 and IPv6 */ + uint32_t ip[4]; + if (inet_pton(AF_INET, input, ip) == 1 || + inet_pton(AF_INET6, input, ip) == 1) + { + strlcpy(output, input, output_size); + return 1; // OK + } + return 0; +} + +/** + * \brief Function to return XFF IP if any in the selected transaction. The + * caller needs to lock the flow. + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, + char *dstbuf, int dstbuflen) +{ + uint8_t xff_chain[XFF_CHAIN_MAXLEN]; + HtpState *htp_state = NULL; + htp_tx_t *tx = NULL; + uint64_t total_txs = 0; + uint8_t *p_xff = NULL; + + htp_state = (HtpState *)FlowGetAppState(p->flow); + + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + return 0; + } + + total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); + if (tx_id >= total_txs) + return 0; + + tx = AppLayerParserGetTx(p->flow->proto, ALPROTO_HTTP, htp_state, tx_id); + if (tx == NULL) { + SCLogDebug("tx is NULL, XFF cannot be retrieved"); + return 0; + } + + htp_header_t *h_xff = NULL; + if (tx->request_headers != NULL) { + h_xff = htp_table_get_c(tx->request_headers, xff_cfg->header); + } + + if (h_xff != NULL && bstr_len(h_xff->value) >= XFF_CHAIN_MINLEN && + bstr_len(h_xff->value) < XFF_CHAIN_MAXLEN) { + + memcpy(xff_chain, bstr_ptr(h_xff->value), bstr_len(h_xff->value)); + xff_chain[bstr_len(h_xff->value)]=0; + + if (xff_cfg->flags & XFF_REVERSE) { + /** Get the last IP address from the chain */ + p_xff = memrchr(xff_chain, ' ', bstr_len(h_xff->value)); + if (p_xff == NULL) { + p_xff = xff_chain; + } else { + p_xff++; + } + } + else { + /** Get the first IP address from the chain */ + p_xff = memchr(xff_chain, ',', bstr_len(h_xff->value)); + if (p_xff != NULL) { + *p_xff = 0; + } + p_xff = xff_chain; + } + return ParseXFFString((char *)p_xff, dstbuf, dstbuflen); + } + return 0; +} + +/** + * \brief Function to return XFF IP if any. The caller needs to lock the flow. + * \retval 1 if the IP has been found and returned in dstbuf + * \retval 0 if the IP has not being found or error + */ +int HttpXFFGetIP(const Packet *p, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen) +{ + HtpState *htp_state = NULL; + uint64_t tx_id = 0; + uint64_t total_txs = 0; + + htp_state = (HtpState *)FlowGetAppState(p->flow); + if (htp_state == NULL) { + SCLogDebug("no http state, XFF IP cannot be retrieved"); + goto end; + } + + total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, htp_state); + for (; tx_id < total_txs; tx_id++) { + if (HttpXFFGetIPFromTx(p, tx_id, xff_cfg, dstbuf, dstbuflen) == 1) + return 1; + } + +end: + return 0; // Not found +} + +/** + * \brief Function to return XFF configuration from a configuration node. + */ +void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result) +{ + BUG_ON(conf == NULL || result == NULL); + + ConfNode *xff_node = NULL; + + if (conf != NULL) + xff_node = ConfNodeLookupChild(conf, "xff"); + + if (xff_node != NULL && ConfNodeChildValueIsTrue(xff_node, "enabled")) { + const char *xff_mode = ConfNodeLookupChildValue(xff_node, "mode"); + + if (xff_mode != NULL && strcasecmp(xff_mode, "overwrite") == 0) { + result->flags |= XFF_OVERWRITE; + } else { + if (xff_mode == NULL) { + SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The XFF mode hasn't been defined, falling back to extra-data mode"); + } + else if (strcasecmp(xff_mode, "extra-data") != 0) { + SCLogWarning(SC_WARN_XFF_INVALID_MODE, "The XFF mode %s is invalid, falling back to extra-data mode", + xff_mode); + } + result->flags |= XFF_EXTRADATA; + } + + const char *xff_deployment = ConfNodeLookupChildValue(xff_node, "deployment"); + + if (xff_deployment != NULL && strcasecmp(xff_deployment, "forward") == 0) { + result->flags |= XFF_FORWARD; + } else { + if (xff_deployment == NULL) { + SCLogWarning(SC_WARN_XFF_INVALID_DEPLOYMENT, "The XFF deployment hasn't been defined, falling back to reverse proxy deployment"); + } + else if (strcasecmp(xff_deployment, "reverse") != 0) { + SCLogWarning(SC_WARN_XFF_INVALID_DEPLOYMENT, "The XFF mode %s is invalid, falling back to reverse proxy deployment", + xff_deployment); + } + result->flags |= XFF_REVERSE; + } + + const char *xff_header = ConfNodeLookupChildValue(xff_node, "header"); + + if (xff_header != NULL) { + result->header = (char *) xff_header; + } else { + SCLogWarning(SC_WARN_XFF_INVALID_HEADER, "The XFF header hasn't been defined, using the default %s", + XFF_DEFAULT); + result->header = XFF_DEFAULT; + } + } + else { + result->flags = XFF_DISABLED; + } +} + + +#ifdef UNITTESTS +static int XFFTest01(void) { + char input[] = "1.2.3.4:5678"; + char output[16]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "1.2.3.4") == 0) { + return 1; + } + return 0; +} + +static int XFFTest02(void) { + char input[] = "[12::34]:1234"; // thanks chort! + char output[16]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "12::34") == 0) { + return 1; + } + return 0; +} + +static int XFFTest03(void) { + char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]:80"; // thanks chort! + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0) { + return 1; + } + return 0; +} + +static int XFFTest04(void) { + char input[] = "[2a03:2880:1010:3f02:face:b00c:0:2]"; // thanks chort! + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "2a03:2880:1010:3f02:face:b00c:0:2") == 0) { + return 1; + } + return 0; +} + +static int XFFTest05(void) { + char input[] = "[::ffff:1.2.3.4]:1234"; // thanks double-p + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "::ffff:1.2.3.4") == 0) { + return 1; + } + return 0; +} + +static int XFFTest06(void) { + char input[] = "12::34"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "12::34") == 0) { + return 1; + } + return 0; +} + +static int XFFTest07(void) { + char input[] = "1.2.3.4"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 1 && strcmp(output, "1.2.3.4") == 0) { + return 1; + } + return 0; +} + +static int XFFTest08(void) { + char input[] = "[1.2.3.4:1234"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 0) { + return 1; + } + return 0; +} + +static int XFFTest09(void) { + char input[] = "999.999.999.999:1234"; + char output[46]; + int r = ParseXFFString(input, output, sizeof(output)); + if (r == 0) { + return 1; + } + return 0; +} + +#endif + +void HTPXFFParserRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("XFFTest01", XFFTest01); + UtRegisterTest("XFFTest02", XFFTest02); + UtRegisterTest("XFFTest03", XFFTest03); + UtRegisterTest("XFFTest04", XFFTest04); + UtRegisterTest("XFFTest05", XFFTest05); + UtRegisterTest("XFFTest06", XFFTest06); + UtRegisterTest("XFFTest07", XFFTest07); + UtRegisterTest("XFFTest08", XFFTest08); + UtRegisterTest("XFFTest09", XFFTest09); +#endif +} diff --git a/src/app-layer-htp-xff.h b/src/app-layer-htp-xff.h new file mode 100644 index 000000000000..1a3b67e16b9d --- /dev/null +++ b/src/app-layer-htp-xff.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Ignacio Sanchez + * \author Duarte Silva + */ + +#ifndef __APP_LAYER_HTP_XFF_H__ +#define __APP_LAYER_HTP_XFF_H__ + +/** XFF is disabled */ +#define XFF_DISABLED 1 +/** XFF extra data mode */ +#define XFF_EXTRADATA 2 +/** XFF overwrite mode */ +#define XFF_OVERWRITE 4 +/** XFF is to be used in a reverse proxy deployment */ +#define XFF_REVERSE 8 +/** XFF is to be used in a forward proxy deployment */ +#define XFF_FORWARD 16 +/** Single XFF IP maximum length (default value based on IPv6 address length) */ +#define XFF_MAXLEN 46 + +typedef struct HttpXFFCfg_ { + uint8_t flags; /**< XFF operation mode and deployment */ + char *header; /**< XFF header name */ +} HttpXFFCfg; + +void HttpXFFGetCfg(ConfNode *conf, HttpXFFCfg *result); + +int HttpXFFGetIPFromTx(const Packet *p, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); + +int HttpXFFGetIP(const Packet *p, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen); + +void HTPXFFParserRegisterTests(void); + +#endif /* __APP_LAYER_HTP_XFF_H__ */ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 7514b374e3cc..4d435cc236d5 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -35,9 +35,11 @@ #include "suricata.h" #include "suricata-common.h" +#include "conf.h" #include "debug.h" #include "decode.h" #include "threads.h" +#include "counters.h" #include "util-print.h" #include "util-pool.h" @@ -57,6 +59,7 @@ #include "app-layer-htp-body.h" #include "app-layer-htp-file.h" #include "app-layer-htp-libhtp.h" +#include "app-layer-htp-xff.h" #include "util-spm.h" #include "util-debug.h" @@ -72,14 +75,9 @@ #include "detect-parse.h" #include "decode-events.h" -#include "conf.h" #include "util-memcmp.h" -#ifndef HAVE_HTP_SET_PATH_DECODE_U_ENCODING -void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); -#endif - //#define PRINT /** Fast lookup tree (radix) for the various HTP configurations */ @@ -144,6 +142,12 @@ SCEnumCharMap http_decoder_event_table[ ] = { HTTP_DECODER_EVENT_URI_HOST_INVALID}, { "REQUEST_HEADER_HOST_INVALID", HTTP_DECODER_EVENT_HEADER_HOST_INVALID}, + { "URI_DELIM_NON_COMPLIANT", + HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, + { "METHOD_DELIM_NON_COMPLIANT", + HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT}, + { "REQUEST_LINE_LEADING_WHITESPACE", + HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE}, /* suricata warnings/errors */ { "MULTIPART_GENERIC_ERROR", @@ -281,8 +285,9 @@ static void *HTPStateAlloc(void) SCEnter(); HtpState *s = HTPMalloc(sizeof(HtpState)); - if (unlikely(s == NULL)) - goto error; + if (unlikely(s == NULL)) { + SCReturnPtr(NULL, "void"); + } memset(s, 0x00, sizeof(HtpState)); @@ -295,18 +300,11 @@ static void *HTPStateAlloc(void) #endif SCReturnPtr((void *)s, "void"); - -error: - if (s != NULL) { - HTPFree(s, sizeof(HtpState)); - } - - SCReturnPtr(NULL, "void"); } -static void HtpTxUserDataFree(HtpTxUserData *htud) +static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud) { - if (htud) { + if (likely(htud)) { HtpBodyFree(&htud->request_body); HtpBodyFree(&htud->response_body); bstr_free(htud->request_uri_normalized); @@ -317,6 +315,14 @@ static void HtpTxUserDataFree(HtpTxUserData *htud) AppLayerDecoderEventsFreeEvents(&htud->decoder_events); if (htud->boundary) HTPFree(htud->boundary, htud->boundary_len); + if (htud->de_state != NULL) { + if (likely(state != NULL)) { // should be impossible that it's null + BUG_ON(state->tx_with_detect_state_cnt == 0); + state->tx_with_detect_state_cnt--; + } + + DetectEngineStateFree(htud->de_state); + } HTPFree(htud, sizeof(HtpTxUserData)); } } @@ -348,15 +354,14 @@ void HTPStateFree(void *state) htp_tx_t *tx = HTPStateGetTx(s, tx_id); if (tx != NULL) { HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - HtpTxUserDataFree(htud); - htp_tx_set_user_data(tx, NULL); - } + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); } } } htp_connp_destroy_all(s->connp); } + BUG_ON(s->tx_with_detect_state_cnt > 0); FileContainerFree(s->files_ts); FileContainerFree(s->files_tc); @@ -391,11 +396,20 @@ static void HTPStateTransactionFree(void *state, uint64_t id) if (tx != NULL) { /* This will remove obsolete body chunks */ HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - HtpTxUserDataFree(htud); - htp_tx_set_user_data(tx, NULL); + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); + + /* hack: even if libhtp considers the tx incomplete, we want to + * free it here. htp_tx_destroy however, will refuse to do this. + * As htp_tx_destroy_incomplete isn't available in the public API, + * we hack around it here. */ + if (unlikely(!( + tx->request_progress == HTP_REQUEST_COMPLETE && + tx->response_progress == HTP_RESPONSE_COMPLETE))) + { + tx->request_progress = HTP_REQUEST_COMPLETE; + tx->response_progress = HTP_RESPONSE_COMPLETE; } - htp_tx_destroy(tx); } } @@ -497,6 +511,9 @@ struct { * luckily, "Request server port=" is unique */ /* { "Request server port number differs from the actual TCP port", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, */ { "Request server port=", HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH}, + { "Request line: URI contains non-compliant delimiter", HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT}, + { "Request line: non-compliant delimiter between Method and URI", HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT}, + { "Request line: leading whitespace", HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE}, }; #define HTP_ERROR_MAX (sizeof(htp_errors) / sizeof(htp_errors[0])) @@ -687,7 +704,9 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, } if (NULL == htp) { +#ifdef DEBUG_VALIDATION BUG_ON(htp == NULL); +#endif /* should never happen if HTPConfigure is properly invoked */ goto error; } @@ -706,7 +725,9 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, } /* the code block above should make sure connp is never NULL here */ +#ifdef DEBUG_VALIDATION BUG_ON(hstate->connp == NULL); +#endif /* Unset the body inspection (the callback should * reactivate it if necessary) */ @@ -724,28 +745,30 @@ static int HTPHandleRequestData(Flow *f, void *htp_state, htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec }; /* pass the new data to the htp parser */ - r = htp_connp_req_data(hstate->connp, &ts, input, input_len); + if (input_len > 0) { + r = htp_connp_req_data(hstate->connp, &ts, input, input_len); - switch(r) { - case HTP_STREAM_ERROR: + switch(r) { + case HTP_STREAM_ERROR: - hstate->flags |= HTP_FLAG_STATE_ERROR; - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - ret = -1; - break; - case HTP_STREAM_DATA: - case HTP_STREAM_DATA_OTHER: + hstate->flags |= HTP_FLAG_STATE_ERROR; + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + ret = -1; + break; + case HTP_STREAM_DATA: + case HTP_STREAM_DATA_OTHER: - hstate->flags |= HTP_FLAG_STATE_DATA; - break; - case HTP_STREAM_TUNNEL: - break; - default: - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + hstate->flags |= HTP_FLAG_STATE_DATA; + break; + case HTP_STREAM_TUNNEL: + break; + default: + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + } + HTPHandleError(hstate); } - HTPHandleError(hstate); /* if the TCP connection is closed, then close the HTTP connection */ if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) && @@ -800,25 +823,27 @@ static int HTPHandleResponseData(Flow *f, void *htp_state, hstate->flags &=~ HTP_FLAG_NEW_BODY_SET; htp_time_t ts = { f->lastts.tv_sec, f->lastts.tv_usec }; - r = htp_connp_res_data(hstate->connp, &ts, input, input_len); - switch(r) { - case HTP_STREAM_ERROR: - hstate->flags = HTP_FLAG_STATE_ERROR; - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - ret = -1; - break; - case HTP_STREAM_DATA: - case HTP_STREAM_DATA_OTHER: - hstate->flags |= HTP_FLAG_STATE_DATA; - break; - case HTP_STREAM_TUNNEL: - break; - default: - hstate->flags &= ~HTP_FLAG_STATE_DATA; - hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; - } - HTPHandleError(hstate); + if (input_len > 0) { + r = htp_connp_res_data(hstate->connp, &ts, input, input_len); + switch(r) { + case HTP_STREAM_ERROR: + hstate->flags = HTP_FLAG_STATE_ERROR; + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + ret = -1; + break; + case HTP_STREAM_DATA: + case HTP_STREAM_DATA_OTHER: + hstate->flags |= HTP_FLAG_STATE_DATA; + break; + case HTP_STREAM_TUNNEL: + break; + default: + hstate->flags &= ~HTP_FLAG_STATE_DATA; + hstate->flags &= ~HTP_FLAG_NEW_BODY_SET; + } + HTPHandleError(hstate); + } /* if we the TCP connection is closed, then close the HTTP connection */ if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) && @@ -1017,10 +1042,6 @@ static int HTTPParseContentTypeHeader(uint8_t *name, size_t name_len, */ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) { - htp_header_t *cl = htp_table_get_c(d->tx->request_headers, "content-length"); - if (cl != NULL) - htud->request_body.content_len = SC_htp_parse_content_length(cl->value); - htp_header_t *h = (htp_header_t *)htp_table_get_c(d->tx->request_headers, "Content-Type"); if (h != NULL && bstr_len(h->value) > 0) { @@ -1056,49 +1077,6 @@ static int HtpRequestBodySetupMultipart(htp_tx_data_t *d, HtpTxUserData *htud) SCReturnInt(0); } -/** - * \brief Setup boundary buffers - */ -static int HtpRequestBodySetupBoundary(HtpTxUserData *htud, - uint8_t **expected_boundary, uint8_t *expected_boundary_len, - uint8_t **expected_boundary_end, uint8_t *expected_boundary_end_len) -{ - uint8_t *eb = NULL; - uint8_t *ebe = NULL; - - uint8_t eb_len = htud->boundary_len + 2; - eb = (uint8_t *)HTPMalloc(eb_len); - if (eb == NULL) { - goto error; - } - memset(eb, '-', eb_len); - memcpy(eb + 2, htud->boundary, htud->boundary_len); - - uint8_t ebe_len = htud->boundary_len + 4; - ebe = (uint8_t *)HTPMalloc(ebe_len); - if (ebe == NULL) { - goto error; - } - memset(ebe, '-', ebe_len); - memcpy(ebe + 2, htud->boundary, htud->boundary_len); - - *expected_boundary = eb; - *expected_boundary_len = eb_len; - *expected_boundary_end = ebe; - *expected_boundary_end_len = ebe_len; - - SCReturnInt(0); - -error: - if (eb != NULL) { - HTPFree(eb, eb_len); - } - if (ebe != NULL) { - HTPFree(ebe, ebe_len); - } - SCReturnInt(-1); -} - #define C_D_HDR "content-disposition:" #define C_D_HDR_LEN 20 #define C_T_HDR "content-type:" @@ -1192,70 +1170,43 @@ static void HtpRequestBodyMultipartParseHeader(HtpState *hstate, * \param chunks_buffer_len pointer to pass back the buffer length to the caller */ static void HtpRequestBodyReassemble(HtpTxUserData *htud, - uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) + const uint8_t **chunks_buffer, uint32_t *chunks_buffer_len) { - uint8_t *buf = NULL; - uint8_t *pbuf = NULL; - uint32_t buf_len = 0; - HtpBodyChunk *cur = htud->request_body.first; - - for ( ; cur != NULL; cur = cur->next) { - SCLogDebug("chunk %p", cur); - - /* skip body chunks entirely before what we parsed already */ - if ((uint64_t )cur->stream_offset + cur->len <= htud->request_body.body_parsed) { - SCLogDebug("skipping chunk"); - continue; - } - - SCLogDebug("cur->stream_offset %"PRIu64", cur->len %"PRIu32", body_parsed %"PRIu64, - cur->stream_offset, cur->len, htud->request_body.body_parsed); - - if (cur->stream_offset < htud->request_body.body_parsed && - cur->stream_offset + cur->len >= htud->request_body.body_parsed) { - SCLogDebug("use part"); - - uint32_t toff = htud->request_body.body_parsed - cur->stream_offset; - uint32_t tlen = (cur->stream_offset + cur->len) - htud->request_body.body_parsed; - uint8_t *pbuf = NULL; - - buf_len += tlen; - if ((pbuf = HTPRealloc(buf, buf_len - tlen, buf_len)) == NULL) { - HTPFree(buf, buf_len - tlen); - buf = NULL; - buf_len = 0; - break; - } - buf = pbuf; - memcpy(buf + buf_len - tlen, cur->data + toff, tlen); - - } else { - SCLogDebug("use entire chunk"); + StreamingBufferGetDataAtOffset(htud->request_body.sb, + chunks_buffer, chunks_buffer_len, + htud->request_body.body_parsed); +} - buf_len += cur->len; - if ((pbuf = HTPRealloc(buf, buf_len - cur->len, buf_len)) == NULL) { - HTPFree(buf, buf_len - cur->len); - buf = NULL; - buf_len = 0; - break; - } - buf = pbuf; - memcpy(buf + buf_len - cur->len, cur->data, cur->len); +static void FlagDetectStateNewFile(HtpTxUserData *tx, int dir) +{ + if (tx && tx->de_state) { + if (dir == STREAM_TOSERVER) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW set"); + tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; + } else if (STREAM_TOCLIENT) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW set"); + tx->de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW; } } +} - *chunks_buffer = buf; - *chunks_buffer_len = buf_len; +/** + * \brief Setup boundary buffers + */ +static void HtpRequestBodySetupBoundary(HtpTxUserData *htud, + uint8_t *boundary, uint32_t boundary_len) +{ + memset(boundary, '-', boundary_len); + memcpy(boundary + 2, htud->boundary, htud->boundary_len); } -int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, - void *tx, uint8_t *chunks_buffer, uint32_t chunks_buffer_len) +int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, void *tx, + const uint8_t *chunks_buffer, uint32_t chunks_buffer_len) { int result = 0; - uint8_t *expected_boundary = NULL; - uint8_t *expected_boundary_end = NULL; - uint8_t expected_boundary_len = 0; - uint8_t expected_boundary_end_len = 0; + uint8_t boundary[htud->boundary_len + 4]; /**< size limited to HTP_BOUNDARY_MAX + 4 */ + uint8_t expected_boundary_len = htud->boundary_len + 2; + uint8_t expected_boundary_end_len = htud->boundary_len + 4; int tx_progress = 0; #ifdef PRINT @@ -1264,21 +1215,18 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, printf("CHUNK END: \n"); #endif - if (HtpRequestBodySetupBoundary(htud, &expected_boundary, &expected_boundary_len, - &expected_boundary_end, &expected_boundary_end_len) < 0) { - goto end; - } + HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4); /* search for the header start, header end and form end */ uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len, - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); uint8_t *header_end = NULL; if (header_start != NULL) { header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer), (uint8_t *)"\r\n\r\n", 4); } uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len, - expected_boundary_end, expected_boundary_end_len); + boundary, expected_boundary_end_len); SCLogDebug("header_start %p, header_end %p, form_end %p", header_start, header_end, form_end); @@ -1291,7 +1239,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, if (header_start != NULL || form_end != NULL || (tx_progress > HTP_REQUEST_BODY)) { SCLogDebug("reached the end of the file"); - uint8_t *filedata = chunks_buffer; + const uint8_t *filedata = chunks_buffer; uint32_t filedata_len = 0; uint8_t flags = 0; @@ -1331,7 +1279,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, SCLogDebug("not yet at the end of the file"); if (chunks_buffer_len > expected_boundary_end_len) { - uint8_t *filedata = chunks_buffer; + const uint8_t *filedata = chunks_buffer; uint32_t filedata_len = chunks_buffer_len - expected_boundary_len; #ifdef PRINT printf("FILEDATA (part) START: \n"); @@ -1415,7 +1363,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, /* or is it? */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); if (header_next != NULL) { filedata_len -= (form_end - header_next); } @@ -1444,6 +1392,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, goto end; } } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->request_body.body_parsed += (header_end - chunks_buffer); htud->tsflags &= ~HTP_FILENAME_SET; @@ -1468,7 +1417,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, /* form doesn't end in this chunk, but part might. Lets * see if have another coming up */ uint8_t *header_next = Bs2bmSearch(filedata, filedata_len, - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); SCLogDebug("header_next %p", header_next); if (header_next == NULL) { /* no, but we'll handle the file data when we see the @@ -1488,6 +1437,8 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); + } else if (header_next - filedata > 2) { filedata_len = header_next - filedata - 2; SCLogDebug("filedata_len %u", filedata_len); @@ -1504,6 +1455,7 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, goto end; } } + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->tsflags &= ~HTP_FILENAME_SET; htud->request_body.body_parsed += (header_end - chunks_buffer); @@ -1518,21 +1470,27 @@ int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, uint32_t cursizeread = header_end - chunks_buffer; header_start = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), - expected_boundary, expected_boundary_len); + boundary, expected_boundary_len); if (header_start != NULL) { header_end = Bs2bmSearch(header_end + 4, chunks_buffer_len - (cursizeread + 4), (uint8_t *) "\r\n\r\n", 4); } } -end: - if (expected_boundary != NULL) { - HTPFree(expected_boundary, expected_boundary_len); - } - if (expected_boundary_end != NULL) { - HTPFree(expected_boundary_end, expected_boundary_end_len); + + /* if we're parsing the multipart and we're not currently processing a + * file, we move the body pointer forward. */ + if (form_end == NULL && !(htud->tsflags & HTP_FILENAME_SET) && header_start == NULL) { + if (chunks_buffer_len > expected_boundary_end_len) { + uint32_t move = chunks_buffer_len - expected_boundary_end_len + 1; + + htud->request_body.body_parsed += move; + SCLogDebug("form not ready, file not set, parsing non-file " + "record: moved %u", move); + } } +end: SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed); return 0; } @@ -1578,6 +1536,7 @@ static int HtpRequestBodyHandlePOST(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; } @@ -1631,6 +1590,7 @@ static int HtpRequestBodyHandlePUT(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tsflags |= HTP_DONTSTORE; } else { + FlagDetectStateNewFile(htud, STREAM_TOSERVER); htud->tsflags |= HTP_FILENAME_SET; htud->tsflags &= ~HTP_DONTSTORE; } @@ -1698,6 +1658,7 @@ int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, } else if (result == -2) { htud->tcflags |= HTP_DONTSTORE; } else { + FlagDetectStateNewFile(htud, STREAM_TOCLIENT); htud->tcflags |= HTP_FILENAME_SET; htud->tcflags &= ~HTP_DONTSTORE; } @@ -1719,6 +1680,7 @@ int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud, } } + htud->response_body.body_parsed += data_len; return 0; end: return -1; @@ -1784,25 +1746,28 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) } } + /* see if we can get rid of htp body chunks */ + HtpBodyPrune(hstate, &tx_ud->request_body, STREAM_TOSERVER); + SCLogDebug("tx_ud->request_body.content_len_so_far %"PRIu64, tx_ud->request_body.content_len_so_far); - SCLogDebug("hstate->cfg->request_body_limit %u", hstate->cfg->request_body_limit); + SCLogDebug("hstate->cfg->request.body_limit %u", hstate->cfg->request.body_limit); /* within limits, add the body chunk to the state. */ - if (hstate->cfg->request_body_limit == 0 || tx_ud->request_body.content_len_so_far < hstate->cfg->request_body_limit) + if (hstate->cfg->request.body_limit == 0 || tx_ud->request_body.content_len_so_far < hstate->cfg->request.body_limit) { uint32_t len = (uint32_t)d->len; - if (hstate->cfg->request_body_limit > 0 && - (tx_ud->request_body.content_len_so_far + len) > hstate->cfg->request_body_limit) + if (hstate->cfg->request.body_limit > 0 && + (tx_ud->request_body.content_len_so_far + len) > hstate->cfg->request.body_limit) { - len = hstate->cfg->request_body_limit - tx_ud->request_body.content_len_so_far; + len = hstate->cfg->request.body_limit - tx_ud->request_body.content_len_so_far; BUG_ON(len > (uint32_t)d->len); } SCLogDebug("len %u", len); - HtpBodyAppendChunk(tx_ud, &tx_ud->request_body, (uint8_t *)d->data, len); + HtpBodyAppendChunk(&hstate->cfg->request, &tx_ud->request_body, d->data, len); - uint8_t *chunks_buffer = NULL; + const uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; if (tx_ud->request_body_type == HTP_BODY_REQUEST_MULTIPART) { @@ -1823,9 +1788,6 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) HtpRequestBodyHandleMultipart(hstate, tx_ud, d->tx, chunks_buffer, chunks_buffer_len); - if (chunks_buffer != NULL) { - HTPFree(chunks_buffer, chunks_buffer_len); - } } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_POST) { HtpRequestBodyHandlePOST(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); } else if (tx_ud->request_body_type == HTP_BODY_REQUEST_PUT) { @@ -1835,9 +1797,6 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d) } end: - /* see if we can get rid of htp body chunks */ - HtpBodyPrune(&tx_ud->request_body); - /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; @@ -1881,37 +1840,38 @@ int HTPCallbackResponseBodyData(htp_tx_data_t *d) if (!tx_ud->request_body_init) { tx_ud->request_body_init = 1; tx_ud->operation = HTP_BODY_RESPONSE; - - htp_header_t *cl = htp_table_get_c(d->tx->response_headers, "content-length"); - if (cl != NULL) - tx_ud->response_body.content_len = SC_htp_parse_content_length(cl->value); - } + /* see if we can get rid of htp body chunks */ + HtpBodyPrune(hstate, &tx_ud->response_body, STREAM_TOCLIENT); + SCLogDebug("tx_ud->response_body.content_len_so_far %"PRIu64, tx_ud->response_body.content_len_so_far); - SCLogDebug("hstate->cfg->response_body_limit %u", hstate->cfg->response_body_limit); + SCLogDebug("hstate->cfg->response.body_limit %u", hstate->cfg->response.body_limit); /* within limits, add the body chunk to the state. */ - if (hstate->cfg->response_body_limit == 0 || tx_ud->response_body.content_len_so_far < hstate->cfg->response_body_limit) + if (hstate->cfg->response.body_limit == 0 || tx_ud->response_body.content_len_so_far < hstate->cfg->response.body_limit) { uint32_t len = (uint32_t)d->len; - if (hstate->cfg->response_body_limit > 0 && - (tx_ud->response_body.content_len_so_far + len) > hstate->cfg->response_body_limit) + if (hstate->cfg->response.body_limit > 0 && + (tx_ud->response_body.content_len_so_far + len) > hstate->cfg->response.body_limit) { - len = hstate->cfg->response_body_limit - tx_ud->response_body.content_len_so_far; + len = hstate->cfg->response.body_limit - tx_ud->response_body.content_len_so_far; BUG_ON(len > (uint32_t)d->len); } SCLogDebug("len %u", len); - HtpBodyAppendChunk(tx_ud, &tx_ud->response_body, (uint8_t *)d->data, len); + HtpBodyAppendChunk(&hstate->cfg->response, &tx_ud->response_body, d->data, len); HtpResponseBodyHandle(hstate, tx_ud, d->tx, (uint8_t *)d->data, (uint32_t)d->len); + } else { + if (tx_ud->tcflags & HTP_FILENAME_SET) { + SCLogDebug("closing file that was being stored"); + (void)HTPFileClose(hstate, NULL, 0, FILE_TRUNCATED, STREAM_TOCLIENT); + tx_ud->tcflags &= ~HTP_FILENAME_SET; + } } - /* see if we can get rid of htp body chunks */ - HtpBodyPrune(&tx_ud->response_body); - /* set the new chunk flag */ hstate->flags |= HTP_FLAG_NEW_BODY_SET; @@ -1958,6 +1918,24 @@ void HTPFreeConfig(void) SCReturn; } +static int HTPCallbackRequestHasTrailer(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + htud->request_has_trailers = 1; + } + return HTP_OK; +} + +static int HTPCallbackResponseHasTrailer(htp_tx_t *tx) +{ + HtpTxUserData *htud = (HtpTxUserData *)htp_tx_get_user_data(tx); + if (htud != NULL) { + htud->response_has_trailers = 1; + } + return HTP_OK; +} + /** * \brief callback for request to store the recent incoming request in to the recent_in_tx for the given htp state @@ -2040,7 +2018,7 @@ static int HTPCallbackRequestLine(htp_tx_t *tx) HtpTxUserData *tx_ud; bstr *request_uri_normalized; HtpState *hstate = htp_connp_get_user_data(tx->connp); - HTPCfgRec *cfg = hstate->cfg; + const HTPCfgRec *cfg = hstate->cfg; request_uri_normalized = SCHTPGenerateNormalizedUri(tx, tx->parsed_uri, cfg->uri_include_all); if (request_uri_normalized == NULL) @@ -2091,7 +2069,7 @@ static int HTPCallbackDoubleDecodePath(htp_tx_t *tx) static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) { void *ptmp; - if (tx_data->len == 0) + if (tx_data->len == 0 || tx_data->tx == NULL) return HTP_OK; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); @@ -2106,10 +2084,9 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) tx_ud->request_headers_raw_len, tx_ud->request_headers_raw_len + tx_data->len); if (ptmp == NULL) { - HTPFree(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len); - tx_ud->request_headers_raw = NULL; - tx_ud->request_headers_raw_len = 0; - HtpTxUserDataFree(tx_ud); + /* error: we're freeing the entire user data */ + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HtpTxUserDataFree(hstate, tx_ud); htp_tx_set_user_data(tx_data->tx, NULL); return HTP_OK; } @@ -2129,7 +2106,7 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) { void *ptmp; - if (tx_data->len == 0) + if (tx_data->len == 0 || tx_data->tx == NULL) return HTP_OK; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx_data->tx); @@ -2144,10 +2121,9 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) tx_ud->response_headers_raw_len, tx_ud->response_headers_raw_len + tx_data->len); if (ptmp == NULL) { - HTPFree(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len); - tx_ud->response_headers_raw = NULL; - tx_ud->response_headers_raw_len = 0; - HtpTxUserDataFree(tx_ud); + /* error: we're freeing the entire user data */ + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HtpTxUserDataFree(hstate, tx_ud); htp_tx_set_user_data(tx_data->tx, NULL); return HTP_OK; } @@ -2166,13 +2142,17 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) { cfg_prec->uri_include_all = FALSE; - cfg_prec->request_body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; - cfg_prec->response_body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; - cfg_prec->request_inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; - cfg_prec->request_inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; - cfg_prec->response_inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; - cfg_prec->response_inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; + cfg_prec->request.body_limit = HTP_CONFIG_DEFAULT_REQUEST_BODY_LIMIT; + cfg_prec->response.body_limit = HTP_CONFIG_DEFAULT_RESPONSE_BODY_LIMIT; + cfg_prec->request.inspect_min_size = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_MIN_SIZE; + cfg_prec->request.inspect_window = HTP_CONFIG_DEFAULT_REQUEST_INSPECT_WINDOW; + cfg_prec->response.inspect_min_size = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_MIN_SIZE; + cfg_prec->response.inspect_window = HTP_CONFIG_DEFAULT_RESPONSE_INSPECT_WINDOW; +#ifndef AFLFUZZ_NO_RANDOM cfg_prec->randomize = HTP_CONFIG_DEFAULT_RANDOMIZE; +#else + cfg_prec->randomize = 0; +#endif cfg_prec->randomize_range = HTP_CONFIG_DEFAULT_RANDOMIZE_RANGE; htp_config_register_request_header_data(cfg_prec->cfg, HTPCallbackRequestHeaderData); @@ -2180,6 +2160,9 @@ static void HTPConfigSetDefaultsPhase1(HTPCfgRec *cfg_prec) htp_config_register_response_header_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); htp_config_register_response_trailer_data(cfg_prec->cfg, HTPCallbackResponseHeaderData); + htp_config_register_request_trailer(cfg_prec->cfg, HTPCallbackRequestHasTrailer); + htp_config_register_response_trailer(cfg_prec->cfg, HTPCallbackResponseHasTrailer); + htp_config_register_request_body_data(cfg_prec->cfg, HTPCallbackRequestBodyData); htp_config_register_response_body_data(cfg_prec->cfg, HTPCallbackResponseBodyData); @@ -2216,37 +2199,54 @@ static void HTPConfigSetDefaultsPhase2(char *name, HTPCfgRec *cfg_prec) if (cfg_prec->randomize) { int rdrange = cfg_prec->randomize_range; - cfg_prec->request_inspect_min_size += - (int) (cfg_prec->request_inspect_min_size * + cfg_prec->request.inspect_min_size += + (int) (cfg_prec->request.inspect_min_size * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - cfg_prec->request_inspect_window += - (int) (cfg_prec->request_inspect_window * + cfg_prec->request.inspect_window += + (int) (cfg_prec->request.inspect_window * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - SCLogInfo("'%s' server has 'request-body-minimal-inspect-size' set to" + SCLogConfig("'%s' server has 'request-body-minimal-inspect-size' set to" " %d and 'request-body-inspect-window' set to %d after" " randomization.", name, - cfg_prec->request_inspect_min_size, - cfg_prec->request_inspect_window); + cfg_prec->request.inspect_min_size, + cfg_prec->request.inspect_window); - cfg_prec->response_inspect_min_size += - (int) (cfg_prec->response_inspect_min_size * + cfg_prec->response.inspect_min_size += + (int) (cfg_prec->response.inspect_min_size * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - cfg_prec->response_inspect_window += - (int) (cfg_prec->response_inspect_window * + cfg_prec->response.inspect_window += + (int) (cfg_prec->response.inspect_window * (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100); - SCLogInfo("'%s' server has 'response-body-minimal-inspect-size' set to" + SCLogConfig("'%s' server has 'response-body-minimal-inspect-size' set to" " %d and 'response-body-inspect-window' set to %d after" " randomization.", name, - cfg_prec->response_inspect_min_size, - cfg_prec->response_inspect_window); + cfg_prec->response.inspect_min_size, + cfg_prec->response.inspect_window); } htp_config_register_request_line(cfg_prec->cfg, HTPCallbackRequestLine); + cfg_prec->request.sbcfg.flags = 0; + cfg_prec->request.sbcfg.buf_size = cfg_prec->request.inspect_window ? + cfg_prec->request.inspect_window : 256; + cfg_prec->request.sbcfg.buf_slide = 0; + cfg_prec->request.sbcfg.Malloc = HTPMalloc; + cfg_prec->request.sbcfg.Calloc = HTPCalloc; + cfg_prec->request.sbcfg.Realloc = HTPRealloc; + cfg_prec->request.sbcfg.Free = HTPFree; + + cfg_prec->response.sbcfg.flags = 0; + cfg_prec->response.sbcfg.buf_size = cfg_prec->response.inspect_window ? + cfg_prec->response.inspect_window : 256; + cfg_prec->response.sbcfg.buf_slide = 0; + cfg_prec->response.sbcfg.Malloc = HTPMalloc; + cfg_prec->response.sbcfg.Calloc = HTPCalloc; + cfg_prec->response.sbcfg.Realloc = HTPRealloc; + cfg_prec->response.sbcfg.Free = HTPFree; return; } @@ -2316,28 +2316,28 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, } else if (strcasecmp("request-body-limit", p->name) == 0 || strcasecmp("request_body_limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request_body_limit) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.body_limit) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-limit " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-limit", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response_body_limit) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.body_limit) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-limit " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("request-body-minimal-inspect-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_min_size) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_min_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-minimal-inspect-size " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("request-body-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->request_inspect_window) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->request.inspect_window) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing request-body-inspect-window " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); @@ -2356,19 +2356,32 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, } } else if (strcasecmp("response-body-minimal-inspect-size", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_min_size) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_min_size) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-minimal-inspect-size " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } } else if (strcasecmp("response-body-inspect-window", p->name) == 0) { - if (ParseSizeStringU32(p->val, &cfg_prec->response_inspect_window) < 0) { + if (ParseSizeStringU32(p->val, &cfg_prec->response.inspect_window) < 0) { SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window " "from conf file - %s. Killing engine", p->val); exit(EXIT_FAILURE); } + } else if (strcasecmp("response-body-decompress-layer-limit", p->name) == 0) { + uint32_t value = 2; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing response-body-inspect-window " + "from conf file - %s. Killing engine", p->val); + exit(EXIT_FAILURE); + } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + htp_config_set_response_decompression_layer_limit(cfg_prec->cfg, value); +#else + SCLogWarning(SC_WARN_OUTDATED_LIBHTP, "can't set response-body-decompress-layer-limit " + "to %u, libhtp version too old", value); +#endif } else if (strcasecmp("path-convert-backslash-separators", p->name) == 0) { htp_config_set_backslash_convert_slashes(cfg_prec->cfg, HTP_DECODER_URL_PATH, @@ -2451,7 +2464,9 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, (size_t)HTP_CONFIG_DEFAULT_FIELD_LIMIT_SOFT, (size_t)limit); } else if (strcasecmp("randomize-inspection-sizes", p->name) == 0) { +#ifndef AFLFUZZ_NO_RANDOM cfg_prec->randomize = ConfValIsTrue(p->val); +#endif } else if (strcasecmp("randomize-inspection-range", p->name) == 0) { uint32_t range = atoi(p->val); if (range > 100) { @@ -2463,6 +2478,21 @@ static void HTPConfigParseParameters(HTPCfgRec *cfg_prec, ConfNode *s, exit(EXIT_FAILURE); } cfg_prec->randomize_range = range; + } else if (strcasecmp("http-body-inline", p->name) == 0) { + if (ConfValIsTrue(p->val)) { + cfg_prec->http_body_inline = 1; + } else if (ConfValIsFalse(p->val)) { + cfg_prec->http_body_inline = 0; + } else { + if (strcmp("auto", p->val) != 0) { + WarnInvalidConfEntry("http_body_inline", "%s", "auto"); + } + if (EngineModeIsIPS()) { + cfg_prec->http_body_inline = 1; + } else { + cfg_prec->http_body_inline = 0; + } + } } else { SCLogWarning(SC_ERR_UNKNOWN_VALUE, "LIBHTP Ignoring unknown " "default config: %s", p->name); @@ -2550,7 +2580,7 @@ void AppLayerHtpPrintStats(void) { #ifdef DEBUG SCMutexLock(&htp_state_mem_lock); - SCLogInfo("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); + SCLogPerf("htp memory %"PRIu64" (%"PRIu64")", htp_state_memuse, htp_state_memcnt); SCMutexUnlock(&htp_state_mem_lock); #endif } @@ -2603,6 +2633,24 @@ static void *HTPStateGetTx(void *alstate, uint64_t tx_id) return NULL; } +static void HTPStateSetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); + if (tx_ud) + tx_ud->logged |= logger; +} + +static int HTPStateGetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = (HtpTxUserData *) htp_tx_get_user_data(tx); + if (tx_ud && (tx_ud->logged & logger)) + return 1; + + return 0; +} + static int HTPStateGetAlstateProgressCompletionStatus(uint8_t direction) { return (direction & STREAM_TOSERVER) ? HTP_REQUEST_COMPLETE : HTP_RESPONSE_COMPLETE; @@ -2632,97 +2680,81 @@ static void HTPStateTruncate(void *state, uint8_t direction) } } -static int HTPRegisterPatternsForProtocolDetection(void) +static int HTPStateHasTxDetectState(void *alstate) { - /* toserver */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "GET|20|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "GET|09|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PUT|20|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "PUT|09|", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "POST|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "POST|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HEAD|20|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HEAD|09|", 5, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "TRACE|20|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "TRACE|09|", 6, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "OPTIONS|20|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "OPTIONS|09|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "CONNECT|20|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "CONNECT|09|", 8, 0, STREAM_TOSERVER) < 0) - { - return -1; - } + HtpState *htp_state = (HtpState *)alstate; + return (htp_state->tx_with_detect_state_cnt > 0); +} - /* toclient */ - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HTTP/0.9", 8, 0, STREAM_TOCLIENT) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HTTP/1.0", 8, 0, STREAM_TOCLIENT) < 0) - { - return -1; +static DetectEngineState *HTPGetTxDetectState(void *vtx) +{ + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + return tx_ud ? tx_ud->de_state : NULL; +} + +static int HTPSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s) +{ + HtpState *htp_state = (HtpState *)alstate; + htp_tx_t *tx = (htp_tx_t *)vtx; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud == NULL) { + tx_ud = HTPMalloc(sizeof(*tx_ud)); + if (unlikely(tx_ud == NULL)) + return -ENOMEM; + memset(tx_ud, 0, sizeof(*tx_ud)); + htp_tx_set_user_data(tx, tx_ud); } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, - "HTTP/1.1", 8, 0, STREAM_TOCLIENT) < 0) - { - return -1; + htp_state->tx_with_detect_state_cnt++; + tx_ud->de_state = s; + return 0; +} + +static int HTPRegisterPatternsForProtocolDetection(void) +{ + char *methods[] = { "GET", "PUT", "POST", "HEAD", "TRACE", "OPTIONS", + "CONNECT", "DELETE", "PATCH", "PROPFIND", "PROPPATCH", "MKCOL", + "COPY", "MOVE", "LOCK", "UNLOCK", "CHECKOUT", "UNCHECKOUT", "CHECKIN", + "UPDATE", "LABEL", "REPORT", "MKWORKSPACE", "MKACTIVITY", "MERGE", + "INVALID", "VERSION-CONTROL", "BASELINE-CONTROL", NULL}; + char *spacings[] = { "|20|", "|09|", NULL }; + char *versions[] = { "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", NULL }; + + uint methods_pos; + uint spacings_pos; + uint versions_pos; + int register_result; + char method_buffer[32] = ""; + + /* Loop through all the methods ands spacings and register the patterns */ + for (methods_pos = 0; methods[methods_pos]; methods_pos++) { + for (spacings_pos = 0; spacings[spacings_pos]; spacings_pos++) { + + /* Combine the method name and the spacing */ + snprintf(method_buffer, sizeof(method_buffer), "%s%s", methods[methods_pos], spacings[spacings_pos]); + + /* Register the new method+spacing pattern + * 3 is subtracted from the length since the spacing is hex typed as |xx| + * but the pattern matching should only be one char + */ + register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, + ALPROTO_HTTP, method_buffer, strlen(method_buffer)-3, 0, STREAM_TOSERVER); + if (register_result < 0) { + return -1; + } + } } + /* Loop through all the http verions patterns that are TO_CLIENT */ + for (versions_pos = 0; versions[versions_pos]; versions_pos++) { + register_result = AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, + ALPROTO_HTTP, versions[versions_pos], strlen(versions[versions_pos]), + 0, STREAM_TOCLIENT); + if (register_result < 0) { + return -1; + } + } + return 0; } @@ -2754,13 +2786,18 @@ void RegisterHTPParsers(void) AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetAlstateProgress); AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxCnt); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTx); - AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP, + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetTxLogged, + HTPStateSetTxLogged); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_HTTP, HTPStateGetAlstateProgressCompletionStatus); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPHasEvents); AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPGetEvents); AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_HTTP, HTPStateGetEventInfo); AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_HTTP, + HTPStateHasTxDetectState, + HTPGetTxDetectState, HTPSetTxDetectState); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER, HTPHandleRequestData); @@ -2801,7 +2838,7 @@ void HtpConfigRestoreBackup(void) * response of the parser from HTP library. */ int HTPParserTest01(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" " Data is c0oL!"; @@ -2832,22 +2869,21 @@ int HTPParserTest01(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -2862,10 +2898,10 @@ int HTPParserTest01(void) " and got: %s \n", bstr_util_strdup_to_c(h->value), bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -2876,15 +2912,18 @@ int HTPParserTest01(void) return result; } -/** \test See how it deals with an incomplete request. */ -int HTPParserTest02(void) +/** \test Test case where chunks are sent in smaller chunks and check the + * response of the parser from HTP library. */ +static int HTPParserTest01a(void) { - int result = 1; + int result = 0; Flow *f = NULL; - uint8_t httpbuf1[] = "POST"; + uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost" + " Data is c0oL!"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; - HtpState *http_state = NULL; + HtpState *htp_state = NULL; + int r = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&ssn, 0, sizeof(ssn)); @@ -2897,33 +2936,106 @@ int HTPParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); - goto end; + uint32_t u; + for (u = 0; u < httplen1; u++) { + uint8_t flags = 0; + + if (u == 0) + flags = STREAM_TOSERVER|STREAM_START; + else if (u == (httplen1 - 1)) + flags = STREAM_TOSERVER|STREAM_EOF; + else + flags = STREAM_TOSERVER; + + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); + if (r != 0) { + printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" + " 0: ", u, r); + FLOWLOCK_UNLOCK(f); + goto end; + } + FLOWLOCK_UNLOCK(f); } - SCMutexUnlock(&f->m); - http_state = f->alstate; - if (http_state == NULL) { + htp_state = f->alstate; + if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } - htp_tx_t *tx = HTPStateGetTx(http_state, 0); + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); - if ((tx->request_method) != NULL || h != NULL) - { - printf("expected method NULL, got %s \n", bstr_util_strdup_to_c(tx->request_method)); - result = 0; + if (strcmp(bstr_util_strdup_to_c(h->value), "Victor/1.0") + || tx->request_method_number != HTP_M_POST || + tx->request_protocol_number != HTP_PROTOCOL_1_0) + { + printf("expected header value: Victor/1.0 and got %s: and expected" + " method: POST and got %s, expected protocol number HTTP/1.0" + " and got: %s \n", bstr_util_strdup_to_c(h->value), + bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); goto end; } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (htp_state != NULL) + HTPStateFree(htp_state); + UTHFreeFlow(f); + return result; +} +/** \test See how it deals with an incomplete request. */ +int HTPParserTest02(void) +{ + int result = 0; + Flow *f = NULL; + uint8_t httpbuf1[] = "POST"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + TcpSession ssn; + HtpState *http_state = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + FLOWLOCK_UNLOCK(f); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if ((tx->request_method) != NULL || h != NULL) + { + printf("expected method NULL, got %s \n", bstr_util_strdup_to_c(tx->request_method)); + goto end; + } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -2938,12 +3050,11 @@ int HTPParserTest02(void) * and check the response of the parser from HTP library. */ int HTPParserTest03(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n"; uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ TcpSession ssn; - HtpState *htp_state = NULL; int r = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2966,21 +3077,20 @@ int HTPParserTest03(void) else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -2993,10 +3103,9 @@ int HTPParserTest03(void) printf("expected method M_UNKNOWN and got %s: , expected protocol " "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } - + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3011,7 +3120,7 @@ int HTPParserTest03(void) * parser from HTP library. */ int HTPParserTest04(void) { - int result = 1; + int result = 0; Flow *f = NULL; HtpState *htp_state = NULL; uint8_t httpbuf1[] = "World!\r\n"; @@ -3030,19 +3139,20 @@ int HTPParserTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3054,10 +3164,9 @@ int HTPParserTest04(void) printf("expected method M_UNKNOWN and got %s: , expected protocol " "NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } - + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3072,7 +3181,7 @@ int HTPParserTest04(void) * properly parsed them and also keeps them separated. */ int HTPParserTest05(void) { - int result = 1; + int result = 0; Flow *f = NULL; HtpState *http_state = NULL; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; @@ -3101,64 +3210,61 @@ int HTPParserTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf4, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, + httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf3, - httplen3); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf6, - httplen6); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3170,7 +3276,6 @@ int HTPParserTest05(void) printf("expected method M_POST and got %s: , expected protocol " "HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } @@ -3179,9 +3284,9 @@ int HTPParserTest05(void) "HTTP/1.0 and got %s \n", tx->response_status_number, bstr_util_strdup_to_c(tx->response_message), bstr_util_strdup_to_c(tx->response_protocol)); - result = 0; goto end; } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3196,7 +3301,7 @@ int HTPParserTest05(void) */ int HTPParserTest06(void) { - int result = 1; + int result = 0; Flow *f = NULL; uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&" "name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: " @@ -3254,30 +3359,29 @@ int HTPParserTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, - httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2, + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3289,7 +3393,6 @@ int HTPParserTest06(void) printf("expected method M_GET and got %s: , expected protocol " "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), bstr_util_strdup_to_c(tx->request_protocol)); - result = 0; goto end; } @@ -3300,9 +3403,9 @@ int HTPParserTest06(void) "col HTTP/1.1 and got %s \n", tx->response_status_number, bstr_util_strdup_to_c(tx->response_message), bstr_util_strdup_to_c(tx->response_protocol)); - result = 0; goto end; } + result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); @@ -3347,15 +3450,16 @@ int HTPParserTest07(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3446,16 +3550,17 @@ libhtp:\n\ uint8_t flags = 0; flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { @@ -3533,21 +3638,20 @@ libhtp:\n\ uint8_t flags = 0; flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk returned %" PRId32 ", expected" " 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -3611,15 +3715,16 @@ int HTPParserTest10(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3703,15 +3808,16 @@ static int HTPParserTest11(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3788,15 +3894,16 @@ static int HTPParserTest12(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -3876,15 +3983,16 @@ int HTPParserTest13(void) else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -4287,16 +4395,17 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; @@ -4470,22 +4579,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -4641,22 +4749,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -4810,22 +4917,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -4949,22 +5055,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5061,22 +5166,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5173,22 +5277,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5286,22 +5389,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5396,22 +5498,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5507,22 +5608,21 @@ libhtp:\n\ else if (u == (httplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, &httpbuf1[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + &httpbuf1[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { printf("no http state: "); - result = 0; goto end; } @@ -5590,12 +5690,12 @@ static int HTPBodyReassemblyTest01(void) uint8_t chunk1[] = "--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; uint8_t chunk2[] = "POST /uri HTTP/1.1\r\nHost: hostname.com\r\nKeep-Alive: 115\r\nAccept-Charset: utf-8\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nConnection: keep-alive\r\nContent-length: 68102\r\nReferer: http://otherhost.com\r\nAccept-Encoding: gzip\r\nContent-Type: multipart/form-data; boundary=e5a320f21416a02493a0a6f561b1c494\r\nCookie: blah\r\nAccept-Language: us\r\n\r\n--e5a320f21416a02493a0a6f561b1c494\r\nContent-Disposition: form-data; name=\"uploadfile\"; filename=\"D2GUef.jpg\"\r"; - int r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk1, sizeof(chunk1)-1); + int r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk1, sizeof(chunk1)-1); BUG_ON(r != 0); - r = HtpBodyAppendChunk(&htud, &htud.request_body, (uint8_t *)chunk2, sizeof(chunk2)-1); + r = HtpBodyAppendChunk(NULL, &htud.request_body, chunk2, sizeof(chunk2)-1); BUG_ON(r != 0); - uint8_t *chunks_buffer = NULL; + const uint8_t *chunks_buffer = NULL; uint32_t chunks_buffer_len = 0; HtpRequestBodyReassemble(&htud, &chunks_buffer, &chunks_buffer_len); @@ -5664,41 +5764,41 @@ libhtp:\n\ StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SCLogDebug("\n>>>> processing chunk 1 again <<<<\n"); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); http_state = f->alstate; if (http_state == NULL) { printf("no http state: "); - result = 0; goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetDecoderEvents(f->alparser); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); result = 1; end: if (alp_tctx != NULL) @@ -5785,30 +5885,29 @@ libhtp:\n\ else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + (uint8_t *)&httpbuf[u], 1); if (u < 18294) { /* first 18294 bytes should result in 0 */ if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } } else if (u == 18294UL) { /* byte 18294 should result in error */ if (r != -1) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " -1: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } /* break out, htp state is in error state now */ - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); break; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { @@ -5825,14 +5924,14 @@ libhtp:\n\ goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events == NULL) { printf("no app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); if (decoder_events->events[0] != HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG) { printf("HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG not set: "); @@ -5929,16 +6028,16 @@ libhtp:\n\ else if (u == (len - 1)) flags = STREAM_TOSERVER|STREAM_EOF; else flags = STREAM_TOSERVER; - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)&httpbuf[u], 1); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + (uint8_t *)&httpbuf[u], 1); if (r != 0) { printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected" " 0: ", u, r); - result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); } htp_state = f->alstate; if (htp_state == NULL) { @@ -5955,14 +6054,14 @@ libhtp:\n\ goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); if (decoder_events != NULL) { printf("app events: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); result = 1; end: @@ -5980,6 +6079,448 @@ libhtp:\n\ HtpConfigRestoreBackup(); return result; } + +/** \test Test unusual delims in request line HTTP_DECODER_EVENT_REQUEST_FIELD_TOO_LONG */ +int HTPParserTest16(void) +{ + int result = 0; + Flow *f = NULL; + TcpSession ssn; + HtpState *htp_state = NULL; + int r = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + uint8_t httpbuf[] = "GET\f/blah/\fHTTP/1.1\r\n" + "Host: myhost.lan\r\n" + "Connection: keep-alive\r\n" + "Accept: */*\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36\r\n" + "Referer: http://blah.lan/\r\n" + "Accept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\n" + "Cookie: blah\r\n\r\n"; + size_t len = sizeof(httpbuf) - 1; + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + uint8_t flags = STREAM_TOSERVER|STREAM_START|STREAM_EOF; + + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, flags, + (uint8_t *)httpbuf, len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + FLOWLOCK_UNLOCK(f); + + htp_state = f->alstate; + if (htp_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(htp_state, 0); + if (tx == NULL || tx->request_method_number != HTP_M_GET || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx ? bstr_util_strdup_to_c(tx->request_method) : "tx null", + tx ? bstr_util_strdup_to_c(tx->request_protocol) : "tx null"); + goto end; + } + + FLOWLOCK_WRLOCK(f); + AppLayerDecoderEvents *decoder_events = AppLayerParserGetEventsByTx(IPPROTO_TCP, ALPROTO_HTTP,f->alstate, 0); + if (decoder_events == NULL) { + printf("no app events: "); + FLOWLOCK_UNLOCK(f); + goto end; + } + FLOWLOCK_UNLOCK(f); + + if (decoder_events->events[0] != HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT) { + printf("HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT not set: "); + goto end; + } + + if (decoder_events->events[1] != HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT) { + printf("HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT not set: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (htp_state != NULL) + HTPStateFree(htp_state); + UTHFreeFlow(f); + return result; +} + +/** \test CONNECT with plain text HTTP being tunneled */ +int HTPParserTest17(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *http_state = NULL; + /* CONNECT setup */ + uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + /* plain text HTTP */ + uint8_t httpbuf3[] = "GET / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint8_t httpbuf4[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, + httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, + httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + FLOWLOCK_UNLOCK(f); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + if (tx == NULL) + goto end; + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_CONNECT || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_POST and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + + tx = HTPStateGetTx(http_state, 1); + if (tx == NULL) + goto end; + h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_GET || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + +/** \test CONNECT with plain text HTTP being tunneled */ +int HTPParserTest18(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *http_state = NULL; + /* CONNECT setup */ + uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + /* plain text HTTP */ + uint8_t httpbuf3[] = "GE"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + uint8_t httpbuf4[] = "T / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ + uint8_t httpbuf5[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, + httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf4, httplen4); + if (r != 0) { + printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, + httpbuf5, httplen5); + if (r != 0) { + printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + FLOWLOCK_UNLOCK(f); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + if (tx == NULL) + goto end; + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_CONNECT || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_POST and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + + tx = HTPStateGetTx(http_state, 1); + if (tx == NULL) + goto end; + h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_GET || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_GET and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + +/** \test CONNECT with TLS content (start of it at least) */ +int HTPParserTest19(void) +{ + int result = 0; + Flow *f = NULL; + HtpState *http_state = NULL; + /* CONNECT setup */ + uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n"; + uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ + uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; + uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ + /* start of TLS/SSL */ + uint8_t httpbuf3[] = "\x16\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); + if (f == NULL) + goto end; + f->protoctx = &ssn; + f->proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, httpbuf2, + httplen2); + if (r != 0) { + printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, + httpbuf3, httplen3); + if (r != 0) { + printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(f); + goto end; + } + + FLOWLOCK_UNLOCK(f); + + http_state = f->alstate; + if (http_state == NULL) { + printf("no http state: "); + goto end; + } + + htp_tx_t *tx = HTPStateGetTx(http_state, 0); + if (tx == NULL) + goto end; + htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL); + if (tx->request_method_number != HTP_M_CONNECT || + h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1) + { + printf("expected method M_POST and got %s: , expected protocol " + "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method), + bstr_util_strdup_to_c(tx->request_protocol)); + goto end; + } + + if (tx->response_status_number != 200) { + printf("expected response 200 OK and got %"PRId32" %s: , expected protocol " + "HTTP/1.1 and got %s \n", tx->response_status_number, + bstr_util_strdup_to_c(tx->response_message), + bstr_util_strdup_to_c(tx->response_protocol)); + goto end; + } + + /* no new tx should have been set up for the tunneled data */ + tx = HTPStateGetTx(http_state, 1); + if (tx != NULL) + goto end; + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + if (http_state != NULL) + HTPStateFree(http_state); + UTHFreeFlow(f); + return result; +} + #endif /* UNITTESTS */ /** @@ -5988,44 +6529,50 @@ libhtp:\n\ void HTPParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HTPParserTest01", HTPParserTest01, 1); - UtRegisterTest("HTPParserTest02", HTPParserTest02, 1); - UtRegisterTest("HTPParserTest03", HTPParserTest03, 1); - UtRegisterTest("HTPParserTest04", HTPParserTest04, 1); - UtRegisterTest("HTPParserTest05", HTPParserTest05, 1); - UtRegisterTest("HTPParserTest06", HTPParserTest06, 1); - UtRegisterTest("HTPParserTest07", HTPParserTest07, 1); - UtRegisterTest("HTPParserTest08", HTPParserTest08, 1); - UtRegisterTest("HTPParserTest09", HTPParserTest09, 1); - UtRegisterTest("HTPParserTest10", HTPParserTest10, 1); - UtRegisterTest("HTPParserTest11", HTPParserTest11, 1); - UtRegisterTest("HTPParserTest12", HTPParserTest12, 1); - UtRegisterTest("HTPParserTest13", HTPParserTest13, 1); - UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01, 1); - UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02, 1); - UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03, 1); + UtRegisterTest("HTPParserTest01", HTPParserTest01); + UtRegisterTest("HTPParserTest01a", HTPParserTest01a); + UtRegisterTest("HTPParserTest02", HTPParserTest02); + UtRegisterTest("HTPParserTest03", HTPParserTest03); + UtRegisterTest("HTPParserTest04", HTPParserTest04); + UtRegisterTest("HTPParserTest05", HTPParserTest05); + UtRegisterTest("HTPParserTest06", HTPParserTest06); + UtRegisterTest("HTPParserTest07", HTPParserTest07); + UtRegisterTest("HTPParserTest08", HTPParserTest08); + UtRegisterTest("HTPParserTest09", HTPParserTest09); + UtRegisterTest("HTPParserTest10", HTPParserTest10); + UtRegisterTest("HTPParserTest11", HTPParserTest11); + UtRegisterTest("HTPParserTest12", HTPParserTest12); + UtRegisterTest("HTPParserTest13", HTPParserTest13); + UtRegisterTest("HTPParserConfigTest01", HTPParserConfigTest01); + UtRegisterTest("HTPParserConfigTest02", HTPParserConfigTest02); + UtRegisterTest("HTPParserConfigTest03", HTPParserConfigTest03); #if 0 /* disabled when we upgraded to libhtp 0.5.x */ UtRegisterTest("HTPParserConfigTest04", HTPParserConfigTest04, 1); #endif - UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01, 1); - UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02, 1); - UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03, 1); - UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04, 1); - UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05, 1); - UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06, 1); - UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07, 1); - UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08, 1); - UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09, 1); + UtRegisterTest("HTPParserDecodingTest01", HTPParserDecodingTest01); + UtRegisterTest("HTPParserDecodingTest02", HTPParserDecodingTest02); + UtRegisterTest("HTPParserDecodingTest03", HTPParserDecodingTest03); + UtRegisterTest("HTPParserDecodingTest04", HTPParserDecodingTest04); + UtRegisterTest("HTPParserDecodingTest05", HTPParserDecodingTest05); + UtRegisterTest("HTPParserDecodingTest06", HTPParserDecodingTest06); + UtRegisterTest("HTPParserDecodingTest07", HTPParserDecodingTest07); + UtRegisterTest("HTPParserDecodingTest08", HTPParserDecodingTest08); + UtRegisterTest("HTPParserDecodingTest09", HTPParserDecodingTest09); - UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01, 1); + UtRegisterTest("HTPBodyReassemblyTest01", HTPBodyReassemblyTest01); - UtRegisterTest("HTPSegvTest01", HTPSegvTest01, 1); + UtRegisterTest("HTPSegvTest01", HTPSegvTest01); - UtRegisterTest("HTPParserTest14", HTPParserTest14, 1); - UtRegisterTest("HTPParserTest15", HTPParserTest15, 1); + UtRegisterTest("HTPParserTest14", HTPParserTest14); + UtRegisterTest("HTPParserTest15", HTPParserTest15); + UtRegisterTest("HTPParserTest16", HTPParserTest16); + UtRegisterTest("HTPParserTest17", HTPParserTest17); + UtRegisterTest("HTPParserTest18", HTPParserTest18); + UtRegisterTest("HTPParserTest19", HTPParserTest19); HTPFileParserRegisterTests(); + HTPXFFParserRegisterTests(); #endif /* UNITTESTS */ } diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index d331dd0e9d84..0e3503c3e8ee 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -36,6 +36,8 @@ #include "util-radix-tree.h" #include "util-file.h" #include "app-layer-htp-mem.h" +#include "detect-engine-state.h" +#include "util-streaming-buffer.h" #include @@ -121,6 +123,9 @@ enum { HTTP_DECODER_EVENT_REQUEST_SERVER_PORT_TCP_PORT_MISMATCH, HTTP_DECODER_EVENT_URI_HOST_INVALID, HTTP_DECODER_EVENT_HEADER_HOST_INVALID, + HTTP_DECODER_EVENT_METHOD_DELIM_NON_COMPLIANT, + HTTP_DECODER_EVENT_URI_DELIM_NON_COMPLIANT, + HTTP_DECODER_EVENT_REQUEST_LINE_LEADING_WHITESPACE, /* suricata errors/warnings */ HTTP_DECODER_EVENT_MULTIPART_GENERIC_ERROR, @@ -128,12 +133,12 @@ enum { HTTP_DECODER_EVENT_MULTIPART_INVALID_HEADER, }; -#define HTP_PCRE_NONE 0x00 /**< No pcre executed yet */ -#define HTP_PCRE_DONE 0x01 /**< Flag to indicate that pcre has - done some inspection in the - chunks */ -#define HTP_PCRE_HAS_MATCH 0x02 /**< Flag to indicate that the chunks - matched on some rule */ +typedef struct HTPCfgDir_ { + uint32_t body_limit; + uint32_t inspect_min_size; + uint32_t inspect_window; + StreamingBufferConfig sbcfg; +} HTPCfgDir; /** Need a linked list in order to keep track of these */ typedef struct HTPCfgRec_ { @@ -143,24 +148,18 @@ typedef struct HTPCfgRec_ { int uri_include_all; /**< use all info in uri (bool) */ /** max size of the client body we inspect */ - uint32_t request_body_limit; - uint32_t response_body_limit; - - uint32_t request_inspect_min_size; - uint32_t request_inspect_window; - - uint32_t response_inspect_min_size; - uint32_t response_inspect_window; int randomize; int randomize_range; + int http_body_inline; + + HTPCfgDir request; + HTPCfgDir response; } HTPCfgRec; /** Struct used to hold chunks of a body on a request */ struct HtpBodyChunk_ { - uint8_t *data; /**< Pointer to the data of the chunk */ struct HtpBodyChunk_ *next; /**< Pointer to the next chunk */ - uint64_t stream_offset; - uint32_t len; /**< Length of the chunk */ + StreamingBufferSegment sbseg; int logged; } __attribute__((__packed__)); typedef struct HtpBodyChunk_ HtpBodyChunk; @@ -170,8 +169,8 @@ typedef struct HtpBody_ { HtpBodyChunk *first; /**< Pointer to the first chunk */ HtpBodyChunk *last; /**< Pointer to the last chunk */ - /* Holds the length of the htp request body */ - uint64_t content_len; + StreamingBuffer *sb; + /* Holds the length of the htp request body seen so far */ uint64_t content_len_so_far; /* parser tracker */ @@ -186,22 +185,19 @@ typedef struct HtpBody_ { #define HTP_FILENAME_SET 0x08 /**< filename is registered in the flow */ #define HTP_DONTSTORE 0x10 /**< not storing this file */ -#define HTP_TX_HAS_FILE 0x01 -#define HTP_TX_HAS_FILENAME 0x02 /**< filename is known at this time */ -#define HTP_TX_HAS_TYPE 0x04 -#define HTP_TX_HAS_FILECONTENT 0x08 /**< file has content so we can do type detect */ - -#define HTP_RULE_NEED_FILE HTP_TX_HAS_FILE -#define HTP_RULE_NEED_FILENAME HTP_TX_HAS_FILENAME -#define HTP_RULE_NEED_TYPE HTP_TX_HAS_TYPE -#define HTP_RULE_NEED_FILECONTENT HTP_TX_HAS_FILECONTENT - /** Now the Body Chunks will be stored per transaction, at * the tx user data */ typedef struct HtpTxUserData_ { /* Body of the request (if any) */ uint8_t request_body_init; uint8_t response_body_init; + + uint8_t request_has_trailers; + uint8_t response_has_trailers; + + /* indicates which loggers that have logged */ + uint32_t logged; + HtpBody request_body; HtpBody response_body; @@ -228,6 +224,7 @@ typedef struct HtpTxUserData_ { uint8_t request_body_type; uint8_t response_body_type; + DetectEngineState *de_state; } HtpTxUserData; typedef struct HtpState_ { @@ -241,10 +238,11 @@ typedef struct HtpState_ { uint64_t store_tx_id; FileContainer *files_ts; FileContainer *files_tc; - struct HTPCfgRec_ *cfg; + const struct HTPCfgRec_ *cfg; uint16_t flags; uint16_t events; uint16_t htp_messages_offset; /**< offset into conn->messages list */ + uint64_t tx_with_detect_state_cnt; } HtpState; /** part of the engine needs the request body (e.g. http_client_body keyword) */ diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c new file mode 100644 index 000000000000..97fd4be0d754 --- /dev/null +++ b/src/app-layer-modbus.c @@ -0,0 +1,3286 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + * + * App-layer parser for Modbus protocol + * + */ + +#include "suricata-common.h" + +#include "util-debug.h" +#include "util-byte.h" +#include "util-enum.h" +#include "util-mem.h" +#include "util-misc.h" + +#include "stream.h" +#include "stream-tcp.h" + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "app-layer-modbus.h" + +#include "app-layer-detect-proto.h" + +#include "conf.h" +#include "conf-yaml-loader.h" +#include "decode.h" + +SCEnumCharMap modbus_decoder_event_table[ ] = { + /* Modbus Application Data Unit messages - ADU Modbus */ + { "INVALID_PROTOCOL_ID", MODBUS_DECODER_EVENT_INVALID_PROTOCOL_ID }, + { "UNSOLICITED_RESPONSE", MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE }, + { "INVALID_LENGTH", MODBUS_DECODER_EVENT_INVALID_LENGTH }, + { "INVALID_UNIT_IDENTIFIER", MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER}, + + /* Modbus Protocol Data Unit messages - PDU Modbus */ + { "INVALID_FUNCTION_CODE", MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE }, + { "INVALID_VALUE", MODBUS_DECODER_EVENT_INVALID_VALUE }, + { "INVALID_EXCEPTION_CODE", MODBUS_DECODER_EVENT_INVALID_EXCEPTION_CODE }, + { "VALUE_MISMATCH", MODBUS_DECODER_EVENT_VALUE_MISMATCH }, + + /* Modbus Decoder event */ + { "FLOODED", MODBUS_DECODER_EVENT_FLOODED}, + { NULL, -1 }, +}; + +/* Modbus Application Data Unit (ADU) length range. */ +#define MODBUS_MIN_ADU_LEN 2 +#define MODBUS_MAX_ADU_LEN 254 + +/* Modbus Protocol version. */ +#define MODBUS_PROTOCOL_VER 0 + +/* Modbus Unit Identifier range. */ +#define MODBUS_MIN_INVALID_UNIT_ID 247 +#define MODBUS_MAX_INVALID_UNIT_ID 255 + +/* Modbus Quantity range. */ +#define MODBUS_MIN_QUANTITY 0 +#define MODBUS_MAX_QUANTITY_IN_BIT_ACCESS 2000 +#define MODBUS_MAX_QUANTITY_IN_WORD_ACCESS 125 + +/* Modbus Count range. */ +#define MODBUS_MIN_COUNT 1 +#define MODBUS_MAX_COUNT 250 + +/* Modbus Function Code. */ +#define MODBUS_FUNC_NONE 0x00 +#define MODBUS_FUNC_READCOILS 0x01 +#define MODBUS_FUNC_READDISCINPUTS 0x02 +#define MODBUS_FUNC_READHOLDREGS 0x03 +#define MODBUS_FUNC_READINPUTREGS 0x04 +#define MODBUS_FUNC_WRITESINGLECOIL 0x05 +#define MODBUS_FUNC_WRITESINGLEREG 0x06 +#define MODBUS_FUNC_READEXCSTATUS 0x07 +#define MODBUS_FUNC_DIAGNOSTIC 0x08 +#define MODBUS_FUNC_GETCOMEVTCOUNTER 0x0b +#define MODBUS_FUNC_GETCOMEVTLOG 0x0c +#define MODBUS_FUNC_WRITEMULTCOILS 0x0f +#define MODBUS_FUNC_WRITEMULTREGS 0x10 +#define MODBUS_FUNC_REPORTSERVERID 0x11 +#define MODBUS_FUNC_READFILERECORD 0x14 +#define MODBUS_FUNC_WRITEFILERECORD 0x15 +#define MODBUS_FUNC_MASKWRITEREG 0x16 +#define MODBUS_FUNC_READWRITEMULTREGS 0x17 +#define MODBUS_FUNC_READFIFOQUEUE 0x18 +#define MODBUS_FUNC_ENCAPINTTRANS 0x2b +#define MODBUS_FUNC_MASK 0x7f +#define MODBUS_FUNC_ERRORMASK 0x80 + +/* Modbus Diagnostic functions: Subfunction Code. */ +#define MODBUS_SUBFUNC_QUERY_DATA 0x00 +#define MODBUS_SUBFUNC_RESTART_COM 0x01 +#define MODBUS_SUBFUNC_DIAG_REGS 0x02 +#define MODBUS_SUBFUNC_CHANGE_DELIMITER 0x03 +#define MODBUS_SUBFUNC_LISTEN_MODE 0x04 +#define MODBUS_SUBFUNC_CLEAR_REGS 0x0a +#define MODBUS_SUBFUNC_BUS_MSG_COUNT 0x0b +#define MODBUS_SUBFUNC_COM_ERR_COUNT 0x0c +#define MODBUS_SUBFUNC_EXCEPT_ERR_COUNT 0x0d +#define MODBUS_SUBFUNC_SERVER_MSG_COUNT 0x0e +#define MODBUS_SUBFUNC_SERVER_NO_RSP_COUNT 0x0f +#define MODBUS_SUBFUNC_SERVER_NAK_COUNT 0x10 +#define MODBUS_SUBFUNC_SERVER_BUSY_COUNT 0x11 +#define MODBUS_SUBFUNC_SERVER_CHAR_COUNT 0x12 +#define MODBUS_SUBFUNC_CLEAR_COUNT 0x14 + +/* Modbus Encapsulated Interface Transport function: MEI type. */ +#define MODBUS_MEI_ENCAPINTTRANS_CAN 0x0d +#define MODBUS_MEI_ENCAPINTTRANS_READ 0x0e + +/* Modbus Exception Codes. */ +#define MODBUS_ERROR_CODE_ILLEGAL_FUNCTION 0x01 +#define MODBUS_ERROR_CODE_ILLEGAL_DATA_ADDRESS 0x02 +#define MODBUS_ERROR_CODE_ILLEGAL_DATA_VALUE 0x03 +#define MODBUS_ERROR_CODE_SERVER_DEVICE_FAILURE 0x04 +#define MODBUS_ERROR_CODE_MEMORY_PARITY_ERROR 0x08 + +/* Modbus Application Protocol (MBAP) header. */ +struct ModbusHeader_ { + uint16_t transactionId; + uint16_t protocolId; + uint16_t length; + uint8_t unitId; +} __attribute__((__packed__)); +typedef struct ModbusHeader_ ModbusHeader; + +/* Modbus Read/Write function and Access Types. */ +#define MODBUS_TYP_WRITE_SINGLE (MODBUS_TYP_WRITE | MODBUS_TYP_SINGLE) +#define MODBUS_TYP_WRITE_MULTIPLE (MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) +#define MODBUS_TYP_READ_WRITE_MULTIPLE (MODBUS_TYP_READ | MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) + +/* Macro to convert quantity value (in bit) into count value (in word): count = Ceil(quantity/8) */ +#define CEIL(quantity) (((quantity) + 7)>>3) + +/* Modbus Default unreplied Modbus requests are considered a flood */ +#define MODBUS_CONFIG_DEFAULT_REQUEST_FLOOD 500 + +/* Modbus default stream reassembly depth */ +#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0 + +static uint32_t request_flood = MODBUS_CONFIG_DEFAULT_REQUEST_FLOOD; +static uint32_t stream_depth = MODBUS_CONFIG_DEFAULT_STREAM_DEPTH; + +int ModbusStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type) { + *event_id = SCMapEnumNameToValue(event_name, modbus_decoder_event_table); + + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "modbus's enum map table.", event_name); + /* yes this is fatal */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +void ModbusSetEvent(ModbusState *modbus, uint8_t e) { + if (modbus && modbus->curr) { + SCLogDebug("modbus->curr->decoder_events %p", modbus->curr->decoder_events); + AppLayerDecoderEventsSetEventRaw(&modbus->curr->decoder_events, e); + SCLogDebug("modbus->curr->decoder_events %p", modbus->curr->decoder_events); + modbus->events++; + } else + SCLogDebug("couldn't set event %u", e); +} + +AppLayerDecoderEvents *ModbusGetEvents(void *state, uint64_t id) { + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx; + + if (modbus->curr && modbus->curr->tx_num == (id + 1)) + return modbus->curr->decoder_events; + + TAILQ_FOREACH(tx, &modbus->tx_list, next) { + if (tx->tx_num == (id+1)) + return tx->decoder_events; + } + + return NULL; +} + +int ModbusHasEvents(void *state) { + return (((ModbusState *) state)->events > 0); +} + +int ModbusGetAlstateProgress(void *modbus_tx, uint8_t direction) { + ModbusTransaction *tx = (ModbusTransaction *) modbus_tx; + ModbusState *modbus = tx->modbus; + + if (tx->replied == 1) + return 1; + + /* Check flood limit */ + if ((modbus->givenup == 1) && + ((modbus->transaction_max - tx->tx_num) > request_flood)) + return 1; + + return 0; +} + +/** \brief Get value for 'complete' status in Modbus + */ +int ModbusGetAlstateProgressCompletionStatus(uint8_t direction) { + return 1; +} + +void *ModbusGetTx(void *alstate, uint64_t tx_id) { + ModbusState *modbus = (ModbusState *) alstate; + ModbusTransaction *tx = NULL; + + if (modbus->curr && modbus->curr->tx_num == tx_id + 1) + return modbus->curr; + + TAILQ_FOREACH(tx, &modbus->tx_list, next) { + SCLogDebug("tx->tx_num %"PRIu64", tx_id %"PRIu64, tx->tx_num, (tx_id+1)); + if (tx->tx_num != (tx_id+1)) + continue; + + SCLogDebug("returning tx %p", tx); + return tx; + } + + return NULL; +} + +void ModbusSetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + tx->logged |= logger; +} + +int ModbusGetTxLogged(void *alstate, void *vtx, uint32_t logger) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + if (tx->logged & logger) + return 1; + + return 0; +} + +uint64_t ModbusGetTxCnt(void *alstate) { + return ((uint64_t) ((ModbusState *) alstate)->transaction_max); +} + +/** \internal + * \brief Find the Modbus Transaction in the state based on Transaction ID. + * + * \param modbus Pointer to Modbus state structure + * \param transactionId Transaction ID of the transaction + * + * \retval tx or NULL if not found + */ +static ModbusTransaction *ModbusTxFindByTransaction(const ModbusState *modbus, + const uint16_t transactionId) { + ModbusTransaction *tx = NULL; + + if (modbus->curr == NULL) + return NULL; + + /* fast path */ + if ((modbus->curr->transactionId == transactionId) && + !(modbus->curr->replied)) { + return modbus->curr; + /* slow path, iterate list */ + } else { + TAILQ_FOREACH(tx, &modbus->tx_list, next) { + if ((tx->transactionId == transactionId) && + !(modbus->curr->replied)) + return tx; + } + } + /* not found */ + return NULL; +} + +/** \internal + * \brief Allocate a Modbus Transaction and + * add it into Transaction list of Modbus State + * + * \param modbus Pointer to Modbus state structure + * + * \retval Pointer to Transaction or NULL pointer + */ +static ModbusTransaction *ModbusTxAlloc(ModbusState *modbus) { + ModbusTransaction *tx; + + tx = (ModbusTransaction *) SCCalloc(1, sizeof(ModbusTransaction)); + if (unlikely(tx == NULL)) + return NULL; + + modbus->transaction_max++; + modbus->unreplied_cnt++; + + /* Check flood limit */ + if ((request_flood != 0) && (modbus->unreplied_cnt > request_flood)) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_FLOODED); + modbus->givenup = 1; + } + + modbus->curr = tx; + + SCLogDebug("modbus->transaction_max updated to %"PRIu64, modbus->transaction_max); + + TAILQ_INSERT_TAIL(&modbus->tx_list, tx, next); + + tx->modbus = modbus; + tx->tx_num = modbus->transaction_max; + + return tx; +} + +/** \internal + * \brief Free a Modbus Transaction + * + * \retval Pointer to Transaction or NULL pointer + */ +static void ModbusTxFree(ModbusTransaction *tx) { + SCEnter(); + if (tx->data != NULL) + SCFree(tx->data); + + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + if (tx->de_state != NULL) + DetectEngineStateFree(tx->de_state); + + SCFree(tx); + SCReturn; +} + +/** + * \brief Modbus transaction cleanup callback + */ +void ModbusStateTxFree(void *state, uint64_t tx_id) { + SCEnter(); + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx = NULL, *ttx; + + SCLogDebug("state %p, id %"PRIu64, modbus, tx_id); + + TAILQ_FOREACH_SAFE(tx, &modbus->tx_list, next, ttx) { + SCLogDebug("tx %p tx->tx_num %"PRIu64", tx_id %"PRIu64, tx, tx->tx_num, (tx_id+1)); + + if (tx->tx_num != (tx_id+1)) + continue; + + if (tx == modbus->curr) + modbus->curr = NULL; + + if (tx->decoder_events != NULL) { + if (tx->decoder_events->cnt <= modbus->events) + modbus->events -= tx->decoder_events->cnt; + else + modbus->events = 0; + } + + modbus->unreplied_cnt--; + + /* Check flood limit */ + if ((modbus->givenup == 1) && + (request_flood != 0) && + (modbus->unreplied_cnt < request_flood) ) + modbus->givenup = 0; + + TAILQ_REMOVE(&modbus->tx_list, tx, next); + ModbusTxFree(tx); + break; + } + SCReturn; +} + +/** \internal + * \brief Extract 8bits data from pointer the received input data + * + * \param res Pointer to the result + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static int ModbusExtractUint8(ModbusState *modbus, + uint8_t *res, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) { + SCEnter(); + if (input_len < (uint32_t) (*offset + sizeof(uint8_t))) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + SCReturnInt(-1); + } + + *res = *(input + *offset); + *offset += sizeof(uint8_t); + SCReturnInt(0); +} + +/** \internal + * \brief Extract 16bits data from pointer the received input data + * + * \param res Pointer to the result + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static int ModbusExtractUint16(ModbusState *modbus, + uint16_t *res, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) { + SCEnter(); + if (input_len < (uint32_t) (*offset + sizeof(uint16_t))) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + SCReturnInt(-1); + } + + ByteExtractUint16(res, BYTE_BIG_ENDIAN, sizeof(uint16_t), (const uint8_t *) (input + *offset)); + *offset += sizeof(uint16_t); + SCReturnInt(0); +} + +/** \internal + * \brief Check length field in Modbus header according to code function + * + * \param modbus Pointer to Modbus state structure + * \param length Length field in Modbus Header + * \param len Length according to code functio + */ +static int ModbusCheckHeaderLength(ModbusState *modbus, + uint16_t length, + uint16_t len) { + SCEnter(); + if (length != len) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + SCReturnInt(-1); + } + SCReturnInt(0); +} + +/** \internal + * \brief Check Modbus header + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param header Pointer to Modbus header state in which the value to be stored + */ +static void ModbusCheckHeader(ModbusState *modbus, + ModbusHeader *header) +{ + SCEnter(); + /* MODBUS protocol is identified by the value 0. */ + if (header->protocolId != MODBUS_PROTOCOL_VER) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_PROTOCOL_ID); + + /* Check Length field that is a byte count of the following fields */ + if ((header->length < MODBUS_MIN_ADU_LEN) || + (header->length > MODBUS_MAX_ADU_LEN) ) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_LENGTH); + + /* Check Unit Identifier field that is not in invalid range */ + if ((header->unitId > MODBUS_MIN_INVALID_UNIT_ID) && + (header->unitId < MODBUS_MAX_INVALID_UNIT_ID) ) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER); + + SCReturn; +} + +/** \internal + * \brief Parse Exception Response and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusExceptionResponse(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) +{ + SCEnter(); + uint8_t exception = 0; + + /* Exception code (1 byte) */ + if (ModbusExtractUint8(modbus, &exception, input, input_len, offset)) + SCReturn; + + switch (exception) { + case MODBUS_ERROR_CODE_ILLEGAL_FUNCTION: + case MODBUS_ERROR_CODE_SERVER_DEVICE_FAILURE: + break; + case MODBUS_ERROR_CODE_ILLEGAL_DATA_VALUE: + if (tx->function == MODBUS_FUNC_DIAGNOSTIC) { + break; + } + /* Fallthrough */ + case MODBUS_ERROR_CODE_ILLEGAL_DATA_ADDRESS: + if ( (tx->type & MODBUS_TYP_ACCESS_FUNCTION_MASK) || + (tx->function == MODBUS_FUNC_READFIFOQUEUE) || + (tx->function == MODBUS_FUNC_ENCAPINTTRANS)) { + break; + } + /* Fallthrough */ + case MODBUS_ERROR_CODE_MEMORY_PARITY_ERROR: + if ( (tx->function == MODBUS_FUNC_READFILERECORD) || + (tx->function == MODBUS_FUNC_WRITEFILERECORD) ) { + break; + } + /* Fallthrough */ + default: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_EXCEPTION_CODE); + break; + } + + SCReturn; +} + +/** \internal + * \brief Parse Read data Request, complete Transaction structure + * and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseReadRequest(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) +{ + SCEnter(); + uint16_t quantity; + uint8_t type = tx->type; + + /* Starting Address (2 bytes) */ + if (ModbusExtractUint16(modbus, &(tx->read.address), input, input_len, offset)) + goto end; + + /* Quantity (2 bytes) */ + if (ModbusExtractUint16(modbus, &(tx->read.quantity), input, input_len, offset)) + goto end; + quantity = tx->read.quantity; + + /* Check Quantity range */ + if (type & MODBUS_TYP_BIT_ACCESS_MASK) { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_BIT_ACCESS)) + goto error; + } else { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_WORD_ACCESS)) + goto error; + } + + if (~type & MODBUS_TYP_WRITE) + /* Except from Read/Write Multiple Registers function (code 23) */ + /* The length of all Read Data function requests is 6 bytes */ + /* Modbus Application Protocol Specification V1.1b3 from 6.1 to 6.4 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_VALUE); +end: + SCReturn; +} + +/** \internal + * \brief Parse Read data Response and verify protocol compliance + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseReadResponse(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) +{ + SCEnter(); + uint8_t count = 0; + + /* Count (1 bytes) */ + if (ModbusExtractUint8(modbus, &count, input, input_len, offset)) + goto end; + + /* Check Count range and value according to the request */ + if ((tx->type) & MODBUS_TYP_BIT_ACCESS_MASK) { + if ( (count < MODBUS_MIN_COUNT) || + (count > MODBUS_MAX_COUNT) || + (count != CEIL(tx->read.quantity))) + goto error; + } else { + if ( (count == MODBUS_MIN_COUNT) || + (count > MODBUS_MAX_COUNT) || + (count != (2 * (tx->read.quantity)))) + goto error; + } + + /* Except from Read/Write Multiple Registers function (code 23) */ + /* The length of all Read Data function responses is (3 bytes + count) */ + /* Modbus Application Protocol Specification V1.1b3 from 6.1 to 6.4 */ + ModbusCheckHeaderLength(modbus, tx->length, 3 + count); + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); +end: + SCReturn; +} + +/** \internal + * \brief Parse Write data Request, complete Transaction structure + * and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + * + * \retval On success returns 0 or on failure returns -1. + */ +static int ModbusParseWriteRequest(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) +{ + SCEnter(); + uint16_t quantity = 1, word = 0; + uint8_t byte = 0, count = 1, type = tx->type; + + int i = 0; + + /* Starting/Output/Register Address (2 bytes) */ + if (ModbusExtractUint16(modbus, &(tx->write.address), input, input_len, offset)) + goto end; + + if (type & MODBUS_TYP_SINGLE) { + /* The length of Write Single Coil (code 5) and */ + /* Write Single Register (code 6) requests is 6 bytes */ + /* Modbus Application Protocol Specification V1.1b3 6.5 and 6.6 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 6)) + goto end; + } else if (type & MODBUS_TYP_MULTIPLE) { + /* Quantity (2 bytes) */ + if (ModbusExtractUint16(modbus, &quantity, input, input_len, offset)) + goto end; + tx->write.quantity = quantity; + + /* Count (1 bytes) */ + if (ModbusExtractUint8(modbus, &count, input, input_len, offset)) + goto end; + tx->write.count = count; + + if (type & MODBUS_TYP_BIT_ACCESS_MASK) { + /* Check Quantity range and conversion in byte (count) */ + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_BIT_ACCESS) || + (quantity != CEIL(count))) + goto error; + + /* The length of Write Multiple Coils (code 15) request is (7 + count) */ + /* Modbus Application Protocol Specification V1.1b3 6.11 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 7 + count)) + goto end; + } else { + /* Check Quantity range and conversion in byte (count) */ + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_WORD_ACCESS) || + (count != (2 * quantity))) + goto error; + + if (type & MODBUS_TYP_READ) { + /* The length of Read/Write Multiple Registers function (code 23) */ + /* request is (11 bytes + count) */ + /* Modbus Application Protocol Specification V1.1b3 6.17 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 11 + count)) + goto end; + } else { + /* The length of Write Multiple Coils (code 15) and */ + /* Write Multiple Registers (code 16) functions requests is (7 bytes + count) */ + /* Modbus Application Protocol Specification V1.1b3 from 6.11 and 6.12 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 7 + count)) + goto end; + } + } + } else { + /* Mask Write Register function (And_Mask and Or_Mask) */ + quantity = 2; + + /* The length of Mask Write Register (code 22) function request is 8 */ + /* Modbus Application Protocol Specification V1.1b3 6.16 */ + if (ModbusCheckHeaderLength(modbus, tx->length, 8)) + goto end; + } + + if (type & MODBUS_TYP_COILS) { + /* Output value (data block) unit is count */ + tx->data = (uint16_t *) SCCalloc(1, count * sizeof(uint16_t)); + if (unlikely(tx->data == NULL)) + SCReturnInt(-1); + + if (type & MODBUS_TYP_SINGLE) { + /* Outputs value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; + tx->data[i] = word; + + if ((word != 0x00) && (word != 0xFF00)) + goto error; + } else { + for (i = 0; i < count; i++) { + /* Outputs value (1 byte) */ + if (ModbusExtractUint8(modbus, &byte, input, input_len, offset)) + goto end; + tx->data[i] = (uint16_t) byte; + } + } + } else { + /* Registers value (data block) unit is quantity */ + tx->data = (uint16_t *) SCCalloc(1, quantity * sizeof(uint16_t)); + if (unlikely(tx->data == NULL)) + SCReturnInt(-1); + + for (i = 0; i < quantity; i++) { + /* Outputs/Registers value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; + tx->data[i] = word; + } + } + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_VALUE); +end: + SCReturnInt(0); +} + +/** \internal + * \brief Parse Write data Response and verify protocol compliance + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseWriteResponse(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) +{ + SCEnter(); + uint16_t address = 0, quantity = 0, word = 0; + uint8_t type = tx->type; + + /* Starting Address (2 bytes) */ + if (ModbusExtractUint16(modbus, &address, input, input_len, offset)) + goto end; + + if (address != tx->write.address) + goto error; + + if (type & MODBUS_TYP_SINGLE) { + /* Check if Outputs/Registers value has been stored */ + if (tx->data != NULL) + { + /* Outputs/Registers value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; + + /* Check with Outputs/Registers from request */ + if (word != tx->data[0]) + goto error; + } + } else if (type & MODBUS_TYP_MULTIPLE) { + /* Quantity (2 bytes) */ + if (ModbusExtractUint16(modbus, &quantity, input, input_len, offset)) + goto end; + + /* Check Quantity range */ + if (type & MODBUS_TYP_BIT_ACCESS_MASK) { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_WORD_ACCESS)) + goto error; + } else { + if ((quantity == MODBUS_MIN_QUANTITY) || + (quantity > MODBUS_MAX_QUANTITY_IN_BIT_ACCESS)) + goto error; + } + + /* Check Quantity value according to the request */ + if (quantity != tx->write.quantity) + goto error; + } else { + /* Check if And_Mask and Or_Mask values have been stored */ + if (tx->data != NULL) + { + /* And_Mask value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; + + /* Check And_Mask value according to the request */ + if (word != tx->data[0]) + goto error; + + /* And_Or_Mask value (2 bytes) */ + if (ModbusExtractUint16(modbus, &word, input, input_len, offset)) + goto end; + + /* Check Or_Mask value according to the request */ + if (word != tx->data[1]) + goto error; + } + + /* The length of Mask Write Register (code 22) function response is 8 */ + /* Modbus Application Protocol Specification V1.1b3 6.16 */ + ModbusCheckHeaderLength(modbus, tx->length, 8); + goto end; + } + + /* Except from Mask Write Register (code 22) */ + /* The length of all Write Data function responses is 6 */ + /* Modbus Application Protocol Specification V1.1b3 6.5, 6.6, 6.11, 6.12 and 6.17 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); +end: + SCReturn; +} + +/** \internal + * \brief Parse Diagnostic Request, complete Transaction + * structure (Category) and verify protocol compliance. + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer to Modbus state structure + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + * + * \retval Reserved category function returns 1 otherwise returns 0. + */ +static int ModbusParseDiagnosticRequest(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len, + uint16_t *offset) +{ + SCEnter(); + uint16_t data = 0; + + /* Sub-function (2 bytes) */ + if (ModbusExtractUint16(modbus, &(tx->subFunction), input, input_len, offset)) + goto end; + + /* Data (2 bytes) */ + if (ModbusExtractUint16(modbus, &data, input, input_len, offset)) + goto end; + + if (tx->subFunction != MODBUS_SUBFUNC_QUERY_DATA) { + switch (tx->subFunction) { + case MODBUS_SUBFUNC_RESTART_COM: + if ((data != 0x00) && (data != 0xFF00)) + goto error; + break; + + case MODBUS_SUBFUNC_CHANGE_DELIMITER: + if ((data & 0xFF) != 0x00) + goto error; + break; + + case MODBUS_SUBFUNC_LISTEN_MODE: + /* No answer is expected then mark tx as completed. */ + tx->replied = 1; + /* Fallthrough */ + case MODBUS_SUBFUNC_DIAG_REGS: + case MODBUS_SUBFUNC_CLEAR_REGS: + case MODBUS_SUBFUNC_BUS_MSG_COUNT: + case MODBUS_SUBFUNC_COM_ERR_COUNT: + case MODBUS_SUBFUNC_EXCEPT_ERR_COUNT: + case MODBUS_SUBFUNC_SERVER_MSG_COUNT: + case MODBUS_SUBFUNC_SERVER_NO_RSP_COUNT: + case MODBUS_SUBFUNC_SERVER_NAK_COUNT: + case MODBUS_SUBFUNC_SERVER_BUSY_COUNT: + case MODBUS_SUBFUNC_SERVER_CHAR_COUNT: + case MODBUS_SUBFUNC_CLEAR_COUNT: + if (data != 0x00) + goto error; + break; + + default: + /* Set function code category */ + tx->category = MODBUS_CAT_RESERVED; + SCReturnInt(1); + } + + /* The length of all Diagnostic Requests is 6 */ + /* Modbus Application Protocol Specification V1.1b3 6.8 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + } + + goto end; + +error: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_VALUE); +end: + SCReturnInt(0); +} + +/* Modbus Function Code Categories structure. */ +typedef struct ModbusFunctionCodeRange_ { + uint8_t function; + uint8_t category; +} ModbusFunctionCodeRange; + +/* Modbus Function Code Categories table. */ +static ModbusFunctionCodeRange modbusFunctionCodeRanges[] = { + { 0, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 9, MODBUS_CAT_RESERVED }, + { 15, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 41, MODBUS_CAT_RESERVED }, + { 43, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 65, MODBUS_CAT_USER_DEFINED }, + { 73, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 90, MODBUS_CAT_RESERVED }, + { 92, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 100, MODBUS_CAT_USER_DEFINED }, + { 111, MODBUS_CAT_PUBLIC_UNASSIGNED}, + { 125, MODBUS_CAT_RESERVED }, + { 128, MODBUS_CAT_NONE } +}; + +/** \internal + * \brief Parse the Modbus Protocol Data Unit (PDU) Request + * + * \param tx Pointer to Modbus Transaction structure + * \param ModbusPdu Pointer the Modbus PDU state in which the value to be stored + * \param input Pointer the received input data + * \param input_len Length of the received input data + */ +static void ModbusParseRequestPDU(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint16_t offset = (uint16_t) sizeof(ModbusHeader); + uint8_t count = 0; + + int i = 0; + + /* Standard function codes used on MODBUS application layer protocol (1 byte) */ + if (ModbusExtractUint8(modbus, &(tx->function), input, input_len, &offset)) + goto end; + + /* Set default function code category */ + tx->category = MODBUS_CAT_NONE; + + /* Set default function primary table */ + tx->type = MODBUS_TYP_NONE; + + switch (tx->function) { + case MODBUS_FUNC_NONE: + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE); + break; + + case MODBUS_FUNC_READCOILS: + /* Set function type */ + tx->type = (MODBUS_TYP_COILS | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_READDISCINPUTS: + /* Set function type */ + tx->type = (MODBUS_TYP_DISCRETES | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_READHOLDREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_READINPUTREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_INPUT | MODBUS_TYP_READ); + break; + + case MODBUS_FUNC_WRITESINGLECOIL: + /* Set function type */ + tx->type = (MODBUS_TYP_COILS | MODBUS_TYP_WRITE_SINGLE); + break; + + case MODBUS_FUNC_WRITESINGLEREG: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_WRITE_SINGLE); + break; + + case MODBUS_FUNC_WRITEMULTCOILS: + /* Set function type */ + tx->type = (MODBUS_TYP_COILS | MODBUS_TYP_WRITE_MULTIPLE); + break; + + case MODBUS_FUNC_WRITEMULTREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_WRITE_MULTIPLE); + break; + + case MODBUS_FUNC_MASKWRITEREG: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_WRITE); + break; + + case MODBUS_FUNC_READWRITEMULTREGS: + /* Set function type */ + tx->type = (MODBUS_TYP_HOLDING | MODBUS_TYP_READ_WRITE_MULTIPLE); + break; + + case MODBUS_FUNC_READFILERECORD: + case MODBUS_FUNC_WRITEFILERECORD: + /* Count/length (1 bytes) */ + if (ModbusExtractUint8(modbus, &count, input, input_len, &offset)) + goto end; + + /* Modbus Application Protocol Specification V1.1b3 6.14 and 6.15 */ + ModbusCheckHeaderLength(modbus, tx->length, 2 + count); + break; + + case MODBUS_FUNC_DIAGNOSTIC: + if(ModbusParseDiagnosticRequest(tx, modbus, input, input_len, &offset)) + goto end; + break; + + case MODBUS_FUNC_READEXCSTATUS: + case MODBUS_FUNC_GETCOMEVTCOUNTER: + case MODBUS_FUNC_GETCOMEVTLOG: + case MODBUS_FUNC_REPORTSERVERID: + /* Modbus Application Protocol Specification V1.1b3 6.7, 6.9, 6.10 and 6.13 */ + ModbusCheckHeaderLength(modbus, tx->length, 2); + break; + + case MODBUS_FUNC_READFIFOQUEUE: + /* Modbus Application Protocol Specification V1.1b3 6.18 */ + ModbusCheckHeaderLength(modbus, tx->length, 4); + break; + + case MODBUS_FUNC_ENCAPINTTRANS: + /* MEI type (1 byte) */ + if (ModbusExtractUint8(modbus, &(tx->mei), input, input_len, &offset)) + goto end; + + if (tx->mei == MODBUS_MEI_ENCAPINTTRANS_READ) { + /* Modbus Application Protocol Specification V1.1b3 6.21 */ + ModbusCheckHeaderLength(modbus, tx->length, 5); + } else if (tx->mei != MODBUS_MEI_ENCAPINTTRANS_CAN) { + /* Set function code category */ + tx->category = MODBUS_CAT_RESERVED; + goto end; + } + break; + + default: + /* Check if request is error. */ + if (tx->function & MODBUS_FUNC_ERRORMASK) { + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE); + goto end; + } + + /* Get and store function code category */ + for (i = 0; modbusFunctionCodeRanges[i].category != MODBUS_CAT_NONE; i++) { + if (tx->function <= modbusFunctionCodeRanges[i].function) + break; + tx->category = modbusFunctionCodeRanges[i].category; + } + goto end; + } + + /* Set function code category */ + tx->category = MODBUS_CAT_PUBLIC_ASSIGNED; + + if (tx->type & MODBUS_TYP_READ) + ModbusParseReadRequest(tx, modbus, input, input_len, &offset); + + if (tx->type & MODBUS_TYP_WRITE) + ModbusParseWriteRequest(tx, modbus, input, input_len, &offset); + +end: + SCReturn; +} + +/** \internal + * \brief Parse the Modbus Protocol Data Unit (PDU) Response + * + * \param tx Pointer to Modbus Transaction structure + * \param modbus Pointer the Modbus PDU state in which the value to be stored + * \param input Pointer the received input data + * \param input_len Length of the received input data + * \param offset Offset of the received input data pointer + */ +static void ModbusParseResponsePDU(ModbusTransaction *tx, + ModbusState *modbus, + uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint16_t offset = (uint16_t) sizeof(ModbusHeader); + uint8_t count = 0, error = FALSE, function = 0, mei = 0; + + /* Standard function codes used on MODBUS application layer protocol (1 byte) */ + if (ModbusExtractUint8(modbus, &function, input, input_len, &offset)) + goto end; + + /* Check if response is error */ + if(function & MODBUS_FUNC_ERRORMASK) { + function &= MODBUS_FUNC_MASK; + error = TRUE; + } + + if (tx->category == MODBUS_CAT_PUBLIC_ASSIGNED) { + /* Check if response is error. */ + if (error) { + ModbusExceptionResponse(tx, modbus, input, input_len, &offset); + } else { + switch(function) { + case MODBUS_FUNC_READEXCSTATUS: + /* Modbus Application Protocol Specification V1.1b3 6.7 */ + ModbusCheckHeaderLength(modbus, tx->length, 3); + goto end; + + case MODBUS_FUNC_GETCOMEVTCOUNTER: + /* Modbus Application Protocol Specification V1.1b3 6.9 */ + ModbusCheckHeaderLength(modbus, tx->length, 6); + goto end; + + case MODBUS_FUNC_READFILERECORD: + case MODBUS_FUNC_WRITEFILERECORD: + /* Count/length (1 bytes) */ + if (ModbusExtractUint8(modbus, &count, input, input_len, &offset)) + goto end; + + /* Modbus Application Protocol Specification V1.1b3 6.14 and 6.15 */ + ModbusCheckHeaderLength(modbus, tx->length, 2 + count); + goto end; + + case MODBUS_FUNC_ENCAPINTTRANS: + /* MEI type (1 byte) */ + if (ModbusExtractUint8(modbus, &mei, input, input_len, &offset)) + goto end; + + if (mei != tx->mei) + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_VALUE_MISMATCH); + goto end; + } + + if (tx->type & MODBUS_TYP_READ) + ModbusParseReadResponse(tx, modbus, input, input_len, &offset); + /* Read/Write response contents none write response part */ + else if (tx->type & MODBUS_TYP_WRITE) + ModbusParseWriteResponse(tx, modbus, input, input_len, &offset); + } + } + +end: + SCReturn; +} + +/** \internal + * \brief Parse the Modbus Application Protocol (MBAP) header + * + * \param header Pointer the Modbus header state in which the value to be stored + * \param input Pointer the received input data + */ +static int ModbusParseHeader(ModbusState *modbus, + ModbusHeader *header, + uint8_t *input, + uint32_t input_len) +{ + SCEnter(); + uint16_t offset = 0; + + int r = 0; + + /* can't pass the header fields directly due to alignment (Bug 2088) */ + uint16_t transaction_id = 0; + uint16_t protocol_id = 0; + uint16_t length = 0; + uint8_t unit_id = 0; + + /* Transaction Identifier (2 bytes) */ + r = ModbusExtractUint16(modbus, &transaction_id, input, input_len, &offset); + /* Protocol Identifier (2 bytes) */ + r |= ModbusExtractUint16(modbus, &protocol_id, input, input_len, &offset); + /* Length (2 bytes) */ + r |= ModbusExtractUint16(modbus, &length, input, input_len, &offset); + /* Unit Identifier (1 byte) */ + r |= ModbusExtractUint8(modbus, &unit_id, input, input_len, &offset); + + if (r != 0) { + SCReturnInt(-1); + } + header->transactionId = transaction_id; + header->protocolId = protocol_id; + header->length = length; + header->unitId = unit_id; + + SCReturnInt(0); +} + +/** \internal + * + * \brief This function is called to retrieve a Modbus Request + * + * \param state Modbus state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int ModbusParseRequest(Flow *f, + void *state, + AppLayerParserState *pstate, + uint8_t *input, + uint32_t input_len, + void *local_data) +{ + SCEnter(); + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx; + ModbusHeader header; + + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + + while (input_len > 0) { + uint32_t adu_len = input_len; + uint8_t *adu = input; + + /* Extract MODBUS Header */ + if (ModbusParseHeader(modbus, &header, adu, adu_len)) + SCReturnInt(0); + + /* Update ADU length with length in Modbus header. */ + adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; + if (adu_len > input_len) + SCReturnInt(0); + + /* Allocate a Transaction Context and add it to Transaction list */ + tx = ModbusTxAlloc(modbus); + if (tx == NULL) + SCReturnInt(0); + + /* Check MODBUS Header */ + ModbusCheckHeader(modbus, &header); + + /* Store Transaction ID & PDU length */ + tx->transactionId = header.transactionId; + tx->length = header.length; + + /* Extract MODBUS PDU and fill Transaction Context */ + ModbusParseRequestPDU(tx, modbus, adu, adu_len); + + /* Update input line and remaining input length of the command */ + input += adu_len; + input_len -= adu_len; + } + + SCReturnInt(1); +} + +/** \internal + * \brief This function is called to retrieve a Modbus response + * + * \param state Pointer to Modbus state structure for the parser + * \param input Input line of the command + * \param input_len Length of the request + * + * \retval 1 when the command is parsed, 0 otherwise + */ +static int ModbusParseResponse(Flow *f, + void *state, + AppLayerParserState *pstate, + uint8_t *input, + uint32_t input_len, + void *local_data) +{ + SCEnter(); + ModbusHeader header; + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx; + + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + + while (input_len > 0) { + uint32_t adu_len = input_len; + uint8_t *adu = input; + + /* Extract MODBUS Header */ + if (ModbusParseHeader(modbus, &header, adu, adu_len)) + SCReturnInt(0); + + /* Update ADU length with length in Modbus header. */ + adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; + if (adu_len > input_len) + SCReturnInt(0); + + /* Find the transaction context thanks to transaction ID (and function code) */ + tx = ModbusTxFindByTransaction(modbus, header.transactionId); + if (tx == NULL) { + /* Allocate a Transaction Context if not previous request */ + /* and add it to Transaction list */ + tx = ModbusTxAlloc(modbus); + if (tx == NULL) + SCReturnInt(0); + + SCLogDebug("MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE"); + ModbusSetEvent(modbus, MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE); + } else { + /* Store PDU length */ + tx->length = header.length; + + /* Extract MODBUS PDU and fill Transaction Context */ + ModbusParseResponsePDU(tx, modbus, adu, adu_len); + } + + /* Check and store MODBUS Header */ + ModbusCheckHeader(modbus, &header); + + /* Mark as completed */ + tx->replied = 1; + + /* Update input line and remaining input length of the command */ + input += adu_len; + input_len -= adu_len; + } + + SCReturnInt(1); +} + +/** \internal + * \brief Function to allocate the Modbus state memory + */ +static void *ModbusStateAlloc(void) +{ + ModbusState *modbus; + + modbus = (ModbusState *) SCCalloc(1, sizeof(ModbusState)); + if (unlikely(modbus == NULL)) + return NULL; + + TAILQ_INIT(&modbus->tx_list); + + return (void *) modbus; +} + +/** \internal + * \brief Function to free the Modbus state memory + */ +static void ModbusStateFree(void *state) +{ + SCEnter(); + ModbusState *modbus = (ModbusState *) state; + ModbusTransaction *tx = NULL, *ttx; + + if (state) { + TAILQ_FOREACH_SAFE(tx, &modbus->tx_list, next, ttx) { + ModbusTxFree(tx); + } + + SCFree(state); + } + SCReturn; +} + +static uint16_t ModbusProbingParser(uint8_t *input, + uint32_t input_len, + uint32_t *offset) +{ + ModbusHeader *header = (ModbusHeader *) input; + + /* Modbus header is 7 bytes long */ + if (input_len < sizeof(ModbusHeader)) + return ALPROTO_UNKNOWN; + + /* MODBUS protocol is identified by the value 0. */ + if (header->protocolId != 0) + return ALPROTO_FAILED; + + return ALPROTO_MODBUS; +} + +DetectEngineState *ModbusGetTxDetectState(void *vtx) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + return tx->de_state; +} + +int ModbusSetTxDetectState(void *state, void *vtx, DetectEngineState *s) +{ + ModbusTransaction *tx = (ModbusTransaction *)vtx; + tx->de_state = s; + return 0; +} + +/** + * \brief Function to register the Modbus protocol parsers and other functions + */ +void RegisterModbusParsers(void) +{ + SCEnter(); + char *proto_name = "modbus"; + + /* Modbus application protocol V1.1b3 */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + AppLayerProtoDetectRegisterProtocol(ALPROTO_MODBUS, proto_name); + + if (RunmodeIsUnittests()) { + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "502", + ALPROTO_MODBUS, + 0, sizeof(ModbusHeader), + STREAM_TOSERVER, + ModbusProbingParser, NULL); + } else { + /* If there is no app-layer section for Modbus, silently + * leave it disabled. */ + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_MODBUS, + 0, sizeof(ModbusHeader), + ModbusProbingParser, NULL)) { +#ifndef AFLFUZZ_APPLAYER + return; +#endif + } + } + + ConfNode *p = NULL; + p = ConfGetNode("app-layer.protocols.modbus.request-flood"); + if (p != NULL) { + uint32_t value; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError(SC_ERR_MODBUS_CONFIG, "invalid value for request-flood %s", p->val); + } else { + request_flood = value; + } + } + SCLogConfig("Modbus request flood protection level: %u", request_flood); + + p = ConfGetNode("app-layer.protocols.modbus.stream-depth"); + if (p != NULL) { + uint32_t value; + if (ParseSizeStringU32(p->val, &value) < 0) { + SCLogError(SC_ERR_MODBUS_CONFIG, "invalid value for stream-depth %s", p->val); + } else { + stream_depth = value; + } + } + SCLogConfig("Modbus stream depth: %u", stream_depth); + } else { +#ifndef AFLFUZZ_APPLAYER + SCLogConfig("Protocol detection and parser disabled for %s protocol.", proto_name); + return; +#endif + } + if (AppLayerParserConfParserEnabled("tcp", proto_name)) { + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER, ModbusParseRequest); + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOCLIENT, ModbusParseResponse); + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateAlloc, ModbusStateFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetEvents); + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusHasEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, NULL, + ModbusGetTxDetectState, ModbusSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTxCnt); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTxLogged, + ModbusSetTxLogged); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateTxFree); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetAlstateProgress); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_MODBUS, + ModbusGetAlstateProgressCompletionStatus); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_MODBUS, ModbusStateGetEventInfo); + + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_MODBUS, STREAM_TOSERVER); + + AppLayerParserSetStreamDepth(IPPROTO_TCP, ALPROTO_MODBUS, stream_depth); + } else { + SCLogConfig("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); + } +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_MODBUS, ModbusParserRegisterTests); +#endif + + SCReturn; +} + +/* UNITTESTS */ +#ifdef UNITTESTS +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" + +#include "flow-util.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "stream-tcp.h" +#include "stream-tcp-private.h" + +/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ +/* Example of a request to read discrete outputs 20-38 */ +static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; + +static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Byte count */ 0x03, + /* Coil Status */ 0xCD, 0x6B, 0x05 }; + +static uint8_t readCoilsErrorRsp[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x03, + /* Unit ID */ 0x00, + /* Function code */ 0x81, + /* Exception code */ 0x05}; + +/* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */ +/* Example of a request to write register 2 to 00 03 hex */ +static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01, + /* Register Value */ 0x00, 0x03}; + +static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x04, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01}; + +static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x06, + /* Register Address */ 0x00, 0x01, + /* Register Value */ 0x00, 0x03}; + +/* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */ +/* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */ +static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x0B, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02, + /* Byte count */ 0x04, + /* Registers Value */ 0x00, 0x0A, + 0x01, 0x02}; + +static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02}; + +/* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */ +/* Example of a request to mask write to register 5 */ +static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x08, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2, + /* Or_Mask */ 0x00, 0x25}; + +static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2}; + +static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x08, + /* Unit ID */ 0x00, + /* Function code */ 0x16, + /* Reference Address */ 0x00, 0x04, + /* And_Mask */ 0x00, 0xF2, + /* Or_Mask */ 0x00, 0x25}; + +/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ +/* Example of a request to read six registers starting at register 4, */ +/* and to write three registers starting at register 15 */ +static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x11, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Read Starting Address */ 0x00, 0x03, + /* Quantity to Read */ 0x00, 0x06, + /* Write Starting Address */ 0x00, 0x0E, + /* Quantity to Write */ 0x00, 0x03, + /* Write Byte count */ 0x06, + /* Write Registers Value */ 0x12, 0x34, + 0x56, 0x78, + 0x9A, 0xBC}; + +/* Mismatch value in Byte count 0x0B instead of 0x0C */ +static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x0E, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Byte count */ 0x0B, + /* Read Registers Value */ 0x00, 0xFE, + 0x0A, 0xCD, + 0x00, 0x01, + 0x00, 0x03, + 0x00, 0x0D, + 0x00}; + +/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */ +/* Example of a request to to remote device to its Listen Only MOde for Modbus Communications. */ +static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x08, + /* Sub-function code */ 0x00, 0x04, + /* Data */ 0x00, 0x00}; + +static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x01, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; + +static uint8_t invalidLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x09, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x00, 0x02, + /* Byte count */ 0x04, + /* Registers Value */ 0x00, 0x0A, + 0x01, 0x02}; + +static uint8_t exceededLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0xff, 0xfa, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x7f, 0xf9, + /* Byte count */ 0xff}; + +static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x02, + /* Unit ID */ 0x00, + /* Function code */ 0x10}; + +/** \test Send Modbus Read Coils request/response. */ +static int ModbusParserTest01(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { + printf("expected function %d, got %" PRIu8 ": ", 1, tx->function); + printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address); + printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus Write Multiple registers request/response. */ +static int ModbusParserTest02(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, writeMultipleRegistersReq, + sizeof(writeMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) || + (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) { + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + printf("expected write quantity %d, got %" PRIu16 ": ", 2, tx->write.quantity); + printf("expected write count %d, got %" PRIu8 ": ", 4, tx->write.count); + printf("expected data %d, got %" PRIu16 ": ", 0x000A, tx->data[0]); + printf("expected data %d, got %" PRIu16 ": ", 0x0102, tx->data[1]); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, writeMultipleRegistersRsp, + sizeof(writeMultipleRegistersRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */ +static int ModbusParserTest03(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus Data mismatch\"; " + "app-layer-event: " + "modbus.value_mismatch; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + readWriteMultipleRegistersReq, + sizeof(readWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 23) || (tx->read.address != 0x03) || (tx->read.quantity != 6) || + (tx->write.address != 0x0E) || (tx->write.quantity != 3) || (tx->write.count != 6) || + (tx->data[0] != 0x1234) || (tx->data[1] != 0x5678) || (tx->data[2] != 0x9ABC)) { + printf("expected function %d, got %" PRIu8 ": ", 23, tx->function); + printf("expected read address %d, got %" PRIu16 ": ", 0x03, tx->read.address); + printf("expected read quantity %d, got %" PRIu16 ": ", 6, tx->read.quantity); + printf("expected write address %d, got %" PRIu16 ": ", 0x0E, tx->write.address); + printf("expected write quantity %d, got %" PRIu16 ": ", 3, tx->write.quantity); + printf("expected write count %d, got %" PRIu8 ": ", 6, tx->write.count); + printf("expected data %d, got %" PRIu16 ": ", 0x1234, tx->data[0]); + printf("expected data %d, got %" PRIu16 ": ", 0x5678, tx->data[1]); + printf("expected data %d, got %" PRIu16 ": ", 0x9ABC, tx->data[2]); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readWriteMultipleRegistersRsp, + sizeof(readWriteMultipleRegistersRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus Force Listen Only Mode request. */ +static int ModbusParserTest04(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, forceListenOnlyMode, + sizeof(forceListenOnlyMode)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 8) || (tx->subFunction != 4)) { + printf("expected function %d, got %" PRIu8 ": ", 8, tx->function); + printf("expected sub-function %d, got %" PRIu16 ": ", 0x04, tx->subFunction); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus invalid Protocol version in request. */ +static int ModbusParserTest05(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Protocol version\"; " + "app-layer-event: " + "modbus.invalid_protocol_id; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, invalidProtocolIdReq, + sizeof(invalidProtocolIdReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus unsolicited response. */ +static int ModbusParserTest06(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus unsolicited response\"; " + "app-layer-event: " + "modbus.unsolicited_response; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readCoilsRsp, + sizeof(readCoilsRsp)); + if (r != 0) { + printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus invalid Length request. */ +static int ModbusParserTest07(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + invalidLengthWriteMultipleRegistersReq, + sizeof(invalidLengthWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus Read Coils request and error response with Exception code invalid. */ +static int ModbusParserTest08(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus Exception code invalid\"; " + "app-layer-event: " + "modbus.invalid_exception_code; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { + printf("expected function %d, got %" PRIu8 ": ", 1, tx->function); + printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address); + printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, readCoilsErrorRsp, + sizeof(readCoilsErrorRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */ +static int ModbusParserTest09(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; + uint8_t *input = readCoilsReq; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, input, input_len - part2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, input, input_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) { + printf("expected function %d, got %" PRIu8 ": ", 1, tx->function); + printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address); + printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity); + goto end; + } + + input_len = sizeof(readCoilsRsp); + part2_len = 10; + input = readCoilsRsp; + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, input, input_len - part2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, input, input_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */ +static int ModbusParserTest10(void) { + uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq); + uint8_t *input, *ptr; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t)); + if (unlikely(input == NULL)) + goto end; + + memcpy(input, readCoilsReq, sizeof(readCoilsReq)); + memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq)); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, input, input_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + if (modbus_state->transaction_max !=2) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 2, modbus_state->transaction_max); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 1); + + if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) || + (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) { + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + printf("expected write quantity %d, got %" PRIu16 ": ", 2, tx->write.quantity); + printf("expected write count %d, got %" PRIu8 ": ", 4, tx->write.count); + printf("expected data %d, got %" PRIu16 ": ", 0x000A, tx->data[0]); + printf("expected data %d, got %" PRIu16 ": ", 0x0102, tx->data[1]); + goto end; + } + + input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp); + + ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t)); + if (unlikely(ptr == NULL)) + goto end; + input = ptr; + + memcpy(input, readCoilsRsp, sizeof(readCoilsRsp)); + memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, input, sizeof(input_len)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + result = 1; +end: + if (input != NULL) + SCFree(input); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus exceed Length request. */ +static int ModbusParserTest11(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + exceededLengthWriteMultipleRegistersReq, + sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 * sizeof(uint8_t)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus invalid PDU Length. */ +static int ModbusParserTest12(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + invalidLengthPDUWriteMultipleRegistersReq, + sizeof(invalidLengthPDUWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send Modbus Mask Write register request/response. */ +static int ModbusParserTest13(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, maskWriteRegisterReq, + sizeof(maskWriteRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 22) || (tx->data[0] != 0x00F2) || (tx->data[1] != 0x0025)) { + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected And_Mask %d, got %" PRIu16 ": ", 0x00F2, tx->data[0]); + printf("expected Or_Mask %d, got %" PRIu16 ": ", 0x0025, tx->data[1]); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, maskWriteRegisterRsp, + sizeof(maskWriteRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send Modbus Write single register request/response. */ +static int ModbusParserTest14(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + int result = 0; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, writeSingleRegisterReq, + sizeof(writeSingleRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 6) || (tx->write.address != 0x0001) || (tx->data[0] != 0x0003)) { + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + printf("expected data %d, got %" PRIu16 ": ", 0x03, tx->data[0]); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, writeSingleRegisterRsp, + sizeof(writeSingleRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +/** \test Send invalid Modbus Mask Write register request. */ +static int ModbusParserTest15(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, invalidMaskWriteRegisterReq, + sizeof(invalidMaskWriteRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if (tx->function != 22) { + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, maskWriteRegisterRsp, + sizeof(maskWriteRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Send invalid Modbus Mask Write register request. */ +static int ModbusParserTest16(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + invalidWriteSingleRegisterReq, + sizeof(invalidWriteSingleRegisterReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + ModbusTransaction *tx = ModbusGetTx(modbus_state, 0); + + if ((tx->function != 6) || (tx->write.address != 0x0001)) { + printf("expected function %d, got %" PRIu8 ": ", 16, tx->function); + printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOCLIENT, writeSingleRegisterRsp, + sizeof(writeSingleRegisterRsp)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (modbus_state->transaction_max !=1) { + printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** \test Checks if stream_depth is correct */ +static int ModbusParserTest17(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + FAIL_IF(alp_tctx == NULL); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + readCoilsReq, sizeof(readCoilsReq)); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(f.alstate == NULL); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + readCoilsRsp, sizeof(readCoilsRsp)); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + PASS; +} + +/*/ \test Checks if stream depth is correct over 2 TCP packets */ +static int ModbusParserTest18(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + Flow f; + TcpSession ssn; + + uint32_t input_len = sizeof(readCoilsReq), part2_len = 3; + uint8_t *input = readCoilsReq; + + FAIL_IF(alp_tctx == NULL); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len - part2_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + input, input_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FAIL_IF(f.alstate == NULL); + + input_len = sizeof(readCoilsRsp); + part2_len = 10; + input = readCoilsRsp; + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, input_len - part2_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, + input, input_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH); + + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + PASS; +} +#endif /* UNITTESTS */ + +void ModbusParserRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request", + ModbusParserTest01); + UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request", + ModbusParserTest02); + UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request", + ModbusParserTest03); + UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request", + ModbusParserTest04); + UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version", + ModbusParserTest05); + UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response", + ModbusParserTest06); + UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request", + ModbusParserTest07); + UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", + ModbusParserTest08); + UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", + ModbusParserTest09); + UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", + ModbusParserTest10); + UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", + ModbusParserTest11); + UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length", + ModbusParserTest12); + UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request", + ModbusParserTest13); + UtRegisterTest("ModbusParserTest14 - Modbus Write single register request", + ModbusParserTest14); + UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request", + ModbusParserTest15); + UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request", + ModbusParserTest16); + UtRegisterTest("ModbusParserTest17 - Modbus stream depth", + ModbusParserTest17); + UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets", + ModbusParserTest18); +#endif /* UNITTESTS */ +} diff --git a/src/app-layer-modbus.h b/src/app-layer-modbus.h new file mode 100644 index 000000000000..a8545dfbdc8c --- /dev/null +++ b/src/app-layer-modbus.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + */ + +#ifndef __APP_LAYER_MODBUS_H__ +#define __APP_LAYER_MODBUS_H__ + +#include "decode.h" +#include "detect-engine-state.h" +#include "queue.h" + +/* Modbus Application Data Unit (ADU) + * and Protocol Data Unit (PDU) messages */ +enum { + MODBUS_DECODER_EVENT_INVALID_PROTOCOL_ID, + MODBUS_DECODER_EVENT_UNSOLICITED_RESPONSE, + MODBUS_DECODER_EVENT_INVALID_LENGTH, + MODBUS_DECODER_EVENT_INVALID_UNIT_IDENTIFIER, + MODBUS_DECODER_EVENT_INVALID_FUNCTION_CODE, + MODBUS_DECODER_EVENT_INVALID_VALUE, + MODBUS_DECODER_EVENT_INVALID_EXCEPTION_CODE, + MODBUS_DECODER_EVENT_VALUE_MISMATCH, + MODBUS_DECODER_EVENT_FLOODED, +}; + +/* Modbus Function Code Categories. */ +#define MODBUS_CAT_NONE 0x0 +#define MODBUS_CAT_PUBLIC_ASSIGNED (1<<0) +#define MODBUS_CAT_PUBLIC_UNASSIGNED (1<<1) +#define MODBUS_CAT_USER_DEFINED (1<<2) +#define MODBUS_CAT_RESERVED (1<<3) +#define MODBUS_CAT_ALL 0xFF + +/* Modbus Read/Write function and Access Types. */ +#define MODBUS_TYP_NONE 0x0 +#define MODBUS_TYP_ACCESS_MASK 0x03 +#define MODBUS_TYP_READ (1<<0) +#define MODBUS_TYP_WRITE (1<<1) +#define MODBUS_TYP_ACCESS_FUNCTION_MASK 0x3C +#define MODBUS_TYP_BIT_ACCESS_MASK 0x0C +#define MODBUS_TYP_DISCRETES (1<<2) +#define MODBUS_TYP_COILS (1<<3) +#define MODBUS_TYP_WORD_ACCESS_MASK 0x30 +#define MODBUS_TYP_INPUT (1<<4) +#define MODBUS_TYP_HOLDING (1<<5) +#define MODBUS_TYP_SINGLE (1<<6) +#define MODBUS_TYP_MULTIPLE (1<<7) +#define MODBUS_TYP_WRITE_SINGLE (MODBUS_TYP_WRITE | MODBUS_TYP_SINGLE) +#define MODBUS_TYP_WRITE_MULTIPLE (MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) +#define MODBUS_TYP_READ_WRITE_MULTIPLE (MODBUS_TYP_READ | MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE) + +/* Modbus Transaction Structure, request/response. */ +typedef struct ModbusTransaction_ { + struct ModbusState_ *modbus; + + uint64_t tx_num; /**< internal: id */ + uint32_t logged; /**< flags indicating which loggers have logged */ + uint16_t transactionId; + uint16_t length; + uint8_t function; + uint8_t category; + uint8_t type; + uint8_t replied; /**< bool indicating request is replied to. */ + + union { + uint16_t subFunction; + uint8_t mei; + struct { + struct { + uint16_t address; + uint16_t quantity; + } read; + struct { + uint16_t address; + uint16_t quantity; + uint8_t count; + } write; + }; + }; + uint16_t *data; /**< to store data to write, bit is converted in 16bits. */ + + AppLayerDecoderEvents *decoder_events; /**< per tx events */ + DetectEngineState *de_state; + + TAILQ_ENTRY(ModbusTransaction_) next; +} ModbusTransaction; + +/* Modbus State Structure. */ +typedef struct ModbusState_ { + TAILQ_HEAD(, ModbusTransaction_) tx_list; /**< transaction list */ + ModbusTransaction *curr; /**< ptr to current tx */ + uint64_t transaction_max; + uint32_t unreplied_cnt; /**< number of unreplied requests */ + uint16_t events; + uint8_t givenup; /**< bool indicating flood. */ +} ModbusState; + +void RegisterModbusParsers(void); +void ModbusParserRegisterTests(void); + +#endif /* __APP_LAYER_MODBUS_H__ */ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index e665cceed6a1..49975175ebae 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -57,6 +57,10 @@ #include "app-layer-smtp.h" #include "app-layer-dns-udp.h" #include "app-layer-dns-tcp.h" +#include "app-layer-modbus.h" +#include "app-layer-enip.h" +#include "app-layer-dnp3.h" +#include "app-layer-template.h" #include "conf.h" #include "util-spm.h" @@ -105,6 +109,16 @@ typedef struct AppLayerParserProtoCtx_ int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); + int (*StateGetTxLogged)(void *alstate, void *tx, uint32_t logger); + void (*StateSetTxLogged)(void *alstate, void *tx, uint32_t logger); + + int (*StateHasTxDetectState)(void *alstate); + DetectEngineState *(*GetTxDetectState)(void *tx); + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *); + + /* each app-layer has its own value */ + uint32_t stream_depth; + /* Indicates the direction the parser is ready to see the data * the first time for a flow. Values accepted - * STREAM_TOSERVER, STREAM_TOCLIENT */ @@ -122,8 +136,6 @@ typedef struct AppLayerParserCtx_ { struct AppLayerParserState_ { uint8_t flags; - /* State version, incremented for each update. Can wrap around. */ - uint16_t version; /* Indicates the current transaction that is being inspected. * We have a var per direction. */ uint64_t inspect_id[2]; @@ -140,6 +152,13 @@ struct AppLayerParserState_ { * Post 2.0 let's look at changing this to move it out to app-layer.c. */ static AppLayerParserCtx alp_ctx; +int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto) +{ + uint8_t ipproto_map = FlowGetProtoMapping(ipproto); + + return (alp_ctx.ctxs[ipproto_map][alproto].StateAlloc != NULL) ? 1 : 0; +} + AppLayerParserState *AppLayerParserStateAlloc(void) { SCEnter(); @@ -168,6 +187,9 @@ int AppLayerParserSetup(void) { SCEnter(); + AppProto alproto = 0; + int flow_proto = 0; + memset(&alp_ctx, 0, sizeof(alp_ctx)); /* set the default tx handler if none was set explicitly */ @@ -175,6 +197,14 @@ int AppLayerParserSetup(void) RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveDetectLog); } + /* lets set a default value for stream_depth */ + for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + alp_ctx.ctxs[flow_proto][alproto].stream_depth = + stream_config.reassembly_depth; + } + } + SCReturnInt(0); } @@ -182,6 +212,8 @@ int AppLayerParserDeSetup(void) { SCEnter(); + SMTPParserCleanup(); + SCReturnInt(0); } @@ -231,6 +263,10 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) SCReturn; } +/** \brief check if a parser is enabled in the config + * Returns enabled always if: were running unittests and + * when compiled with --enable-afl + */ int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name) { @@ -241,6 +277,9 @@ int AppLayerParserConfParserEnabled(const char *ipproto, ConfNode *node; int r; +#ifdef AFLFUZZ_APPLAYER + goto enabled; +#endif if (RunmodeIsUnittests()) goto enabled; @@ -274,12 +313,12 @@ int AppLayerParserConfParserEnabled(const char *ipproto, } } - if (strcasecmp(node->val, "yes") == 0) { + if (ConfValIsTrue(node->val)) { goto enabled; - } else if (strcasecmp(node->val, "no") == 0) { + } else if (ConfValIsFalse(node->val)) { goto disabled; } else if (strcasecmp(node->val, "detection-only") == 0) { - goto enabled; + goto disabled; } else { SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); exit(EXIT_FAILURE); @@ -380,6 +419,21 @@ void AppLayerParserRegisterHasEventsFunc(uint8_t ipproto, AppProto alproto, SCReturn; } +void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, + int (*StateGetTxLogged)(void *, void *, uint32_t), + void (*StateSetTxLogged)(void *, void *, uint32_t)) +{ + SCEnter(); + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxLogged = + StateGetTxLogged; + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateSetTxLogged = + StateSetTxLogged; + + SCReturn; +} + void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto) { SCEnter(); @@ -443,13 +497,12 @@ void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, SCReturn; } -void AppLayerParserRegisterGetStateProgressCompletionStatus(uint8_t ipproto, - AppProto alproto, +void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int (*StateGetProgressCompletionStatus)(uint8_t direction)) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. StateGetProgressCompletionStatus = StateGetProgressCompletionStatus; SCReturn; @@ -467,6 +520,20 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, SCReturn; } +void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + int (*StateHasTxDetectState)(void *alstate), + DetectEngineState *(*GetTxDetectState)(void *tx), + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)) +{ + SCEnter(); + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState = StateHasTxDetectState; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState = GetTxDetectState; + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState = SetTxDetectState; + + SCReturn; +} + /***** Get and transaction functions *****/ void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto) @@ -499,6 +566,35 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a SCReturn; } +void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, uint32_t logger) +{ + SCEnter(); + + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateSetTxLogged != NULL) { + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateSetTxLogged(alstate, tx, logger); + } + + SCReturn; +} + +int AppLayerParserGetTxLogged(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, uint32_t logger) +{ + SCEnter(); + + uint8_t r = 0; + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetTxLogged != NULL) { + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetTxLogged(alstate, tx, logger); + } + + SCReturnInt(r); +} + uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate) { SCEnter(); @@ -506,12 +602,12 @@ uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate) SCReturnCT((pstate == NULL) ? 0 : pstate->log_id, "uint64_t"); } -void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate) +void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id) { SCEnter(); if (pstate != NULL) - pstate->log_id++; + pstate->log_id = tx_id; SCReturn; } @@ -527,15 +623,15 @@ uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint } void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, - uint8_t ipproto, AppProto alproto, void *alstate, - uint8_t direction) + const uint8_t ipproto, const AppProto alproto, + void *alstate, const uint8_t flags) { SCEnter(); - uint8_t dir = (direction & STREAM_TOSERVER) ? 0 : 1; + int direction = (flags & STREAM_TOSERVER) ? 0 : 1; uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate); - uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, direction); - int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(ipproto, alproto, direction); + uint64_t idx = AppLayerParserGetTransactionInspectId(pstate, flags); + int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(alproto, flags); void *tx; int state_progress; @@ -543,13 +639,13 @@ void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx); if (tx == NULL) continue; - state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, direction); + state_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags); if (state_progress >= state_done_progress) continue; else break; } - pstate->inspect_id[dir] = idx; + pstate->inspect_id[direction] = idx; SCReturn; } @@ -584,12 +680,6 @@ AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alp SCReturnPtr(ptr, "AppLayerDecoderEvents *"); } -uint16_t AppLayerParserGetStateVersion(AppLayerParserState *pstate) -{ - SCEnter(); - SCReturnCT((pstate == NULL) ? 0 : pstate->version, "uint16_t"); -} - FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction) { @@ -641,10 +731,9 @@ uint64_t AppLayerTransactionGetActiveLogOnly(Flow *f, uint8_t flags) } /* logger is disabled, return highest 'complete' tx id */ - uint8_t direction = flags & (STREAM_TOSERVER|STREAM_TOCLIENT); uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate); - uint64_t idx = AppLayerParserGetTransactionInspectId(f->alparser, direction); - int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->proto, f->alproto, direction); + uint64_t idx = AppLayerParserGetTransactionInspectId(f->alparser, flags); + int state_done_progress = AppLayerParserGetStateProgressCompletionStatus(f->alproto, flags); void *tx; int state_progress; @@ -652,7 +741,7 @@ uint64_t AppLayerTransactionGetActiveLogOnly(Flow *f, uint8_t flags) tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, idx); if (tx == NULL) continue; - state_progress = AppLayerParserGetStateProgress(f->proto, f->alproto, tx, direction); + state_progress = AppLayerParserGetStateProgress(f->proto, f->alproto, tx, flags); if (state_progress >= state_done_progress) continue; else @@ -706,13 +795,26 @@ static void AppLayerParserTransactionsCleanup(Flow *f) } } +#define IS_DISRUPTED(flags) \ + ((flags) & (STREAM_DEPTH|STREAM_GAP)) + +/** + * \brief get the progress value for a tx/protocol + * + * If the stream is disrupted, we return the 'completion' value. + */ int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, - void *alstate, uint8_t direction) + void *alstate, uint8_t flags) { SCEnter(); int r = 0; - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetProgress(alstate, direction); + if (unlikely(IS_DISRUPTED(flags))) { + r = alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. + StateGetProgressCompletionStatus(flags); + } else { + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + StateGetProgress(alstate, flags); + } SCReturnInt(r); } @@ -734,12 +836,12 @@ void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint SCReturnPtr(r, "void *"); } -int AppLayerParserGetStateProgressCompletionStatus(uint8_t ipproto, AppProto alproto, - uint8_t direction) +int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, + uint8_t direction) { SCEnter(); int r = 0; - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. + r = alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto]. StateGetProgressCompletionStatus(direction); SCReturnInt(r); } @@ -781,9 +883,52 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, SCReturnCT(active_id, "uint64_t"); } +int AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto) +{ + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetFiles != NULL) + return TRUE; + return FALSE; +} + +int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto) +{ + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState != NULL) + return TRUE; + return FALSE; +} + +int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate) +{ + int r; + SCEnter(); + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState == NULL) + return -ENOSYS; + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState(alstate); + SCReturnInt(r); +} + +DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx) +{ + SCEnter(); + DetectEngineState *s; + s = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx); + SCReturnPtr(s, "DetectEngineState"); +} + +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, DetectEngineState *s) +{ + int r; + SCEnter(); + if ((alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx) != NULL)) + SCReturnInt(-EBUSY); + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(alstate, tx, s); + SCReturnInt(r); +} + /***** General *****/ -int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, +int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len) { SCEnter(); @@ -793,6 +938,7 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp AppLayerParserState *pstate = NULL; AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][alproto]; void *alstate = NULL; + uint64_t p_tx_cnt = 0; /* we don't have the parser registered for this protocol */ if (p->StateAlloc == NULL) @@ -815,9 +961,6 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp if (pstate == NULL) goto error; } - pstate->version++; - SCLogDebug("app layer parser state version incremented to %"PRIu16, - pstate->version); if (flags & STREAM_EOF) AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); @@ -834,8 +977,12 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp alstate, AppLayerGetProtoName(f->alproto)); } + if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) { + p_tx_cnt = AppLayerParserGetTxCnt(f->proto, alproto, f->alstate); + } + /* invoke the recursive parser, but only on data. We may get empty msgs on EOF */ - if (input_len > 0) { + if (input_len > 0 || (flags & STREAM_EOF)) { /* invoke the parser */ if (p->Parser[(flags & STREAM_TOSERVER) ? 0 : 1](f, alstate, pstate, input, input_len, @@ -849,17 +996,20 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION) { AppLayerParserSetEOF(pstate); FlowSetNoPayloadInspectionFlag(f); - FlowSetSessionNoApplayerInspectionFlag(f); - /* Set the no reassembly flag for both the stream in this TcpSession */ - if (f->proto == IPPROTO_TCP && pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { - /* Used only if it's TCP */ - TcpSession *ssn = f->protoctx; - if (ssn != NULL) { - StreamTcpSetSessionNoReassemblyFlag(ssn, - flags & STREAM_TOCLIENT ? 1 : 0); - StreamTcpSetSessionNoReassemblyFlag(ssn, - flags & STREAM_TOSERVER ? 1 : 0); + if (f->proto == IPPROTO_TCP) { + StreamTcpDisableAppLayer(f); + + /* Set the no reassembly flag for both the stream in this TcpSession */ + if (pstate->flags & APP_LAYER_PARSER_NO_REASSEMBLY) { + /* Used only if it's TCP */ + TcpSession *ssn = f->protoctx; + if (ssn != NULL) { + StreamTcpSetSessionNoReassemblyFlag(ssn, + flags & STREAM_TOCLIENT ? 1 : 0); + StreamTcpSetSessionNoReassemblyFlag(ssn, + flags & STREAM_TOSERVER ? 1 : 0); + } } } } @@ -878,6 +1028,14 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp } } + if (AppLayerParserProtocolIsTxAware(f->proto, alproto)) { + if (likely(tv)) { + uint64_t cur_tx_cnt = AppLayerParserGetTxCnt(f->proto, alproto, f->alstate); + if (cur_tx_cnt > p_tx_cnt) { + AppLayerIncTxCounter(tv, f, cur_tx_cnt - p_tx_cnt); + } + } + } /* next, see if we can get rid of transactions now */ AppLayerParserTransactionsCleanup(f); @@ -890,7 +1048,9 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp error: /* Set the no app layer inspection flag for both * the stream in this Flow */ - FlowSetSessionNoApplayerInspectionFlag(f); + if (f->proto == IPPROTO_TCP) { + StreamTcpDisableAppLayer(f); + } AppLayerParserSetEOF(pstate); SCReturnInt(-1); } @@ -903,9 +1063,6 @@ void AppLayerParserSetEOF(AppLayerParserState *pstate) goto end; AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_EOF); - /* increase version so we will inspect it one more time - * with the EOF flags now set */ - pstate->version++; end: SCReturn; @@ -955,6 +1112,15 @@ int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto, SCReturnInt(1); } +/** \brief simpler way to globally test if a alproto is registered + * and fully enabled in the configuration. + */ +int AppLayerParserIsTxAware(AppProto alproto) +{ + return (alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto] + .StateGetProgressCompletionStatus != NULL); +} + int AppLayerParserProtocolIsTxAware(uint8_t ipproto, AppProto alproto) { SCEnter(); @@ -997,6 +1163,20 @@ void AppLayerParserTriggerRawStreamReassembly(Flow *f) SCReturn; } +void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth) +{ + SCEnter(); + + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].stream_depth = stream_depth; + + SCReturn; +} + +uint32_t AppLayerParserGetStreamDepth(uint8_t ipproto, AppProto alproto) +{ + SCReturnInt(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].stream_depth); +} + /***** Cleanup *****/ void AppLayerParserStateCleanup(uint8_t ipproto, AppProto alproto, void *alstate, @@ -1033,6 +1213,11 @@ void AppLayerParserRegisterProtocolParsers(void) RegisterSMTPParsers(); RegisterDNSUDPParsers(); RegisterDNSTCPParsers(); + RegisterModbusParsers(); + RegisterENIPUDPParsers(); + RegisterENIPTCPParsers(); + RegisterDNP3Parsers(); + RegisterTemplateParsers(); /** IMAP */ AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap"); @@ -1105,15 +1290,176 @@ void AppLayerParserStatePrintDetails(AppLayerParserState *pstate) "p->inspect_id[0](%"PRIu64"), " "p->inspect_id[1](%"PRIu64"), " "p->log_id(%"PRIu64"), " - "p->version(%"PRIu16"), " "p->decoder_events(%p).", pstate, p->inspect_id[0], p->inspect_id[1], p->log_id, - p->version, p->decoder_events); + p->decoder_events); SCReturn; } #endif +#ifdef AFLFUZZ_APPLAYER +int AppLayerParserRequestFromFile(uint8_t ipproto, AppProto alproto, char *filename) +{ + int result = 1; + Flow *f = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = SCCalloc(1, sizeof(Flow)); + if (f == NULL) + goto end; + FLOW_INITIALIZE(f); + + f->flags |= FLOW_IPV4; + f->src.addr_data32[0] = 0x01020304; + f->dst.addr_data32[0] = 0x05060708; + f->sp = 10000; + f->dp = 80; + f->protoctx = &ssn; + f->proto = ipproto; + f->protomap = FlowGetProtoMapping(f->proto); + f->alproto = alproto; + + uint8_t buffer[64]; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + int start = 1; + while (1) { + int done = 0; + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) + done = 1; + + //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + + uint8_t flags = STREAM_TOSERVER; + + if (start--) { + flags |= STREAM_START; + } + if (done) { + flags |= STREAM_EOF; + } + //PrintRawDataFp(stdout, buffer, result); + + (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, + buffer, size); + if (done) + break; + } + + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + result = 0; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (f != NULL) { + FlowFree(f); + } + return result; +} + +int AppLayerParserFromFile(uint8_t ipproto, AppProto alproto, char *filename) +{ + int result = 1; + Flow *f = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&ssn, 0, sizeof(ssn)); + + f = SCCalloc(1, sizeof(Flow)); + if (f == NULL) + goto end; + FLOW_INITIALIZE(f); + + f->flags |= FLOW_IPV4; + f->src.addr_data32[0] = 0x01020304; + f->dst.addr_data32[0] = 0x05060708; + f->sp = 10000; + f->dp = 80; + f->protoctx = &ssn; + f->proto = ipproto; + f->protomap = FlowGetProtoMapping(f->proto); + f->alproto = alproto; + + uint8_t buffer[64]; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + int start = 1; + int flip = 0; + while (1) { + int done = 0; + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) + done = 1; + + //SCLogInfo("result %u done %d start %d", (uint)result, done, start); + + uint8_t flags = 0; + if (flip) { + flags = STREAM_TOCLIENT; + flip = 0; + } else { + flags = STREAM_TOSERVER; + flip = 1; + } + + if (start--) { + flags |= STREAM_START; + } + if (done) { + flags |= STREAM_EOF; + } + //PrintRawDataFp(stdout, buffer, result); + + (void)AppLayerParserParse(NULL, alp_tctx, f, alproto, flags, + buffer, size); + if (done) + break; + } + + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + result = 0; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (f != NULL) { + FlowFree(f); + } + return result; +} +#endif /* AFLFUZZ_APPLAYER */ /***** Unittests *****/ @@ -1214,17 +1560,18 @@ static int AppLayerParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, - testbuf, testlen); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, + STREAM_TOSERVER | STREAM_EOF, testbuf, + testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: ", r); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); - if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { + if (!(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { printf("flag should have been set, but is not: "); goto end; } @@ -1267,16 +1614,17 @@ static int AppLayerParserTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_TEST, STREAM_TOSERVER|STREAM_EOF, testbuf, - testlen); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_TEST, + STREAM_TOSERVER | STREAM_EOF, testbuf, + testlen); if (r != -1) { printf("returned %" PRId32 ", expected -1: \n", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); end: AppLayerParserRestoreParserTable(); @@ -1303,8 +1651,8 @@ void AppLayerParserRegisterUnittests(void) } } - UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01, 1); - UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02, 1); + UtRegisterTest("AppLayerParserTest01", AppLayerParserTest01); + UtRegisterTest("AppLayerParserTest02", AppLayerParserTest02); SCReturn; } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index a000f0fbb082..29e668ce7f14 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -26,13 +26,16 @@ #define __APP_LAYER_PARSER_H__ #include "app-layer-events.h" +#include "detect-engine-state.h" #include "util-file.h" +#include "stream-tcp-private.h" #define APP_LAYER_PARSER_EOF 0x01 #define APP_LAYER_PARSER_NO_INSPECTION 0x02 #define APP_LAYER_PARSER_NO_REASSEMBLY 0x04 #define APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD 0x08 +int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto); /***** transaction handling *****/ @@ -124,6 +127,9 @@ void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto proto, AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t)); void AppLayerParserRegisterHasEventsFunc(uint8_t ipproto, AppProto alproto, int (*StateHasEvents)(void *)); +void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, + int (*StateGetTxLogged)(void *, void *, uint32_t), + void (*StateSetTxLogged)(void *, void *, uint32_t)); void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto); void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, void (*Truncate)(void *, uint8_t)); @@ -135,12 +141,18 @@ void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t (*StateGetTxCnt)(void *alstate)); void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id)); -void AppLayerParserRegisterGetStateProgressCompletionStatus(uint8_t ipproto, - AppProto alproto, +void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int (*StateGetStateProgressCompletionStatus)(uint8_t direction)); void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type)); +void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + int (*StateHasTxDetectState)(void *alstate), + DetectEngineState *(*GetTxDetectState)(void *tx), + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)); +void AppLayerParserRegisterGetStreamDepth(uint8_t ipproto, + AppProto alproto, + uint32_t (*GetStreamDepth)(void)); /***** Get and transaction functions *****/ @@ -150,24 +162,26 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a uint64_t AppLayerParserGetTransactionLogId(AppLayerParserState *pstate); -void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate); +void AppLayerParserSetTransactionLogId(AppLayerParserState *pstate, uint64_t tx_id); +void AppLayerParserSetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, + void *tx, uint32_t logger); +int AppLayerParserGetTxLogged(uint8_t ipproto, AppProto alproto, void *alstate, + void *tx, uint32_t logger); uint64_t AppLayerParserGetTransactionInspectId(AppLayerParserState *pstate, uint8_t direction); void AppLayerParserSetTransactionInspectId(AppLayerParserState *pstate, - uint8_t ipproto, AppProto alproto, void *alstate, - uint8_t direction); + const uint8_t ipproto, const AppProto alproto, void *alstate, + const uint8_t flags); AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate); void AppLayerParserSetDecoderEvents(AppLayerParserState *pstate, AppLayerDecoderEvents *devents); AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id); -uint16_t AppLayerParserGetStateVersion(AppLayerParserState *pstate); FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction); int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t direction); uint64_t AppLayerParserGetTxCnt(uint8_t ipproto, AppProto alproto, void *alstate); void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id); -int AppLayerParserGetStateProgressCompletionStatus(uint8_t ipproto, AppProto alproto, - uint8_t direction); +int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction); int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *event_name, int *event_id, AppLayerEventType *event_type); @@ -175,18 +189,27 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, A uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto); +int AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto); +int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto); +int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate); +DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx); +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate, void *tx, DetectEngineState *s); + /***** General *****/ -int AppLayerParserParse(AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto, +int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len); void AppLayerParserSetEOF(AppLayerParserState *pstate); int AppLayerParserHasDecoderEvents(uint8_t ipproto, AppProto alproto, void *alstate, AppLayerParserState *pstate, uint8_t flags); +int AppLayerParserIsTxAware(AppProto alproto); int AppLayerParserProtocolIsTxAware(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolIsTxEventAware(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolSupportsTxs(uint8_t ipproto, AppProto alproto); int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto); void AppLayerParserTriggerRawStreamReassembly(Flow *f); +void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t stream_depth); +uint32_t AppLayerParserGetStreamDepth(uint8_t ipproto, AppProto alproto); /***** Cleanup *****/ @@ -212,6 +235,11 @@ void AppLayerParserStateFree(AppLayerParserState *pstate); void AppLayerParserStatePrintDetails(AppLayerParserState *pstate); #endif +#ifdef AFLFUZZ_APPLAYER +int AppLayerParserRequestFromFile(uint8_t ipproto, AppProto alproto, char *filename); +int AppLayerParserFromFile(uint8_t ipproto, AppProto alproto, char *filename); +#endif + /***** Unittests *****/ #ifdef UNITTESTS diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index fd874125711d..9830af5b2cbd 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -30,8 +30,9 @@ const char *AppProtoToString(AppProto alproto) { const char *proto_name = NULL; + enum AppProtoEnum proto = alproto; - switch (alproto) { + switch (proto) { case ALPROTO_HTTP: proto_name = "http"; break; @@ -71,7 +72,21 @@ const char *AppProtoToString(AppProto alproto) case ALPROTO_DNS: proto_name = "dns"; break; + case ALPROTO_MODBUS: + proto_name = "modbus"; + break; + case ALPROTO_ENIP: + proto_name = "enip"; + break; + case ALPROTO_DNP3: + proto_name = "dnp3"; + break; + case ALPROTO_TEMPLATE: + proto_name = "template"; + break; case ALPROTO_FAILED: + proto_name = "failed"; + break; #ifdef UNITTESTS case ALPROTO_TEST: #endif diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 39c729c41a33..bcecc79577e4 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -25,7 +25,7 @@ #ifndef __APP_LAYER_PROTOS_H__ #define __APP_LAYER_PROTOS_H__ -enum { +enum AppProtoEnum { ALPROTO_UNKNOWN = 0, ALPROTO_HTTP, ALPROTO_FTP, @@ -41,6 +41,10 @@ enum { ALPROTO_IRC, ALPROTO_DNS, + ALPROTO_MODBUS, + ALPROTO_ENIP, + ALPROTO_DNP3, + ALPROTO_TEMPLATE, /* used by the probing parser when alproto detection fails * permanently for that particular stream */ @@ -52,6 +56,7 @@ enum { ALPROTO_MAX, }; +/* not using the enum as that is a unsigned int, so 4 bytes */ typedef uint16_t AppProto; /** diff --git a/src/app-layer-smb.c b/src/app-layer-smb.c index b7ae55d3d196..9c8031261f15 100644 --- a/src/app-layer-smb.c +++ b/src/app-layer-smb.c @@ -42,6 +42,7 @@ #include "app-layer-detect-proto.h" #include "app-layer-protos.h" #include "app-layer-parser.h" +#include "app-layer-dcerpc.h" #include "util-spm.h" #include "util-unittest.h" @@ -413,7 +414,7 @@ static uint32_t SMBParseTransact(Flow *f, void *smb_state, switch (sstate->andx.andxbytesprocessed) { case 0: sstate->andx.paddingparsed = 0; - if (input_len >= sstate->wordcount.wordcount) { + if (input_len >= 26) { sstate->andx.datalength = *(p + 22); sstate->andx.datalength |= *(p + 23) << 8; sstate->andx.dataoffset = *(p + 24); @@ -422,8 +423,8 @@ static uint32_t SMBParseTransact(Flow *f, void *smb_state, sstate->andx.datalength |= (uint64_t) *(p + 15) << 48; sstate->andx.datalength |= (uint64_t) *(p + 16) << 40; sstate->andx.datalength |= (uint64_t) *(p + 17) << 32; - sstate->bytesprocessed += sstate->wordcount.wordcount; - sstate->andx.andxbytesprocessed += sstate->wordcount.wordcount; + sstate->bytesprocessed += 26; + sstate->andx.andxbytesprocessed += 26; SCReturnUInt(sstate->wordcount.wordcount); } else { /* total parameter count 1 */ @@ -669,7 +670,7 @@ static int32_t DataParser(void *smb_state, AppLayerParserState *pstate, int32_t parsed = 0; if (sstate->andx.paddingparsed) { - parsed = DCERPCParser(&sstate->dcerpc, input, input_len); + parsed = DCERPCParser(&sstate->ds.dcerpc, input, input_len); if (parsed == -1 || parsed > sstate->bytecount.bytecountleft || parsed > (int32_t)input_len) { SCReturnInt(-1); } else { @@ -677,6 +678,7 @@ static int32_t DataParser(void *smb_state, AppLayerParserState *pstate, sstate->bytesprocessed += parsed; sstate->bytecount.bytecountleft -= parsed; input_len -= parsed; + (void)input_len; /* for scan-build */ } } SCReturnInt(parsed); @@ -832,7 +834,9 @@ static uint32_t SMBParseByteCount(Flow *f, void *smb_state, sres = DataParser(sstate, pstate, input + parsed, input_len); if (sres != -1 && sres <= (int32_t)input_len) { parsed += (uint32_t)sres; + (void)parsed; /* for scan-build */ input_len -= (uint32_t)sres; + (void)input_len; /* for scan-build */ } else { /* Did not Validate as DCERPC over SMB */ while (sstate->bytecount.bytecountleft-- && input_len--) { SCLogDebug("0x%02x bytecount %"PRIu16"/%"PRIu16" input_len %"PRIu32, *p, @@ -945,10 +949,10 @@ static int SMBParseHeader(Flow *f, void *smb_state, SCReturnInt(-1); } sstate->smb.command = *(p + 4); - sstate->smb.status = *(p + 5) << 24; - sstate->smb.status |= *(p + 6) << 16; - sstate->smb.status |= *(p + 7) << 8; - sstate->smb.status |= *(p + 8); + sstate->smb.status = (uint32_t) *(p + 5) << 24; + sstate->smb.status |= (uint32_t) *(p + 6) << 16; + sstate->smb.status |= (uint32_t) *(p + 7) << 8; + sstate->smb.status |= (uint32_t) *(p + 8); sstate->smb.flags = *(p + 9); sstate->smb.flags2 = *(p + 10) << 8; sstate->smb.flags2 |= *(p + 11); @@ -1172,6 +1176,10 @@ static int SMBParse(Flow *f, void *smb_state, AppLayerParserState *pstate, SCReturnInt(0); } + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } + if (sstate->bytesprocessed != 0 && sstate->data_needed_for_dir != dir) { SCReturnInt(-1); } @@ -1422,12 +1430,12 @@ static void *SMBStateAlloc(void) { SCEnter(); - void *s = SCMalloc(sizeof(SMBState)); + SMBState *s = (SMBState *)SCCalloc(1, sizeof(SMBState)); if (unlikely(s == NULL)) { SCReturnPtr(NULL, "void"); } - memset(s, 0, sizeof(SMBState)); + DCERPCInit(&s->ds.dcerpc); SCReturnPtr(s, "void"); } @@ -1440,28 +1448,64 @@ static void SMBStateFree(void *s) SCEnter(); SMBState *sstate = (SMBState *) s; - DCERPCUuidEntry *item; + DCERPCCleanup(&sstate->ds.dcerpc); - while ((item = TAILQ_FIRST(&sstate->dcerpc.dcerpcbindbindack.uuid_list))) { - //printUUID("Free", item); - TAILQ_REMOVE(&sstate->dcerpc.dcerpcbindbindack.uuid_list, item, next); - SCFree(item); - } - if (sstate->dcerpc.dcerpcrequest.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcrequest.stub_data_buffer); - sstate->dcerpc.dcerpcrequest.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcrequest.stub_data_buffer_len = 0; - } - if (sstate->dcerpc.dcerpcresponse.stub_data_buffer != NULL) { - SCFree(sstate->dcerpc.dcerpcresponse.stub_data_buffer); - sstate->dcerpc.dcerpcresponse.stub_data_buffer = NULL; - sstate->dcerpc.dcerpcresponse.stub_data_buffer_len = 0; + if (sstate->ds.de_state) { + DetectEngineStateFree(sstate->ds.de_state); } SCFree(s); SCReturn; } +static int SMBStateHasTxDetectState(void *state) +{ + SMBState *smb_state = (SMBState *)state; + if (smb_state->ds.de_state) + return 1; + return 0; +} + +static int SMBSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SMBState *smb_state = (SMBState *)state; + smb_state->ds.de_state = de_state; + return 0; +} + +static DetectEngineState *SMBGetTxDetectState(void *vtx) +{ + SMBState *smb_state = (SMBState *)vtx; + return smb_state->ds.de_state; +} + +static void SMBStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *SMBGetTx(void *state, uint64_t tx_id) +{ + SMBState *smb_state = (SMBState *)state; + return smb_state; +} + +static uint64_t SMBGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static int SMBGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return 1; +} + +static int SMBGetAlstateProgress(void *tx, uint8_t direction) +{ + return 0; +} + #define SMB_PROBING_PARSER_MIN_DEPTH 8 static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset) @@ -1484,7 +1528,7 @@ static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset case NBSS_RETARGET_SESSION_RESPONSE: case NBSS_SESSION_KEEP_ALIVE: len = (input[1] & 0x01) << 16; - len = input[2] << 8; + len |= input[2] << 8; len |= input[3]; break; default: @@ -1508,18 +1552,17 @@ static uint16_t SMBProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset static int SMBRegisterPatternsForProtocolDetection(void) { - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, - "|ff|SMB", 8, 4, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, - "|fe|SMB", 8, 4, STREAM_TOSERVER) < 0) - { - return -1; - } - - return 0; + int r = 0; + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, + "|ff|SMB", 8, 4, STREAM_TOSERVER); + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, + "|ff|SMB", 8, 4, STREAM_TOCLIENT); + + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, + "|fe|SMB", 8, 4, STREAM_TOSERVER); + r |= AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, + "|fe|SMB", 8, 4, STREAM_TOCLIENT); + return r == 0 ? 0 : -1; } void RegisterSMBParsers(void) @@ -1537,12 +1580,12 @@ void RegisterSMBParsers(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser); + SMBProbingParser, SMBProbingParser); } else { AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, - SMBProbingParser); + SMBProbingParser, SMBProbingParser); } AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOSERVER); @@ -1556,8 +1599,22 @@ void RegisterSMBParsers(void) AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOSERVER, SMBParseRequest); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMB, STREAM_TOCLIENT, SMBParseResponse); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMB, SMBStateAlloc, SMBStateFree); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMB, SMBStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMB, SMBStateHasTxDetectState, + SMBGetTxDetectState, SMBSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMB, SMBGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMB, SMBGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMB, SMBGetAlstateProgress); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMB, + SMBGetAlstateProgressCompletionStatus); } else { - SCLogInfo("Parsed disabled for %s protocol. Protocol detection" + SCLogInfo("Parsed disabled for %s protocol. Protocol detection " "still on.", proto_name); } @@ -1569,6 +1626,7 @@ void RegisterSMBParsers(void) /* UNITTESTS */ #ifdef UNITTESTS +#include "flow-util.h" /** * \test SMBParserTest01 tests the NBSS and SMB header decoding @@ -1596,19 +1654,21 @@ int SMBParserTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -1636,6 +1696,7 @@ int SMBParserTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1673,19 +1734,21 @@ int SMBParserTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_EOF, smbbuf, smblen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_EOF, smbbuf, smblen); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -1708,12 +1771,13 @@ int SMBParserTest02(void) goto end; } - printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); + printUUID("BIND", smb_state->ds.dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1969,19 +2033,21 @@ int SMBParserTest03(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -1994,28 +2060,31 @@ int SMBParserTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - printUUID("BIND", smb_state->dcerpc.dcerpcbindbindack.uuid_entry); + FLOWLOCK_UNLOCK(&f); + printUUID("BIND", smb_state->ds.dcerpc.dcerpcbindbindack.uuid_entry); result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2086,19 +2155,21 @@ int SMBParserTest04(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER|STREAM_START, smbbuf1, smblen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2111,36 +2182,40 @@ int SMBParserTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf3, smblen3); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf3, smblen3); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf4, smblen4); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf4, smblen4); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2210,7 +2285,7 @@ int SMBParserTest05(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser); + SMBProbingParser, NULL); AppLayerProtoDetectPrepareState(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); @@ -2241,6 +2316,7 @@ int SMBParserTest05(void) AppLayerProtoDetectUnittestCtxRestore(); if (alpd_tctx != NULL) AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + FLOW_DESTROY(&f); return result; } @@ -2293,7 +2369,7 @@ int SMBParserTest06(void) ALPROTO_SMB, SMB_PROBING_PARSER_MIN_DEPTH, 0, STREAM_TOSERVER, - SMBProbingParser); + SMBProbingParser, NULL); AppLayerProtoDetectPrepareState(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); @@ -2324,6 +2400,7 @@ int SMBParserTest06(void) AppLayerProtoDetectUnittestCtxRestore(); if (alpd_tctx != NULL) AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + FLOW_DESTROY(&f); return result; } @@ -2341,19 +2418,21 @@ int SMBParserTest07(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2382,6 +2461,7 @@ int SMBParserTest07(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2415,19 +2495,21 @@ int SMBParserTest08(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOCLIENT | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2451,14 +2533,15 @@ int SMBParserTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("we should expect SMB command 0x%02x , got 0x%02x : ", @@ -2482,6 +2565,7 @@ int SMBParserTest08(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2529,19 +2613,21 @@ int SMBParserTest09(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2565,14 +2651,15 @@ int SMBParserTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, smbbuf2, smblen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER, + smbbuf2, smblen2); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smb_state->smb.command != SMB_COM_NEGOTIATE) { printf("we should expect SMB command 0x%02x , got 0x%02x : ", @@ -2596,6 +2683,7 @@ int SMBParserTest09(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2651,19 +2739,21 @@ int SMBParserTest10(void) int r = 0; memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, + STREAM_TOSERVER | STREAM_START, smbbuf1, smblen1); if (r != 0) { printf("smb header check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMBState *smb_state = f.alstate; if (smb_state == NULL) { @@ -2676,20 +2766,22 @@ int SMBParserTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, smbbuf2, smblen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB, STREAM_TOCLIENT, + smbbuf2, smblen2); if (r == 0) { printf("smb parser didn't return fail\n"); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2698,16 +2790,16 @@ int SMBParserTest10(void) void SMBParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SMBParserTest01", SMBParserTest01, 1); - UtRegisterTest("SMBParserTest02", SMBParserTest02, 1); - UtRegisterTest("SMBParserTest03", SMBParserTest03, 1); - UtRegisterTest("SMBParserTest04", SMBParserTest04, 1); - UtRegisterTest("SMBParserTest05", SMBParserTest05, 1); - UtRegisterTest("SMBParserTest06", SMBParserTest06, 1); - UtRegisterTest("SMBParserTest07", SMBParserTest07, 1); - UtRegisterTest("SMBParserTest08", SMBParserTest08, 1); - UtRegisterTest("SMBParserTest09", SMBParserTest09, 1); - UtRegisterTest("SMBParserTest10", SMBParserTest10, 1); + UtRegisterTest("SMBParserTest01", SMBParserTest01); + UtRegisterTest("SMBParserTest02", SMBParserTest02); + UtRegisterTest("SMBParserTest03", SMBParserTest03); + UtRegisterTest("SMBParserTest04", SMBParserTest04); + UtRegisterTest("SMBParserTest05", SMBParserTest05); + UtRegisterTest("SMBParserTest06", SMBParserTest06); + UtRegisterTest("SMBParserTest07", SMBParserTest07); + UtRegisterTest("SMBParserTest08", SMBParserTest08); + UtRegisterTest("SMBParserTest09", SMBParserTest09); + UtRegisterTest("SMBParserTest10", SMBParserTest10); #endif } diff --git a/src/app-layer-smb.h b/src/app-layer-smb.h index 48d4fa84308a..8e7ec4fadcb0 100644 --- a/src/app-layer-smb.h +++ b/src/app-layer-smb.h @@ -30,6 +30,7 @@ #include "stream.h" #include "app-layer-nbss.h" #include "app-layer-dcerpc-common.h" +#include "app-layer-dcerpc.h" typedef struct SMBHdr_ { uint8_t protocol[4]; @@ -83,7 +84,7 @@ typedef struct SMBState_ { SMBWordCount wordcount; SMBByteCount bytecount; SMBAndX andx; - DCERPC dcerpc; + DCERPCState ds; uint8_t dcerpc_present; uint8_t data_needed_for_dir; } SMBState; diff --git a/src/app-layer-smb2.c b/src/app-layer-smb2.c index 6a49bd751c1d..58821cb13d24 100644 --- a/src/app-layer-smb2.c +++ b/src/app-layer-smb2.c @@ -532,6 +532,12 @@ static int SMB2Parse(Flow *f, void *smb2_state, AppLayerParserState *pstate, if (pstate == NULL) return -1; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + while (sstate->bytesprocessed < NBSS_HDR_LEN && input_len) { retval = NBSSParseHeader(smb2_state, pstate, input, input_len); if (retval <= input_len) { @@ -634,15 +640,17 @@ int SMB2ParserTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMB2, STREAM_TOSERVER|STREAM_EOF, smb2buf, smb2len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMB2, + STREAM_TOSERVER | STREAM_EOF, smb2buf, + smb2len); if (r != 0) { printf("smb2 header check returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMB2State *smb2_state = f.alstate; if (smb2_state == NULL) { @@ -678,7 +686,7 @@ int SMB2ParserTest01(void) void SMB2ParserRegisterTests(void) { - UtRegisterTest("SMB2ParserTest01", SMB2ParserTest01, 1); + UtRegisterTest("SMB2ParserTest01", SMB2ParserTest01); } #endif diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index fc3b9f7dadb4..c12eee7359b3 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -42,7 +42,6 @@ #include "util-debug.h" #include "util-byte.h" #include "util-unittest.h" -#include "util-byte.h" #include "util-unittest-helper.h" #include "util-memcmp.h" #include "flow-util.h" @@ -54,6 +53,16 @@ #include "decode-events.h" #include "conf.h" +#include "util-mem.h" +#include "util-misc.h" + +/* content-limit default value */ +#define FILEDATA_CONTENT_LIMIT 100000 +/* content-inspect-min-size default value */ +#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768 +/* content-inspect-window default value */ +#define FILEDATA_CONTENT_INSPECT_WINDOW 4096 + #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510 #define SMTP_COMMAND_BUFFER_STEPS 5 @@ -113,13 +122,44 @@ SCEnumCharMap smtp_decoder_event_table[ ] = { SMTP_DECODER_EVENT_TLS_REJECTED }, { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED }, + + /* MIME Events */ + { "MIME_PARSE_FAILED", + SMTP_DECODER_EVENT_MIME_PARSE_FAILED }, + { "MIME_MALFORMED_MSG", + SMTP_DECODER_EVENT_MIME_MALFORMED_MSG }, + { "MIME_INVALID_BASE64", + SMTP_DECODER_EVENT_MIME_INVALID_BASE64 }, + { "MIME_INVALID_QP", + SMTP_DECODER_EVENT_MIME_INVALID_QP }, + { "MIME_LONG_LINE", + SMTP_DECODER_EVENT_MIME_LONG_LINE }, + { "MIME_LONG_ENC_LINE", + SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE }, + { "MIME_LONG_HEADER_NAME", + SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME }, + { "MIME_LONG_HEADER_VALUE", + SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE }, + { "MIME_LONG_BOUNDARY", + SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG }, + + /* Invalid behavior or content */ + { "DUPLICATE_FIELDS", + SMTP_DECODER_EVENT_DUPLICATE_FIELDS }, + { "UNPARSABLE_CONTENT", + SMTP_DECODER_EVENT_UNPARSABLE_CONTENT }, + { NULL, -1 }, }; -#define SMTP_MPM DEFAULT_MPM +typedef struct SMTPThreadCtx_ { + MpmThreadCtx *smtp_mpm_thread_ctx; + PrefilterRuleStore *pmq; +} SMTPThreadCtx; + +#define SMTP_MPM mpm_default_matcher static MpmCtx *smtp_mpm_ctx = NULL; -MpmThreadCtx *smtp_mpm_thread_ctx; /* smtp reply codes. If an entry is made here, please make a simultaneous * entry in smtp_reply_map */ @@ -128,10 +168,12 @@ enum { SMTP_REPLY_214, SMTP_REPLY_220, SMTP_REPLY_221, + SMTP_REPLY_235, SMTP_REPLY_250, SMTP_REPLY_251, SMTP_REPLY_252, + SMTP_REPLY_334, SMTP_REPLY_354, SMTP_REPLY_421, @@ -158,10 +200,12 @@ SCEnumCharMap smtp_reply_map[ ] = { { "214", SMTP_REPLY_214 }, { "220", SMTP_REPLY_220 }, { "221", SMTP_REPLY_221 }, + { "235", SMTP_REPLY_235 }, { "250", SMTP_REPLY_250 }, { "251", SMTP_REPLY_251 }, { "252", SMTP_REPLY_252 }, + { "334", SMTP_REPLY_334 }, { "354", SMTP_REPLY_354 }, { "421", SMTP_REPLY_421 }, @@ -183,10 +227,288 @@ SCEnumCharMap smtp_reply_map[ ] = { { "555", SMTP_REPLY_555 }, { NULL, -1 }, }; -//static void SMTPParserReset(void) -//{ -// return; -//} + +/* Create SMTP config structure */ +SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, STREAMING_BUFFER_CONFIG_INITIALIZER}; + +static SMTPString *SMTPStringAlloc(void); + +/** + * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML + * config file + * + * \return none + */ +static void SMTPConfigure(void) { + + SCEnter(); + int ret = 0, val; + intmax_t imval; + uint32_t content_limit = 0; + uint32_t content_inspect_min_size = 0; + uint32_t content_inspect_window = 0; + + ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime"); + if (config != NULL) { + + ret = ConfGetChildValueBool(config, "decode-mime", &val); + if (ret) { + smtp_config.decode_mime = val; + } + + ret = ConfGetChildValueBool(config, "decode-base64", &val); + if (ret) { + smtp_config.mime_config.decode_base64 = val; + } + + ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val); + if (ret) { + smtp_config.mime_config.decode_quoted_printable = val; + } + + ret = ConfGetChildValueInt(config, "header-value-depth", &imval); + if (ret) { + smtp_config.mime_config.header_value_depth = (uint32_t) imval; + } + + ret = ConfGetChildValueBool(config, "extract-urls", &val); + if (ret) { + smtp_config.mime_config.extract_urls = val; + } + + ret = ConfGetChildValueBool(config, "body-md5", &val); + if (ret) { + smtp_config.mime_config.body_md5 = val; + } + } + + /* Pass mime config data to MimeDec API */ + MimeDecSetConfig(&smtp_config.mime_config); + + smtp_config.content_limit = FILEDATA_CONTENT_LIMIT; + smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + + ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker"); + ConfNode *p = NULL; + + if (t != NULL) { + TAILQ_FOREACH(p, &t->head, next) { + if (strcasecmp("content-limit", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_limit) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, + "parsing content-limit %s failed", p->val); + content_limit = FILEDATA_CONTENT_LIMIT; + } + smtp_config.content_limit = content_limit; + } + + if (strcasecmp("content-inspect-min-size", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, + "parsing content-inspect-min-size %s failed", p->val); + content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + } + smtp_config.content_inspect_min_size = content_inspect_min_size; + } + + if (strcasecmp("content-inspect-window", p->name) == 0) { + if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) { + SCLogWarning(SC_ERR_SIZE_PARSE, + "parsing content-inspect-window %s failed", p->val); + content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + } + smtp_config.content_inspect_window = content_inspect_window; + } + } + } + + smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256; + + SCReturn; +} + +void SMTPSetEvent(SMTPState *s, uint8_t e) +{ + SCLogDebug("setting event %u", e); + + if (s->curr_tx != NULL) { + AppLayerDecoderEventsSetEventRaw(&s->curr_tx->decoder_events, e); +// s->events++; + return; + } + SCLogDebug("couldn't set event %u", e); +} + +static SMTPTransaction *SMTPTransactionCreate(void) +{ + SMTPTransaction *tx = SCCalloc(1, sizeof(*tx)); + if (tx == NULL) { + return NULL; + } + + TAILQ_INIT(&tx->rcpt_to_list); + tx->mime_state = NULL; + return tx; +} + +/** \internal + * \brief update inspected tracker if it gets to far behind + * + * As smtp uses the FILE_USE_DETECT flag in the file API, we are responsible + * for making sure that File::content_inspected is not getting too far + * behind. + */ +static void SMTPPruneFiles(FileContainer *files) +{ + SCLogDebug("cfg: win %"PRIu32" min_size %"PRIu32, + smtp_config.content_inspect_window, smtp_config.content_inspect_min_size); + + File *file = files->head; + while (file) { + SCLogDebug("file %p", file); + uint32_t window = smtp_config.content_inspect_window; + if (file->sb->stream_offset == 0) + window = MAX(window, smtp_config.content_inspect_min_size); + + uint64_t file_size = FileDataSize(file); + uint64_t data_size = file_size - file->sb->stream_offset; + + SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, + window, file_size, data_size); + + if (data_size > (window * 3)) { + uint64_t left_edge = file_size - window; + SCLogDebug("file->content_inspected now %"PRIu64, left_edge); + file->content_inspected = left_edge; + } + + file = file->next; + } +} + +static void FlagDetectStateNewFile(SMTPTransaction *tx) +{ + if (tx && tx->de_state) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW set"); + tx->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; + } else if (tx == NULL) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW NOT set, no TX"); + } else if (tx->de_state == NULL) { + SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW NOT set, no TX DESTATE"); + } +} + +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) +{ + SCEnter(); + int ret = MIME_DEC_OK; + Flow *flow = (Flow *) state->data; + SMTPState *smtp_state = (SMTPState *) flow->alstate; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + FileContainer *files = NULL; + + uint16_t flags = FileFlowToFlags(flow, STREAM_TOSERVER); + /* we depend on detection engine for file pruning */ + flags |= FILE_USE_DETECT; + + /* Find file */ + if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { + + /* Make sure file container allocated */ + if (smtp_state->files_ts == NULL) { + smtp_state->files_ts = FileContainerAlloc(); + if (smtp_state->files_ts == NULL) { + ret = MIME_DEC_ERR_MEM; + SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container"); + SCReturnInt(ret); + } + } + files = smtp_state->files_ts; + + /* Open file if necessary */ + if (state->body_begin) { + + if (SCLogDebugEnabled()) { + SCLogDebug("Opening file...%u bytes", len); + printf("File - "); + for (uint32_t i = 0; i < entity->filename_len; i++) { + printf("%c", entity->filename[i]); + } + printf("\n"); + } + + /* Set storage flag if applicable since only the first file in the + * flow seems to be processed by the 'filestore' detector */ + if (files->head != NULL && (files->head->flags & FILE_STORE)) { + flags |= FILE_STORE; + } + + if (FileOpenFile(files, &smtp_config.sbcfg, (uint8_t *) entity->filename, entity->filename_len, + (uint8_t *) chunk, len, flags) == NULL) { + ret = MIME_DEC_ERR_DATA; + SCLogDebug("FileOpenFile() failed"); + } + FlagDetectStateNewFile(smtp_state->curr_tx); + + /* If close in the same chunk, then pass in empty bytes */ + if (state->body_end) { + + SCLogDebug("Closing file...%u bytes", len); + + if (files->tail->state == FILE_STATE_OPENED) { + ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags); + if (ret != 0) { + SCLogDebug("FileCloseFile() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; + } + } else { + SCLogDebug("File already closed"); + } + } + } else if (state->body_end) { + /* Close file */ + SCLogDebug("Closing file...%u bytes", len); + + if (files && files->tail && files->tail->state == FILE_STATE_OPENED) { + ret = FileCloseFile(files, (uint8_t *) chunk, len, flags); + if (ret != 0) { + SCLogDebug("FileCloseFile() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; + } + } else { + SCLogDebug("File already closed"); + } + } else { + /* Append data chunk to file */ + SCLogDebug("Appending file...%u bytes", len); + + /* 0 is ok, -2 is not stored, -1 is error */ + ret = FileAppendData(files, (uint8_t *) chunk, len); + if (ret == -2) { + ret = 0; + SCLogDebug("FileAppendData() - file no longer being extracted"); + } else if (ret < 0) { + SCLogDebug("FileAppendData() failed: %d", ret); + ret = MIME_DEC_ERR_DATA; + } + } + + if (ret == 0) { + SCLogDebug("Successfully processed file data!"); + } + } else { + SCLogDebug("Body not a Ctnt_attachment"); + } + + if (files != NULL) { + SMTPPruneFiles(files); + FilePrune(files); + } + + SCReturnInt(ret); +} /** * \internal @@ -441,8 +763,7 @@ static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) || (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE); /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP, * STARTTLS as the last command in pipelined mode */ } @@ -469,8 +790,7 @@ static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f, if (state->bdat_chunk_idx > state->bdat_chunk_len) { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED); SCReturnInt(-1); } else if (state->bdat_chunk_idx == state->bdat_chunk_len) { state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE; @@ -496,6 +816,59 @@ static int SMTPProcessCommandDATA(SMTPState *state, Flow *f, * the command buffer to be used by the reply handler to match * the reply received */ SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f); + + if (smtp_config.decode_mime && state->curr_tx->mime_state != NULL) { + /* Complete parsing task */ + int ret = MimeDecParseComplete(state->curr_tx->mime_state); + if (ret != MIME_DEC_OK) { + + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED); + SCLogDebug("MimeDecParseComplete() function failed"); + } + + /* Generate decoder events */ + MimeDecEntity *msg = state->curr_tx->mime_state->msg; + if (msg->anomaly_flags & ANOM_INVALID_BASE64) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64); + } + if (msg->anomaly_flags & ANOM_INVALID_QP) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP); + } + if (msg->anomaly_flags & ANOM_LONG_LINE) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE); + } + if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE); + } + if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME); + } + if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE); + } + if (msg->anomaly_flags & ANOM_MALFORMED_MSG) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG); + } + if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG); + } + } + state->curr_tx->done = 1; + SCLogDebug("marked tx as done"); + } + + /* If DATA, then parse out a MIME message */ + if (state->current_command == SMTP_COMMAND_DATA && + (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + + if (smtp_config.decode_mime && state->curr_tx->mime_state) { + int ret = MimeDecParseLine((const uint8_t *) state->current_line, + state->current_line_len, state->current_line_delimiter_len, + state->curr_tx->mime_state); + if (ret != MIME_DEC_OK) { + SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret); + } + } } return 0; @@ -508,19 +881,18 @@ static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f, } static int SMTPProcessReply(SMTPState *state, Flow *f, - AppLayerParserState *pstate) + AppLayerParserState *pstate, + SMTPThreadCtx *td) { SCEnter(); uint64_t reply_code = 0; - PatternMatcherQueue *pmq = state->thread_local_data; /* the reply code has to contain at least 3 bytes, to hold the 3 digit * reply code */ if (state->current_line_len < 3) { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_INVALID_REPLY); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); return -1; } @@ -542,31 +914,37 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, /* I don't like this pmq reset here. We'll devise a method later, that * should make the use of the mpm very efficient */ - PmqReset(pmq); - int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx, - pmq, state->current_line, + PmqReset(td->pmq); + int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, td->smtp_mpm_thread_ctx, + td->pmq, state->current_line, 3); if (mpm_cnt == 0) { /* set decoder event - reply code invalid */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_INVALID_REPLY); + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); SCLogDebug("invalid reply code %02x %02x %02x", state->current_line[0], state->current_line[1], state->current_line[2]); SCReturnInt(-1); } - reply_code = smtp_reply_map[pmq->pattern_id_array[0]].enum_value; + reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value; if (state->cmds_idx == state->cmds_cnt) { if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; + /* the first server reply can be a multiline message. Let's + * flag the fact that we have seen the first reply only at the end + * of a multiline reply + */ + if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) + state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; if (reply_code == SMTP_REPLY_220) SCReturnInt(0); - else - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_INVALID_REPLY); + else { + SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY); + SCReturnInt(0); + } } else { /* decoder event - unable to match reply with request */ SCLogDebug("unable to match reply with request"); - SCReturnInt(-1); + SCReturnInt(0); } } @@ -581,8 +959,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, APP_LAYER_PARSER_NO_REASSEMBLY); } else { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_TLS_REJECTED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED); } } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) { if (reply_code == SMTP_REPLY_354) { @@ -590,8 +967,7 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; } else { /* decoder event */ - AppLayerDecoderEventsSetEvent(f, - SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); + SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED); } } else { /* we don't care for any other command for now */ @@ -634,10 +1010,10 @@ static int SMTPParseCommandBDAT(SMTPState *state) /* decoder event */ return -1; } - uint8_t *endptr = NULL; + char *endptr = NULL; state->bdat_chunk_len = strtoul((const char *)state->current_line + i, (char **)&endptr, 10); - if (endptr == state->current_line + i) { + if ((uint8_t *)endptr == state->current_line + i) { /* decoder event */ return -1; } @@ -645,13 +1021,111 @@ static int SMTPParseCommandBDAT(SMTPState *state) return 0; } +static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len) +{ + int i = prefix_len + 1; + int spc_i = 0; + + while (i < state->current_line_len) { + if (state->current_line[i] != ' ') { + break; + } + i++; + } + + /* rfc1870: with the size extension the mail from can be followed by an option. + We use the space separator to detect it. */ + spc_i = i; + while (spc_i < state->current_line_len) { + if (state->current_line[spc_i] == ' ') { + break; + } + spc_i++; + } + + *target = SCMalloc(spc_i - i + 1); + if (*target == NULL) + return -1; + memcpy(*target, state->current_line + i, spc_i - i); + (*target)[spc_i - i] = '\0'; + *target_len = spc_i - i; + + return 0; +} + +static int SMTPParseCommandHELO(SMTPState *state) +{ + if (state->helo) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); + return 0; + } + return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len); +} + +static int SMTPParseCommandMAILFROM(SMTPState *state) +{ + if (state->curr_tx->mail_from) { + SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS); + return 0; + } + return SMTPParseCommandWithParam(state, 9, + &state->curr_tx->mail_from, + &state->curr_tx->mail_from_len); +} + +static int SMTPParseCommandRCPTTO(SMTPState *state) +{ + uint8_t *rcptto; + uint16_t rcptto_len; + + if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) { + SMTPString *rcptto_str = SMTPStringAlloc(); + if (rcptto_str) { + rcptto_str->str = rcptto; + rcptto_str->len = rcptto_len; + TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next); + } else { + SCFree(rcptto); + return -1; + } + } else { + return -1; + } + return 0; +} + +/* consider 'rset' and 'quit' to be part of the existing state */ +static int NoNewTx(SMTPState *state) +{ + if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + if (state->current_line_len >= 4 && + SCMemcmpLowercase("rset", state->current_line, 4) == 0) { + return 1; + } else if (state->current_line_len >= 4 && + SCMemcmpLowercase("quit", state->current_line, 4) == 0) { + return 1; + } + } + return 0; +} + static int SMTPProcessRequest(SMTPState *state, Flow *f, AppLayerParserState *pstate) { SCEnter(); + SMTPTransaction *tx = state->curr_tx; + + if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) { + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + } if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { - AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); + SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE); } /* there are 2 commands that can push it into this COMMAND_DATA mode - @@ -665,6 +1139,37 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, } else if (state->current_line_len >= 4 && SCMemcmpLowercase("data", state->current_line, 4) == 0) { state->current_command = SMTP_COMMAND_DATA; + if (smtp_config.decode_mime) { + if (tx->mime_state) { + /* We have 2 chained mails and did not detect the end + * of first one. So we start a new transaction. */ + tx->mime_state->state_flag = PARSE_ERROR; + SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT); + tx = SMTPTransactionCreate(); + if (tx == NULL) + return -1; + state->curr_tx = tx; + TAILQ_INSERT_TAIL(&state->tx_list, tx, next); + tx->tx_id = state->tx_cnt++; + } + tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk); + if (tx->mime_state == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to " + "allocate data"); + return MIME_DEC_ERR_MEM; + } + + /* Add new MIME message to end of list */ + if (tx->msg_head == NULL) { + tx->msg_head = tx->mime_state->msg; + tx->msg_tail = tx->mime_state->msg; + } + else { + tx->msg_tail->next = tx->mime_state->msg; + tx->msg_tail = tx->mime_state->msg; + } + } + } else if (state->current_line_len >= 4 && SCMemcmpLowercase("bdat", state->current_line, 4) == 0) { r = SMTPParseCommandBDAT(state); @@ -673,6 +1178,28 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, } state->current_command = SMTP_COMMAND_BDAT; state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } else if (state->current_line_len >= 4 && + ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) || + SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) { + r = SMTPParseCommandHELO(state); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (state->current_line_len >= 9 && + SCMemcmpLowercase("mail from", state->current_line, 9) == 0) { + r = SMTPParseCommandMAILFROM(state); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; + } else if (state->current_line_len >= 7 && + SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) { + r = SMTPParseCommandRCPTTO(state); + if (r == -1) { + SCReturnInt(-1); + } + state->current_command = SMTP_COMMAND_OTHER_CMD; } else { state->current_command = SMTP_COMMAND_OTHER_CMD; } @@ -707,14 +1234,19 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, static int SMTPParse(int direction, Flow *f, SMTPState *state, AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, - PatternMatcherQueue *local_data) + SMTPThreadCtx *thread_data) { SCEnter(); + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + state->input = input; state->input_len = input_len; state->direction = direction; - state->thread_local_data = local_data; /* toserver */ if (direction == 0) { @@ -726,7 +1258,7 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state, /* toclient */ } else { while (SMTPGetLine(state) >= 0) { - if (SMTPProcessReply(state, f, pstate) == -1) + if (SMTPProcessReply(state, f, pstate, thread_data) == -1) SCReturnInt(-1); } } @@ -762,7 +1294,7 @@ static int SMTPParseServerRecord(Flow *f, void *alstate, * \internal * \brief Function to allocate SMTP state memory. */ -static void *SMTPStateAlloc(void) +void *SMTPStateAlloc(void) { SMTPState *smtp_state = SCMalloc(sizeof(SMTPState)); if (unlikely(smtp_state == NULL)) @@ -777,32 +1309,103 @@ static void *SMTPStateAlloc(void) } smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS; + TAILQ_INIT(&smtp_state->tx_list); + return smtp_state; } +static SMTPString *SMTPStringAlloc(void) +{ + SMTPString *smtp_string = SCMalloc(sizeof(SMTPString)); + if (unlikely(smtp_string == NULL)) + return NULL; + memset(smtp_string, 0, sizeof(SMTPString)); + + return smtp_string; +} + + +static void SMTPStringFree(SMTPString *str) +{ + if (str->str) { + SCFree(str->str); + } + SCFree(str); +} + static void *SMTPLocalStorageAlloc(void) { /* needed by the mpm */ - PatternMatcherQueue *pmq = SCMalloc(sizeof(PatternMatcherQueue)); - if (unlikely(pmq == NULL)) { + SMTPThreadCtx *td = SCCalloc(1, sizeof(*td)); + if (td == NULL) { exit(EXIT_FAILURE); } - PmqSetup(pmq, - sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2); - return pmq; + td->pmq = SCCalloc(1, sizeof(*td->pmq)); + if (td->pmq == NULL) { + exit(EXIT_FAILURE); + } + PmqSetup(td->pmq); + + td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx)); + if (unlikely(td->smtp_mpm_thread_ctx == NULL)) { + exit(EXIT_FAILURE); + } + MpmInitThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM); + return td; } -static void SMTPLocalStorageFree(void *pmq) +static void SMTPLocalStorageFree(void *ptr) { - if (pmq != NULL) { - PmqFree(pmq); - SCFree(pmq); + SMTPThreadCtx *td = ptr; + if (td != NULL) { + if (td->pmq != NULL) { + PmqFree(td->pmq); + SCFree(td->pmq); + } + + if (td->smtp_mpm_thread_ctx != NULL) { + mpm_table[SMTP_MPM].DestroyThreadCtx(smtp_mpm_ctx, td->smtp_mpm_thread_ctx); + SCFree(td->smtp_mpm_thread_ctx); + } + + SCFree(td); } return; } +static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state) +{ + if (tx->mime_state != NULL) { + MimeDecDeInitParser(tx->mime_state); + } + /* Free list of MIME message recursively */ + MimeDecFreeEntity(tx->msg_head); + + if (tx->decoder_events != NULL) + AppLayerDecoderEventsFreeEvents(&tx->decoder_events); + + if (tx->de_state != NULL) + DetectEngineStateFree(tx->de_state); + + if (tx->mail_from) + SCFree(tx->mail_from); + + SMTPString *str = NULL; + while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) { + TAILQ_REMOVE(&tx->rcpt_to_list, str, next); + SMTPStringFree(str); + } +#if 0 + if (tx->decoder_events->cnt <= smtp_state->events) + smtp_state->events -= tx->decoder_events->cnt; + else + smtp_state->events = 0; +#endif + SCFree(tx); +} + /** * \internal * \brief Function to free SMTP state memory. @@ -821,6 +1424,18 @@ static void SMTPStateFree(void *p) SCFree(smtp_state->tc_db); } + if (smtp_state->helo) { + SCFree(smtp_state->helo); + } + + FileContainerFree(smtp_state->files_ts); + + SMTPTransaction *tx = NULL; + while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) { + TAILQ_REMOVE(&smtp_state->tx_list, tx, next); + SMTPTransactionFree(tx, smtp_state); + } + SCFree(smtp_state); return; @@ -835,23 +1450,26 @@ static void SMTPSetMpmState(void) memset(smtp_mpm_ctx, 0, sizeof(MpmCtx)); MpmInitCtx(smtp_mpm_ctx, SMTP_MPM); - smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx)); - if (unlikely(smtp_mpm_thread_ctx == NULL)) { - exit(EXIT_FAILURE); - } - memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM, 0); - uint32_t i = 0; for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) { SCEnumCharMap *map = &smtp_reply_map[i]; /* The third argument is 3, because reply code is always 3 bytes. */ MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, 0 /* defunct */, 0 /* defunct */, - i /* pattern id */, 0, 0 /* no flags */); + i /* pattern id */, i /* rule id */ , 0 /* no flags */); } mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); + +} + +static void SMTPFreeMpmState(void) +{ + if (smtp_mpm_ctx != NULL) { + mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx); + SCFree(smtp_mpm_ctx); + smtp_mpm_ctx = NULL; + } } int SMTPStateGetEventInfo(const char *event_name, @@ -865,34 +1483,160 @@ int SMTPStateGetEventInfo(const char *event_name, return -1; } - *event_type = APP_LAYER_EVENT_TYPE_GENERAL; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static int SMTPRegisterPatternsForProtocolDetection(void) +{ + if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, + "EHLO", 4, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, + "HELO", 4, 0, STREAM_TOSERVER) < 0) + { + return -1; + } + if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP, + "QUIT", 4, 0, STREAM_TOSERVER) < 0) + { + return -1; + } return 0; } -static int SMTPRegisterPatternsForProtocolDetection(void) +static void SMTPStateTransactionFree (void *state, uint64_t tx_id) +{ + SMTPState *smtp_state = state; + SMTPTransaction *tx = NULL; + TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { + if (tx_id < tx->tx_id) + break; + else if (tx_id > tx->tx_id) + continue; + + if (tx == smtp_state->curr_tx) + smtp_state->curr_tx = NULL; + TAILQ_REMOVE(&smtp_state->tx_list, tx, next); + SMTPTransactionFree(tx, state); + break; + } + + +} + +/** \retval cnt highest tx id */ +static uint64_t SMTPStateGetTxCnt(void *state) +{ + uint64_t cnt = 0; + SMTPState *smtp_state = state; + if (smtp_state) { + cnt = smtp_state->tx_cnt; + } + SCLogDebug("returning %"PRIu64, cnt); + return cnt; +} + +static void *SMTPStateGetTx(void *state, uint64_t id) +{ + SMTPState *smtp_state = state; + if (smtp_state) { + SMTPTransaction *tx = NULL; + + if (smtp_state->curr_tx == NULL) + return NULL; + if (smtp_state->curr_tx->tx_id == id) + return smtp_state->curr_tx; + + TAILQ_FOREACH(tx, &smtp_state->tx_list, next) { + if (tx->tx_id == id) + return tx; + } + } + return NULL; + +} + +static void SMTPStateSetTxLogged(void *state, void *vtx, uint32_t logger) +{ + SMTPTransaction *tx = vtx; + tx->logged |= logger; +} + +static int SMTPStateGetTxLogged(void *state, void *vtx, uint32_t logger) +{ + SMTPTransaction *tx = vtx; + if (tx->logged & logger) + return 1; + + return 0; +} + +static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) { + return 1; +} + +static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction) +{ + SMTPTransaction *tx = vtx; + return tx->done; +} + +static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction) +{ + if (state == NULL) + return NULL; + + SMTPState *smtp_state = (SMTPState *)state; + + if (direction & STREAM_TOCLIENT) { + SCReturnPtr(NULL, "FileContainer"); + } else { + SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts); + SCReturnPtr(smtp_state->files_ts, "FileContainer"); + } +} + +static void SMTPStateTruncate(void *state, uint8_t direction) +{ + FileContainer *fc = SMTPStateGetFiles(state, direction); + if (fc != NULL) { + SCLogDebug("truncating stream, closing files in %s direction (container %p)", + direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc); + FileTruncateAllOpenFiles(fc); + } +} + +static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id) +{ + SCLogDebug("get SMTP events for TX %"PRIu64, tx_id); + + SMTPTransaction *tx = SMTPStateGetTx(state, tx_id); + if (tx != NULL) { + return tx->decoder_events; + } + return NULL; +} + +static DetectEngineState *SMTPGetTxDetectState(void *vtx) { - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP, - "EHLO", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP, - "HELO", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } - if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP, - "QUIT", 4, 0, STREAM_TOSERVER) < 0) - { - return -1; - } + SMTPTransaction *tx = (SMTPTransaction *)vtx; + return tx->de_state; +} +static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s) +{ + SMTPTransaction *tx = (SMTPTransaction *)vtx; + tx->de_state = s; return 0; } /** - * \brief Register the SMPT Protocol parser. + * \brief Register the SMTP Protocol parser. */ void RegisterSMTPParsers(void) { @@ -917,9 +1661,23 @@ void RegisterSMTPParsers(void) SMTPParseServerRecord); AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents); + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL, + SMTPGetTxDetectState, SMTPSetTxDetectState); AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, SMTPLocalStorageFree); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree); + AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles); + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress); + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt); + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx); + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxLogged, + SMTPStateSetTxLogged); + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMTP, + SMTPStateGetAlstateProgressCompletionStatus); + AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate); } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" "still on.", proto_name); @@ -927,20 +1685,41 @@ void RegisterSMTPParsers(void) SMTPSetMpmState(); + SMTPConfigure(); + #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests); #endif return; } +/** + * \brief Free memory allocated for global SMTP parser state. + */ +void SMTPParserCleanup(void) +{ + SMTPFreeMpmState(); +} + /***************************************Unittests******************************/ #ifdef UNITTESTS +static void SMTPTestInitConfig(void) +{ + MimeDecSetConfig(&smtp_config.mime_config); + + smtp_config.content_limit = FILEDATA_CONTENT_LIMIT; + smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW; + smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; + + smtp_config.sbcfg.buf_size = FILEDATA_CONTENT_INSPECT_WINDOW; +} + /* * \test Test STARTTLS. */ -int SMTPParserTest01(void) +static int SMTPParserTest01(void) { int result = 0; Flow f; @@ -1016,16 +1795,17 @@ int SMTPParserTest01(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -1039,15 +1819,15 @@ int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1057,15 +1837,15 @@ int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1074,15 +1854,15 @@ int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1092,15 +1872,15 @@ int SMTPParserTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1111,7 +1891,7 @@ int SMTPParserTest01(void) } if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || + !(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { goto end; @@ -1129,7 +1909,7 @@ int SMTPParserTest01(void) /** * \test Test multiple DATA commands(full mail transactions). */ -int SMTPParserTest02(void) +static int SMTPParserTest02(void) { int result = 0; Flow f; @@ -1374,16 +2154,17 @@ int SMTPParserTest02(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -1397,15 +2178,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1415,15 +2196,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1432,15 +2213,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1450,15 +2231,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1467,15 +2248,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1485,15 +2266,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1502,15 +2283,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4, request4_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1520,15 +2301,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply4, reply4_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply4, reply4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1538,15 +2319,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_1, request5_1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_1, request5_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1557,15 +2338,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_2, request5_2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_2, request5_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1576,15 +2357,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_3, request5_3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_3, request5_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1595,15 +2376,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_4, request5_4_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_4, request5_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1614,15 +2395,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5_5, request5_5_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5_5, request5_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1632,15 +2413,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply5, reply5_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply5, reply5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1649,15 +2430,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request6, request6_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1667,15 +2448,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply6, reply6_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply6, reply6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1684,15 +2465,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request7, request7_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request7, request7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1702,15 +2483,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply7, reply7_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply7, reply7_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1719,15 +2500,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request8, request8_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request8, request8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1737,15 +2518,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply8, reply8_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply8, reply8_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1755,15 +2536,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_1, request9_1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_1, request9_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1774,15 +2555,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_2, request9_2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_2, request9_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1793,15 +2574,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_3, request9_3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_3, request9_3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1812,15 +2593,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_4, request9_4_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_4, request9_4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1831,15 +2612,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request9_5, request9_5_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request9_5, request9_5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1849,15 +2630,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply9, reply9_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply9, reply9_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1866,15 +2647,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request10, request10_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request10, request10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -1884,15 +2665,15 @@ int SMTPParserTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply10, reply10_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply10, reply10_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -1913,7 +2694,7 @@ int SMTPParserTest02(void) /** * \test Testing parsing pipelined commands. */ -int SMTPParserTest03(void) +static int SMTPParserTest03(void) { int result = 0; Flow f; @@ -2008,16 +2789,17 @@ int SMTPParserTest03(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2031,15 +2813,15 @@ int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2049,15 +2831,15 @@ int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2066,15 +2848,15 @@ int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 || @@ -2086,15 +2868,15 @@ int SMTPParserTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2116,7 +2898,7 @@ int SMTPParserTest03(void) /* * \test Test smtp with just delimter instead of . */ -int SMTPParserTest04(void) +static int SMTPParserTest04(void) { int result = 0; Flow f; @@ -2155,16 +2937,17 @@ int SMTPParserTest04(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2178,15 +2961,15 @@ int SMTPParserTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2208,7 +2991,7 @@ int SMTPParserTest04(void) /* * \test Test STARTTLS fail. */ -int SMTPParserTest05(void) +static int SMTPParserTest05(void) { int result = 0; Flow f; @@ -2302,16 +3085,17 @@ int SMTPParserTest05(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2325,15 +3109,15 @@ int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2343,15 +3127,15 @@ int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2360,15 +3144,15 @@ int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2378,15 +3162,15 @@ int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2396,21 +3180,21 @@ int SMTPParserTest05(void) } if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) || - (f.flags & FLOW_NO_APPLAYER_INSPECTION) || + (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) || (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2420,15 +3204,15 @@ int SMTPParserTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2449,7 +3233,7 @@ int SMTPParserTest05(void) /** * \test Test multiple DATA commands(full mail transactions). */ -int SMTPParserTest06(void) +static int SMTPParserTest06(void) { int result = 0; Flow f; @@ -2598,16 +3382,17 @@ int SMTPParserTest06(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - welcome_reply, welcome_reply_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2621,15 +3406,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2639,15 +3424,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2656,15 +3441,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2674,15 +3459,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply2, reply2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2691,15 +3476,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request3, request3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2709,15 +3494,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply3, reply3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || @@ -2726,15 +3511,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request4, request4_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4, request4_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2747,15 +3532,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request5, request5_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5, request5_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2767,15 +3552,15 @@ int SMTPParserTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request6, request6_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request6, request6_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || @@ -2798,7 +3583,7 @@ int SMTPParserTest06(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest07(void) +static int SMTPParserTest07(void) { int result = 0; Flow f; @@ -2836,16 +3621,17 @@ int SMTPParserTest07(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2861,15 +3647,15 @@ int SMTPParserTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -2880,15 +3666,15 @@ int SMTPParserTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -2911,7 +3697,7 @@ int SMTPParserTest07(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest08(void) +static int SMTPParserTest08(void) { int result = 0; Flow f; @@ -2949,16 +3735,17 @@ int SMTPParserTest08(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -2974,15 +3761,15 @@ int SMTPParserTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -2993,15 +3780,15 @@ int SMTPParserTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3024,7 +3811,7 @@ int SMTPParserTest08(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest09(void) +static int SMTPParserTest09(void) { int result = 0; Flow f; @@ -3062,16 +3849,17 @@ int SMTPParserTest09(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3087,15 +3875,15 @@ int SMTPParserTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -3106,15 +3894,15 @@ int SMTPParserTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3137,7 +3925,7 @@ int SMTPParserTest09(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest10(void) +static int SMTPParserTest10(void) { int result = 0; Flow f; @@ -3175,16 +3963,17 @@ int SMTPParserTest10(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_1, request1_1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_1, request1_1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3200,15 +3989,15 @@ int SMTPParserTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1_2, request1_2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1_2, request1_2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 1 || smtp_state->ts_db == NULL || smtp_state->ts_db_len != (int32_t)strlen(request1_str) || @@ -3219,15 +4008,15 @@ int SMTPParserTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3250,7 +4039,7 @@ int SMTPParserTest10(void) /* * \test Test retrieving lines when frag'ed. */ -int SMTPParserTest11(void) +static int SMTPParserTest11(void) { int result = 0; Flow f; @@ -3282,16 +4071,17 @@ int SMTPParserTest11(void) f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SMTPState *smtp_state = f.alstate; if (smtp_state == NULL) { printf("no smtp state: "); @@ -3307,15 +4097,15 @@ int SMTPParserTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("smtp check returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); if (smtp_state->ts_current_line_db != 0 || smtp_state->ts_db != NULL || smtp_state->ts_db_len != 0 || @@ -3335,7 +4125,7 @@ int SMTPParserTest11(void) return result; } -int SMTPParserTest12(void) +static int SMTPParserTest12(void) { int result = 0; Signature *s = NULL; @@ -3380,6 +4170,7 @@ int SMTPParserTest12(void) f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) @@ -3397,15 +4188,16 @@ int SMTPParserTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER | STREAM_START, request1, + request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); smtp_state = f.alstate; if (smtp_state == NULL) { @@ -3421,15 +4213,16 @@ int SMTPParserTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT | STREAM_TOCLIENT, reply1, + reply1_len); if (r == 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3456,7 +4249,7 @@ int SMTPParserTest12(void) return result; } -int SMTPParserTest13(void) +static int SMTPParserTest13(void) { int result = 0; Signature *s = NULL; @@ -3519,6 +4312,7 @@ int SMTPParserTest13(void) f.alproto = ALPROTO_SMTP; StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) @@ -3537,15 +4331,16 @@ int SMTPParserTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START, - request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER | STREAM_START, request1, + request1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); smtp_state = f.alstate; if (smtp_state == NULL) { @@ -3561,15 +4356,15 @@ int SMTPParserTest13(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT, - reply1, reply1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3579,15 +4374,15 @@ int SMTPParserTest13(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER, - request2, request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); if (r != 0) { printf("AppLayerParse for smtp failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3614,24 +4409,754 @@ int SMTPParserTest13(void) return result; } +/** + * \test Test DATA command w/MIME message. + */ +static int SMTPParserTest14(void) +{ + int result = 0; + Flow f; + int r = 0; + + /* 220 mx.google.com ESMTP d15sm986283wfl.6 */ + static uint8_t welcome_reply[] = { + 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, + 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36, + 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36, + 0x0d, 0x0a + }; + static uint32_t welcome_reply_len = sizeof(welcome_reply); + + /* EHLO boo.com */ + static uint8_t request1[] = { + 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a + }; + static uint32_t request1_len = sizeof(request1); + /* 250-mx.google.com at your service, [117.198.115.50] + * 250-SIZE 35882577 + * 250-8BITMIME + * 250-STARTTLS + * 250 ENHANCEDSTATUSCODES + */ + static uint8_t reply1[] = { + 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e, + 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, + 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, + 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, + 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, + 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, + 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35, + 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a, + 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41, + 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d, + 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, + 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, + 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a + }; + static uint32_t reply1_len = sizeof(reply1); + + /* MAIL FROM:asdff@asdf.com */ + static uint8_t request2[] = { + 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, + 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40, + 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d, + 0x0d, 0x0a + }; + static uint32_t request2_len = sizeof(request2); + /* 250 2.1.0 Ok */ + static uint8_t reply2[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + static uint32_t reply2_len = sizeof(reply2); + + /* RCPT TO:bimbs@gmail.com */ + static uint8_t request3[] = { + 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, + 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d, + 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d, + 0x0a + }; + static uint32_t request3_len = sizeof(request3); + /* 250 2.1.5 Ok */ + static uint8_t reply3[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, + 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a + }; + static uint32_t reply3_len = sizeof(reply3); + + /* DATA */ + static uint8_t request4[] = { + 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a + }; + static uint32_t request4_len = sizeof(request4); + /* 354 End data with .|| */ + static uint8_t reply4[] = { + 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20, + 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c, + 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c, + 0x4c, 0x46, 0x3e, 0x0d, 0x0a + }; + static uint32_t reply4_len = sizeof(reply4); + + /* MIME_MSG */ + static uint64_t filesize = 133; + static uint8_t request4_msg[] = { + 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, + 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, + 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78, + 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41, + 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61, + 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43, + 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41, + 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65, + 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D,0x0A }; + static uint32_t request4_msg_len = sizeof(request4_msg); + + /* DATA COMPLETED */ + static uint8_t request4_end[] = { + 0x0d, 0x0a, 0x2e, 0x0d, 0x0a + }; + static uint32_t request4_end_len = sizeof(request4_end); + /* 250 2.0.0 Ok: queued as 6A1AF20BF2 */ + static uint8_t reply4_end[] = { + 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75, + 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, + 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42, + 0x46, 0x32, 0x0d, 0x0a + }; + static uint32_t reply4_end_len = sizeof(reply4_end); + + /* QUIT */ + static uint8_t request5[] = { + 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a + }; + static uint32_t request5_len = sizeof(request5); + /* 221 2.0.0 Bye */ + static uint8_t reply5[] = { + 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e, + 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a + }; + static uint32_t reply5_len = sizeof(reply5); + + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + + StreamTcpInitConfig(TRUE); + SMTPTestInitConfig(); + + FLOWLOCK_WRLOCK(&f); + /* Welcome reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, welcome_reply, welcome_reply_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + SMTPState *smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request1, request1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* EHLO Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply1, reply1_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) { + printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* MAIL FROM Request */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request2, request2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* MAIL FROM Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply2, reply2_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + if ((smtp_state->curr_tx->mail_from_len != 14) || + strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) { + printf("incorrect parsing of MAIL FROM field '%s' (%d)\n", + smtp_state->curr_tx->mail_from, + smtp_state->curr_tx->mail_from_len); + FLOWLOCK_UNLOCK(&f); + goto end; + } + + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* RCPT TO Request */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request3, request3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* RCPT TO Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply3, reply3_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + /* Enable mime decoding */ + smtp_config.decode_mime = 1; + smtp_config.mime_config.decode_base64 = 1; + smtp_config.mime_config.decode_quoted_printable = 1; + MimeDecSetConfig(&smtp_config.mime_config); + + FLOWLOCK_WRLOCK(&f); + /* DATA request */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4, request4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* Data reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply4, reply4_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* DATA message */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4_msg, request4_msg_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* DATA . request */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request4_end, request4_end_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE || + smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */ + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + SMTPState *state = (SMTPState *) f.alstate; + FileContainer *files = state->files_ts; + if (files != NULL && files->head != NULL) { + File *file = files->head; + + if(strncmp((const char *)file->name, "test.exe", 8) != 0){ + printf("smtp-mime file name is incorrect"); + goto end; + } + if (FileTrackedSize(file) != filesize){ + printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file)); + goto end; + } + static uint8_t org_binary[] = { + 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, + 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36, + 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36, + 0x5C, 0x7A, 0x00, 0x00, 0x38,}; + + if (StreamingBufferCompareRawData(file->sb, + org_binary, sizeof(org_binary)) != 1) + { + printf("smtp-mime file data incorrect\n"); + goto end; + } + } + + FLOWLOCK_WRLOCK(&f); + /* DATA . reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply4_end, reply4_end_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* QUIT Request */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, request5, request5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 1 || + smtp_state->cmds_idx != 0 || + smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || + smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + /* QUIT Reply */ + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOCLIENT, reply5, reply5_len); + if (r != 0) { + printf("smtp check returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + if (smtp_state->input_len != 0 || + smtp_state->cmds_cnt != 0 || + smtp_state->cmds_idx != 0 || + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + printf("smtp parser in inconsistent state l.%d\n", __LINE__); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + +static int SMTPProcessDataChunkTest01(void){ + Flow f; + FLOW_INITIALIZE(&f); + f.file_flags = FLOWFILE_NO_STORE_TS; + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + int ret; + ret = SMTPProcessDataChunk(NULL, 0, state); + + return ret == 0; +} + + +static int SMTPProcessDataChunkTest02(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, + 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, + 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, + 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78, + 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41, + 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61, + 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43, + 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41, + 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65, + 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, + 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D, 0x0A,}; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + int ret; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + + return ret == 0; +} + + + +static int SMTPProcessDataChunkTest03(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, }; + char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, }; + char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, }; + char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, }; + char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, }; + char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, }; + char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, }; + char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, }; + char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, }; + char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, }; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + int ret; + + state->body_begin = 1; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + if(ret) goto end; + state->body_begin = 0; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state); + if(ret) goto end; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state); + if(ret) goto end; + state->body_end = 1; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state); + if(ret) goto end; + + end: + return ret == 0; +} + + +static int SMTPProcessDataChunkTest04(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, }; + char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, }; + char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, }; + char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, }; + char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, }; + char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, }; + char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, }; + char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, }; + char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, }; + char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, }; + + Flow f; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + int ret = MIME_DEC_OK; + + state->body_begin = 1; + if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end; + state->body_begin = 0; + state->body_end = 1; + if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end; + state->body_end = 0; + if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end; + if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end; + + end: + return ret == 0; +} + +static int SMTPProcessDataChunkTest05(void){ + char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C, + 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F, + 0x41, 0x3D, 0x3D, 0x0D, 0x0A,}; + + Flow f; + int ret; + FLOW_INITIALIZE(&f); + f.alstate = SMTPStateAlloc(); + FAIL_IF(f.alstate == NULL); + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + FAIL_IF(state == NULL); + state->body_begin = 1; + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + FAIL_IF(ret != 0); + state->body_begin = 0; + SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate; + FileContainer *files = smtp_state->files_ts; + FAIL_IF(files == NULL); + File *file = files->head; + FAIL_IF(file == NULL); + ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state); + FAIL_IF(ret != 0); + FAIL_IF((uint32_t)FileDataSize(file) != 106); + SMTPStateFree(smtp_state); + FLOW_DESTROY(&f); + PASS; +} + #endif /* UNITTESTS */ void SMTPParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1); - UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1); - UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1); - UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1); - UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1); - UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1); - UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1); - UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1); - UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1); - UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1); - UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1); - UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1); - UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1); + UtRegisterTest("SMTPParserTest01", SMTPParserTest01); + UtRegisterTest("SMTPParserTest02", SMTPParserTest02); + UtRegisterTest("SMTPParserTest03", SMTPParserTest03); + UtRegisterTest("SMTPParserTest04", SMTPParserTest04); + UtRegisterTest("SMTPParserTest05", SMTPParserTest05); + UtRegisterTest("SMTPParserTest06", SMTPParserTest06); + UtRegisterTest("SMTPParserTest07", SMTPParserTest07); + UtRegisterTest("SMTPParserTest08", SMTPParserTest08); + UtRegisterTest("SMTPParserTest09", SMTPParserTest09); + UtRegisterTest("SMTPParserTest10", SMTPParserTest10); + UtRegisterTest("SMTPParserTest11", SMTPParserTest11); + UtRegisterTest("SMTPParserTest12", SMTPParserTest12); + UtRegisterTest("SMTPParserTest13", SMTPParserTest13); + UtRegisterTest("SMTPParserTest14", SMTPParserTest14); + UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01); + UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02); + UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03); + UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04); + UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05); #endif /* UNITTESTS */ return; diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 0a29a35b3705..face8f93fa64 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -25,6 +25,9 @@ #define __APP_LAYER_SMTP_H__ #include "decode-events.h" +#include "util-decode-mime.h" +#include "queue.h" +#include "util-streaming-buffer.h" enum { SMTP_DECODER_EVENT_INVALID_REPLY, @@ -36,9 +39,71 @@ enum { SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE, SMTP_DECODER_EVENT_TLS_REJECTED, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED, + + /* MIME Events */ + SMTP_DECODER_EVENT_MIME_PARSE_FAILED, + SMTP_DECODER_EVENT_MIME_MALFORMED_MSG, + SMTP_DECODER_EVENT_MIME_INVALID_BASE64, + SMTP_DECODER_EVENT_MIME_INVALID_QP, + SMTP_DECODER_EVENT_MIME_LONG_LINE, + SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE, + SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME, + SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE, + SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG, + + /* Invalid behavior or content */ + SMTP_DECODER_EVENT_DUPLICATE_FIELDS, + SMTP_DECODER_EVENT_UNPARSABLE_CONTENT, }; +typedef struct SMTPString_ { + uint8_t *str; + uint16_t len; + + TAILQ_ENTRY(SMTPString_) next; +} SMTPString; + +typedef struct SMTPTransaction_ { + /** id of this tx, starting at 0 */ + uint64_t tx_id; + int done; + /** indicates loggers done logging */ + uint32_t logged; + /** the first message contained in the session */ + MimeDecEntity *msg_head; + /** the last message contained in the session */ + MimeDecEntity *msg_tail; + /** the mime decoding parser state */ + MimeDecParseState *mime_state; + + AppLayerDecoderEvents *decoder_events; /**< per tx events */ + DetectEngineState *de_state; + + /* MAIL FROM parameters */ + uint8_t *mail_from; + uint16_t mail_from_len; + + TAILQ_HEAD(, SMTPString_) rcpt_to_list; /**< rcpt to string list */ + + TAILQ_ENTRY(SMTPTransaction_) next; +} SMTPTransaction; + +typedef struct SMTPConfig { + + int decode_mime; + MimeDecConfig mime_config; + uint32_t content_limit; + uint32_t content_inspect_min_size; + uint32_t content_inspect_window; + + StreamingBufferConfig sbcfg; +} SMTPConfig; + typedef struct SMTPState_ { + SMTPTransaction *curr_tx; + TAILQ_HEAD(, SMTPTransaction_) tx_list; /**< transaction list */ + uint64_t tx_cnt; + /* current input that is being parsed */ uint8_t *input; int32_t input_len; @@ -50,7 +115,6 @@ typedef struct SMTPState_ { /** length of the line in current_line. Doesn't include the delimiter */ int32_t current_line_len; uint8_t current_line_delimiter_len; - PatternMatcherQueue *thread_local_data; /** used to indicate if the current_line buffer is a malloced buffer. We * use a malloced buffer, if a line is fragmented */ @@ -89,9 +153,22 @@ typedef struct SMTPState_ { * handler */ uint16_t cmds_idx; + /* SMTP Mime decoding and file extraction */ + /** the list of files sent to the server */ + FileContainer *files_ts; + + /* HELO of HELO message content */ + uint8_t *helo; + uint16_t helo_len; } SMTPState; +/* Create SMTP config structure */ +extern SMTPConfig smtp_config; + +int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state); +void *SMTPStateAlloc(void); void RegisterSMTPParsers(void); +void SMTPParserCleanup(void); void SMTPParserRegisterTests(void); #endif /* __APP_LAYER_SMTP_H__ */ diff --git a/src/app-layer-ssh.c b/src/app-layer-ssh.c index 9d610b8c6b8e..0b965eb74810 100644 --- a/src/app-layer-ssh.c +++ b/src/app-layer-ssh.c @@ -85,7 +85,7 @@ static int SSHParseBanner(SshState *state, SshHeader *header, const uint8_t *inp if ((banner_end - line_ptr) > 255) { SCLogDebug("Invalid version string, it should be less than 255 " "characters including , input value is %"PRIuMAX, - (banner_end - line_ptr)); + (uintmax_t)(banner_end - line_ptr)); SCReturnInt(-1); } @@ -422,6 +422,12 @@ static int SSHParseRequest(Flow *f, void *state, AppLayerParserState *pstate, SshState *ssh_state = (SshState *)state; SshHeader *ssh_header = &ssh_state->cli_hdr; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + int r = SSHParseData(ssh_state, ssh_header, input, input_len); if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && @@ -440,6 +446,12 @@ static int SSHParseResponse(Flow *f, void *state, AppLayerParserState *pstate, SshState *ssh_state = (SshState *)state; SshHeader *ssh_header = &ssh_state->srv_hdr; + if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + int r = SSHParseData(ssh_state, ssh_header, input, input_len); if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && @@ -482,9 +494,96 @@ static void SSHStateFree(void *state) if (s->srv_hdr.banner_buffer != NULL) SCFree(s->srv_hdr.banner_buffer); + //AppLayerDecoderEventsFreeEvents(&s->decoder_events); + + if (s->de_state != NULL) { + DetectEngineStateFree(s->de_state); + } + SCFree(s); } +static int SSHStateHasTxDetectState(void *state) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state->de_state) + return 1; + return 0; +} + +static int SSHSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SshState *ssh_state = (SshState *)state; + ssh_state->de_state = de_state; + return 0; +} + +static DetectEngineState *SSHGetTxDetectState(void *vtx) +{ + SshState *ssh_state = (SshState *)vtx; + return ssh_state->de_state; +} + +static void SSHStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + +static void *SSHGetTx(void *state, uint64_t tx_id) +{ + SshState *ssh_state = (SshState *)state; + return ssh_state; +} + +static uint64_t SSHGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +static void SSHSetTxLogged(void *state, void *tx, uint32_t logger) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state) + ssh_state->logged |= logger; +} + +static int SSHGetTxLogged(void *state, void *tx, uint32_t logger) +{ + SshState *ssh_state = (SshState *)state; + if (ssh_state && (ssh_state->logged & logger)) { + return 1; + } + return 0; +} + +static int SSHGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return SSH_STATE_FINISHED; +} + +static int SSHGetAlstateProgress(void *tx, uint8_t direction) +{ + SshState *ssh_state = (SshState *)tx; + + if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE && + ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_FINISHED; + } + + if (direction == STREAM_TOSERVER) { + if (ssh_state->cli_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_BANNER_DONE; + } + } else { + if (ssh_state->srv_hdr.flags & SSH_FLAG_PARSER_DONE) { + return SSH_STATE_BANNER_DONE; + } + } + + return SSH_STATE_IN_PROGRESS; +} + static int SSHRegisterPatternsForProtocolDetection(void) { if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SSH, @@ -520,6 +619,22 @@ void RegisterSSHParsers(void) AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateAlloc, SSHStateFree); AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_SSH, STREAM_TOSERVER|STREAM_TOCLIENT); + + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SSH, SSHStateTransactionFree); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHStateHasTxDetectState, + SSHGetTxDetectState, SSHSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SSH, SSHGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SSH, SSHGetAlstateProgress); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SSH, SSHGetTxLogged, SSHSetTxLogged); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SSH, + SSHGetAlstateProgressCompletionStatus); } else { // SCLogInfo("Parsed disabled for %s protocol. Protocol detection" // "still on.", proto_name); @@ -532,6 +647,7 @@ void RegisterSSHParsers(void) /* UNITTESTS */ #ifdef UNITTESTS +#include "flow-util.h" /** \test Send a version string in one chunk (client version str). */ static int SSHParserTest01(void) @@ -545,18 +661,20 @@ static int SSHParserTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -594,6 +712,7 @@ static int SSHParserTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -611,18 +730,20 @@ static int SSHParserTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -660,6 +781,7 @@ static int SSHParserTest02(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -677,18 +799,20 @@ static int SSHParserTest03(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned %" PRId32 ", expected != 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -714,6 +838,7 @@ static int SSHParserTest03(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -729,18 +854,20 @@ static int SSHParserTest04(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -779,6 +906,7 @@ static int SSHParserTest04(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -795,18 +923,20 @@ static int SSHParserTest05(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -844,6 +974,7 @@ static int SSHParserTest05(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -860,18 +991,20 @@ static int SSHParserTest06(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT | STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toserver chunk 1 returned %" PRId32 ", expected != 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* Ok, it returned an error. Let's make sure we didn't parse the string at all */ SshState *ssh_state = f.alstate; @@ -898,6 +1031,7 @@ static int SSHParserTest06(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -914,27 +1048,30 @@ static int SSHParserTest07(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -973,6 +1110,7 @@ static int SSHParserTest07(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -992,36 +1130,40 @@ static int SSHParserTest08(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1059,6 +1201,7 @@ static int SSHParserTest08(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1075,27 +1218,30 @@ static int SSHParserTest09(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1134,6 +1280,7 @@ static int SSHParserTest09(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1153,36 +1300,40 @@ static int SSHParserTest10(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1220,6 +1371,7 @@ static int SSHParserTest10(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1237,27 +1389,30 @@ static int SSHParserTest11(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1300,6 +1455,7 @@ static int SSHParserTest11(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1319,36 +1475,40 @@ static int SSHParserTest12(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1391,6 +1551,7 @@ static int SSHParserTest12(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1411,37 +1572,41 @@ static int SSHParserTest13(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); for (u = 0; u < sshlen2; u++) { - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf2[u], 1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, &sshbuf2[u], 1); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); } for (u = 0; u < sshlen3; u++) { - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, &sshbuf3[u], 1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, &sshbuf3[u], 1); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); } SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1484,6 +1649,7 @@ static int SSHParserTest13(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1510,50 +1676,56 @@ static int SSHParserTest14(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf5, sshlen5); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1596,6 +1768,7 @@ static int SSHParserTest14(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1622,50 +1795,56 @@ static int SSHParserTest15(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf5, sshlen5); + FLOWLOCK_UNLOCK(&f); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf5, sshlen5); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1708,6 +1887,7 @@ static int SSHParserTest15(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1727,36 +1907,40 @@ static int SSHParserTest16(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1799,6 +1983,7 @@ static int SSHParserTest16(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1820,45 +2005,50 @@ static int SSHParserTest17(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -1901,6 +2091,7 @@ static int SSHParserTest17(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -1930,54 +2121,60 @@ static int SSHParserTest18(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server1, serverlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, server1, serverlen1); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, server2, serverlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + server2, serverlen2); if (r != 0) { printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2005,6 +2202,7 @@ static int SSHParserTest18(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2036,45 +2234,50 @@ static int SSHParserTest19(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2097,13 +2300,13 @@ static int SSHParserTest19(void) goto end; } - char *name = SCMalloc(256); + char *name = SCCalloc(1, 256); if (name == NULL) goto end; - memset(name, 0x00, 256); - strlcpy(name, (char *)sshbuf3, strlen((char *)sshbuf3) - 1); + strlcpy(name, (char *)sshbuf3, 256); + name[strlen(name) - 1] = '\0'; // strip \r - if (strncmp((char*)ssh_state->srv_hdr.software_version, name, strlen(name)) != 0) { + if (strcmp((char*)ssh_state->srv_hdr.software_version, name) != 0) { printf("Client version string not parsed correctly: "); goto end; } @@ -2123,6 +2326,7 @@ static int SSHParserTest19(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2156,46 +2360,51 @@ static int SSHParserTest20(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("chunk 4:"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2232,6 +2441,7 @@ static int SSHParserTest20(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2263,46 +2473,51 @@ static int SSHParserTest21(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("chunk 4:"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2340,6 +2555,7 @@ static int SSHParserTest21(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2398,46 +2614,50 @@ static int SSHParserTest22(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOCLIENT, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf2, sshlen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf3, sshlen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); #if 0 SCLogDebug("chunk 4:"); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOCLIENT, sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); #endif SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2475,6 +2695,7 @@ static int SSHParserTest22(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2490,24 +2711,27 @@ static int SSHParserTest23(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r == 0) { printf("toclient chunk 1 returned 0 expected non null: "); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); result = 1; end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2523,18 +2747,20 @@ static int SSHParserTest24(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER|STREAM_EOF, sshbuf, sshlen); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER | STREAM_EOF, sshbuf, sshlen); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -2557,6 +2783,7 @@ static int SSHParserTest24(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2566,30 +2793,30 @@ static int SSHParserTest24(void) void SSHParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01, 1); - UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02, 1); - UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03, 1); - UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04, 1); - UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05, 1); - UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06, 1); - UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07, 1); - UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08, 1); - UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09, 1); - UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10, 1); - UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11, 1); - UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12, 1); - UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13, 1); - UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14, 1); - UtRegisterTest("SSHParserTest15", SSHParserTest15, 1); - UtRegisterTest("SSHParserTest16", SSHParserTest16, 1); - UtRegisterTest("SSHParserTest17", SSHParserTest17, 1); - UtRegisterTest("SSHParserTest18", SSHParserTest18, 1); - UtRegisterTest("SSHParserTest19", SSHParserTest19, 1); - UtRegisterTest("SSHParserTest20", SSHParserTest20, 1); - UtRegisterTest("SSHParserTest21", SSHParserTest21, 1); - UtRegisterTest("SSHParserTest22", SSHParserTest22, 1); - UtRegisterTest("SSHParserTest23", SSHParserTest23, 1); - UtRegisterTest("SSHParserTest24", SSHParserTest24, 1); + UtRegisterTest("SSHParserTest01 - ToServer", SSHParserTest01); + UtRegisterTest("SSHParserTest02 - ToServer", SSHParserTest02); + UtRegisterTest("SSHParserTest03 - ToServer", SSHParserTest03); + UtRegisterTest("SSHParserTest04 - ToClient", SSHParserTest04); + UtRegisterTest("SSHParserTest05 - ToClient", SSHParserTest05); + UtRegisterTest("SSHParserTest06 - ToClient", SSHParserTest06); + UtRegisterTest("SSHParserTest07 - ToServer 2 chunks", SSHParserTest07); + UtRegisterTest("SSHParserTest08 - ToServer 3 chunks", SSHParserTest08); + UtRegisterTest("SSHParserTest09 - ToClient 2 chunks", SSHParserTest09); + UtRegisterTest("SSHParserTest10 - ToClient 3 chunks", SSHParserTest10); + UtRegisterTest("SSHParserTest11 - ToClient 4 chunks", SSHParserTest11); + UtRegisterTest("SSHParserTest12 - ToClient 4 chunks", SSHParserTest12); + UtRegisterTest("SSHParserTest13 - ToClient 4 chunks", SSHParserTest13); + UtRegisterTest("SSHParserTest14 - ToClient 4 chunks", SSHParserTest14); + UtRegisterTest("SSHParserTest15", SSHParserTest15); + UtRegisterTest("SSHParserTest16", SSHParserTest16); + UtRegisterTest("SSHParserTest17", SSHParserTest17); + UtRegisterTest("SSHParserTest18", SSHParserTest18); + UtRegisterTest("SSHParserTest19", SSHParserTest19); + UtRegisterTest("SSHParserTest20", SSHParserTest20); + UtRegisterTest("SSHParserTest21", SSHParserTest21); + UtRegisterTest("SSHParserTest22", SSHParserTest22); + UtRegisterTest("SSHParserTest23", SSHParserTest23); + UtRegisterTest("SSHParserTest24", SSHParserTest24); #endif /* UNITTESTS */ } diff --git a/src/app-layer-ssh.h b/src/app-layer-ssh.h index 7a6a9b723427..7fa368812b95 100644 --- a/src/app-layer-ssh.h +++ b/src/app-layer-ssh.h @@ -32,8 +32,6 @@ * must be ciphered, so the parsing finish here */ #define SSH_FLAG_PARSER_DONE 0x02 -#define SSH_FLAG_STATE_LOGGED 0x04 - /* MSG_CODE */ #define SSH_MSG_NEWKEYS 21 @@ -54,6 +52,7 @@ typedef struct SshHeader_ { uint32_t pkt_len; uint8_t padding_len; uint8_t msg_code; + uint16_t banner_len; uint8_t buf[6]; uint8_t buf_offset; uint8_t flags; @@ -61,13 +60,23 @@ typedef struct SshHeader_ { uint8_t *proto_version; uint8_t *software_version; uint8_t *banner_buffer; - uint16_t banner_len; } SshHeader; +enum { + SSH_STATE_IN_PROGRESS, + SSH_STATE_BANNER_DONE, + SSH_STATE_FINISHED, +}; + /** structure to store the SSH state values */ typedef struct SshState_ { SshHeader srv_hdr; SshHeader cli_hdr; + + /* specifies which loggers are done logging */ + uint32_t logged; + + DetectEngineState *de_state; } SshState; void RegisterSSHParsers(void); diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index fc7583b1d0c4..f6839adc5ff2 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -20,6 +20,7 @@ * * \author Anoop Saldanha * \author Pierre Chifflier + * \author Mats Klepsland * */ @@ -28,9 +29,6 @@ #include "decode.h" #include "threads.h" -#include "util-print.h" -#include "util-pool.h" - #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" @@ -40,7 +38,6 @@ #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-ssl.h" - #include "app-layer-tls-handshake.h" #include "decode-events.h" @@ -49,11 +46,12 @@ #include "util-spm.h" #include "util-unittest.h" #include "util-debug.h" +#include "util-print.h" +#include "util-pool.h" +#include "util-byte.h" #include "flow-util.h" #include "flow-private.h" -#include "util-byte.h" - SCEnumCharMap tls_decoder_event_table[ ] = { /* TLS protocol messages */ { "INVALID_SSLV2_HEADER", TLS_DECODER_EVENT_INVALID_SSLV2_HEADER }, @@ -65,7 +63,12 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { "INVALID_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_INVALID_HEARTBEAT }, { "OVERFLOW_HEARTBEAT_MESSAGE", TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT }, { "DATALEAK_HEARTBEAT_MISMATCH", TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH }, - /* Certificates decoding messages */ + { "HANDSHAKE_INVALID_LENGTH", TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH }, + { "MULTIPLE_SNI_EXTENSIONS", TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS }, + { "INVALID_SNI_TYPE", TLS_DECODER_EVENT_INVALID_SNI_TYPE }, + { "INVALID_SNI_LENGTH", TLS_DECODER_EVENT_INVALID_SNI_LENGTH }, + { "TOO_MANY_RECORDS_IN_PACKET", TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET }, + /* certificate decoding messages */ { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT }, { "CERTIFICATE_UNKNOWN_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT }, @@ -77,6 +80,9 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { NULL, -1 }, }; +/* by default we keep tracking */ +#define SSL_CONFIG_DEFAULT_NOREASSEMBLE 0 + typedef struct SslConfig_ { int no_reassemble; } SslConfig; @@ -84,50 +90,305 @@ typedef struct SslConfig_ { SslConfig ssl_config; /* SSLv3 record types */ -#define SSLV3_CHANGE_CIPHER_SPEC 20 -#define SSLV3_ALERT_PROTOCOL 21 -#define SSLV3_HANDSHAKE_PROTOCOL 22 -#define SSLV3_APPLICATION_PROTOCOL 23 -#define SSLV3_HEARTBEAT_PROTOCOL 24 +#define SSLV3_CHANGE_CIPHER_SPEC 20 +#define SSLV3_ALERT_PROTOCOL 21 +#define SSLV3_HANDSHAKE_PROTOCOL 22 +#define SSLV3_APPLICATION_PROTOCOL 23 +#define SSLV3_HEARTBEAT_PROTOCOL 24 /* SSLv3 handshake protocol types */ -#define SSLV3_HS_HELLO_REQUEST 0 -#define SSLV3_HS_CLIENT_HELLO 1 -#define SSLV3_HS_SERVER_HELLO 2 -#define SSLV3_HS_NEW_SESSION_TICKET 4 -#define SSLV3_HS_CERTIFICATE 11 -#define SSLV3_HS_SERVER_KEY_EXCHANGE 12 -#define SSLV3_HS_CERTIFICATE_REQUEST 13 -#define SSLV3_HS_SERVER_HELLO_DONE 14 -#define SSLV3_HS_CERTIFICATE_VERIFY 15 -#define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 -#define SSLV3_HS_FINISHED 20 -#define SSLV3_HS_CERTIFICATE_URL 21 -#define SSLV3_HS_CERTIFICATE_STATUS 22 +#define SSLV3_HS_HELLO_REQUEST 0 +#define SSLV3_HS_CLIENT_HELLO 1 +#define SSLV3_HS_SERVER_HELLO 2 +#define SSLV3_HS_NEW_SESSION_TICKET 4 +#define SSLV3_HS_CERTIFICATE 11 +#define SSLV3_HS_SERVER_KEY_EXCHANGE 12 +#define SSLV3_HS_CERTIFICATE_REQUEST 13 +#define SSLV3_HS_SERVER_HELLO_DONE 14 +#define SSLV3_HS_CERTIFICATE_VERIFY 15 +#define SSLV3_HS_CLIENT_KEY_EXCHANGE 16 +#define SSLV3_HS_FINISHED 20 +#define SSLV3_HS_CERTIFICATE_URL 21 +#define SSLV3_HS_CERTIFICATE_STATUS 22 /* SSLv2 protocol message types */ -#define SSLV2_MT_ERROR 0 -#define SSLV2_MT_CLIENT_HELLO 1 -#define SSLV2_MT_CLIENT_MASTER_KEY 2 -#define SSLV2_MT_CLIENT_FINISHED 3 -#define SSLV2_MT_SERVER_HELLO 4 -#define SSLV2_MT_SERVER_VERIFY 5 -#define SSLV2_MT_SERVER_FINISHED 6 -#define SSLV2_MT_REQUEST_CERTIFICATE 7 -#define SSLV2_MT_CLIENT_CERTIFICATE 8 - -#define SSLV3_RECORD_HDR_LEN 5 -#define SSLV3_MESSAGE_HDR_LEN 4 +#define SSLV2_MT_ERROR 0 +#define SSLV2_MT_CLIENT_HELLO 1 +#define SSLV2_MT_CLIENT_MASTER_KEY 2 +#define SSLV2_MT_CLIENT_FINISHED 3 +#define SSLV2_MT_SERVER_HELLO 4 +#define SSLV2_MT_SERVER_VERIFY 5 +#define SSLV2_MT_SERVER_FINISHED 6 +#define SSLV2_MT_REQUEST_CERTIFICATE 7 +#define SSLV2_MT_CLIENT_CERTIFICATE 8 + +#define SSLV3_RECORD_HDR_LEN 5 +#define SSLV3_MESSAGE_HDR_LEN 4 + +#define SSLV3_CLIENT_HELLO_VERSION_LEN 2 +#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32 /* TLS heartbeat protocol types */ -#define TLS_HB_REQUEST 1 -#define TLS_HB_RESPONSE 2 +#define TLS_HB_REQUEST 1 +#define TLS_HB_RESPONSE 2 + +#define SSL_PACKET_MAX_RECORDS 255 + +#define HAS_SPACE(n) ((uint32_t)((input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1 static void SSLParserReset(SSLState *ssl_state) { ssl_state->curr_connp->bytes_processed = 0; } +void SSLSetEvent(SSLState *ssl_state, uint8_t event) +{ + if (ssl_state == NULL) { + SCLogDebug("Could not set decoder event: %u", event); + return; + } + + AppLayerDecoderEventsSetEventRaw(&ssl_state->decoder_events, event); + ssl_state->events++; +} + +AppLayerDecoderEvents *SSLGetEvents(void *state, uint64_t id) +{ + SSLState *ssl_state = (SSLState *)state; + return ssl_state->decoder_events; +} + +int SSLHasEvents(void *state) +{ + SSLState *ssl_state = (SSLState *)state; + return (ssl_state->events > 0); +} + +int SSLStateHasTxDetectState(void *state) +{ + SSLState *ssl_state = (SSLState *)state; + if (ssl_state->de_state) + return 1; + + return 0; +} + +int SSLSetTxDetectState(void *state, void *vtx, DetectEngineState *de_state) +{ + SSLState *ssl_state = (SSLState *)state; + ssl_state->de_state = de_state; + return 0; +} + +DetectEngineState *SSLGetTxDetectState(void *vtx) +{ + SSLState *ssl_state = (SSLState *)vtx; + return ssl_state->de_state; +} + +void *SSLGetTx(void *state, uint64_t tx_id) +{ + SSLState *ssl_state = (SSLState *)state; + return ssl_state; +} + +uint64_t SSLGetTxCnt(void *state) +{ + /* single tx */ + return 1; +} + +void SSLSetTxLogged(void *state, void *tx, uint32_t logger) +{ + SSLState *ssl_state = (SSLState *)state; + if (ssl_state) + ssl_state->logged |= logger; +} + +int SSLGetTxLogged(void *state, void *tx, uint32_t logger) +{ + SSLState *ssl_state = (SSLState *)state; + if (ssl_state && (ssl_state->logged & logger)) + return 1; + + return 0; +} + +int SSLGetAlstateProgressCompletionStatus(uint8_t direction) +{ + return TLS_STATE_FINISHED; +} + +int SSLGetAlstateProgress(void *tx, uint8_t direction) +{ + SSLState *ssl_state = (SSLState *)tx; + + /* we don't care about direction, only that app-layer parser is done + and have sent an EOF */ + if (ssl_state->flags & SSL_AL_FLAG_STATE_FINISHED) { + return TLS_STATE_FINISHED; + } + + /* we want the logger to log when the handshake is done, even if the + state is not finished */ + if (ssl_state->flags & SSL_AL_FLAG_HANDSHAKE_DONE) { + return TLS_HANDSHAKE_DONE; + } + + if (direction == STREAM_TOSERVER && + (ssl_state->server_connp.cert0_subject != NULL || + ssl_state->server_connp.cert0_issuerdn != NULL)) + { + return TLS_STATE_CERT_READY; + } + + return TLS_STATE_IN_PROGRESS; +} + +static int TLSDecodeHandshakeHello(SSLState *ssl_state, uint8_t *input, + uint32_t input_len) +{ + uint8_t *initial_input = input; + + /* only parse the message if it is complete */ + if (input_len < ssl_state->curr_connp->message_length || input_len < 40) + return 0; + + /* skip version */ + input += SSLV3_CLIENT_HELLO_VERSION_LEN; + + /* skip random */ + input += SSLV3_CLIENT_HELLO_RANDOM_LEN; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + /* skip session id */ + uint8_t session_id_length = *(input++); + + input += session_id_length; + + if (!(HAS_SPACE(2))) + goto invalid_length; + + /* skip cipher suites */ + uint16_t cipher_suites_length = input[0] << 8 | input[1]; + input += 2; + + input += cipher_suites_length; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + /* skip compression methods */ + uint8_t compression_methods_length = *(input++); + + input += compression_methods_length; + + /* extensions are optional (RFC5246 section 7.4.1.2) */ + if (!(HAS_SPACE(2))) + goto end; + + uint16_t extensions_len = input[0] << 8 | input[1]; + input += 2; + + if (!(HAS_SPACE(extensions_len))) + goto invalid_length; + + uint16_t processed_len = 0; + while (processed_len < extensions_len) + { + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t ext_type = input[0] << 8 | input[1]; + input += 2; + + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t ext_len = input[0] << 8 | input[1]; + input += 2; + + switch (ext_type) { + case SSL_EXTENSION_SNI: + { + /* there must not be more than one extension of the same + type (RFC5246 section 7.4.1.4) */ + if (ssl_state->curr_connp->sni) { + SCLogDebug("Multiple SNI extensions"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS); + return -1; + } + + /* skip sni_list_length */ + input += 2; + + if (!(HAS_SPACE(1))) + goto invalid_length; + + uint8_t sni_type = *(input++); + + /* currently the only type allowed is host_name + (RFC6066 section 3) */ + if (sni_type != SSL_SNI_TYPE_HOST_NAME) { + SCLogDebug("Unknown SNI type"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SNI_TYPE); + return -1; + } + + if (!(HAS_SPACE(2))) + goto invalid_length; + + uint16_t sni_len = input[0] << 8 | input[1]; + input += 2; + + if (!(HAS_SPACE(sni_len))) + goto invalid_length; + + /* host_name contains the fully qualified domain name, + and should therefore be limited by the maximum domain + name length */ + if (sni_len > 255) { + SCLogDebug("SNI length >255"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SNI_LENGTH); + return -1; + } + + size_t sni_strlen = sni_len + 1; + ssl_state->curr_connp->sni = SCMalloc(sni_strlen); + + if (unlikely(ssl_state->curr_connp->sni == NULL)) + goto end; + + memcpy(ssl_state->curr_connp->sni, input, sni_strlen - 1); + ssl_state->curr_connp->sni[sni_strlen-1] = 0; + + input += sni_len; + break; + } + default: + { + input += ext_len; + break; + } + } + processed_len += ext_len + 4; + } + +end: + return 0; + +invalid_length: + SCLogDebug("TLS handshake invalid length"); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH); + return 0; +} + static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, uint32_t input_len) { @@ -142,69 +403,96 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, switch (ssl_state->curr_connp->handshake_type) { case SSLV3_HS_CLIENT_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; + + rc = TLSDecodeHandshakeHello(ssl_state, input, input_len); + + if (rc < 0) + return rc; + break; case SSLV3_HS_SERVER_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; - + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; break; case SSLV3_HS_SERVER_KEY_EXCHANGE: - ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_KEYX; + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_KEYX; break; case SSLV3_HS_CLIENT_KEY_EXCHANGE: - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; break; case SSLV3_HS_CERTIFICATE: if (ssl_state->curr_connp->trec == NULL) { - ssl_state->curr_connp->trec_len = 2 * ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN + 1; - ssl_state->curr_connp->trec = SCMalloc( ssl_state->curr_connp->trec_len ); + ssl_state->curr_connp->trec_len = + 2 * ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN + 1; + ssl_state->curr_connp->trec = + SCMalloc(ssl_state->curr_connp->trec_len); } - if (ssl_state->curr_connp->trec_pos + input_len >= ssl_state->curr_connp->trec_len) { - ssl_state->curr_connp->trec_len = ssl_state->curr_connp->trec_len + 2 * input_len + 1; + if (ssl_state->curr_connp->trec_pos + input_len >= + ssl_state->curr_connp->trec_len) { + ssl_state->curr_connp->trec_len = + ssl_state->curr_connp->trec_len + 2 * input_len + 1; ptmp = SCRealloc(ssl_state->curr_connp->trec, - ssl_state->curr_connp->trec_len); + ssl_state->curr_connp->trec_len); + if (unlikely(ptmp == NULL)) { SCFree(ssl_state->curr_connp->trec); } + ssl_state->curr_connp->trec = ptmp; } if (unlikely(ssl_state->curr_connp->trec == NULL)) { ssl_state->curr_connp->trec_len = 0; /* error, skip packet */ parsed += input_len; + (void)parsed; /* for scan-build */ ssl_state->curr_connp->bytes_processed += input_len; return -1; } uint32_t write_len = 0; - if ((ssl_state->curr_connp->bytes_processed + input_len) > ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { - if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + if ((ssl_state->curr_connp->bytes_processed + input_len) > + ssl_state->curr_connp->record_length + + (SSLV3_RECORD_HDR_LEN)) { + if ((ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) < + ssl_state->curr_connp->bytes_processed) { + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - write_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; + write_len = (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) - + ssl_state->curr_connp->bytes_processed; } else { write_len = input_len; } - memcpy(ssl_state->curr_connp->trec + ssl_state->curr_connp->trec_pos, initial_input, write_len); + + memcpy(ssl_state->curr_connp->trec + + ssl_state->curr_connp->trec_pos, initial_input, write_len); ssl_state->curr_connp->trec_pos += write_len; - rc = DecodeTLSHandshakeServerCertificate(ssl_state, ssl_state->curr_connp->trec, ssl_state->curr_connp->trec_pos); + rc = DecodeTLSHandshakeServerCertificate(ssl_state, + ssl_state->curr_connp->trec, + ssl_state->curr_connp->trec_pos); + if (rc > 0) { /* do not return normally if the packet was fragmented: - * we would return the size of the *entire* message, - * while we expect only the number of bytes parsed bytes - * from the *current* fragment - */ + we would return the size of the _entire_ message, + while we expect only the number of bytes parsed bytes + from the _current_ fragment */ if (write_len < (ssl_state->curr_connp->trec_pos - rc)) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - uint32_t diff = write_len - (ssl_state->curr_connp->trec_pos - rc); + + uint32_t diff = write_len - + (ssl_state->curr_connp->trec_pos - rc); ssl_state->curr_connp->bytes_processed += diff; ssl_state->curr_connp->trec_pos = 0; @@ -231,28 +519,39 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input, SCLogDebug("new session ticket"); break; default: - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } + ssl_state->flags |= ssl_state->current_flags; + uint32_t write_len = 0; - if ((ssl_state->curr_connp->bytes_processed + input_len) >= ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { - if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + if ((ssl_state->curr_connp->bytes_processed + input_len) >= + ssl_state->curr_connp->record_length + (SSLV3_RECORD_HDR_LEN)) { + if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < + ssl_state->curr_connp->bytes_processed) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - write_len = (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; + write_len = (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) - ssl_state->curr_connp->bytes_processed; } else { write_len = input_len; } - if ((ssl_state->curr_connp->trec_pos + write_len) >= ssl_state->curr_connp->message_length) { - if (ssl_state->curr_connp->message_length < ssl_state->curr_connp->trec_pos) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + + if ((ssl_state->curr_connp->trec_pos + write_len) >= + ssl_state->curr_connp->message_length) { + if (ssl_state->curr_connp->message_length < + ssl_state->curr_connp->trec_pos) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - parsed += ssl_state->curr_connp->message_length - ssl_state->curr_connp->trec_pos; + parsed += ssl_state->curr_connp->message_length - + ssl_state->curr_connp->trec_pos; - ssl_state->curr_connp->bytes_processed += ssl_state->curr_connp->message_length - ssl_state->curr_connp->trec_pos; + ssl_state->curr_connp->bytes_processed += + ssl_state->curr_connp->message_length - + ssl_state->curr_connp->trec_pos; ssl_state->curr_connp->handshake_type = 0; ssl_state->curr_connp->hs_bytes_processed = 0; @@ -274,10 +573,8 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, uint8_t *initial_input = input; int retval; - if (input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) { return 0; } @@ -286,40 +583,41 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, ssl_state->curr_connp->handshake_type = *(input++); ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; - if (--input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } + /* fall through */ case 1: ssl_state->curr_connp->message_length = *(input++) << 16; ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; - if (--input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } + /* fall through */ case 2: ssl_state->curr_connp->message_length |= *(input++) << 8; ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; - if (--input_len == 0 || - ssl_state->curr_connp->bytes_processed == - (ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN)) - { + if (--input_len == 0 || ssl_state->curr_connp->bytes_processed == + (ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN)) { return (input - initial_input); } + /* fall through */ case 3: ssl_state->curr_connp->message_length |= *(input++); ssl_state->curr_connp->bytes_processed++; ssl_state->curr_connp->hs_bytes_processed++; --input_len; + /* fall through */ } @@ -327,6 +625,7 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, if (retval < 0) { return retval; } + input += retval; return (input - initial_input); @@ -337,7 +636,7 @@ static int SSLv3ParseHandshakeProtocol(SSLState *ssl_state, uint8_t *input, * \brief TLS Heartbeat parser (see RFC 6520) * * \param sslstate Pointer to the SSL state. - * \param input Pointer the received input data. + * \param input Pointer to the received input data. * \param input_len Length in bytes of the received data. * \param direction 1 toclient, 0 toserver * @@ -350,16 +649,16 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, uint16_t payload_len; uint16_t padding_len; - // expect at least 3 bytes, heartbeat type (1) + length (2) + /* expect at least 3 bytes: heartbeat type (1) + length (2) */ if (input_len < 3) { return 0; } + hb_type = *input++; if (!(ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { if (!(hb_type == TLS_HB_REQUEST || hb_type == TLS_HB_RESPONSE)) { - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } } @@ -368,85 +667,91 @@ static int SSLv3ParseHeartbeatProtocol(SSLState *ssl_state, uint8_t *input, ssl_state->flags |= SSL_AL_FLAG_HB_INFLIGHT; if (direction) { + SCLogDebug("HeartBeat Record type sent in the toclient direction!"); ssl_state->flags |= SSL_AL_FLAG_HB_SERVER_INIT; - SCLogDebug("HeartBeat Record type sent in the toclient " - "direction!"); } else { + SCLogDebug("HeartBeat Record type sent in the toserver direction!"); ssl_state->flags |= SSL_AL_FLAG_HB_CLIENT_INIT; - SCLogDebug("HeartBeat Record type sent in the toserver " - "direction!"); } - /* if we reach this poin then can we assume that the HB request - * is encrypted if so lets set the heartbeat record len */ + + /* if we reach this point, then we can assume that the HB request + is encrypted. If so, let's set the HB record length */ if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { ssl_state->hb_record_len = ssl_state->curr_connp->record_length; - SCLogDebug("Encrypted HeartBeat Request In-flight. Storing len %u", ssl_state->hb_record_len); + SCLogDebug("Encrypted HeartBeat Request In-flight. Storing len %u", + ssl_state->hb_record_len); return (ssl_state->curr_connp->record_length - 3); } payload_len = (*input++) << 8; payload_len |= (*input++); - // check that the requested payload length is really present in record (CVE-2014-0160) + /* check that the requested payload length is really present in + the record (CVE-2014-0160) */ if ((uint32_t)(payload_len+3) > ssl_state->curr_connp->record_length) { SCLogDebug("We have a short record in HeartBeat Request"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT); return -1; } - // check the padding length - // it must be at least 16 bytes (RFC 6520, section 4) + /* check the padding length. It must be at least 16 bytes + (RFC 6520, section 4) */ padding_len = ssl_state->curr_connp->record_length - payload_len - 3; if (padding_len < 16) { SCLogDebug("We have a short record in HeartBeat Request"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; } - if (input_len < payload_len+padding_len) { // we don't have the payload + /* we don't have the payload */ + if (input_len < payload_len + padding_len) { return 0; } /* OpenSSL still seems to discard multiple in-flight - * heartbeats although some tools send multiple at once */ + heartbeats although some tools send multiple at once */ } else if (direction == 1 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_SERVER_INIT)) { - SCLogDebug("Multiple In-Flight Server Intiated HeartBeats"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SCLogDebug("Multiple in-flight server initiated HeartBeats"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; + } else if (direction == 0 && (ssl_state->flags & SSL_AL_FLAG_HB_INFLIGHT) && (ssl_state->flags & SSL_AL_FLAG_HB_CLIENT_INIT)) { - SCLogDebug("Multiple In-Flight Client Intiated HeartBeats"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HEARTBEAT); + SCLogDebug("Multiple in-flight client initiated HeartBeats"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_HEARTBEAT); return -1; + } else { - /* we have a HB record in the opposite direction of the request - * lets reset our flags */ + /* we have a HB record in the opposite direction of the request, + let's reset our flags */ ssl_state->flags &= ~SSL_AL_FLAG_HB_INFLIGHT; ssl_state->flags &= ~SSL_AL_FLAG_HB_SERVER_INIT; ssl_state->flags &= ~SSL_AL_FLAG_HB_CLIENT_INIT; - /* if we reach this poin then can we assume that the HB request is - *encrypted if so lets set the heartbeat record len */ + /* if we reach this point, then we can assume that the HB request + is encrypted. If so, let's set the HB record length */ if (ssl_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) { /* check to see if the encrypted response is longer than the - * encrypted request */ - if (ssl_state->hb_record_len > 0 && - ssl_state->hb_record_len < ssl_state->curr_connp->record_length) - { - SCLogDebug("My Heart It's Bleeding.. OpenSSL HeartBleed Response (%u)", + encrypted request */ + if (ssl_state->hb_record_len > 0 && ssl_state->hb_record_len < + ssl_state->curr_connp->record_length) { + SCLogDebug("My heart is bleeding.. OpenSSL HeartBleed response (%u)", ssl_state->hb_record_len); - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH); ssl_state->hb_record_len = 0; return -1; } } - /* reset the hb record len in-case we have legit hb's followed by a bad one */ + + /* reset the HB record length in case we have a legit HB followed + by a bad one */ ssl_state->hb_record_len = 0; } - /* skip the heartbeat, 3 bytes were already parsed, e.g |18 03 02| for TLS 1.2 */ + /* skip the HeartBeat, 3 bytes were already parsed, + e.g |18 03 02| for TLS 1.2 */ return (ssl_state->curr_connp->record_length - 3); } @@ -474,28 +779,33 @@ static int SSLv3ParseRecord(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + /* fall through */ case 1: ssl_state->curr_connp->version = *(input++) << 8; if (--input_len == 0) break; + /* fall through */ case 2: ssl_state->curr_connp->version |= *(input++); if (--input_len == 0) break; + /* fall through */ case 3: ssl_state->curr_connp->record_length = *(input++) << 8; if (--input_len == 0) break; + /* fall through */ case 4: ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } ssl_state->curr_connp->bytes_processed += (input - initial_input); @@ -531,14 +841,16 @@ static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, ssl_state->curr_connp->record_length |= *(input++); if (--input_len == 0) break; + /* fall through */ case 2: ssl_state->curr_connp->content_type = *(input++); ssl_state->curr_connp->version = SSL_VERSION_2; if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } } else { switch (ssl_state->curr_connp->bytes_processed) { @@ -554,6 +866,7 @@ static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + /* fall through */ case 1: ssl_state->curr_connp->record_length |= *(input++); @@ -573,8 +886,9 @@ static int SSLv2ParseRecord(uint8_t direction, SSLState *ssl_state, ssl_state->curr_connp->version = SSL_VERSION_2; if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } } ssl_state->curr_connp->bytes_processed += (input - initial_input); @@ -597,12 +911,13 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, } } - /* the + 1 because, we also read one extra byte inside SSLv2ParseRecord - * to read the msg_type */ - if (ssl_state->curr_connp->bytes_processed < (ssl_state->curr_connp->record_lengths_length + 1)) { + /* the +1 is because we read one extra byte inside SSLv2ParseRecord + to read the msg_type */ + if (ssl_state->curr_connp->bytes_processed < + (ssl_state->curr_connp->record_lengths_length + 1)) { retval = SSLv2ParseRecord(direction, ssl_state, input, input_len); if (retval == -1) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); return -1; } else { input += retval; @@ -614,18 +929,31 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, return (input - initial_input); } + /* record_length should never be zero */ + if (ssl_state->curr_connp->record_length == 0) { + SCLogDebug("SSLv2 record length is zero"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return -1; + } + + /* record_lenghts_length should never be zero */ + if (ssl_state->curr_connp->record_lengths_length == 0) { + SCLogDebug("SSLv2 record lengths length is zero"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSLV2_HEADER); + return -1; + } + switch (ssl_state->curr_connp->content_type) { case SSLV2_MT_ERROR: - SCLogDebug("SSLV2_MT_ERROR msg_type received. " - "Error encountered in establishing the sslv2 " - "session, may be version"); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); + SCLogDebug("SSLV2_MT_ERROR msg_type received. Error encountered " + "in establishing the sslv2 session, may be version"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED); break; case SSLV2_MT_CLIENT_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO; - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_HS; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_HELLO; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_HS; if (ssl_state->curr_connp->record_lengths_length == 3) { switch (ssl_state->curr_connp->bytes_processed) { @@ -637,8 +965,9 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, input_len -= 6; ssl_state->curr_connp->bytes_processed += 6; if (ssl_state->curr_connp->session_id_length == 0) { - ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } + break; } else { input++; @@ -646,40 +975,45 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + /* fall through */ case 5: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 6: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 7: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 8: ssl_state->curr_connp->session_id_length = *(input++) << 8; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ case 9: ssl_state->curr_connp->session_id_length |= *(input++); ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + /* fall through */ - } /* switch (ssl_state->curr_connp->bytes_processed) */ + } - /* ssl_state->curr_connp->record_lengths_length is 3 */ } else { switch (ssl_state->curr_connp->bytes_processed) { case 3: @@ -690,8 +1024,9 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, input_len -= 6; ssl_state->curr_connp->bytes_processed += 6; if (ssl_state->curr_connp->session_id_length == 0) { - ssl_state->flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_NO_SESSION_ID; } + break; } else { input++; @@ -699,42 +1034,47 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, if (--input_len == 0) break; } + case 4: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 5: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 6: input++; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 7: ssl_state->curr_connp->session_id_length = *(input++) << 8; ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; + case 8: ssl_state->curr_connp->session_id_length |= *(input++); ssl_state->curr_connp->bytes_processed++; if (--input_len == 0) break; - } /* switch (ssl_state->curr_connp->bytes_processed) */ - } /* else - if (ssl_state->curr_connp->record_lengths_length == 3) */ + } + } break; case SSLV2_MT_CLIENT_MASTER_KEY: - if ( !(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { + if (!(ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS)) { SCLogDebug("Client hello is not seen before master key " - "message!!"); + "message!"); } - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; + ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY; break; @@ -743,42 +1083,46 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, SCLogDebug("Incorrect SSL Record type sent in the toclient " "direction!"); } else { - ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_KEYX; + ssl_state->current_flags = SSL_AL_FLAG_STATE_CLIENT_KEYX; } + /* fall through */ case SSLV2_MT_SERVER_VERIFY: case SSLV2_MT_SERVER_FINISHED: if (direction == 0 && - !(ssl_state->curr_connp->content_type & SSLV2_MT_CLIENT_CERTIFICATE)) { + !(ssl_state->curr_connp->content_type & + SSLV2_MT_CLIENT_CERTIFICATE)) { SCLogDebug("Incorrect SSL Record type sent in the toserver " "direction!"); } + /* fall through */ case SSLV2_MT_CLIENT_FINISHED: case SSLV2_MT_REQUEST_CERTIFICATE: - /* both ways hello seen */ + /* both client hello and server hello must be seen */ if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) && - (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { + (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_HS)) { if (direction == 0) { if (ssl_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) { - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 client side has started the encryption"); } else if (ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_MASTER_KEY) { - ssl_state->flags |= SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; + ssl_state->current_flags = SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED; SCLogDebug("SSLv2 client side has started the encryption"); } } else { - ssl_state->flags |= SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; + ssl_state->current_flags = SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED; SCLogDebug("SSLv2 Server side has started the encryption"); } if ((ssl_state->flags & SSL_AL_FLAG_SSL_CLIENT_SSN_ENCRYPTED) && - (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { + (ssl_state->flags & SSL_AL_FLAG_SSL_SERVER_SSN_ENCRYPTED)) { AppLayerParserStateSetFlag(pstate, - APP_LAYER_PARSER_NO_INSPECTION); + APP_LAYER_PARSER_NO_INSPECTION); if (ssl_config.no_reassemble == 1) - AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); + AppLayerParserStateSetFlag(pstate, + APP_LAYER_PARSER_NO_REASSEMBLY); SCLogDebug("SSLv2 No reassembly & inspection has been set"); } } @@ -786,23 +1130,28 @@ static int SSLv2Decode(uint8_t direction, SSLState *ssl_state, break; case SSLV2_MT_SERVER_HELLO: - ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO; - ssl_state->flags |= SSL_AL_FLAG_SSL_SERVER_HS; + ssl_state->current_flags = SSL_AL_FLAG_STATE_SERVER_HELLO; + ssl_state->current_flags |= SSL_AL_FLAG_SSL_SERVER_HS; break; } + ssl_state->flags |= ssl_state->current_flags; + if (input_len + ssl_state->curr_connp->bytes_processed >= - (ssl_state->curr_connp->record_length + ssl_state->curr_connp->record_lengths_length)) { - /* looks like we have another record after this*/ + (ssl_state->curr_connp->record_length + + ssl_state->curr_connp->record_lengths_length)) { + + /* looks like we have another record after this */ uint32_t diff = ssl_state->curr_connp->record_length + - ssl_state->curr_connp->record_lengths_length + - ssl_state->curr_connp->bytes_processed; + ssl_state->curr_connp->record_lengths_length + - + ssl_state->curr_connp->bytes_processed; input += diff; SSLParserReset(ssl_state); return (input - initial_input); - /* we still don't have the entire record for the one we are - * currently parsing */ + /* we still don't have the entire record for the one we are + currently parsing */ } else { input += input_len; ssl_state->curr_connp->bytes_processed += input_len; @@ -820,7 +1169,7 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->bytes_processed < SSLV3_RECORD_HDR_LEN) { retval = SSLv3ParseRecord(direction, ssl_state, input, input_len); if (retval < 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_TLS_HEADER); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } else { parsed += retval; @@ -834,10 +1183,16 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, /* check record version */ if (ssl_state->curr_connp->version < SSL_VERSION_3 || - ssl_state->curr_connp->version > TLS_VERSION_12) { + ssl_state->curr_connp->version > TLS_VERSION_12) { + + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_VERSION); + return -1; + } - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_RECORD_VERSION); + /* record_length should never be zero */ + if (ssl_state->curr_connp->record_length == 0) { + SCLogDebug("SSLv3 Record length is 0"); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_TLS_HEADER); return -1; } @@ -856,15 +1211,28 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, case SSLV3_ALERT_PROTOCOL: break; + case SSLV3_APPLICATION_PROTOCOL: if ((ssl_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) && - (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) { + (ssl_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC)) { /* AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION); if (ssl_config.no_reassemble == 1) AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); */ - AppLayerParserStateSetFlag(pstate,APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); + AppLayerParserStateSetFlag(pstate, + APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD); + } + + /* if we see (encrypted) aplication data, then this means the + handshake must be done */ + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + + /* Encrypted data, reassembly not asked, bypass asked, let's sacrifice + * heartbeat lke inspection to be able to be able to bypass the flow */ + if (ssl_config.no_reassemble == 1) { + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_REASSEMBLY); + AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION); } break; @@ -875,59 +1243,80 @@ static int SSLv3Decode(uint8_t direction, SSLState *ssl_state, if (ssl_state->curr_connp->record_length < 4) { SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } retval = SSLv3ParseHandshakeProtocol(ssl_state, input + parsed, input_len); if (retval < 0) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_HANDSHAKE_MESSAGE); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { if ((uint32_t)retval > input_len) { - SCLogDebug("Error parsing SSLv3.x. Reseting parser " - "state. Let's get outta here"); + SCLogDebug("Error parsing SSLv3.x. Reseting parser " + "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } + parsed += retval; input_len -= retval; - if (ssl_state->curr_connp->bytes_processed == ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { + (void)input_len; /* for scan-build */ + + if (ssl_state->curr_connp->bytes_processed == + ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN) { SSLParserReset(ssl_state); } + + SCLogDebug("trigger RAW! (post HS)"); + AppLayerParserTriggerRawStreamReassembly(ssl_state->f); return parsed; } break; + case SSLV3_HEARTBEAT_PROTOCOL: - retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, input_len, direction); + retval = SSLv3ParseHeartbeatProtocol(ssl_state, input + parsed, + input_len, direction); if (retval < 0) return -1; + break; default: /* \todo fix the event from invalid rule to unknown rule */ - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_RECORD_TYPE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } - if (input_len + ssl_state->curr_connp->bytes_processed >= ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { - if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < ssl_state->curr_connp->bytes_processed) { - /* defensive checks. Something's wrong. */ - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + if (input_len + ssl_state->curr_connp->bytes_processed >= + ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) { + if ((ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN) < + ssl_state->curr_connp->bytes_processed) { + /* defensive checks. Something is wrong. */ + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } + + SCLogDebug("record complete, trigger RAW"); + AppLayerParserTriggerRawStreamReassembly(ssl_state->f); + /* looks like we have another record */ - uint32_t diff = ssl_state->curr_connp->record_length + SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed; + uint32_t diff = ssl_state->curr_connp->record_length + + SSLV3_RECORD_HDR_LEN - ssl_state->curr_connp->bytes_processed; parsed += diff; SSLParserReset(ssl_state); return parsed; - /* we still don't have the entire record for the one we are - * currently parsing */ + /* we still don't have the entire record for the one we are + currently parsing */ } else { parsed += input_len; ssl_state->curr_connp->bytes_processed += input_len; @@ -967,24 +1356,38 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt ssl_state->f = f; + if (input == NULL && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + /* flag session as finished if APP_LAYER_PARSER_EOF is set */ + ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; + SCReturnInt(1); + } else if (input == NULL || input_len == 0) { + SCReturnInt(-1); + } + if (direction == 0) ssl_state->curr_connp = &ssl_state->client_connp; else ssl_state->curr_connp = &ssl_state->server_connp; + /* If entering on a new record, reset the current flags. */ + if (ssl_state->curr_connp->bytes_processed == 0) { + ssl_state->current_flags = 0; + } + /* if we have more than one record */ while (input_len > 0) { - if (counter++ == 30) { - SCLogDebug("Looks like we have looped quite a bit. Reset state " + if (counter++ == SSL_PACKET_MAX_RECORDS) { + SCLogDebug("Looks like we have looped quite a bit. Reset state " "and get out of here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET); return -1; } - /* ssl_state->bytes_processed is 0 for a - * fresh record or positive to indicate a record currently being - * parsed */ + /* ssl_state->bytes_processed is zero for a fresh record or + positive to indicate a record currently being parsed */ switch (ssl_state->curr_connp->bytes_processed) { /* fresh record */ case 0: @@ -995,10 +1398,11 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt retval = SSLv2Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { - SCLogDebug("Error parsing SSLv2.x. Reseting parser " - "state. Let's get outta here"); + SCLogDebug("Error parsing SSLv2.x. Reseting parser " + "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { input_len -= retval; @@ -1007,15 +1411,16 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt } else { SCLogDebug("SSLv3.x detected"); /* we will keep it this way till our record parser tells - * us what exact version it is */ + us what exact version this is */ ssl_state->curr_connp->version = TLS_VERSION_UNKNOWN; retval = SSLv3Decode(direction, ssl_state, pstate, input, input_len); if (retval < 0) { - SCLogDebug("Error parsing SSLv3.x. Reseting parser " - "state. Let's get outta here"); + SCLogDebug("Error parsing SSLv3.x. Reseting parser " + "state. Let's get outta here"); SSLParserReset(ssl_state); - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_SSL_RECORD); + SSLSetEvent(ssl_state, + TLS_DECODER_EVENT_INVALID_SSL_RECORD); return -1; } else { input_len -= retval; @@ -1038,7 +1443,7 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt "previously left off"); retval = SSLv2Decode(direction, ssl_state, pstate, input, input_len); - if (retval == -1) { + if (retval < 0) { SCLogDebug("Error parsing SSLv2.x. Reseting parser " "state. Let's get outta here"); SSLParserReset(ssl_state); @@ -1077,6 +1482,15 @@ static int SSLDecode(Flow *f, uint8_t direction, void *alstate, AppLayerParserSt } /* switch (ssl_state->curr_connp->bytes_processed) */ } /* while (input_len) */ + /* mark handshake as done if we have subject and issuer */ + if (ssl_state->server_connp.cert0_subject && + ssl_state->server_connp.cert0_issuerdn) + ssl_state->flags |= SSL_AL_FLAG_HANDSHAKE_DONE; + + /* flag session as finished if APP_LAYER_PARSER_EOF is set */ + if (AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) + ssl_state->flags |= SSL_AL_FLAG_STATE_FINISHED; + return 1; } @@ -1126,8 +1540,12 @@ void SSLStateFree(void *p) SCFree(ssl_state->client_connp.cert0_subject); if (ssl_state->client_connp.cert0_issuerdn) SCFree(ssl_state->client_connp.cert0_issuerdn); + if (ssl_state->server_connp.cert0_serial) + SCFree(ssl_state->server_connp.cert0_serial); if (ssl_state->client_connp.cert0_fingerprint) SCFree(ssl_state->client_connp.cert0_fingerprint); + if (ssl_state->client_connp.sni) + SCFree(ssl_state->client_connp.sni); if (ssl_state->server_connp.trec) SCFree(ssl_state->server_connp.trec); @@ -1137,6 +1555,14 @@ void SSLStateFree(void *p) SCFree(ssl_state->server_connp.cert0_issuerdn); if (ssl_state->server_connp.cert0_fingerprint) SCFree(ssl_state->server_connp.cert0_fingerprint); + if (ssl_state->server_connp.sni) + SCFree(ssl_state->server_connp.sni); + + AppLayerDecoderEventsFreeEvents(&ssl_state->decoder_events); + + if (ssl_state->de_state != NULL) { + DetectEngineStateFree(ssl_state->de_state); + } /* Free certificate chain */ while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) { @@ -1150,6 +1576,11 @@ void SSLStateFree(void *p) return; } +void SSLStateTransactionFree(void *state, uint64_t tx_id) +{ + /* do nothing */ +} + static uint16_t SSLProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset) { /* probably a rst/fin sending an eof */ @@ -1176,7 +1607,7 @@ int SSLStateGetEventInfo(const char *event_name, return -1; } - *event_type = APP_LAYER_EVENT_TYPE_GENERAL; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; return 0; } @@ -1346,12 +1777,12 @@ void RegisterSSLParsers(void) ALPROTO_TLS, 0, 3, STREAM_TOSERVER, - SSLProbingParser); + SSLProbingParser, NULL); } else { AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, proto_name, ALPROTO_TLS, 0, 3, - SSLProbingParser); + SSLProbingParser, NULL); } } else { SCLogInfo("Protocol detection and parser disabled for %s protocol", @@ -1365,18 +1796,40 @@ void RegisterSSLParsers(void) AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOCLIENT, SSLParseServerRecord); + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TLS, SSLStateGetEventInfo); AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateAlloc, SSLStateFree); + AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_TLS, STREAM_TOSERVER); + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TLS, SSLStateTransactionFree); + + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetEvents); + + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_TLS, SSLHasEvents); + + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLStateHasTxDetectState, + SSLGetTxDetectState, SSLSetTxDetectState); + + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TLS, SSLGetTx); + + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxCnt); + + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_TLS, SSLGetAlstateProgress); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_TLS, SSLGetTxLogged, SSLSetTxLogged); + + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TLS, + SSLGetAlstateProgressCompletionStatus); + /* Get the value of no reassembly option from the config file */ if (ConfGetNode("app-layer.protocols.tls.no-reassemble") == NULL) { if (ConfGetBool("tls.no-reassemble", &ssl_config.no_reassemble) != 1) - ssl_config.no_reassemble = 1; + ssl_config.no_reassemble = SSL_CONFIG_DEFAULT_NOREASSEMBLE; } else { if (ConfGetBool("app-layer.protocols.tls.no-reassemble", &ssl_config.no_reassemble) != 1) - ssl_config.no_reassemble = 1; + ssl_config.no_reassemble = SSL_CONFIG_DEFAULT_NOREASSEMBLE; } } else { SCLogInfo("Parsed disabled for %s protocol. Protocol detection" @@ -1386,11 +1839,6 @@ void RegisterSSLParsers(void) #ifdef UNITTESTS AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TLS, SSLParserRegisterTests); #endif - - /* Get the value of no reassembly option from the config file */ - if (ConfGetBool("tls.no-reassemble", &ssl_config.no_reassemble) != 1) - ssl_config.no_reassemble = 1; - return; } @@ -1403,7 +1851,6 @@ void RegisterSSLParsers(void) */ static int SSLParserTest01(void) { - int result = 1; Flow f; uint8_t tlsbuf[] = { 0x16, 0x03, 0x01 }; uint32_t tlslen = sizeof(tlsbuf); @@ -1412,52 +1859,36 @@ static int SSLParserTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_EOF, tlsbuf, tlslen); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** \test Send a get request in two chunks. */ static int SSLParserTest02(void) { - int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -1468,62 +1899,41 @@ static int SSLParserTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** \test Send a get request in three chunks. */ static int SSLParserTest03(void) { - int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -1536,72 +1946,47 @@ static int SSLParserTest03(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** \test Send a get request in three chunks + more data. */ static int SSLParserTest04(void) { - int result = 1; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -1616,76 +2001,48 @@ static int SSLParserTest04(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } #if 0 @@ -1702,6 +2059,7 @@ static int SSLParserTest05(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1792,6 +2150,7 @@ static int SSLParserTest05(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } #endif @@ -1811,6 +2170,7 @@ static int SSLParserTest06(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -1917,6 +2277,7 @@ static int SSLParserTest06(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } #endif @@ -1924,7 +2285,6 @@ static int SSLParserTest06(void) /** \test multimsg test */ static int SSLParserMultimsgTest01(void) { - int result = 1; Flow f; /* 3 msgs */ uint8_t tlsbuf1[] = { @@ -1960,52 +2320,35 @@ static int SSLParserMultimsgTest01(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** \test multimsg test server */ static int SSLParserMultimsgTest02(void) { - int result = 1; Flow f; /* 3 msgs */ uint8_t tlsbuf1[] = { @@ -2041,46 +2384,30 @@ static int SSLParserMultimsgTest02(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOCLIENT, tlsbuf1, tlslen1); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->server_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->server_connp.content_type != 0x16); - if (ssl_state->server_connp.version != 0x0301) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", 0x0301, - ssl_state->server_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(ssl_state->server_connp.version != 0x0301); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2088,70 +2415,48 @@ static int SSLParserMultimsgTest02(void) */ static int SSLParserTest07(void) { - int result = 1; Flow f; - uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 }; + uint8_t tlsbuf[] = { 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t tlslen = sizeof(tlsbuf); TcpSession ssn; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf, tlslen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf, tlslen); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } #if 0 @@ -2168,6 +2473,7 @@ static int SSLParserTest08(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; @@ -2257,6 +2563,7 @@ static int SSLParserTest08(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } @@ -2267,29 +2574,24 @@ static int SSLParserTest08(void) */ static int SSLParserTest09(void) { - int result = 1; Flow f; uint8_t buf1[] = { - 0x16, + 0x16, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x03, 0x00, 0x00, 0x6f, 0x01, - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x03, 0x00, 0x00, 0x4c, 0x01, + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; @@ -2297,57 +2599,36 @@ static int SSLParserTest09(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2355,7 +2636,6 @@ static int SSLParserTest09(void) */ static int SSLParserTest10(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, @@ -2363,21 +2643,17 @@ static int SSLParserTest10(void) uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6f, 0x01, - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x00, 0x00, 0x4c, 0x01, + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; @@ -2385,57 +2661,36 @@ static int SSLParserTest10(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2443,28 +2698,23 @@ static int SSLParserTest10(void) */ static int SSLParserTest11(void) { - int result = 1; Flow f; uint8_t buf1[] = { - 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, + 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6b, 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x00, 0x00, 0x48, 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf2_len = sizeof(buf2); TcpSession ssn; @@ -2472,57 +2722,36 @@ static int SSLParserTest11(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2530,33 +2759,28 @@ static int SSLParserTest11(void) */ static int SSLParserTest12(void) { - int result = 1; Flow f; uint8_t buf1[] = { - 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, + 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6b, + 0x00, 0x00, 0x48, }; uint32_t buf2_len = sizeof(buf2); uint8_t buf3[] = { - 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf3_len = sizeof(buf2); TcpSession ssn; @@ -2564,67 +2788,42 @@ static int SSLParserTest12(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf3, buf3_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2632,38 +2831,33 @@ static int SSLParserTest12(void) */ static int SSLParserTest13(void) { - int result = 1; Flow f; uint8_t buf1[] = { - 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, + 0x16, 0x03, 0x00, 0x00, 0x4c, 0x01, }; uint32_t buf1_len = sizeof(buf1); uint8_t buf2[] = { - 0x00, 0x00, 0x6b, + 0x00, 0x00, 0x48, }; uint32_t buf2_len = sizeof(buf2); uint8_t buf3[] = { - 0x03, 0x00, 0x4b, 0x2f, 0xdc, - 0x4e, 0xe6, 0x95, 0xf1, 0xa0, 0xc7, + 0x03, 0x00, 0x57, 0x04, 0x9f, + 0x8c, 0x66, 0x61, 0xf6, 0x3d, 0x4f, }; uint32_t buf3_len = sizeof(buf3); uint8_t buf4[] = { - 0xcf, 0x8e, - 0xf6, 0xeb, 0x22, 0x6d, 0xce, 0x9c, 0x44, 0xfb, - 0xc8, 0xa0, 0x44, 0x31, 0x15, 0x4c, 0xe9, 0x97, - 0xa7, 0xa1, 0xfe, 0xea, 0xcc, 0x20, 0x4b, 0x5d, - 0xfb, 0xa5, 0x63, 0x7a, 0x73, 0x95, 0xf7, 0xff, - 0x42, 0xac, 0x8f, 0x46, 0xed, 0xe4, 0xb1, 0x35, - 0x35, 0x78, 0x1a, 0x9d, 0xaf, 0x10, 0xc5, 0x52, - 0xf3, 0x7b, 0xfb, 0xb5, 0xe9, 0xa8, 0x00, 0x24, - 0x00, 0x88, 0x00, 0x87, 0x00, 0x39, 0x00, 0x38, - 0x00, 0x84, 0x00, 0x35, 0x00, 0x45, 0x00, 0x44, - 0x00, 0x33, 0x00, 0x32, 0x00, 0x96, 0x00, 0x41, - 0x00, 0x2f, 0x00, 0x16, 0x00, 0x13, 0xfe, 0xff, - 0x00, 0x0a, 0x00, 0x02, 0x01, 0x00 + 0xbf, 0xbb, + 0xa7, 0x47, 0x21, 0x76, 0x6c, 0x21, 0x08, 0x9f, + 0xef, 0x3d, 0x0e, 0x5f, 0x65, 0x1a, 0xe1, 0x93, + 0xb8, 0xaf, 0xd2, 0x82, 0xbd, 0x00, 0x00, 0x06, + 0x00, 0x0a, 0x00, 0x16, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, + 0x00, 0x00, 0x10, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x2e, 0x65, 0x66, 0x67, 0x68, + 0x2e, 0x6e, 0x6f }; uint32_t buf4_len = sizeof(buf4); TcpSession ssn; @@ -2671,77 +2865,48 @@ static int SSLParserTest13(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf3, buf3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf4, buf4_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf3, buf3_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf4, buf4_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x17, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2749,7 +2914,6 @@ static int SSLParserTest13(void) */ static int SSLParserTest14(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -2767,43 +2931,32 @@ static int SSLParserTest14(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2811,7 +2964,6 @@ static int SSLParserTest14(void) */ static int SSLParserTest15(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -2824,26 +2976,23 @@ static int SSLParserTest15(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2851,7 +3000,6 @@ static int SSLParserTest15(void) */ static int SSLParserTest16(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -2864,26 +3012,23 @@ static int SSLParserTest16(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2891,7 +3036,6 @@ static int SSLParserTest16(void) */ static int SSLParserTest17(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -2904,26 +3048,23 @@ static int SSLParserTest17(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2931,7 +3072,6 @@ static int SSLParserTest17(void) */ static int SSLParserTest18(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -2950,43 +3090,32 @@ static int SSLParserTest18(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -2994,7 +3123,6 @@ static int SSLParserTest18(void) */ static int SSLParserTest19(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3008,33 +3136,26 @@ static int SSLParserTest19(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -3042,7 +3163,6 @@ static int SSLParserTest19(void) */ static int SSLParserTest20(void) { - int result = 1; Flow f; uint8_t buf1[] = { @@ -3056,26 +3176,23 @@ static int SSLParserTest20(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r == 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r == 0); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -3083,7 +3200,6 @@ static int SSLParserTest20(void) */ static int SSLParserTest21(void) { - int result = 0; Flow f; uint8_t buf[] = { 0x80, 0x31, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, @@ -3103,41 +3219,24 @@ static int SSLParserTest21(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_EOF, buf, - buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_EOF, buf, buf_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV2_MT_SERVER_HELLO, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO); - if (app_state->client_connp.version != SSL_VERSION_2) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_2, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_2); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3145,7 +3244,6 @@ static int SSLParserTest21(void) */ static int SSLParserTest22(void) { - int result = 1; Flow f; uint8_t buf[] = { 0x80, 0x31, 0x04, 0x00, 0x01, 0x00, @@ -3170,43 +3268,24 @@ static int SSLParserTest22(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT | STREAM_EOF, buf, - buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOCLIENT | STREAM_EOF, buf, buf_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->server_connp.content_type != SSLV2_MT_SERVER_HELLO) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV2_MT_SERVER_HELLO, app_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.content_type != SSLV2_MT_SERVER_HELLO); - if (app_state->server_connp.version != SSL_VERSION_2) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_2, app_state->server_connp.version); - result = 0; - goto end; - } -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + FAIL_IF(app_state->server_connp.version != SSL_VERSION_2); + + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3214,7 +3293,6 @@ static int SSLParserTest22(void) */ static int SSLParserTest23(void) { - int result = 1; Flow f; uint8_t chello_buf[] = { 0x80, 0x67, 0x01, 0x03, 0x00, 0x00, 0x4e, 0x00, @@ -3475,203 +3553,109 @@ static int SSLParserTest23(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - result = 0; - goto end; - } - - if (app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV2_MT_CLIENT_HELLO, app_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.version != SSL_VERSION_2) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_2, app_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV2_MT_CLIENT_HELLO); - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID)) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_2); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, - shello_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + shello_buf, shello_buf_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_HANDSHAKE_PROTOCOL, app_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL); - if (app_state->server_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->server_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.version != SSL_VERSION_3); - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO)) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* with multiple records the client content type hold the type from the last * record */ - if (app_state->client_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_HANDSHAKE_PROTOCOL, app_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL); - if (app_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_3); - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | - SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* with multiple records the serve content type hold the type from the last * record */ - if (app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_HANDSHAKE_PROTOCOL, app_state->server_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.content_type != SSLV3_HANDSHAKE_PROTOCOL); - if (app_state->server_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->server_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->server_connp.version != SSL_VERSION_3); - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | - SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, - toserver_app_data_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + toserver_app_data_buf, toserver_app_data_buf_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - if (app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - SSLV3_APPLICATION_PROTOCOL, app_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.content_type != SSLV3_APPLICATION_PROTOCOL); - if (app_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, app_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(app_state->client_connp.version != SSL_VERSION_3); - if (app_state->flags != - (SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_SSL_CLIENT_HS | - SSL_AL_FLAG_SSL_NO_SESSION_ID | SSL_AL_FLAG_STATE_SERVER_HELLO | - SSL_AL_FLAG_STATE_CLIENT_KEYX | SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC | SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC | - SSL_AL_FLAG_CHANGE_CIPHER_SPEC)) { - printf("flags not set\n"); - result = 0; - goto end; - } + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_CLIENT_HS) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SSL_NO_SESSION_ID) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CLIENT_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC) == 0); + FAIL_IF((app_state->flags & SSL_AL_FLAG_CHANGE_CIPHER_SPEC) == 0); - if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION)) { - printf("The flags should be set\n"); - result = 0; - goto end; - } + FAIL_IF_NOT(f.flags & FLOW_NOPAYLOAD_INSPECTION); -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - return result; + + PASS; } /** @@ -3679,7 +3663,6 @@ static int SSLParserTest23(void) */ static int SSLParserTest24(void) { - int result = 1; Flow f; uint8_t buf1[] = { 0x16, 0x03, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, @@ -3709,57 +3692,36 @@ static int SSLParserTest24(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf1, buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf1, buf1_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, buf2, buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + buf2, buf2_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, - ssl_state->client_connp.content_type); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != SSL_VERSION_3) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - SSL_VERSION_3, ssl_state->client_connp.version); - result = 0; - goto end; - } + FAIL_IF(ssl_state->client_connp.version != SSL_VERSION_3); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } /** @@ -3768,7 +3730,6 @@ static int SSLParserTest24(void) */ static int SSLParserTest25(void) { - int result = 0; Flow f; uint8_t client_hello[] = { 0x16, 0x03, 0x01, 0x00, 0xd3, 0x01, 0x00, 0x00, @@ -4088,61 +4049,41 @@ static int SSLParserTest25(void) memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); + FLOW_INITIALIZE(&f); f.protoctx = (void *)&ssn; f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_hello, client_hello_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + client_hello_len); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.bytes_processed != 0 || - ssl_state->client_connp.hs_bytes_processed != 0) - { - printf("client_hello error\n"); - goto end; - } + FAIL_IF(ssl_state->client_connp.bytes_processed != 0); + FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_hello_certificate_done, server_hello_certificate_done_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - if (ssl_state->client_connp.bytes_processed != 0 || - ssl_state->client_connp.hs_bytes_processed != 0) - { - printf("server_hello_certificate_done error\n"); - goto end; - } + FAIL_IF(ssl_state->client_connp.bytes_processed != 0); + FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_key_exchange_cipher_enc_hs, client_key_exchange_cipher_enc_hs_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); /* The reason hs_bytes_processed is 2 is because, the record * immediately after the client key exchange is 2 bytes long, @@ -4151,19 +4092,14 @@ static int SSLParserTest25(void) * handshake, we immediately break and don't parse the pdu from * where we left off, and leave the hs_bytes_processed var * isn't reset. */ - if (ssl_state->client_connp.bytes_processed != 0 || - ssl_state->client_connp.hs_bytes_processed != 2) - { - printf("client_key_exchange_cipher_enc_hs error\n"); - goto end; - } + FAIL_IF(ssl_state->client_connp.bytes_processed != 0); + FAIL_IF(ssl_state->client_connp.hs_bytes_processed != 2); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - return result; + FLOW_DESTROY(&f); + + PASS; } #endif /* UNITTESTS */ @@ -4171,36 +4107,36 @@ static int SSLParserTest25(void) void SSLParserRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SSLParserTest01", SSLParserTest01, 1); - UtRegisterTest("SSLParserTest02", SSLParserTest02, 1); - UtRegisterTest("SSLParserTest03", SSLParserTest03, 1); - UtRegisterTest("SSLParserTest04", SSLParserTest04, 1); + UtRegisterTest("SSLParserTest01", SSLParserTest01); + UtRegisterTest("SSLParserTest02", SSLParserTest02); + UtRegisterTest("SSLParserTest03", SSLParserTest03); + UtRegisterTest("SSLParserTest04", SSLParserTest04); /* Updated by Anoop Saldanha. Faulty tests. Disable it for now */ //UtRegisterTest("SSLParserTest05", SSLParserTest05, 1); //UtRegisterTest("SSLParserTest06", SSLParserTest06, 1); - UtRegisterTest("SSLParserTest07", SSLParserTest07, 1); + UtRegisterTest("SSLParserTest07", SSLParserTest07); //UtRegisterTest("SSLParserTest08", SSLParserTest08, 1); - UtRegisterTest("SSLParserTest09", SSLParserTest09, 1); - UtRegisterTest("SSLParserTest10", SSLParserTest10, 1); - UtRegisterTest("SSLParserTest11", SSLParserTest11, 1); - UtRegisterTest("SSLParserTest12", SSLParserTest12, 1); - UtRegisterTest("SSLParserTest13", SSLParserTest13, 1); - - UtRegisterTest("SSLParserTest14", SSLParserTest14, 1); - UtRegisterTest("SSLParserTest15", SSLParserTest15, 1); - UtRegisterTest("SSLParserTest16", SSLParserTest16, 1); - UtRegisterTest("SSLParserTest17", SSLParserTest17, 1); - UtRegisterTest("SSLParserTest18", SSLParserTest18, 1); - UtRegisterTest("SSLParserTest19", SSLParserTest19, 1); - UtRegisterTest("SSLParserTest20", SSLParserTest20, 1); - UtRegisterTest("SSLParserTest21", SSLParserTest21, 1); - UtRegisterTest("SSLParserTest22", SSLParserTest22, 1); - UtRegisterTest("SSLParserTest23", SSLParserTest23, 1); - UtRegisterTest("SSLParserTest24", SSLParserTest24, 1); - UtRegisterTest("SSLParserTest25", SSLParserTest25, 1); - - UtRegisterTest("SSLParserMultimsgTest01", SSLParserMultimsgTest01, 1); - UtRegisterTest("SSLParserMultimsgTest02", SSLParserMultimsgTest02, 1); + UtRegisterTest("SSLParserTest09", SSLParserTest09); + UtRegisterTest("SSLParserTest10", SSLParserTest10); + UtRegisterTest("SSLParserTest11", SSLParserTest11); + UtRegisterTest("SSLParserTest12", SSLParserTest12); + UtRegisterTest("SSLParserTest13", SSLParserTest13); + + UtRegisterTest("SSLParserTest14", SSLParserTest14); + UtRegisterTest("SSLParserTest15", SSLParserTest15); + UtRegisterTest("SSLParserTest16", SSLParserTest16); + UtRegisterTest("SSLParserTest17", SSLParserTest17); + UtRegisterTest("SSLParserTest18", SSLParserTest18); + UtRegisterTest("SSLParserTest19", SSLParserTest19); + UtRegisterTest("SSLParserTest20", SSLParserTest20); + UtRegisterTest("SSLParserTest21", SSLParserTest21); + UtRegisterTest("SSLParserTest22", SSLParserTest22); + UtRegisterTest("SSLParserTest23", SSLParserTest23); + UtRegisterTest("SSLParserTest24", SSLParserTest24); + UtRegisterTest("SSLParserTest25", SSLParserTest25); + + UtRegisterTest("SSLParserMultimsgTest01", SSLParserMultimsgTest01); + UtRegisterTest("SSLParserMultimsgTest02", SSLParserMultimsgTest02); #endif /* UNITTESTS */ return; diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 1e5bbebddb8d..f23757836683 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -26,6 +26,8 @@ #ifndef __APP_LAYER_SSL_H__ #define __APP_LAYER_SSL_H__ +#include "app-layer-protos.h" +#include "app-layer-parser.h" #include "decode-events.h" #include "queue.h" @@ -40,6 +42,11 @@ enum { TLS_DECODER_EVENT_INVALID_HEARTBEAT, TLS_DECODER_EVENT_OVERFLOW_HEARTBEAT, TLS_DECODER_EVENT_DATALEAK_HEARTBEAT_MISMATCH, + TLS_DECODER_EVENT_HANDSHAKE_INVALID_LENGTH, + TLS_DECODER_EVENT_MULTIPLE_SNI_EXTENSIONS, + TLS_DECODER_EVENT_INVALID_SNI_TYPE, + TLS_DECODER_EVENT_INVALID_SNI_LENGTH, + TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET, /* Certificates decoding messages */ TLS_DECODER_EVENT_INVALID_CERTIFICATE, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT, @@ -50,6 +57,13 @@ enum { TLS_DECODER_EVENT_INVALID_SSL_RECORD, }; +enum { + TLS_STATE_IN_PROGRESS = 0, + TLS_STATE_CERT_READY = 1, + TLS_HANDSHAKE_DONE = 2, + TLS_STATE_FINISHED = 3 +}; + /* Flag to indicate that server will now on send encrypted msgs */ #define SSL_AL_FLAG_SERVER_CHANGE_CIPHER_SPEC 0x0001 /* Flag to indicate that client will now on send encrypted msgs */ @@ -71,17 +85,25 @@ enum { #define SSL_AL_FLAG_STATE_SERVER_KEYX 0x1000 #define SSL_AL_FLAG_STATE_UNKNOWN 0x2000 -#define SSL_AL_FLAG_STATE_LOGGED 0x4000 +/* flag to indicate that session is finished */ +#define SSL_AL_FLAG_STATE_FINISHED 0x4000 /* flags specific to HeartBeat state */ #define SSL_AL_FLAG_HB_INFLIGHT 0x8000 #define SSL_AL_FLAG_HB_CLIENT_INIT 0x10000 -#define SSL_AL_FLAG_HB_SERVER_INIT 0x20000 +#define SSL_AL_FLAG_HB_SERVER_INIT 0x20000 + +/* flag to indicate that handshake is done */ +#define SSL_AL_FLAG_HANDSHAKE_DONE 0x80000 /* config flags */ #define SSL_TLS_LOG_PEM (1 << 0) +/* extensions */ +#define SSL_EXTENSION_SNI 0x0000 +/* SNI types */ +#define SSL_SNI_TYPE_HOST_NAME 0 /* SSL versions. We'll use a unified format for all, with the top byte * holding the major version and the lower byte the minor version */ @@ -127,8 +149,14 @@ typedef struct SSLStateConnp_ { char *cert0_subject; char *cert0_issuerdn; + char *cert0_serial; + time_t cert0_not_before; + time_t cert0_not_after; char *cert0_fingerprint; + /* ssl server name indication extension */ + char *sni; + uint8_t *cert_input; uint32_t cert_input_len; @@ -154,16 +182,27 @@ typedef struct SSLState_ { /* holds some state flags we need */ uint32_t flags; + /* specifies which loggers are done logging */ + uint32_t logged; + + /* there might be a better place to store this*/ + uint16_t hb_record_len; + + uint16_t events; + + uint32_t current_flags; + SSLStateConnp *curr_connp; SSLStateConnp client_connp; SSLStateConnp server_connp; - /* there might be a better place to store this*/ - uint16_t hb_record_len; + DetectEngineState *de_state; + AppLayerDecoderEvents *decoder_events; } SSLState; void RegisterSSLParsers(void); void SSLParserRegisterTests(void); +void SSLSetEvent(SSLState *ssl_state, uint8_t event); #endif /* __APP_LAYER_SSL_H__ */ diff --git a/src/app-layer-template.c b/src/app-layer-template.c new file mode 100644 index 000000000000..fd5bc7cc88c8 --- /dev/null +++ b/src/app-layer-template.c @@ -0,0 +1,568 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * TODO: Update \author in this file and app-layer-template.h. + * TODO: Implement your app-layer logic with unit tests. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Template application layer detector and parser for learning and + * template pruposes. + * + * This template implements a simple application layer for something + * like the echo protocol running on port 7. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "conf.h" + +#include "util-unittest.h" + +#include "app-layer-detect-proto.h" +#include "app-layer-parser.h" + +#include "app-layer-template.h" + +/* The default port to probe for echo traffic if not provided in the + * configuration file. */ +#define TEMPLATE_DEFAULT_PORT "7" + +/* The minimum size for an echo message. For some protocols this might + * be the size of a header. */ +#define TEMPLATE_MIN_FRAME_LEN 1 + +/* Enum of app-layer events for an echo protocol. Normally you might + * have events for errors in parsing data, like unexpected data being + * received. For echo we'll make something up, and log an app-layer + * level alert if an empty message is received. + * + * Example rule: + * + * alert template any any -> any any (msg:"SURICATA Template empty message"; \ + * app-layer-event:template.empty_message; sid:X; rev:Y;) + */ +enum { + TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE, +}; + +SCEnumCharMap template_decoder_event_table[] = { + {"EMPTY_MESSAGE", TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE}, +}; + +static TemplateTransaction *TemplateTxAlloc(TemplateState *echo) +{ + TemplateTransaction *tx = SCCalloc(1, sizeof(TemplateTransaction)); + if (unlikely(tx == NULL)) { + return NULL; + } + + /* Increment the transaction ID on the state each time one is + * allocated. */ + tx->tx_id = echo->transaction_max++; + + TAILQ_INSERT_TAIL(&echo->tx_list, tx, next); + + return tx; +} + +static void TemplateTxFree(void *tx) +{ + TemplateTransaction *templatetx = tx; + + if (templatetx->request_buffer != NULL) { + SCFree(templatetx->request_buffer); + } + + if (templatetx->response_buffer != NULL) { + SCFree(templatetx->response_buffer); + } + + AppLayerDecoderEventsFreeEvents(&templatetx->decoder_events); + + SCFree(tx); +} + +static void *TemplateStateAlloc(void) +{ + SCLogNotice("Allocating template state."); + TemplateState *state = SCCalloc(1, sizeof(TemplateState)); + if (unlikely(state == NULL)) { + return NULL; + } + TAILQ_INIT(&state->tx_list); + return state; +} + +static void TemplateStateFree(void *state) +{ + TemplateState *template_state = state; + TemplateTransaction *tx; + SCLogNotice("Freeing template state."); + while ((tx = TAILQ_FIRST(&template_state->tx_list)) != NULL) { + TAILQ_REMOVE(&template_state->tx_list, tx, next); + TemplateTxFree(tx); + } + SCFree(template_state); +} + +/** + * \brief Callback from the application layer to have a transaction freed. + * + * \param state a void pointer to the TemplateState object. + * \param tx_id the transaction ID to free. + */ +static void TemplateStateTxFree(void *state, uint64_t tx_id) +{ + TemplateState *echo = state; + TemplateTransaction *tx = NULL, *ttx; + + SCLogNotice("Freeing transaction %"PRIu64, tx_id); + + TAILQ_FOREACH_SAFE(tx, &echo->tx_list, next, ttx) { + + /* Continue if this is not the transaction we are looking + * for. */ + if (tx->tx_id != tx_id) { + continue; + } + + /* Remove and free the transaction. */ + TAILQ_REMOVE(&echo->tx_list, tx, next); + TemplateTxFree(tx); + return; + } + + SCLogNotice("Transaction %"PRIu64" not found.", tx_id); +} + +static int TemplateStateGetEventInfo(const char *event_name, int *event_id, + AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, template_decoder_event_table); + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "template enum map table.", event_name); + /* This should be treated as fatal. */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static AppLayerDecoderEvents *TemplateGetEvents(void *state, uint64_t tx_id) +{ + TemplateState *template_state = state; + TemplateTransaction *tx; + + TAILQ_FOREACH(tx, &template_state->tx_list, next) { + if (tx->tx_id == tx_id) { + return tx->decoder_events; + } + } + + return NULL; +} + +static int TemplateHasEvents(void *state) +{ + TemplateState *echo = state; + return echo->events; +} + +/** + * \brief Probe the input to see if it looks like echo. + * + * \retval ALPROTO_TEMPLATE if it looks like echo, otherwise + * ALPROTO_UNKNOWN. + */ +static AppProto TemplateProbingParser(uint8_t *input, uint32_t input_len, + uint32_t *offset) +{ + /* Very simple test - if there is input, this is echo. */ + if (input_len >= TEMPLATE_MIN_FRAME_LEN) { + SCLogNotice("Detected as ALPROTO_TEMPLATE."); + return ALPROTO_TEMPLATE; + } + + SCLogNotice("Protocol not detected as ALPROTO_TEMPLATE."); + return ALPROTO_UNKNOWN; +} + +static int TemplateParseRequest(Flow *f, void *state, + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, + void *local_data) +{ + TemplateState *echo = state; + + SCLogNotice("Parsing echo request: len=%"PRIu32, input_len); + + /* Likely connection closed, we can just return here. */ + if ((input == NULL || input_len == 0) && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + return 0; + } + + /* Probably don't want to create a transaction in this case + * either. */ + if (input == NULL || input_len == 0) { + return 0; + } + + /* Normally you would parse out data here and store it in the + * transaction object, but as this is echo, we'll just record the + * request data. */ + + /* Also, if this protocol may have a "protocol data unit" span + * multiple chunks of data, which is always a possibility with + * TCP, you may need to do some buffering here. + * + * For the sake of simplicity, buffering is left out here, but + * even for an echo protocol we may want to buffer until a new + * line is seen, assuming its text based. + */ + + /* Allocate a transaction. + * + * But note that if a "protocol data unit" is not received in one + * chunk of data, and the buffering is done on the transaction, we + * may need to look for the transaction that this newly recieved + * data belongs to. + */ + TemplateTransaction *tx = TemplateTxAlloc(echo); + if (unlikely(tx == NULL)) { + SCLogNotice("Failed to allocate new Template tx."); + goto end; + } + SCLogNotice("Allocated Template tx %"PRIu64".", tx->tx_id); + + /* Make a copy of the request. */ + tx->request_buffer = SCCalloc(1, input_len); + if (unlikely(tx->request_buffer == NULL)) { + goto end; + } + memcpy(tx->request_buffer, input, input_len); + tx->request_buffer_len = input_len; + + /* Here we check for an empty message and create an app-layer + * event. */ + if ((input_len == 1 && tx->request_buffer[0] == '\n') || + (input_len == 2 && tx->request_buffer[0] == '\r')) { + SCLogNotice("Creating event for empty message."); + AppLayerDecoderEventsSetEventRaw(&tx->decoder_events, + TEMPLATE_DECODER_EVENT_EMPTY_MESSAGE); + echo->events++; + } + +end: + return 0; +} + +static int TemplateParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + TemplateState *echo = state; + TemplateTransaction *tx = NULL, *ttx;; + + SCLogNotice("Parsing Template response."); + + /* Likely connection closed, we can just return here. */ + if ((input == NULL || input_len == 0) && + AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) { + return 0; + } + + /* Probably don't want to create a transaction in this case + * either. */ + if (input == NULL || input_len == 0) { + return 0; + } + + /* Look up the existing transaction for this response. In the case + * of echo, it will be the most recent transaction on the + * TemplateState object. */ + + /* We should just grab the last transaction, but this is to + * illustrate how you might traverse the transaction list to find + * the transaction associated with this response. */ + TAILQ_FOREACH(ttx, &echo->tx_list, next) { + tx = ttx; + } + + if (tx == NULL) { + SCLogNotice("Failed to find transaction for response on echo state %p.", + echo); + goto end; + } + + SCLogNotice("Found transaction %"PRIu64" for response on echo state %p.", + tx->tx_id, echo); + + /* If the protocol requires multiple chunks of data to complete, you may + * run into the case where you have existing response data. + * + * In this case, we just log that there is existing data and free it. But + * you might want to realloc the buffer and append the data. + */ + if (tx->response_buffer != NULL) { + SCLogNotice("WARNING: Transaction already has response data, " + "existing data will be overwritten."); + SCFree(tx->response_buffer); + } + + /* Make a copy of the response. */ + tx->response_buffer = SCCalloc(1, input_len); + if (unlikely(tx->response_buffer == NULL)) { + goto end; + } + memcpy(tx->response_buffer, input, input_len); + tx->response_buffer_len = input_len; + + /* Set the response_done flag for transaction state checking in + * TemplateGetStateProgress(). */ + tx->response_done = 1; + +end: + return 0; +} + +static uint64_t TemplateGetTxCnt(void *state) +{ + TemplateState *echo = state; + SCLogNotice("Current tx count is %"PRIu64".", echo->transaction_max); + return echo->transaction_max; +} + +static void *TemplateGetTx(void *state, uint64_t tx_id) +{ + TemplateState *echo = state; + TemplateTransaction *tx; + + SCLogNotice("Requested tx ID %"PRIu64".", tx_id); + + TAILQ_FOREACH(tx, &echo->tx_list, next) { + if (tx->tx_id == tx_id) { + SCLogNotice("Transaction %"PRIu64" found, returning tx object %p.", + tx_id, tx); + return tx; + } + } + + SCLogNotice("Transaction ID %"PRIu64" not found.", tx_id); + return NULL; +} + +static void TemplateSetTxLogged(void *state, void *vtx, uint32_t logger) +{ + TemplateTransaction *tx = (TemplateTransaction *)vtx; + tx->logged |= logger; +} + +static int TemplateGetTxLogged(void *state, void *vtx, uint32_t logger) +{ + TemplateTransaction *tx = (TemplateTransaction *)vtx; + if (tx->logged & logger) + return 1; + + return 0; +} + +/** + * \brief Called by the application layer. + * + * In most cases 1 can be returned here. + */ +static int TemplateGetAlstateProgressCompletionStatus(uint8_t direction) { + return 1; +} + +/** + * \brief Return the state of a transaction in a given direction. + * + * In the case of the echo protocol, the existence of a transaction + * means that the request is done. However, some protocols that may + * need multiple chunks of data to complete the request may need more + * than just the existence of a transaction for the request to be + * considered complete. + * + * For the response to be considered done, the response for a request + * needs to be seen. The response_done flag is set on response for + * checking here. + */ +static int TemplateGetStateProgress(void *tx, uint8_t direction) +{ + TemplateTransaction *echotx = tx; + + SCLogNotice("Transaction progress requested for tx ID %"PRIu64 + ", direction=0x%02x", echotx->tx_id, direction); + + if (direction & STREAM_TOCLIENT && echotx->response_done) { + return 1; + } + else if (direction & STREAM_TOSERVER) { + /* For echo, just the existence of the transaction means the + * request is done. */ + return 1; + } + + return 0; +} + +/** + * \brief ??? + */ +static DetectEngineState *TemplateGetTxDetectState(void *vtx) +{ + TemplateTransaction *tx = vtx; + return tx->de_state; +} + +/** + * \brief ??? + */ +static int TemplateSetTxDetectState(void *state, void *vtx, + DetectEngineState *s) +{ + TemplateTransaction *tx = vtx; + tx->de_state = s; + return 0; +} + +void RegisterTemplateParsers(void) +{ + char *proto_name = "template"; + + /* TEMPLATE_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + /* TEMPLATE_END_REMOVE */ + /* Check if Template TCP detection is enabled. If it does not exist in + * the configuration file then it will be enabled by default. */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) { + + SCLogNotice("Template TCP protocol detection enabled."); + + AppLayerProtoDetectRegisterProtocol(ALPROTO_TEMPLATE, proto_name); + + if (RunmodeIsUnittests()) { + + SCLogNotice("Unittest mode, registeringd default configuration."); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, TEMPLATE_DEFAULT_PORT, + ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, + TemplateProbingParser, NULL); + + } + else { + + if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP, + proto_name, ALPROTO_TEMPLATE, 0, TEMPLATE_MIN_FRAME_LEN, + TemplateProbingParser, NULL)) { + SCLogNotice("No echo app-layer configuration, enabling echo" + " detection TCP detection on port %s.", + TEMPLATE_DEFAULT_PORT); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + TEMPLATE_DEFAULT_PORT, ALPROTO_TEMPLATE, 0, + TEMPLATE_MIN_FRAME_LEN, STREAM_TOSERVER, + TemplateProbingParser, NULL); + } + + } + + } + + else { + SCLogNotice("Protocol detecter and parser disabled for Template."); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) { + + SCLogNotice("Registering Template protocol parser."); + + /* Register functions for state allocation and freeing. A + * state is allocated for every new Template flow. */ + AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateStateAlloc, TemplateStateFree); + + /* Register request parser for parsing frame from server to client. */ + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, + STREAM_TOSERVER, TemplateParseRequest); + + /* Register response parser for parsing frames from server to client. */ + AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_TEMPLATE, + STREAM_TOCLIENT, TemplateParseResponse); + + /* Register a function to be called by the application layer + * when a transaction is to be freed. */ + AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateStateTxFree); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetTxLogged, TemplateSetTxLogged); + + /* Register a function to return the current transaction count. */ + AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetTxCnt); + + /* Transaction handling. */ + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_TEMPLATE, + TemplateGetAlstateProgressCompletionStatus); + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, + ALPROTO_TEMPLATE, TemplateGetStateProgress); + AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetTx); + + /* Application layer event handling. */ + AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateHasEvents); + + /* What is this being registered for? */ + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_TEMPLATE, + NULL, TemplateGetTxDetectState, TemplateSetTxDetectState); + + AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateStateGetEventInfo); + AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateGetEvents); + } + else { + SCLogNotice("Template protocol parsing disabled."); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_TEMPLATE, + TemplateParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#endif + +void TemplateParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} diff --git a/src/app-layer-template.h b/src/app-layer-template.h new file mode 100644 index 000000000000..2dd944a01a8c --- /dev/null +++ b/src/app-layer-template.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author FirstName LastName + */ + +#ifndef __APP_LAYER_TEMPLATE_H__ +#define __APP_LAYER_TEMPLATE_H__ + +#include "detect-engine-state.h" + +#include "queue.h" + +void RegisterTemplateParsers(void); +void TemplateParserRegisterTests(void); + +typedef struct TemplateTransaction_ { + + uint64_t tx_id; /*<< Internal transaction ID. */ + + AppLayerDecoderEvents *decoder_events; /*<< Application layer + * events that occurred + * while parsing this + * transaction. */ + + uint8_t *request_buffer; + uint32_t request_buffer_len; + + /* flags indicating which loggers that have logged */ + uint32_t logged; + + uint8_t *response_buffer; + uint32_t response_buffer_len; + + uint8_t response_done; /*<< Flag to be set when the response is + * seen. */ + + DetectEngineState *de_state; + + TAILQ_ENTRY(TemplateTransaction_) next; + +} TemplateTransaction; + +typedef struct TemplateState_ { + + TAILQ_HEAD(, TemplateTransaction_) tx_list; /**< List of Template transactions + * associated with this + * state. */ + + uint64_t transaction_max; /**< A count of the number of + * transactions created. The + * transaction ID for each transaction + * is allocted by incrementing this + * value. */ + + uint16_t events; /**< Number of application layer events created + * for this state. */ + +} TemplateState; + +#endif /* __APP_LAYER_TEMPLATE_H__ */ diff --git a/src/app-layer-tls-handshake.c b/src/app-layer-tls-handshake.c index ca2e7f491c84..6c3226f2d5bc 100644 --- a/src/app-layer-tls-handshake.c +++ b/src/app-layer-tls-handshake.c @@ -39,22 +39,18 @@ #include "decode.h" #include "app-layer-parser.h" -#include "decode-events.h" - #include "app-layer-ssl.h" - #include "app-layer-tls-handshake.h" - -#include +#include "decode-events.h" #include "util-decode-der.h" #include "util-decode-der-get.h" - #include "util-crypt.h" #define SSLV3_RECORD_LEN 5 -static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, uint32_t errcode) +static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, + uint32_t errcode) { if (errcode == 0) return; @@ -62,35 +58,36 @@ static void TLSCertificateErrCodeToWarning(SSLState *ssl_state, uint32_t errcode switch (errcode) { case ERR_DER_ELEMENT_SIZE_TOO_BIG: case ERR_DER_INVALID_SIZE: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH); break; case ERR_DER_UNSUPPORTED_STRING: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING); break; case ERR_DER_UNKNOWN_ELEMENT: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT); break; case ERR_DER_MISSING_ELEMENT: - AppLayerDecoderEventsSetEvent(ssl_state->f, + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT); break; case ERR_DER_GENERIC: default: - AppLayerDecoderEventsSetEvent(ssl_state->f, - TLS_DECODER_EVENT_INVALID_CERTIFICATE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); break; }; } -int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uint32_t input_len) +int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, + uint32_t input_len) { uint32_t certificates_length, cur_cert_length; int i; Asn1Generic *cert; char buffer[256]; + time_t not_before, not_after; int rc; int parsed; uint8_t *start_data; @@ -110,25 +107,40 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin i = 0; while (certificates_length > 0) { + if ((uint32_t)(input + 3 - start_data) > (uint32_t)input_len) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + return -1; + } + cur_cert_length = input[0]<<16 | input[1]<<8 | input[2]; input += 3; parsed += 3; + /* current certificate length should be greater than zero */ + if (cur_cert_length == 0) { + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + return -1; + } + if (input - start_data + cur_cert_length > input_len) { - AppLayerDecoderEventsSetEvent(ssl_state->f, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); return -1; } + cert = DecodeDer(input, cur_cert_length, &errcode); if (cert == NULL) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } + if (cert != NULL) { rc = Asn1DerGetSubjectDN(cert, buffer, sizeof(buffer), &errcode); + if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); } else { SSLCertsChain *ncert; //SCLogInfo("TLS Cert %d: %s\n", i, buffer); + if (i == 0) { if (ssl_state->server_connp.cert0_subject == NULL) ssl_state->server_connp.cert0_subject = SCStrdup(buffer); @@ -137,16 +149,19 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin return -1; } } + ncert = (SSLCertsChain *)SCMalloc(sizeof(SSLCertsChain)); if (ncert == NULL) { DerFree(cert); return -1; } + memset(ncert, 0, sizeof(*ncert)); ncert->cert_data = input; ncert->cert_len = cur_cert_length; TAILQ_INSERT_TAIL(&ssl_state->server_connp.certs, ncert, next); } + rc = Asn1DerGetIssuerDN(cert, buffer, sizeof(buffer), &errcode); if (rc != 0) { TLSCertificateErrCodeToWarning(ssl_state, errcode); @@ -161,35 +176,63 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin } } } + + rc = Asn1DerGetSerial(cert, buffer, sizeof(buffer), &errcode); + if (rc != 0) { + TLSCertificateErrCodeToWarning(ssl_state, errcode); + } else { + if (i == 0) { + if (ssl_state->server_connp.cert0_serial == NULL) { + ssl_state->server_connp.cert0_serial = SCStrdup(buffer); + } + if (ssl_state->server_connp.cert0_serial == NULL) { + DerFree(cert); + return -1; + } + } + } + + rc = Asn1DerGetValidity(cert, ¬_before, ¬_after, &errcode); + if (rc != 0) { + TLSCertificateErrCodeToWarning(ssl_state, errcode); + } else { + if (i == 0) { + ssl_state->server_connp.cert0_not_before = not_before; + ssl_state->server_connp.cert0_not_after = not_after; + } + } + DerFree(cert); if (i == 0 && ssl_state->server_connp.cert0_fingerprint == NULL) { int msg_len = cur_cert_length; - int hash_len = 20; - int out_len = 60; - char out[out_len]; unsigned char *hash; hash = ComputeSHA1((unsigned char *) input, (int) msg_len); - char *p = out; - int j = 0; if (hash == NULL) { - SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string"); + // TODO maybe an event here? } else { - for (j = 0; j < hash_len; j++, p += 3) { - snprintf(p, 4, j == hash_len - 1 ? "%02x" : "%02x:", hash[j]); + int hash_len = 20; + int out_len = hash_len * 3 + 1; + char out[out_len]; + memset(out, 0x00, out_len); + + int j = 0; + for (j = 0; j < hash_len; j++) { + char one[4]; + snprintf(one, sizeof(one), j == hash_len - 1 ? "%02x" : "%02x:", hash[j]); + strlcat(out, one, out_len); } SCFree(hash); ssl_state->server_connp.cert0_fingerprint = SCStrdup(out); if (ssl_state->server_connp.cert0_fingerprint == NULL) { - SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string"); + // TODO do we need an event here? } } ssl_state->server_connp.cert_input = input; ssl_state->server_connp.cert_input_len = cur_cert_length; } - } i++; @@ -199,6 +242,5 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin } return parsed; - } diff --git a/src/app-layer.c b/src/app-layer.c index 4c7770c1ac13..8cbb86838d59 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -33,8 +33,10 @@ #include "stream-tcp-reassemble.h" #include "stream-tcp-private.h" #include "stream-tcp-inline.h" +#include "stream-tcp.h" #include "flow.h" #include "flow-util.h" +#include "flow-private.h" #include "util-debug.h" #include "util-print.h" @@ -55,10 +57,6 @@ struct AppLayerThreadCtx_ { /* App layer parser thread context, from AppLayerParserThreadCtxAlloc(). */ AppLayerParserThreadCtx *alp_tctx; - uint16_t counter_dns_memuse; - uint16_t counter_dns_memcap_state; - uint16_t counter_dns_memcap_global; - #ifdef PROFILING uint64_t ticks_start; uint64_t ticks_end; @@ -70,367 +68,525 @@ struct AppLayerThreadCtx_ { #endif }; -/** \todo move this into the DNS code. Problem is that there we can't - * access AppLayerThreadCtx internals. */ -static void DNSUpdateCounters(ThreadVars *tv, AppLayerThreadCtx *app_tctx) +#define MAX_COUNTER_SIZE 64 +typedef struct AppLayerCounterNames_ { + char name[MAX_COUNTER_SIZE]; + char tx_name[MAX_COUNTER_SIZE]; +} AppLayerCounterNames; + +typedef struct AppLayerCounters_ { + uint16_t counter_id; + uint16_t counter_tx_id; +} AppLayerCounters; + +/* counter names. Only used at init. */ +AppLayerCounterNames applayer_counter_names[FLOW_PROTO_APPLAYER_MAX][ALPROTO_MAX]; +/* counter id's. Used that runtime. */ +AppLayerCounters applayer_counters[FLOW_PROTO_APPLAYER_MAX][ALPROTO_MAX]; + +void AppLayerSetupCounters(); +void AppLayerDeSetupCounters(); + +/***** L7 layer dispatchers *****/ + +static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t direction) { + const TcpStream *stream = (direction & STREAM_TOSERVER) ? &ssn->client : &ssn->server; + return ((stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) || + (FLOW_IS_PM_DONE(f, direction) && FLOW_IS_PP_DONE(f, direction))); +} + +static void AppLayerIncFlowCounter(ThreadVars *tv, Flow *f) { - uint64_t memuse = 0, memcap_state = 0, memcap_global = 0; + if (likely(tv)) { + StatsIncr(tv, applayer_counters[f->protomap][f->alproto].counter_id); + } +} - DNSMemcapGetCounters(&memuse, &memcap_state, &memcap_global); +void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) +{ + if (likely(tv)) { + StatsAddUI64(tv, applayer_counters[f->protomap][f->alproto].counter_tx_id, step); + } +} - SCPerfCounterSetUI64(app_tctx->counter_dns_memuse, - tv->sc_perf_pca, memuse); - SCPerfCounterSetUI64(app_tctx->counter_dns_memcap_state, - tv->sc_perf_pca, memcap_state); - SCPerfCounterSetUI64(app_tctx->counter_dns_memcap_global, - tv->sc_perf_pca, memcap_global); +/* in IDS mode protocol detection is done in reverse order: + * when TCP data is ack'd. We want to flag the correct packet, + * so in this case we set a flag in the flow so that the first + * packet in the correct direction can be tagged. + * + * For IPS things are much simpler, and we don't use the flow + * flag. We just tag the packet directly. */ +static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t flags) +{ + if (EngineModeIsIPS()) { + if (flags & STREAM_TOSERVER) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + p->flags |= PKT_PROTO_DETECT_TS_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TS_DONE; + } + } else { + if (p->flowflags & FLOW_PKT_TOCLIENT) { + p->flags |= PKT_PROTO_DETECT_TC_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TC_DONE; + } + } + } else { + if (flags & STREAM_TOSERVER) { + f->flags |= FLOW_PROTO_DETECT_TS_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TC_DONE; + } + } } -/***** L7 layer dispatchers *****/ +static void DisableAppLayer(ThreadVars *tv, Flow *f, Packet *p) +{ + SCLogDebug("disable app layer for flow %p alproto %u ts %u tc %u", + f, f->alproto, f->alproto_ts, f->alproto_tc); + FlowCleanupAppLayer(f); + StreamTcpDisableAppLayer(f); + TcpSession *ssn = f->protoctx; + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + f->alproto = ALPROTO_FAILED; + AppLayerIncFlowCounter(tv, f); + + if (f->alproto_tc != ALPROTO_FAILED) { + if (f->alproto_tc == ALPROTO_UNKNOWN) { + f->alproto_tc = ALPROTO_FAILED; + } + FlagPacketFlow(p, f, STREAM_TOCLIENT); + } + if (f->alproto_ts != ALPROTO_FAILED) { + if (f->alproto_ts == ALPROTO_UNKNOWN) { + f->alproto_ts = ALPROTO_FAILED; + } + FlagPacketFlow(p, f, STREAM_TOSERVER); + } + SCLogDebug("disabled app layer for flow %p alproto %u ts %u tc %u", + f, f->alproto, f->alproto_ts, f->alproto_tc); +} -int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - Packet *p, Flow *f, - TcpSession *ssn, TcpStream *stream, - uint8_t *data, uint32_t data_len, - uint8_t flags) +/* See if we're going to have to give up: + * + * If we're getting a lot of data in one direction and the + * proto for this direction is unknown, proto detect will + * hold up segments in the segment list in the stream. + * They are held so that if we detect the protocol on the + * opposing stream, we can still parse this side of the stream + * as well. However, some sessions are very unbalanced. FTP + * data channels, large PUT/POST request and many others, can + * lead to cases where we would have to store many megabytes + * worth of segments before we see the opposing stream. This + * leads to risks of resource starvation. + * + * Here a cutoff point is enforced. If we've stored 100k in + * one direction and we've seen no data in the other direction, + * we give up. + * + * Giving up means we disable applayer an set an applayer event + */ +static void TCPProtoDetectCheckBailConditions(ThreadVars *tv, + Flow *f, TcpSession *ssn, Packet *p) { - SCEnter(); + uint32_t size_ts = ssn->client.last_ack - ssn->client.isn - 1; + uint32_t size_tc = ssn->server.last_ack - ssn->server.isn - 1; + SCLogDebug("size_ts %u, size_tc %u", size_ts, size_tc); + +#ifdef DEBUG_VALIDATION + if (!(ssn->client.flags & STREAMTCP_STREAM_FLAG_GAP)) + BUG_ON(size_ts > 1000000UL); + if (!(ssn->server.flags & STREAMTCP_STREAM_FLAG_GAP)) + BUG_ON(size_tc > 1000000UL); +#endif /* DEBUG_VALIDATION */ + + if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && + ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) + { + goto failure; + + } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && + size_ts > 100000 && size_tc == 0) + { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; + + } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && + size_tc > 100000 && size_ts == 0) + { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; + + /* little data in ts direction, pp done, pm not done (max + * depth not reached), ts direction done, lots of data in + * tc direction. */ + } else if (size_tc > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && + FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) + { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; + + /* little data in tc direction, pp done, pm not done (max + * depth not reached), tc direction done, lots of data in + * ts direction. */ + } else if (size_ts > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && + FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) + { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; + + /* in case of really low TS data (e.g. 4 bytes) we can have + * the PP complete, PM not complete (depth not reached) and + * the TC side also not recognized (proto unknown) */ + } else if (size_tc > 100000 && + FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && + (!FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && !FLOW_IS_PP_DONE(f, STREAM_TOCLIENT))) + { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; + } + return; + +failure: + DisableAppLayer(tv, f, p); + return; +} - DEBUG_ASSERT_FLOW_LOCKED(f); +/** \todo modifying p this way seems too hacky */ +static int TCPProtoDetectTriggerOpposingSide(ThreadVars *tv, + TcpReassemblyThreadCtx *ra_ctx, + Packet *p, TcpSession *ssn, TcpStream *stream, + uint8_t flags) +{ + TcpStream *opposing_stream = NULL; + if (stream == &ssn->client) { + opposing_stream = &ssn->server; + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } else { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } + } else { + opposing_stream = &ssn->client; + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } else { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } + } - AppLayerThreadCtx *app_tctx = ra_ctx->app_tctx; + int ret = 0; + /* if the opposing side is not going to work, then + * we just have to give up. */ + if (opposing_stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) + ret = -1; + else + ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, + opposing_stream, p); + if (stream == &ssn->client) { + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } else { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } + } else { + if (StreamTcpInlineMode()) { + p->flowflags &= ~FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_TOCLIENT; + } else { + p->flowflags &= ~FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_TOSERVER; + } + } + return ret; +} + +/** \todo data const */ +static int TCPProtoDetect(ThreadVars *tv, + TcpReassemblyThreadCtx *ra_ctx, AppLayerThreadCtx *app_tctx, + Packet *p, Flow *f, TcpSession *ssn, TcpStream *stream, + uint8_t *data, uint32_t data_len, uint8_t flags) +{ AppProto *alproto; AppProto *alproto_otherdir; - uint8_t dir; - uint32_t data_al_so_far; - int r = 0; - uint8_t first_data_dir; - - SCLogDebug("data_len %u flags %02X", data_len, flags); - if (f->flags & FLOW_NO_APPLAYER_INSPECTION) { - SCLogDebug("FLOW_AL_NO_APPLAYER_INSPECTION is set"); - goto end; - } if (flags & STREAM_TOSERVER) { alproto = &f->alproto_ts; alproto_otherdir = &f->alproto_tc; - dir = 0; } else { alproto = &f->alproto_tc; alproto_otherdir = &f->alproto_ts; - dir = 1; } - /* if we don't know the proto yet and we have received a stream - * initializer message, we run proto detection. - * We receive 2 stream init msgs (one for each direction) but we - * only run the proto detection once. */ - if (*alproto == ALPROTO_UNKNOWN && (flags & STREAM_GAP)) { + SCLogDebug("Stream initializer (len %" PRIu32 ")", data_len); +#ifdef PRINT + if (data_len > 0) { + printf("=> Init Stream Data (app layer) -- start %s%s\n", + flags & STREAM_TOCLIENT ? "toclient" : "", + flags & STREAM_TOSERVER ? "toserver" : ""); + PrintRawDataFp(stdout, data, data_len); + printf("=> Init Stream Data -- end\n"); + } +#endif + + PACKET_PROFILING_APP_PD_START(app_tctx); + *alproto = AppLayerProtoDetectGetProto(app_tctx->alpd_tctx, + f, data, data_len, + IPPROTO_TCP, flags); + PACKET_PROFILING_APP_PD_END(app_tctx); + + if (*alproto != ALPROTO_UNKNOWN) { + if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); + + if (ssn->data_first_seen_dir == APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { + /* if we already invoked the parser, we go with that proto */ + f->alproto = *alproto_otherdir; + } else { + /* no data sent to parser yet, we can still choose + * we're trusting the server more. */ + if (flags & STREAM_TOCLIENT) + f->alproto = *alproto; + else + f->alproto = *alproto_otherdir; + } + } else { + f->alproto = *alproto; + } + StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - StreamTcpSetSessionNoReassemblyFlag(ssn, dir); - SCLogDebug("ALPROTO_UNKNOWN flow %p, due to GAP in stream start", f); - } else if (*alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) { - if (data_len == 0) - data_al_so_far = 0; - else - data_al_so_far = f->data_al_so_far[dir]; + TcpSessionSetReassemblyDepth(ssn, + AppLayerParserGetStreamDepth(f->proto, f->alproto)); + FlagPacketFlow(p, f, flags); - SCLogDebug("Stream initializer (len %" PRIu32 ")", data_len); -#ifdef PRINT - if (data_len > 0) { - printf("=> Init Stream Data (app layer) -- start %s%s\n", - flags & STREAM_TOCLIENT ? "toclient" : "", - flags & STREAM_TOSERVER ? "toserver" : ""); - PrintRawDataFp(stdout, data, data_len); - printf("=> Init Stream Data -- end\n"); + /* account flow if we have both sides */ + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + AppLayerIncFlowCounter(tv, f); } -#endif - PACKET_PROFILING_APP_PD_START(app_tctx); - *alproto = AppLayerProtoDetectGetProto(app_tctx->alpd_tctx, - f, - data, data_len, - IPPROTO_TCP, flags); - PACKET_PROFILING_APP_PD_END(app_tctx); + /* if we have seen data from the other direction first, send + * data for that direction first to the parser. This shouldn't + * be an issue, since each stream processing happens + * independently of the other stream direction. At this point of + * call, you need to know that this function's already being + * called by the very same StreamReassembly() function that we + * will now call shortly for the opposing direction. */ + if ((ssn->data_first_seen_dir & (STREAM_TOSERVER | STREAM_TOCLIENT)) && + !(flags & ssn->data_first_seen_dir)) + { + if (TCPProtoDetectTriggerOpposingSide(tv, ra_ctx, + p, ssn, stream, flags) != 0) + { + DisableAppLayer(tv, f, p); + goto failure; + } + } - if (*alproto != ALPROTO_UNKNOWN) { - if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != *alproto) { + /* if the parser operates such that it needs to see data from + * a particular direction first, we check if we have seen + * data from that direction first for the flow. IF it is not + * the same, we set an event and exit. + * + * \todo We need to figure out a more robust solution for this, + * as this can lead to easy evasion tactics, where the + * attackeer can first send some dummy data in the wrong + * direction first to mislead our proto detection process. + * While doing this we need to update the parsers as well, + * since the parsers must be robust to see such wrong + * direction data. + * Either ways the moment we see the + * APPLAYER_WRONG_DIRECTION_FIRST_DATA event set for the + * flow, it shows something's fishy. + */ + if (ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { + uint8_t first_data_dir; + first_data_dir = AppLayerParserGetFirstDataDir(f->proto, f->alproto); + + if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS); - /* it indicates some data has already been sent to the parser */ - if (ssn->data_first_seen_dir == APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - f->alproto = *alproto = *alproto_otherdir; - } else { - if (flags & STREAM_TOCLIENT) - f->alproto = *alproto_otherdir = *alproto; - else - f->alproto = *alproto = *alproto_otherdir; - } + APPLAYER_WRONG_DIRECTION_FIRST_DATA); + DisableAppLayer(tv, f, p); + goto failure; + } + /* This can happen if the current direction is not the + * right direction, and the data from the other(also + * the right direction) direction is available to be sent + * to the app layer, but it is not ack'ed yet and hence + * the forced call to STreamTcpAppLayerReassemble still + * hasn't managed to send data from the other direction + * to the app layer. */ + if (first_data_dir && !(first_data_dir & flags)) { + FlowCleanupAppLayer(f); + StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream); + FLOW_RESET_PP_DONE(f, flags); + FLOW_RESET_PM_DONE(f, flags); + goto failure; } + } - f->alproto = *alproto; - StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - - /* if we have seen data from the other direction first, send - * data for that direction first to the parser. This shouldn't - * be an issue, since each stream processing happens - * independently of the other stream direction. At this point of - * call, you need to know that this function's already being - * called by the very same StreamReassembly() function that we - * will now call shortly for the opposing direction. */ - if ((ssn->data_first_seen_dir & (STREAM_TOSERVER | STREAM_TOCLIENT)) && - !(flags & ssn->data_first_seen_dir)) { - TcpStream *opposing_stream = NULL; - if (stream == &ssn->client) { - opposing_stream = &ssn->server; - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } else { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } - } else { - opposing_stream = &ssn->client; - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } else { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } - } - int ret; - if (StreamTcpInlineMode()) { - ret = StreamTcpReassembleInlineAppLayer(tv, ra_ctx, ssn, - opposing_stream, p); - } else { - ret = StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, - opposing_stream, p); - } - if (stream == &ssn->client) { - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } else { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } - } else { - if (StreamTcpInlineMode()) { - p->flowflags &= ~FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_TOCLIENT; - } else { - p->flowflags &= ~FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_TOSERVER; - } - } - if (ret < 0) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - goto failure; - } + /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + + /* finally, invoke the parser */ + PACKET_PROFILING_APP_START(app_tctx, f->alproto); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, + flags, data, data_len); + PACKET_PROFILING_APP_END(app_tctx, f->alproto); + if (r < 0) + goto failure; + + } else { + /* if the ssn is midstream, we may end up with a case where the + * start of an HTTP request is missing. We won't detect HTTP based + * on the request. However, the reply is fine, so we detect + * HTTP anyway. This leads to passing the incomplete request to + * the htp parser. + * + * This has been observed, where the http parser then saw many + * bogus requests in the incomplete data. + * + * To counter this case, a midstream session MUST find it's + * protocol in the toserver direction. If not, we assume the + * start of the request/toserver is incomplete and no reliable + * detection and parsing is possible. So we give up. + */ + if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && + !(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) + { + if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { + SCLogDebug("midstream end pd %p", ssn); + /* midstream and toserver detection failed: give up */ + DisableAppLayer(tv, f, p); + goto end; } + } - /* if the parser operates such that it needs to see data from - * a particular direction first, we check if we have seen - * data from that direction first for the flow. IF it is not - * the same, we set an event and exit. - * - * \todo We need to figure out a more robust solution for this, - * as this can lead to easy evasion tactics, where the - * attackeer can first send some dummy data in the wrong - * direction first to mislead our proto detection process. - * While doing this we need to update the parsers as well, - * since the parsers must be robust to see such wrong - * direction data. - * Either ways the moment we see the - * APPLAYER_WRONG_DIRECTION_FIRST_DATA event set for the - * flow, it shows something's fishy. + if (*alproto_otherdir != ALPROTO_UNKNOWN) { + uint8_t first_data_dir; + first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto_otherdir); + + /* this would handle this test case - + * http parser which says it wants to see toserver data first only. + * tcp handshake + * toclient data first received. - RUBBISH DATA which + * we don't detect as http + * toserver data next sent - we detect this as http. + * at this stage we see that toclient is the first data seen + * for this session and we try and redetect the app protocol, + * but we are unable to detect the app protocol like before. + * But since we have managed to detect the protocol for the + * other direction as http, we try to use that. At this + * stage we check if the direction of this stream matches + * to that acceptable by the app parser. If it is not the + * acceptable direction we error out. */ - if (ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto); - - if (first_data_dir && !(first_data_dir & ssn->data_first_seen_dir)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_WRONG_DIRECTION_FIRST_DATA); - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - goto failure; - } - /* This can happen if the current direction is not the - * right direction, and the data from the other(also - * the right direction) direction is available to be sent - * to the app layer, but it is not ack'ed yet and hence - * the forced call to STreamTcpAppLayerReassemble still - * hasn't managed to send data from the other direction - * to the app layer. */ - if (first_data_dir && !(first_data_dir & flags)) { - BUG_ON(*alproto_otherdir != ALPROTO_UNKNOWN); - FlowCleanupAppLayer(f); - f->alproto = *alproto = ALPROTO_UNKNOWN; - StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream); - FLOW_RESET_PP_DONE(f, flags); - FLOW_RESET_PM_DONE(f, flags); - goto failure; - } + if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && + (first_data_dir) && !(first_data_dir & flags)) + { + DisableAppLayer(tv, f, p); + goto failure; } - /* Set a value that is neither STREAM_TOSERVER, nor STREAM_TOCLIENT */ - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - - PACKET_PROFILING_APP_START(app_tctx, *alproto); - r = AppLayerParserParse(app_tctx->alp_tctx, f, *alproto, flags, data + data_al_so_far, data_len - data_al_so_far); - PACKET_PROFILING_APP_END(app_tctx, *alproto); - f->data_al_so_far[dir] = 0; - } else { - /* if the ssn is midstream, we may end up with a case where the - * start of an HTTP request is missing. We won't detect HTTP based - * on the request. However, the reply is fine, so we detect - * HTTP anyway. This leads to passing the incomplete request to - * the htp parser. - * - * This has been observed, where the http parser then saw many - * bogus requests in the incomplete data. + /* if protocol detection is marked done for our direction we + * pass our data on. We're only succeeded in finding one + * direction: the opposing stream * - * To counter this case, a midstream session MUST find it's - * protocol in the toserver direction. If not, we assume the - * start of the request/toserver is incomplete and no reliable - * detection and parsing is possible. So we give up. + * If PD was not yet complete, we don't do anything. */ - if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) && !(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) { - if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - SCLogDebug("midstream end pd %p", ssn); - /* midstream and toserver detection failed: give up */ - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + if (FLOW_IS_PM_DONE(f, flags) && FLOW_IS_PP_DONE(f, flags)) { + if (data_len > 0) ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - goto end; - } - } - if (*alproto_otherdir != ALPROTO_UNKNOWN) { - first_data_dir = AppLayerParserGetFirstDataDir(f->proto, *alproto_otherdir); - - /* this would handle this test case - - * http parser which says it wants to see toserver data first only. - * tcp handshake - * toclient data first received. - RUBBISH DATA which - * we don't detect as http - * toserver data next sent - we detect this as http. - * at this stage we see that toclient is the first data seen - * for this session and we try and redetect the app protocol, - * but we are unable to detect the app protocol like before. - * But since we have managed to detect the protocol for the - * other direction as http, we try to use that. At this - * stage we check if the direction of this stream matches - * to that acceptable by the app parser. If it is not the - * acceptable direction we error out. - */ - if ((ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) && - (first_data_dir) && !(first_data_dir & flags)) - { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + PACKET_PROFILING_APP_START(app_tctx, f->alproto); + int r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, + f->alproto, flags, + data, data_len); + PACKET_PROFILING_APP_END(app_tctx, f->alproto); + + AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, + APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); + StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + TcpSessionSetReassemblyDepth(ssn, + AppLayerParserGetStreamDepth(f->proto, f->alproto)); + *alproto = ALPROTO_FAILED; + FlagPacketFlow(p, f, flags); + + SCLogDebug("packet %u: pd done(us %u them %u), parser called (r==%d), APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION set", + (uint)p->pcap_cnt, *alproto, *alproto_otherdir, r); + if (r < 0) goto failure; - } + } + } else { + /* both sides unknown, let's see if we need to give up */ + TCPProtoDetectCheckBailConditions(tv, f, ssn, p); + } + } +end: + return 0; - if (data_len > 0) - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; +failure: + return -1; +} - PACKET_PROFILING_APP_START(app_tctx, *alproto_otherdir); - r = AppLayerParserParse(app_tctx->alp_tctx, f, *alproto_otherdir, flags, - data + data_al_so_far, data_len - data_al_so_far); - PACKET_PROFILING_APP_END(app_tctx, *alproto_otherdir); - if (FLOW_IS_PM_DONE(f, flags) && FLOW_IS_PP_DONE(f, flags)) { - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); - f->data_al_so_far[dir] = 0; - } else { - f->data_al_so_far[dir] = data_len; - } - } else { - /* See if we're going to have to give up: - * - * If we're getting a lot of data in one direction and the - * proto for this direction is unknown, proto detect will - * hold up segments in the segment list in the stream. - * They are held so that if we detect the protocol on the - * opposing stream, we can still parse this side of the stream - * as well. However, some sessions are very unbalanced. FTP - * data channels, large PUT/POST request and many others, can - * lead to cases where we would have to store many megabytes - * worth of segments before we see the opposing stream. This - * leads to risks of resource starvation. - * - * Here a cutoff point is enforced. If we've stored 100k in - * one direction and we've seen no data in the other direction, - * we give up. */ - uint32_t size_ts = ssn->client.last_ack - ssn->client.isn - 1; - uint32_t size_tc = ssn->server.last_ack - ssn->server.isn - 1; - SCLogDebug("size_ts %u, size_tc %u", size_ts, size_tc); - - if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && - FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; +/** \brief handle TCP data for the app-layer. + * + * First run protocol detection and then when the protocol is known invoke + * the app layer parser. + */ +int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + Packet *p, Flow *f, + TcpSession *ssn, TcpStream *stream, + uint8_t *data, uint32_t data_len, + uint8_t flags) +{ + SCEnter(); - } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && - size_ts > 100000 && size_tc == 0) - { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && - size_tc > 100000 && size_ts == 0) - { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - /* little data in ts direction, pp done, pm not done (max - * depth not reached), ts direction done, lots of data in - * tc direction. */ - } else if (size_tc > 100000 && - FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && - FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) - { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - /* little data in tc direction, pp done, pm not done (max - * depth not reached), tc direction done, lots of data in - * ts direction. */ - } else if (size_ts > 100000 && - FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && - FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) - { - FlowSetSessionNoApplayerInspectionFlag(f); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - } - } + DEBUG_ASSERT_FLOW_LOCKED(f); + + AppLayerThreadCtx *app_tctx = ra_ctx->app_tctx; + AppProto alproto; + int r = 0; + + SCLogDebug("data_len %u flags %02X", data_len, flags); + if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) { + SCLogDebug("STREAMTCP_FLAG_APP_LAYER_DISABLED is set"); + goto end; + } + + if (flags & STREAM_TOSERVER) { + alproto = f->alproto_ts; + } else { + alproto = f->alproto_tc; + } + + /* if we don't know the proto yet and we have received a stream + * initializer message, we run proto detection. + * We receive 2 stream init msgs (one for each direction) but we + * only run the proto detection once. */ + if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_GAP)) { + StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); + SCLogDebug("ALPROTO_UNKNOWN flow %p, due to GAP in stream start", f); + + } else if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) { + /* run protocol detection */ + if (TCPProtoDetect(tv, ra_ctx, app_tctx, p, f, ssn, stream, + data, data_len, flags) != 0) { + goto failure; } } else { SCLogDebug("stream data (len %" PRIu32 " alproto " @@ -448,18 +604,14 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * a start msg should have gotten us one */ if (f->alproto != ALPROTO_UNKNOWN) { PACKET_PROFILING_APP_START(app_tctx, f->alproto); - r = AppLayerParserParse(app_tctx->alp_tctx, f, f->alproto, flags, data, data_len); + r = AppLayerParserParse(tv, app_tctx->alp_tctx, f, f->alproto, + flags, data, data_len); PACKET_PROFILING_APP_END(app_tctx, f->alproto); } else { SCLogDebug(" smsg not start, but no l7 data? Weird"); } } - /** \fixme a bit hacky but will be improved in 2.1 */ - if (*alproto == ALPROTO_HTTP) - HTPMemuseCounter(tv, ra_ctx); - else if (*alproto == ALPROTO_DNS) - DNSUpdateCounters(tv, app_tctx); goto end; failure: r = -1; @@ -473,7 +625,7 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, * If the protocol is yet unknown, the proto detection code is run first. * * \param dp_ctx Thread app layer detect context - * \param f unlocked flow + * \param f *locked* flow * \param p UDP packet * * \retval 0 ok @@ -484,9 +636,6 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * SCEnter(); int r = 0; - AppProto alproto; - - FLOWLOCK_WRLOCK(f); uint8_t flags = 0; if (p->flowflags & FLOW_PKT_TOSERVER) { @@ -495,11 +644,11 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * flags |= STREAM_TOCLIENT; } - /* if we don't know the proto yet and we have received a stream - * initializer message, we run proto detection. - * We receive 2 stream init msgs (one for each direction) but we - * only run the proto detection once. */ - if (f->alproto == ALPROTO_UNKNOWN && !(f->flags & FLOW_ALPROTO_DETECT_DONE)) { + if (f->alproto == ALPROTO_FAILED) { + SCReturnInt(0); + + /* if the protocol is still unknown, run detection */ + } else if (f->alproto == ALPROTO_UNKNOWN) { SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")", p->payload_len); @@ -511,41 +660,34 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow * PACKET_PROFILING_APP_PD_END(tctx); if (f->alproto != ALPROTO_UNKNOWN) { - f->flags |= FLOW_ALPROTO_DETECT_DONE; + AppLayerIncFlowCounter(tv, f); PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tctx->alp_tctx, - f, f->alproto, flags, - p->payload, p->payload_len); + r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, + flags, p->payload, p->payload_len); PACKET_PROFILING_APP_END(tctx, f->alproto); } else { - f->flags |= FLOW_ALPROTO_DETECT_DONE; + f->alproto = ALPROTO_FAILED; + AppLayerIncFlowCounter(tv, f); SCLogDebug("ALPROTO_UNKNOWN flow %p", f); } + /* we do only inspection in one direction, so flag both + * sides as done here */ + FlagPacketFlow(p, f, STREAM_TOSERVER); + FlagPacketFlow(p, f, STREAM_TOCLIENT); } else { - SCLogDebug("stream data (len %" PRIu32 " ), alproto " + SCLogDebug("data (len %" PRIu32 " ), alproto " "%"PRIu16" (flow %p)", p->payload_len, f->alproto, f); - /* if we don't have a data object here we are not getting it - * a start msg should have gotten us one */ - if (f->alproto != ALPROTO_UNKNOWN) { - PACKET_PROFILING_APP_START(tctx, f->alproto); - r = AppLayerParserParse(tctx->alp_tctx, - f, f->alproto, flags, - p->payload, p->payload_len); - PACKET_PROFILING_APP_END(tctx, f->alproto); - } else { - SCLogDebug("udp session has started, but failed to detect alproto " - "for l7"); - } + /* run the parser */ + PACKET_PROFILING_APP_START(tctx, f->alproto); + r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto, + flags, p->payload, p->payload_len); + PACKET_PROFILING_APP_END(tctx, f->alproto); } - alproto = f->alproto; - FLOWLOCK_UNLOCK(f); PACKET_PROFILING_APP_STORE(tctx, p); - if (alproto == ALPROTO_DNS) - DNSUpdateCounters(tv, tctx); SCReturnInt(r); } @@ -595,6 +737,8 @@ int AppLayerSetup(void) AppLayerParserRegisterProtocolParsers(); AppLayerProtoDetectPrepareState(); + AppLayerSetupCounters(); + SCReturnInt(0); } @@ -605,6 +749,8 @@ int AppLayerDeSetup(void) AppLayerProtoDetectDeSetup(); AppLayerParserDeSetup(); + AppLayerDeSetupCounters(); + SCReturnInt(0); } @@ -622,16 +768,6 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv) if ((app_tctx->alp_tctx = AppLayerParserThreadCtxAlloc()) == NULL) goto error; - /* tv is allowed to be NULL in unittests */ - if (tv != NULL) { - app_tctx->counter_dns_memuse = SCPerfTVRegisterCounter("dns.memuse", tv, - SC_PERF_TYPE_UINT64, "NULL"); - app_tctx->counter_dns_memcap_state = SCPerfTVRegisterCounter("dns.memcap_state", tv, - SC_PERF_TYPE_UINT64, "NULL"); - app_tctx->counter_dns_memcap_global = SCPerfTVRegisterCounter("dns.memcap_global", tv, - SC_PERF_TYPE_UINT64, "NULL"); - } - goto done; error: AppLayerDestroyCtxThread(app_tctx); @@ -656,136 +792,219 @@ void AppLayerDestroyCtxThread(AppLayerThreadCtx *app_tctx) SCReturn; } -/* profiling */ - -void AppLayerProfilingReset(AppLayerThreadCtx *app_tctx) +void AppLayerProfilingResetInternal(AppLayerThreadCtx *app_tctx) { -#ifdef PROFILING PACKET_PROFILING_APP_RESET(app_tctx); -#endif } -void AppLayerProfilingStore(AppLayerThreadCtx *app_tctx, Packet *p) +void AppLayerProfilingStoreInternal(AppLayerThreadCtx *app_tctx, Packet *p) { -#ifdef PROFILING PACKET_PROFILING_APP_STORE(app_tctx, p); -#endif +} + +/** \brief HACK to work around our broken unix manager (re)init loop + */ +void AppLayerRegisterGlobalCounters(void) +{ + StatsRegisterGlobalCounter("dns.memuse", DNSMemcapGetMemuseCounter); + StatsRegisterGlobalCounter("dns.memcap_state", DNSMemcapGetMemcapStateCounter); + StatsRegisterGlobalCounter("dns.memcap_global", DNSMemcapGetMemcapGlobalCounter); + StatsRegisterGlobalCounter("http.memuse", HTPMemuseGlobalCounter); + StatsRegisterGlobalCounter("http.memcap", HTPMemcapGlobalCounter); +} + +#define IPPROTOS_MAX 2 +void AppLayerSetupCounters() +{ + uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; + uint8_t ipproto; + AppProto alproto; + AppProto alprotos[ALPROTO_MAX]; + const char *str = "app_layer.flow."; + + AppLayerProtoDetectSupportedAppProtocols(alprotos); + + for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); + uint8_t other_ipproto = (ipprotos[ipproto] == IPPROTO_TCP) ? IPPROTO_UDP : IPPROTO_TCP; + const char *ipproto_suffix = (ipprotos[ipproto] == IPPROTO_TCP) ? "_tcp" : "_udp"; + + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + if (alprotos[alproto] == 1) { + const char *tx_str = "app_layer.tx."; + const char *alproto_str = AppLayerGetProtoName(alproto); + + if (AppLayerParserProtoIsRegistered(ipprotos[ipproto], alproto) && + AppLayerParserProtoIsRegistered(other_ipproto, alproto)) + { + snprintf(applayer_counter_names[ipproto_map][alproto].name, + sizeof(applayer_counter_names[ipproto_map][alproto].name), + "%s%s%s", str, alproto_str, ipproto_suffix); + if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { + snprintf(applayer_counter_names[ipproto_map][alproto].tx_name, + sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), + "%s%s%s", tx_str, alproto_str, ipproto_suffix); + } + } else { + snprintf(applayer_counter_names[ipproto_map][alproto].name, + sizeof(applayer_counter_names[ipproto_map][alproto].name), + "%s%s", str, alproto_str); + if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { + snprintf(applayer_counter_names[ipproto_map][alproto].tx_name, + sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), + "%s%s", tx_str, alproto_str); + } + } + } else if (alproto == ALPROTO_FAILED) { + snprintf(applayer_counter_names[ipproto_map][alproto].name, + sizeof(applayer_counter_names[ipproto_map][alproto].name), + "%s%s%s", str, "failed", ipproto_suffix); + } + } + } +} + +void AppLayerRegisterThreadCounters(ThreadVars *tv) +{ + uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; + uint8_t ipproto; + AppProto alproto; + AppProto alprotos[ALPROTO_MAX]; + + AppLayerProtoDetectSupportedAppProtocols(alprotos); + + for (ipproto = 0; ipproto < IPPROTOS_MAX; ipproto++) { + uint8_t ipproto_map = FlowGetProtoMapping(ipprotos[ipproto]); + + for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + if (alprotos[alproto] == 1) { + applayer_counters[ipproto_map][alproto].counter_id = + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); + + if (AppLayerParserProtocolIsTxAware(ipprotos[ipproto], alproto)) { + applayer_counters[ipproto_map][alproto].counter_tx_id = + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].tx_name, tv); + } + } else if (alproto == ALPROTO_FAILED) { + applayer_counters[ipproto_map][alproto].counter_id = + StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); + } + } + } +} + +void AppLayerDeSetupCounters() +{ + memset(applayer_counter_names, 0, sizeof(applayer_counter_names)); + memset(applayer_counters, 0, sizeof(applayer_counters)); } /***** Unittests *****/ #ifdef UNITTESTS - +#include "pkt-var.h" #include "stream-tcp.h" -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp-inline.h" #include "stream-tcp-util.h" #include "stream.h" #include "util-unittest.h" +#define TEST_START \ + Packet *p = SCMalloc(SIZE_OF_PACKET);\ + FAIL_IF_NULL(p);\ + Flow f;\ + ThreadVars tv;\ + StreamTcpThread *stt = NULL;\ + TCPHdr tcph;\ + PacketQueue pq;\ + memset(&pq,0,sizeof(PacketQueue));\ + memset(p, 0, SIZE_OF_PACKET);\ + memset (&f, 0, sizeof(Flow));\ + memset(&tv, 0, sizeof (ThreadVars));\ + memset(&tcph, 0, sizeof (TCPHdr));\ +\ + FLOW_INITIALIZE(&f);\ + f.flags = FLOW_IPV4;\ + f.proto = IPPROTO_TCP;\ + p->flow = &f;\ + p->tcph = &tcph;\ +\ + StreamTcpInitConfig(TRUE);\ + StreamTcpThreadInit(&tv, NULL, (void **)&stt);\ +\ + /* handshake */\ + tcph.th_win = htons(5480);\ + tcph.th_flags = TH_SYN;\ + p->flowflags = FLOW_PKT_TOSERVER;\ + p->payload_len = 0;\ + p->payload = NULL;\ + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);\ + TcpSession *ssn = (TcpSession *)f.protoctx;\ +\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));\ + FAIL_IF(f.alproto != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);\ + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(ssn->data_first_seen_dir != 0);\ +\ + /* handshake */\ + p->tcph->th_ack = htonl(1);\ + p->tcph->th_flags = TH_SYN | TH_ACK;\ + p->flowflags = FLOW_PKT_TOCLIENT;\ + p->payload_len = 0;\ + p->payload = NULL;\ + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));\ + FAIL_IF(f.alproto != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);\ + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(ssn->data_first_seen_dir != 0);\ +\ + /* handshake */\ + p->tcph->th_ack = htonl(1);\ + p->tcph->th_seq = htonl(1);\ + p->tcph->th_flags = TH_ACK;\ + p->flowflags = FLOW_PKT_TOSERVER;\ + p->payload_len = 0;\ + p->payload = NULL;\ + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1);\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));\ + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));\ + FAIL_IF(f.alproto != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);\ + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);\ + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));\ + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));\ + FAIL_IF(ssn->data_first_seen_dir != 0); +#define TEST_END \ + StreamTcpSessionClear(p->flow->protoctx);\ + StreamTcpThreadDeinit(&tv, (void *)stt); \ + StreamTcpFreeConfig(TRUE);\ + PACKET_DESTRUCTOR(p);\ + SCFree(p);\ + FLOW_DESTROY(&f); \ + StatsThreadCleanup(&tv); + /** * \test GET -> HTTP/1.1 */ static int AppLayerTest01(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -806,22 +1025,18 @@ static int AppLayerTest01(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -872,22 +1087,18 @@ static int AppLayerTest01(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -896,30 +1107,21 @@ static int AppLayerTest01(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -927,103 +1129,7 @@ static int AppLayerTest01(void) */ static int AppLayerTest02(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - /* handshake */ - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* partial request */ uint8_t request1[] = { 0x47, 0x45, }; @@ -1033,22 +1139,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack against partial request */ p->tcph->th_ack = htonl(3); @@ -1057,22 +1159,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* complete partial request */ uint8_t request2[] = { @@ -1093,22 +1191,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request2); p->payload = request2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ uint8_t response[] = { @@ -1159,22 +1253,18 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -1183,30 +1273,21 @@ static int AppLayerTest02(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -1214,102 +1295,7 @@ static int AppLayerTest02(void) */ static int AppLayerTest03(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* request */ uint8_t request[] = { @@ -1330,22 +1316,18 @@ static int AppLayerTest03(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* rubbish response */ uint8_t response[] = { @@ -1396,22 +1378,18 @@ static int AppLayerTest03(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -1420,30 +1398,21 @@ static int AppLayerTest03(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -1451,102 +1420,7 @@ static int AppLayerTest03(void) */ static int AppLayerTest04(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - /* handshake */ - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* request */ uint8_t request[] = { @@ -1561,53 +1435,47 @@ static int AppLayerTest04(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + PrintRawDataFp(stdout, request, sizeof(request)); p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); // TOSERVER data now seen /* partial response */ uint8_t response1[] = { 0x58, 0x54, 0x54, 0x50, }; + PrintRawDataFp(stdout, response1, sizeof(response1)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response1); p->payload = response1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* partial response ack */ p->tcph->th_ack = htonl(5); @@ -1616,22 +1484,18 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 4 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* remaining response */ uint8_t response2[] = { @@ -1676,28 +1540,25 @@ static int AppLayerTest04(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + PrintRawDataFp(stdout, response2, sizeof(response2)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response2); p->payload = response2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 4 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer /* response ack */ p->tcph->th_ack = htonl(328); @@ -1706,30 +1567,21 @@ static int AppLayerTest04(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); // toclient complete (failed) + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); // toserver complete + FAIL_IF(f.alproto != ALPROTO_HTTP); // http based on ts + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); // ts complete + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); // tc failed + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); // to client pp got nothing + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); // first data sent to applayer + + TEST_END; + PASS; } /** @@ -1737,103 +1589,7 @@ static int AppLayerTest04(void) */ static int AppLayerTest05(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -1848,28 +1604,25 @@ static int AppLayerTest05(void) 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; + PrintRawDataFp(stdout, request, sizeof(request)); p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -1914,164 +1667,56 @@ static int AppLayerTest05(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; + PrintRawDataFp(stdout, response, sizeof(response)); p->tcph->th_ack = htonl(88); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(88); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; -} - -/** - * \test HTTP/1.1 -> GET - */ -static int AppLayerTest06(void) -{ - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); + p->tcph->th_seq = htonl(88); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; +} + +/** + * \test HTTP/1.1 -> GET + */ +static int AppLayerTest06(void) +{ + TEST_START; /* full response - request ack */ uint8_t response[] = { @@ -2122,22 +1767,18 @@ static int AppLayerTest06(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOCLIENT) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOCLIENT); /* full request - response ack*/ uint8_t request[] = { @@ -2158,30 +1799,21 @@ static int AppLayerTest06(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -2189,103 +1821,7 @@ static int AppLayerTest06(void) */ static int AppLayerTest07(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -2306,22 +1842,18 @@ static int AppLayerTest07(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2372,22 +1904,18 @@ static int AppLayerTest07(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -2396,30 +1924,21 @@ static int AppLayerTest07(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - (f.flags & FLOW_NO_APPLAYER_INSPECTION) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_HTTP); + FAIL_IF(f.alproto_ts != ALPROTO_HTTP); + FAIL_IF(f.alproto_tc != ALPROTO_DCERPC); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -2427,103 +1946,7 @@ static int AppLayerTest07(void) */ static int AppLayerTest08(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request[] = { @@ -2544,22 +1967,18 @@ static int AppLayerTest08(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request); p->payload = request; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2610,22 +2029,18 @@ static int AppLayerTest08(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_DCERPC || - f.alproto_ts != ALPROTO_DCERPC || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_DCERPC); + FAIL_IF(f.alproto_ts != ALPROTO_DCERPC); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); /* response ack */ p->tcph->th_ack = htonl(328); @@ -2634,30 +2049,21 @@ static int AppLayerTest08(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_DCERPC || - f.alproto_ts != ALPROTO_DCERPC || - f.alproto_tc != ALPROTO_DCERPC || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 6\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_DCERPC); + FAIL_IF(f.alproto_ts != ALPROTO_DCERPC); + FAIL_IF(f.alproto_tc != ALPROTO_HTTP); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -2667,103 +2073,7 @@ static int AppLayerTest08(void) */ static int AppLayerTest09(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request1[] = { @@ -2774,22 +2084,18 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ p->tcph->th_ack = htonl(9); @@ -2798,48 +2104,40 @@ static int AppLayerTest09(void) p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full request */ uint8_t request2[] = { - 0x44, 0x44, 0x45, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + 0x44, 0x44, 0x45, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(9); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request2); p->payload = request2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -2884,60 +2182,47 @@ static int AppLayerTest09(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -2946,154 +2231,50 @@ static int AppLayerTest09(void) */ static int AppLayerTest10(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, - 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response[] = { @@ -3138,60 +2319,47 @@ static int AppLayerTest10(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response); p->payload = response; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } /** @@ -3201,204 +2369,92 @@ static int AppLayerTest10(void) */ static int AppLayerTest11(void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(p, 0, SIZE_OF_PACKET); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - int ret = 0; - - StreamTcpInitConfig(TRUE); - - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - /* handshake */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } + TEST_START; /* full request */ uint8_t request1[] = { 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, - 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64 }; + 0x47, 0x47, 0x49, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0xff }; p->tcph->th_ack = htonl(1); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = sizeof(request1); p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response - request ack */ - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* full response - request ack */ uint8_t response1[] = { 0x55, 0x74, 0x54, 0x50, }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(1); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response1); p->payload = response1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack from request */ p->tcph->th_ack = htonl(5); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 7\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); uint8_t response2[] = { 0x2f, 0x31, 0x2e, 0x31, @@ -3442,77 +2498,64 @@ static int AppLayerTest11(void) 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(17); + p->tcph->th_ack = htonl(18); p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; p->payload_len = sizeof(response2); p->payload = response2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 8\n"); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN); + FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN); + FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER); /* response ack from request */ p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(17); + p->tcph->th_seq = htonl(18); p->tcph->th_flags = TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; p->payload_len = 0; p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - !(f.flags & FLOW_NO_APPLAYER_INSPECTION) || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || !FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 9\n"); - goto end; - } - - StreamTcpSessionClear(p->flow->protoctx); - - ret = 1; - end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; + FAIL_IF(StreamTcpPacket(&tv, p, stt, &pq) == -1); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server)); + FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client)); + FAIL_IF(f.alproto != ALPROTO_FAILED); + FAIL_IF(f.alproto_ts != ALPROTO_FAILED); + FAIL_IF(f.alproto_tc != ALPROTO_FAILED); + FAIL_IF(!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER)); + FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT)); + FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER); + + TEST_END; + PASS; } void AppLayerUnittestsRegister(void) { SCEnter(); - UtRegisterTest("AppLayerTest01", AppLayerTest01, 1); - UtRegisterTest("AppLayerTest02", AppLayerTest02, 1); - UtRegisterTest("AppLayerTest03", AppLayerTest03, 1); - UtRegisterTest("AppLayerTest04", AppLayerTest04, 1); - UtRegisterTest("AppLayerTest05", AppLayerTest05, 1); - UtRegisterTest("AppLayerTest06", AppLayerTest06, 1); - UtRegisterTest("AppLayerTest07", AppLayerTest07, 1); - UtRegisterTest("AppLayerTest08", AppLayerTest08, 1); - UtRegisterTest("AppLayerTest09", AppLayerTest09, 1); - UtRegisterTest("AppLayerTest10", AppLayerTest10, 1); - UtRegisterTest("AppLayerTest11", AppLayerTest11, 1); + UtRegisterTest("AppLayerTest01", AppLayerTest01); + UtRegisterTest("AppLayerTest02", AppLayerTest02); + UtRegisterTest("AppLayerTest03", AppLayerTest03); + UtRegisterTest("AppLayerTest04", AppLayerTest04); + UtRegisterTest("AppLayerTest05", AppLayerTest05); + UtRegisterTest("AppLayerTest06", AppLayerTest06); + UtRegisterTest("AppLayerTest07", AppLayerTest07); + UtRegisterTest("AppLayerTest08", AppLayerTest08); + UtRegisterTest("AppLayerTest09", AppLayerTest09); + UtRegisterTest("AppLayerTest10", AppLayerTest10); + UtRegisterTest("AppLayerTest11", AppLayerTest11); SCReturn; } diff --git a/src/app-layer.h b/src/app-layer.h index 5d4f51ca3211..e7e83c629230 100644 --- a/src/app-layer.h +++ b/src/app-layer.h @@ -31,6 +31,8 @@ #include "stream-tcp-reassemble.h" #include "stream.h" +#include "util-profiling.h" + #define APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER \ (~STREAM_TOSERVER & ~STREAM_TOCLIENT) @@ -107,9 +109,33 @@ AppLayerThreadCtx *AppLayerGetCtxThread(ThreadVars *tv); */ void AppLayerDestroyCtxThread(AppLayerThreadCtx *tctx); +/** + * \brief Registers per flow counters for all protocols + * + */ +void AppLayerRegisterThreadCounters(ThreadVars *tv); + +/***** Profiling *****/ + +void AppLayerProfilingResetInternal(AppLayerThreadCtx *app_tctx); -void AppLayerProfilingReset(AppLayerThreadCtx *tctx); -void AppLayerProfilingStore(AppLayerThreadCtx *tctx, Packet *p); +static inline void AppLayerProfilingReset(AppLayerThreadCtx *app_tctx) +{ +#ifdef PROFILING + AppLayerProfilingResetInternal(app_tctx); +#endif +} + +void AppLayerProfilingStoreInternal(AppLayerThreadCtx *app_tctx, Packet *p); + +static inline void AppLayerProfilingStore(AppLayerThreadCtx *app_tctx, Packet *p) +{ +#ifdef PROFILING + AppLayerProfilingStoreInternal(app_tctx, p); +#endif +} + +void AppLayerRegisterGlobalCounters(void); /***** Unittests *****/ @@ -117,4 +143,6 @@ void AppLayerProfilingStore(AppLayerThreadCtx *tctx, Packet *p); void AppLayerUnittestsRegister(void); #endif +void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step); + #endif diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index 8e873079432f..6f40ab784e1a 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -167,6 +167,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) { ConfNode *node = parent; yaml_event_t event; + memset(&event, 0, sizeof(event)); int done = 0; int state = 0; int seq_idx = 0; @@ -192,8 +193,8 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) fprintf(stderr, "%%YAML 1.1\n---\n\n"); goto fail; } - int major = event.data.document_start.version_directive->major; - int minor = event.data.document_start.version_directive->minor; + int major = ver->major; + int minor = ver->minor; if (!(major == YAML_VERSION_MAJOR && minor == YAML_VERSION_MINOR)) { fprintf(stderr, "ERROR: Invalid YAML version. Must be 1.1\n"); goto fail; @@ -244,9 +245,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) } else if (state == CONF_KEY) { - /* Top level include statements. */ - if ((strcmp(value, "include") == 0) && - (parent == ConfGetRootNode())) { + if (strcmp(value, "include") == 0) { state = CONF_INCLUDE; goto next; } @@ -310,6 +309,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) SCLogDebug("event.type=YAML_SEQUENCE_START_EVENT; state=%d", state); if (ConfYamlParse(parser, node, 1) != 0) goto fail; + node->is_seq = 1; state = CONF_KEY; } else if (event.type == YAML_SEQUENCE_END_EVENT) { @@ -448,10 +448,77 @@ ConfYamlLoadString(const char *string, size_t len) return ret; } +/** + * \brief Load configuration from a YAML file, insert in tree at 'prefix' + * + * This function will load a configuration file and insert it into the + * config tree at 'prefix'. This means that if this is called with prefix + * "abc" and the file contains a parameter "def", it will be loaded as + * "abc.def". + * + * \param filename Filename of configuration file to load. + * \param prefix Name prefix to use. + * + * \retval 0 on success, -1 on failure. + */ +int +ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix) +{ + FILE *infile; + yaml_parser_t parser; + int ret; + ConfNode *root = ConfGetNode(prefix); + + if (yaml_parser_initialize(&parser) != 1) { + SCLogError(SC_ERR_FATAL, "failed to initialize yaml parser."); + return -1; + } + + struct stat stat_buf; + /* coverity[toctou] */ + if (stat(filename, &stat_buf) == 0) { + if (stat_buf.st_mode & S_IFDIR) { + SCLogError(SC_ERR_FATAL, "yaml argument is not a file but a directory: %s. " + "Please specify the yaml file in your -c option.", filename); + return -1; + } + } + + /* coverity[toctou] */ + infile = fopen(filename, "r"); + if (infile == NULL) { + SCLogError(SC_ERR_FATAL, "failed to open file: %s: %s", filename, + strerror(errno)); + yaml_parser_delete(&parser); + return -1; + } + + if (conf_dirname == NULL) { + ConfYamlSetConfDirname(filename); + } + + if (root == NULL) { + /* if node at 'prefix' doesn't yet exist, add a place holder */ + ConfSet(prefix, ""); + root = ConfGetNode(prefix); + if (root == NULL) { + fclose(infile); + yaml_parser_delete(&parser); + return -1; + } + } + yaml_parser_set_input_file(&parser, infile); + ret = ConfYamlParse(&parser, root, 0); + yaml_parser_delete(&parser); + fclose(infile); + + return ret; +} + #ifdef UNITTESTS static int -ConfYamlRuleFileTest(void) +ConfYamlSequenceTest(void) { char input[] = "\ %YAML 1.1\n\ @@ -472,6 +539,8 @@ default-log-dir: /tmp\n\ node = ConfGetNode("rule-files"); if (node == NULL) return 0; + if (!ConfNodeIsSequence(node)) + return 0; if (TAILQ_EMPTY(&node->head)) return 0; int i = 0; @@ -480,10 +549,16 @@ default-log-dir: /tmp\n\ if (i == 0) { if (strcmp(filename->val, "netbios.rules") != 0) return 0; + if (ConfNodeIsSequence(filename)) + return 0; + if (filename->is_seq != 0) + return 0; } else if (i == 1) { if (strcmp(filename->val, "x11.rules") != 0) return 0; + if (ConfNodeIsSequence(filename)) + return 0; } else { return 0; @@ -864,14 +939,14 @@ void ConfYamlRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ConfYamlRuleFileTest", ConfYamlRuleFileTest, 1); - UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest, 1); - UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest, 1); - UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest, 1); + UtRegisterTest("ConfYamlSequenceTest", ConfYamlSequenceTest); + UtRegisterTest("ConfYamlLoggingOutputTest", ConfYamlLoggingOutputTest); + UtRegisterTest("ConfYamlNonYamlFileTest", ConfYamlNonYamlFileTest); + UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest); UtRegisterTest("ConfYamlSecondLevelSequenceTest", - ConfYamlSecondLevelSequenceTest, 1); - UtRegisterTest("ConfYamlFileIncludeTest", ConfYamlFileIncludeTest, 1); - UtRegisterTest("ConfYamlOverrideTest", ConfYamlOverrideTest, 1); - UtRegisterTest("ConfYamlOverrideFinalTest", ConfYamlOverrideFinalTest, 1); + ConfYamlSecondLevelSequenceTest); + UtRegisterTest("ConfYamlFileIncludeTest", ConfYamlFileIncludeTest); + UtRegisterTest("ConfYamlOverrideTest", ConfYamlOverrideTest); + UtRegisterTest("ConfYamlOverrideFinalTest", ConfYamlOverrideFinalTest); #endif /* UNITTESTS */ } diff --git a/src/conf-yaml-loader.h b/src/conf-yaml-loader.h index 22dfb8777377..6c599d0ac8ff 100644 --- a/src/conf-yaml-loader.h +++ b/src/conf-yaml-loader.h @@ -26,6 +26,8 @@ int ConfYamlLoadFile(const char *); int ConfYamlLoadString(const char *, size_t); +int ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix); + void ConfYamlRegisterTests(void); #endif /* !__CONF_YAML_LOADER_H__ */ diff --git a/src/conf.c b/src/conf.c index cabde9e36fb9..59e5aef47aae 100644 --- a/src/conf.c +++ b/src/conf.c @@ -61,8 +61,7 @@ static ConfNode *root_backup = NULL; * \retval The existing configuration node if it exists, or a newly * created node for the provided name. On error, NULL will be returned. */ -static ConfNode * -ConfGetNodeOrCreate(char *name, int final) +static ConfNode *ConfGetNodeOrCreate(const char *name, int final) { ConfNode *parent = root; ConfNode *node = NULL; @@ -111,8 +110,7 @@ ConfGetNodeOrCreate(char *name, int final) /** * \brief Initialize the configuration system. */ -void -ConfInit(void) +void ConfInit(void) { if (root != NULL) { SCLogDebug("already initialized"); @@ -133,8 +131,7 @@ ConfInit(void) * * \retval An allocated configuration node on success, NULL on failure. */ -ConfNode * -ConfNodeNew(void) +ConfNode *ConfNodeNew(void) { ConfNode *new; @@ -152,8 +149,7 @@ ConfNodeNew(void) * * \param node The configuration node to SCFree. */ -void -ConfNodeFree(ConfNode *node) +void ConfNodeFree(ConfNode *node) { ConfNode *tmp; @@ -177,8 +173,7 @@ ConfNodeFree(ConfNode *node) * \retval A pointer to ConfNode is found or NULL if the configuration * node does not exist. */ -ConfNode * -ConfGetNode(char *name) +ConfNode *ConfGetNode(const char *name) { ConfNode *node = root; char node_name[NODE_NAME_MAX]; @@ -205,8 +200,7 @@ ConfGetNode(char *name) /** * \brief Get the root configuration node. */ -ConfNode * -ConfGetRootNode(void) +ConfNode *ConfGetRootNode(void) { return root; } @@ -223,8 +217,7 @@ ConfGetRootNode(void) * * \retval 1 if the value was set otherwise 0. */ -int -ConfSet(char *name, char *val) +int ConfSet(const char *name, char *val) { ConfNode *node = ConfGetNodeOrCreate(name, 0); if (node == NULL || node->final) { @@ -239,6 +232,56 @@ ConfSet(char *name, char *val) return 1; } +/** + * \brief Set a configuration parameter from a string. + * + * Where the input string is something like: + * stream.midstream=true + * + * \param input the input string to be parsed. + * + * \retval 1 if the value of set, otherwise 0. + */ +int ConfSetFromString(const char *input, int final) +{ + int retval = 0; + char *name = SCStrdup(input), *val = NULL; + if (unlikely(name == NULL)) { + goto done; + } + val = strchr(name, '='); + if (val == NULL) { + goto done; + } + *val++ = '\0'; + + while (isspace((int)name[strlen(name) - 1])) { + name[strlen(name) - 1] = '\0'; + } + + while (isspace((int)*val)) { + val++; + } + + if (final) { + if (!ConfSetFinal(name, val)) { + goto done; + } + } + else { + if (!ConfSet(name, val)) { + goto done; + } + } + + retval = 1; +done: + if (name != NULL) { + SCFree(name); + } + return retval; +} + /** * \brief Set a final configuration value. * @@ -253,8 +296,7 @@ ConfSet(char *name, char *val) * * \retval 1 if the value was set otherwise 0. */ -int -ConfSetFinal(char *name, char *val) +int ConfSetFinal(const char *name, char *val) { ConfNode *node = ConfGetNodeOrCreate(name, 1); if (node == NULL) { @@ -286,8 +328,7 @@ ConfSetFinal(char *name, char *val) * \retval 1 will be returned if the name is found, otherwise 0 will * be returned. */ -int -ConfGet(char *name, char **vptr) +int ConfGet(const char *name, char **vptr) { ConfNode *node = ConfGetNode(name); if (node == NULL) { @@ -300,7 +341,7 @@ ConfGet(char *name, char **vptr) } } -int ConfGetChildValue(ConfNode *base, char *name, char **vptr) +int ConfGetChildValue(const ConfNode *base, const char *name, char **vptr) { ConfNode *node = ConfNodeLookupChild(base, name); @@ -315,7 +356,8 @@ int ConfGetChildValue(ConfNode *base, char *name, char **vptr) } -int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, char **vptr) +int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, + const char *name, char **vptr) { int ret = ConfGetChildValue(base, name, vptr); /* Get 'default' value */ @@ -335,10 +377,9 @@ int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, cha * \retval 1 will be returned if the name is found and was properly * converted to an interger, otherwise 0 will be returned. */ -int -ConfGetInt(char *name, intmax_t *val) +int ConfGetInt(const char *name, intmax_t *val) { - char *strval; + char *strval = NULL; intmax_t tmpint; char *endptr; @@ -356,9 +397,9 @@ ConfGetInt(char *name, intmax_t *val) return 1; } -int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val) +int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val) { - char *strval; + char *strval = NULL; intmax_t tmpint; char *endptr; @@ -376,7 +417,8 @@ int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val) } -int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, intmax_t *val) +int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, + const char *name, intmax_t *val) { int ret = ConfGetChildValueInt(base, name, val); /* Get 'default' value */ @@ -397,10 +439,9 @@ int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, * \retval 1 will be returned if the name is found and was properly * converted to a boolean, otherwise 0 will be returned. */ -int -ConfGetBool(char *name, int *val) +int ConfGetBool(const char *name, int *val) { - char *strval; + char *strval = NULL; *val = 0; if (ConfGet(name, &strval) != 1) @@ -411,9 +452,9 @@ ConfGetBool(char *name, int *val) return 1; } -int ConfGetChildValueBool(ConfNode *base, char *name, int *val) +int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val) { - char *strval; + char *strval = NULL; *val = 0; if (ConfGetChildValue(base, name, &strval) == 0) @@ -424,7 +465,8 @@ int ConfGetChildValueBool(ConfNode *base, char *name, int *val) return 1; } -int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val) +int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, + const char *name, int *val) { int ret = ConfGetChildValueBool(base, name, val); /* Get 'default' value */ @@ -446,8 +488,7 @@ int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, * * \retval 1 If the value is true, 0 if not. */ -int -ConfValIsTrue(const char *val) +int ConfValIsTrue(const char *val) { char *trues[] = {"1", "yes", "true", "on"}; size_t u; @@ -472,8 +513,7 @@ ConfValIsTrue(const char *val) * * \retval 1 If the value is false, 0 if not. */ -int -ConfValIsFalse(const char *val) +int ConfValIsFalse(const char *val) { char *falses[] = {"0", "no", "false", "off"}; size_t u; @@ -497,10 +537,9 @@ ConfValIsFalse(const char *val) * \retval 1 will be returned if the name is found and was properly * converted to a double, otherwise 0 will be returned. */ -int -ConfGetDouble(char *name, double *val) +int ConfGetDouble(const char *name, double *val) { - char *strval; + char *strval = NULL; double tmpdo; char *endptr; @@ -528,10 +567,9 @@ ConfGetDouble(char *name, double *val) * \retval 1 will be returned if the name is found and was properly * converted to a double, otherwise 0 will be returned. */ -int -ConfGetFloat(char *name, float *val) +int ConfGetFloat(const char *name, float *val) { - char *strval; + char *strval = NULL; double tmpfl; char *endptr; @@ -552,8 +590,7 @@ ConfGetFloat(char *name, float *val) /** * \brief Remove (and SCFree) the provided configuration node. */ -void -ConfNodeRemove(ConfNode *node) +void ConfNodeRemove(ConfNode *node) { if (node->parent != NULL) TAILQ_REMOVE(&node->parent->head, node, next); @@ -568,8 +605,7 @@ ConfNodeRemove(ConfNode *node) * \retval Returns 1 if the parameter was removed, otherwise 0 is returned * most likely indicating the parameter was not set. */ -int -ConfRemove(char *name) +int ConfRemove(const char *name) { ConfNode *node; @@ -585,8 +621,7 @@ ConfRemove(char *name) /** * \brief Creates a backup of the conf_hash hash_table used by the conf API. */ -void -ConfCreateContextBackup(void) +void ConfCreateContextBackup(void) { root_backup = root; root = NULL; @@ -598,8 +633,7 @@ ConfCreateContextBackup(void) * \brief Restores the backup of the hash_table present in backup_conf_hash * back to conf_hash. */ -void -ConfRestoreContextBackup(void) +void ConfRestoreContextBackup(void) { root = root_backup; root_backup = NULL; @@ -610,8 +644,7 @@ ConfRestoreContextBackup(void) /** * \brief De-initializes the configuration system. */ -void -ConfDeInit(void) +void ConfDeInit(void) { if (root != NULL) { ConfNodeFree(root); @@ -621,8 +654,7 @@ ConfDeInit(void) SCLogDebug("configuration module de-initialized"); } -static char * -ConfPrintNameArray(char **name_arr, int level) +static char *ConfPrintNameArray(char **name_arr, int level) { static char name[128*128]; int i; @@ -640,8 +672,7 @@ ConfPrintNameArray(char **name_arr, int level) /** * \brief Dump a configuration node and all its children. */ -void -ConfNodeDump(ConfNode *node, const char *prefix) +void ConfNodeDump(const ConfNode *node, const char *prefix) { ConfNode *child; @@ -671,8 +702,7 @@ ConfNodeDump(ConfNode *node, const char *prefix) /** * \brief Dump configuration to stdout. */ -void -ConfDump(void) +void ConfDump(void) { ConfNodeDump(root, NULL); } @@ -688,13 +718,16 @@ ConfDump(void) * * \retval A pointer the child ConfNode if found otherwise NULL. */ -ConfNode * -ConfNodeLookupChild(ConfNode *node, const char *name) +ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *name) { ConfNode *child; + if (node == NULL || name == NULL) { + return NULL; + } + TAILQ_FOREACH(child, &node->head, next) { - if (strcmp(child->name, name) == 0) + if (child->name != NULL && strcmp(child->name, name) == 0) return child; } @@ -713,8 +746,7 @@ ConfNodeLookupChild(ConfNode *node, const char *name) * * \retval A pointer the child ConfNodes value if found otherwise NULL. */ -const char * -ConfNodeLookupChildValue(ConfNode *node, const char *name) +const char *ConfNodeLookupChildValue(const ConfNode *node, const char *name) { ConfNode *child; @@ -731,7 +763,8 @@ ConfNodeLookupChildValue(ConfNode *node, const char *name) * \return the ConfNode matching or NULL */ -ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *value) +ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, + const char *value) { ConfNode *child; @@ -758,8 +791,7 @@ ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *va * \retval 1 if the child node has a true value, otherwise 0 is * returned, even if the child node does not exist. */ -int -ConfNodeChildValueIsTrue(ConfNode *node, const char *key) +int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key) { const char *val; @@ -773,7 +805,7 @@ ConfNodeChildValueIsTrue(ConfNode *node, const char *key) * \param file The name of the file * \retval str Pointer to the string path + sig_file */ -char *ConfLoadCompleteIncludePath(char *file) +char *ConfLoadCompleteIncludePath(const char *file) { char *defaultpath = NULL; char *path = NULL; @@ -814,8 +846,7 @@ char *ConfLoadCompleteIncludePath(char *file) * * \param node The configuration node to prune. */ -void -ConfNodePrune(ConfNode *node) +void ConfNodePrune(ConfNode *node) { ConfNode *item, *it; @@ -840,142 +871,124 @@ ConfNodePrune(ConfNode *node) } } +/** + * \brief Check if a node is a sequence or node. + * + * \param node the node to check. + * + * \return 1 if node is a seuence, otherwise 0. + */ +int ConfNodeIsSequence(const ConfNode *node) +{ + return node->is_seq == 0 ? 0 : 1; +} + #ifdef UNITTESTS /** * Lookup a non-existant value. */ -static int -ConfTestGetNonExistant(void) +static int ConfTestGetNonExistant(void) { char name[] = "non-existant-value"; char *value; - return !ConfGet(name, &value); + FAIL_IF(ConfGet(name, &value)); + PASS; } /** * Set then lookup a value. */ -static int -ConfTestSetAndGet(void) +static int ConfTestSetAndGet(void) { char name[] = "some-name"; char value[] = "some-value"; char *value0; - if (ConfSet(name, value) != 1) - return 0; - if (ConfGet(name, &value0) != 1) - return 0; - if (strcmp(value, value0) != 0) - return 0; + FAIL_IF(ConfSet(name, value) != 1); + FAIL_IF(ConfGet(name, &value0) != 1); + FAIL_IF(strcmp(value, value0) != 0); /* Cleanup. */ ConfRemove(name); - return 1; + PASS; } /** * Test that overriding a value is allowed provided allow_override is * true and that the config parameter gets the new value. */ -static int -ConfTestOverrideValue1(void) +static int ConfTestOverrideValue1(void) { char name[] = "some-name"; char value0[] = "some-value"; char value1[] = "new-value"; char *val; - int rc; - if (ConfSet(name, value0) != 1) - return 0; - if (ConfSet(name, value1) != 1) - return 0; - if (ConfGet(name, &val) != 1) - return 0; - - rc = !strcmp(val, value1); + FAIL_IF(ConfSet(name, value0) != 1); + FAIL_IF(ConfSet(name, value1) != 1); + FAIL_IF(ConfGet(name, &val) != 1); + FAIL_IF(strcmp(val, value1)); /* Cleanup. */ ConfRemove(name); - return rc; + PASS; } /** * Test that a final value will not be overrided by a ConfSet. */ -static int -ConfTestOverrideValue2(void) +static int ConfTestOverrideValue2(void) { char name[] = "some-name"; char value0[] = "some-value"; char value1[] = "new-value"; char *val; - int rc; - - if (ConfSetFinal(name, value0) != 1) - return 0; - if (ConfSet(name, value1) != 0) - return 0; - if (ConfGet(name, &val) != 1) - return 0; - rc = !strcmp(val, value0); + FAIL_IF(ConfSetFinal(name, value0) != 1); + FAIL_IF(ConfSet(name, value1) != 0); + FAIL_IF(ConfGet(name, &val) != 1); + FAIL_IF(strcmp(val, value0)); /* Cleanup. */ ConfRemove(name); - return rc; + PASS; } /** * Test retrieving an integer value from the configuration db. */ -static int -ConfTestGetInt(void) +static int ConfTestGetInt(void) { char name[] = "some-int.x"; intmax_t val; - if (ConfSet(name, "0") != 1) - return 0; - if (ConfGetInt(name, &val) != 1) - return 0; + FAIL_IF(ConfSet(name, "0") != 1); + FAIL_IF(ConfGetInt(name, &val) != 1); + FAIL_IF(val != 0); - if (val != 0) - return 0; + FAIL_IF(ConfSet(name, "-1") != 1); + FAIL_IF(ConfGetInt(name, &val) != 1); + FAIL_IF(val != -1); - if (ConfSet(name, "-1") != 1) - return 0; - if (ConfGetInt(name, &val) != 1) - return 0; - if (val != -1) - return 0; + FAIL_IF(ConfSet(name, "0xffff") != 1); + FAIL_IF(ConfGetInt(name, &val) != 1); + FAIL_IF(val != 0xffff); - if (ConfSet(name, "0xffff") != 1) - return 0; - if (ConfGetInt(name, &val) != 1) - return 0; - if (val != 0xffff) - return 0; + FAIL_IF(ConfSet(name, "not-an-int") != 1); + FAIL_IF(ConfGetInt(name, &val) != 0); - if (ConfSet(name, "not-an-int") != 1) - return 0; - if (ConfGetInt(name, &val) != 0) - return 0; - - return 1; + PASS; } /** * Test retrieving a boolean value from the configuration db. */ -static int -ConfTestGetBool(void) +static int ConfTestGetBool(void) { char name[] = "some-bool"; char *trues[] = { @@ -995,28 +1008,21 @@ ConfTestGetBool(void) size_t u; for (u = 0; u < sizeof(trues) / sizeof(trues[0]); u++) { - if (ConfSet(name, trues[u]) != 1) - return 0; - if (ConfGetBool(name, &val) != 1) - return 0; - if (val != 1) - return 0; + FAIL_IF(ConfSet(name, trues[u]) != 1); + FAIL_IF(ConfGetBool(name, &val) != 1); + FAIL_IF(val != 1); } for (u = 0; u < sizeof(falses) / sizeof(falses[0]); u++) { - if (ConfSet(name, falses[u]) != 1) - return 0; - if (ConfGetBool(name, &val) != 1) - return 0; - if (val != 0) - return 0; + FAIL_IF(ConfSet(name, falses[u]) != 1); + FAIL_IF(ConfGetBool(name, &val) != 1); + FAIL_IF(val != 0); } - return 1; + PASS; } -static int -ConfNodeLookupChildTest(void) +static int ConfNodeLookupChildTest(void) { char *test_vals[] = { "one", "two", "three" }; size_t u; @@ -1032,40 +1038,33 @@ ConfNodeLookupChildTest(void) } child = ConfNodeLookupChild(parent, "one"); - if (child == NULL) - return 0; - if (strcmp(child->name, "one") != 0) - return 0; - if (strcmp(child->val, "one") != 0) - return 0; + FAIL_IF(child == NULL); + FAIL_IF(strcmp(child->name, "one") != 0); + FAIL_IF(strcmp(child->val, "one") != 0); child = ConfNodeLookupChild(parent, "two"); - if (child == NULL) - return 0; - if (strcmp(child->name, "two") != 0) - return 0; - if (strcmp(child->val, "two") != 0) - return 0; + FAIL_IF(child == NULL); + FAIL_IF(strcmp(child->name, "two") != 0); + FAIL_IF(strcmp(child->val, "two") != 0); child = ConfNodeLookupChild(parent, "three"); - if (child == NULL) - return 0; - if (strcmp(child->name, "three") != 0) - return 0; - if (strcmp(child->val, "three") != 0) - return 0; + FAIL_IF(child == NULL); + FAIL_IF(strcmp(child->name, "three") != 0); + FAIL_IF(strcmp(child->val, "three") != 0); child = ConfNodeLookupChild(parent, "four"); - if (child != NULL) - return 0; + FAIL_IF(child != NULL); - ConfNodeFree(parent); + FAIL_IF(ConfNodeLookupChild(NULL, NULL) != NULL); - return 1; + if (parent != NULL) { + ConfNodeFree(parent); + } + + PASS; } -static int -ConfNodeLookupChildValueTest(void) +static int ConfNodeLookupChildValueTest(void) { char *test_vals[] = { "one", "two", "three" }; size_t u; @@ -1082,60 +1081,47 @@ ConfNodeLookupChildValueTest(void) } value = (char *)ConfNodeLookupChildValue(parent, "one"); - if (value == NULL) - return 0; - if (strcmp(value, "one") != 0) - return 0; + FAIL_IF(value == NULL); + FAIL_IF(strcmp(value, "one") != 0); value = (char *)ConfNodeLookupChildValue(parent, "two"); - if (value == NULL) - return 0; - if (strcmp(value, "two") != 0) - return 0; + FAIL_IF(value == NULL); + FAIL_IF(strcmp(value, "two") != 0); value = (char *)ConfNodeLookupChildValue(parent, "three"); - if (value == NULL) - return 0; - if (strcmp(value, "three") != 0) - return 0; + FAIL_IF(value == NULL); + FAIL_IF(strcmp(value, "three") != 0); value = (char *)ConfNodeLookupChildValue(parent, "four"); - if (value != NULL) - return 0; + FAIL_IF(value != NULL); ConfNodeFree(parent); - return 1; + PASS; } static int ConfGetChildValueWithDefaultTest(void) { char *val = ""; - int ret = 1; ConfCreateContextBackup(); ConfInit(); ConfSet("af-packet.0.interface", "eth0"); ConfSet("af-packet.1.interface", "default"); ConfSet("af-packet.1.cluster-type", "cluster_cpu"); - ConfNode *root = ConfGetNode("af-packet.0"); + ConfNode *myroot = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); - ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); - if (strcmp(val, "cluster_cpu")) { - ConfDeInit(); - ConfRestoreContextBackup(); - return 0; - } + ConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val); + FAIL_IF(strcmp(val, "cluster_cpu")); ConfSet("af-packet.0.cluster-type", "cluster_flow"); - ConfGetChildValueWithDefault(root, dflt, "cluster-type", &val); + ConfGetChildValueWithDefault(myroot, dflt, "cluster-type", &val); + + FAIL_IF(strcmp(val, "cluster_flow")); - if (strcmp(val, "cluster_flow")) { - ret = 0; - } ConfDeInit(); ConfRestoreContextBackup(); - return ret; + PASS; } static int ConfGetChildValueIntWithDefaultTest(void) @@ -1147,24 +1133,19 @@ static int ConfGetChildValueIntWithDefaultTest(void) ConfSet("af-packet.1.interface", "default"); ConfSet("af-packet.1.threads", "2"); - ConfNode *root = ConfGetNode("af-packet.0"); + ConfNode *myroot = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); - ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); - if (val != 2) { - ConfDeInit(); - ConfRestoreContextBackup(); - return 0; - } + ConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val); + FAIL_IF(val != 2); ConfSet("af-packet.0.threads", "1"); - ConfGetChildValueIntWithDefault(root, dflt, "threads", &val); + ConfGetChildValueIntWithDefault(myroot, dflt, "threads", &val); + FAIL_IF(val != 1); ConfDeInit(); ConfRestoreContextBackup(); - if (val != 1) { - return 0; - } - return 1; + + PASS; } static int ConfGetChildValueBoolWithDefaultTest(void) @@ -1176,92 +1157,75 @@ static int ConfGetChildValueBoolWithDefaultTest(void) ConfSet("af-packet.1.interface", "default"); ConfSet("af-packet.1.use-mmap", "yes"); - ConfNode *root = ConfGetNode("af-packet.0"); + ConfNode *myroot = ConfGetNode("af-packet.0"); ConfNode *dflt = ConfGetNode("af-packet.1"); - ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); - if (val == 0) { - ConfDeInit(); - ConfRestoreContextBackup(); - return 0; - } + ConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val); + FAIL_IF(val == 0); ConfSet("af-packet.0.use-mmap", "no"); - ConfGetChildValueBoolWithDefault(root, dflt, "use-mmap", &val); + ConfGetChildValueBoolWithDefault(myroot, dflt, "use-mmap", &val); + FAIL_IF(val); ConfDeInit(); ConfRestoreContextBackup(); - if (val) { - return 0; - } - return 1; + + PASS; } /** * Test the removal of a configuration node. */ -static int -ConfNodeRemoveTest(void) +static int ConfNodeRemoveTest(void) { ConfCreateContextBackup(); ConfInit(); - if (ConfSet("some.nested.parameter", "blah") != 1) - return 0; + FAIL_IF(ConfSet("some.nested.parameter", "blah") != 1); ConfNode *node = ConfGetNode("some.nested.parameter"); - if (node == NULL) - return 0; + FAIL_IF(node == NULL); ConfNodeRemove(node); node = ConfGetNode("some.nested.parameter"); - if (node != NULL) - return 0; + FAIL_IF(node != NULL); ConfDeInit(); ConfRestoreContextBackup(); - return 1; + PASS; } -static int -ConfSetTest(void) +static int ConfSetTest(void) { ConfCreateContextBackup(); ConfInit(); /* Set some value with 2 levels. */ - if (ConfSet("one.two", "three") != 1) - return 0; + FAIL_IF(ConfSet("one.two", "three") != 1); ConfNode *n = ConfGetNode("one.two"); - if (n == NULL) - return 0; + FAIL_IF(n == NULL); /* Set another 2 level parameter with the same first level, this * used to trigger a bug that caused the second level of the name * to become a first level node. */ - if (ConfSet("one.three", "four") != 1) - return 0; + FAIL_IF(ConfSet("one.three", "four") != 1); n = ConfGetNode("one.three"); - if (n == NULL) - return 0; + FAIL_IF(n == NULL); /* A top level node of "three" should not exist. */ n = ConfGetNode("three"); - if (n != NULL) - return 0; + FAIL_IF(n != NULL); ConfDeInit(); ConfRestoreContextBackup(); - return 1; + PASS; } -static int -ConfGetNodeOrCreateTest(void) +static int ConfGetNodeOrCreateTest(void) { ConfNode *node; - int ret = 0; ConfCreateContextBackup(); ConfInit(); @@ -1269,153 +1233,140 @@ ConfGetNodeOrCreateTest(void) /* Get a node that should not exist, give it a value, re-get it * and make sure the second time it returns the existing node. */ node = ConfGetNodeOrCreate("node0", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->parent == NULL || node->parent != root) { - fprintf(stderr, "unexpected parent node\n"); - goto end; - } - if (node->val != NULL) { - fprintf(stderr, "node already existed\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->parent == NULL || node->parent != root); + FAIL_IF(node->val != NULL); node->val = SCStrdup("node0"); node = ConfGetNodeOrCreate("node0", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->val == NULL) { - fprintf(stderr, "new node was allocated\n"); - goto end; - } - if (strcmp(node->val, "node0") != 0) { - fprintf(stderr, "node did not have expected value\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->val == NULL); + FAIL_IF(strcmp(node->val, "node0") != 0); /* Do the same, but for something deeply nested. */ node = ConfGetNodeOrCreate("parent.child.grandchild", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->parent == NULL || node->parent == root) { - fprintf(stderr, "unexpected parent node\n"); - goto end; - } - if (node->val != NULL) { - fprintf(stderr, "node already existed\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->parent == NULL || node->parent == root); + FAIL_IF(node->val != NULL); node->val = SCStrdup("parent.child.grandchild"); node = ConfGetNodeOrCreate("parent.child.grandchild", 0); - if (node == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (node->val == NULL) { - fprintf(stderr, "new node was allocated\n"); - goto end; - } - if (strcmp(node->val, "parent.child.grandchild") != 0) { - fprintf(stderr, "node did not have expected value\n"); - goto end; - } + FAIL_IF(node == NULL); + FAIL_IF(node->val == NULL); + FAIL_IF(strcmp(node->val, "parent.child.grandchild") != 0); /* Test that 2 child nodes have the same root. */ ConfNode *child1 = ConfGetNodeOrCreate("parent.kids.child1", 0); ConfNode *child2 = ConfGetNodeOrCreate("parent.kids.child2", 0); - if (child1 == NULL || child2 == NULL) { - fprintf(stderr, "returned null\n"); - goto end; - } - if (child1->parent != child2->parent) { - fprintf(stderr, "child nodes have different parents\n"); - goto end; - } - if (strcmp(child1->parent->name, "kids") != 0) { - fprintf(stderr, "parent node had unexpected name\n"); - goto end; - } + FAIL_IF(child1 == NULL || child2 == NULL); + FAIL_IF(child1->parent != child2->parent); + FAIL_IF(strcmp(child1->parent->name, "kids") != 0); - ret = 1; - -end: ConfDeInit(); ConfRestoreContextBackup(); - return ret; + PASS; } -static int -ConfNodePruneTest(void) +static int ConfNodePruneTest(void) { - int ret = 0; ConfNode *node; ConfCreateContextBackup(); ConfInit(); /* Test that final nodes exist after a prune. */ - if (ConfSet("node.notfinal", "notfinal") != 1) - goto end; - if (ConfSetFinal("node.final", "final") != 1) - goto end; - if (ConfGetNode("node.notfinal") == NULL) - goto end; - if (ConfGetNode("node.final") == NULL) - goto end; - if ((node = ConfGetNode("node")) == NULL) - goto end; + FAIL_IF(ConfSet("node.notfinal", "notfinal") != 1); + FAIL_IF(ConfSetFinal("node.final", "final") != 1); + FAIL_IF(ConfGetNode("node.notfinal") == NULL); + FAIL_IF(ConfGetNode("node.final") == NULL); + FAIL_IF((node = ConfGetNode("node")) == NULL); ConfNodePrune(node); - if (ConfGetNode("node.notfinal") != NULL) - goto end; - if (ConfGetNode("node.final") == NULL) - goto end; + FAIL_IF(ConfGetNode("node.notfinal") != NULL); + FAIL_IF(ConfGetNode("node.final") == NULL); /* Test that everything under a final node exists after a prune. */ - if (ConfSet("node.final.one", "one") != 1) - goto end; - if (ConfSet("node.final.two", "two") != 1) - goto end; + FAIL_IF(ConfSet("node.final.one", "one") != 1); + FAIL_IF(ConfSet("node.final.two", "two") != 1); ConfNodePrune(node); - if (ConfNodeLookupChild(node, "final") == NULL) - goto end; - if (ConfGetNode("node.final.one") == NULL) - goto end; - if (ConfGetNode("node.final.two") == NULL) - goto end; - - ret = 1; + FAIL_IF(ConfNodeLookupChild(node, "final") == NULL); + FAIL_IF(ConfGetNode("node.final.one") == NULL); + FAIL_IF(ConfGetNode("node.final.two") == NULL); -end: ConfDeInit(); ConfRestoreContextBackup(); - return ret; + PASS; +} + +int ConfNodeIsSequenceTest(void) +{ + ConfNode *node = ConfNodeNew(); + FAIL_IF(node == NULL); + FAIL_IF(ConfNodeIsSequence(node)); + node->is_seq = 1; + FAIL_IF(!ConfNodeIsSequence(node)); + + if (node != NULL) { + ConfNodeFree(node); + } + PASS; +} + +static int ConfSetFromStringTest(void) +{ + ConfNode *n; + + ConfCreateContextBackup(); + ConfInit(); + + FAIL_IF_NOT(ConfSetFromString("stream.midstream=true", 0)); + n = ConfGetNode("stream.midstream"); + FAIL_IF_NULL(n); + FAIL_IF_NULL(n->val); + FAIL_IF(strcmp("true", n->val)); + + FAIL_IF_NOT(ConfSetFromString("stream.midstream =false", 0)); + n = ConfGetNode("stream.midstream"); + FAIL_IF_NULL(n); + FAIL_IF(n->val == NULL || strcmp("false", n->val)); + + FAIL_IF_NOT(ConfSetFromString("stream.midstream= true", 0)); + n = ConfGetNode("stream.midstream"); + FAIL_IF_NULL(n); + FAIL_IF(n->val == NULL || strcmp("true", n->val)); + + FAIL_IF_NOT(ConfSetFromString("stream.midstream = false", 0)); + n = ConfGetNode("stream.midstream"); + FAIL_IF_NULL(n); + FAIL_IF(n->val == NULL || strcmp("false", n->val)); + + ConfDeInit(); + ConfRestoreContextBackup(); + PASS; } -void -ConfRegisterTests(void) +void ConfRegisterTests(void) { - UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); - UtRegisterTest("ConfSetTest", ConfSetTest, 1); - UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet, 1); - UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1, 1); - UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2, 1); - UtRegisterTest("ConfTestGetInt", ConfTestGetInt, 1); - UtRegisterTest("ConfTestGetBool", ConfTestGetBool, 1); - UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest, 1); - UtRegisterTest("ConfNodeLookupChildValueTest", ConfNodeLookupChildValueTest, 1); - UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest, 1); - UtRegisterTest("ConfGetChildValueWithDefaultTest", ConfGetChildValueWithDefaultTest, 1); - UtRegisterTest("ConfGetChildValueIntWithDefaultTest", ConfGetChildValueIntWithDefaultTest, 1); - UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", ConfGetChildValueBoolWithDefaultTest, 1); - UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest, 1); - UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest, 1); + UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant); + UtRegisterTest("ConfSetTest", ConfSetTest); + UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet); + UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1); + UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2); + UtRegisterTest("ConfTestGetInt", ConfTestGetInt); + UtRegisterTest("ConfTestGetBool", ConfTestGetBool); + UtRegisterTest("ConfNodeLookupChildTest", ConfNodeLookupChildTest); + UtRegisterTest("ConfNodeLookupChildValueTest", + ConfNodeLookupChildValueTest); + UtRegisterTest("ConfNodeRemoveTest", ConfNodeRemoveTest); + UtRegisterTest("ConfGetChildValueWithDefaultTest", + ConfGetChildValueWithDefaultTest); + UtRegisterTest("ConfGetChildValueIntWithDefaultTest", + ConfGetChildValueIntWithDefaultTest); + UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", + ConfGetChildValueBoolWithDefaultTest); + UtRegisterTest("ConfGetNodeOrCreateTest", ConfGetNodeOrCreateTest); + UtRegisterTest("ConfNodePruneTest", ConfNodePruneTest); + UtRegisterTest("ConfNodeIsSequenceTest", ConfNodeIsSequenceTest); + UtRegisterTest("ConfSetFromStringTest", ConfSetFromStringTest); } #endif /* UNITTESTS */ diff --git a/src/conf.h b/src/conf.h index c819eb049361..2318580a6504 100644 --- a/src/conf.h +++ b/src/conf.h @@ -56,36 +56,38 @@ typedef struct ConfNode_ { void ConfInit(void); void ConfDeInit(void); ConfNode *ConfGetRootNode(void); -int ConfGet(char *name, char **vptr); -int ConfGetInt(char *name, intmax_t *val); -int ConfGetBool(char *name, int *val); -int ConfGetDouble(char *name, double *val); -int ConfGetFloat(char *name, float *val); -int ConfSet(char *name, char *val); -int ConfSetFinal(char *name, char *val); +int ConfGet(const char *name, char **vptr); +int ConfGetInt(const char *name, intmax_t *val); +int ConfGetBool(const char *name, int *val); +int ConfGetDouble(const char *name, double *val); +int ConfGetFloat(const char *name, float *val); +int ConfSet(const char *name, char *val); +int ConfSetFromString(const char *input, int final); +int ConfSetFinal(const char *name, char *val); void ConfDump(void); -void ConfNodeDump(ConfNode *node, const char *prefix); +void ConfNodeDump(const ConfNode *node, const char *prefix); ConfNode *ConfNodeNew(void); void ConfNodeFree(ConfNode *); -ConfNode *ConfGetNode(char *key); +ConfNode *ConfGetNode(const char *key); void ConfCreateContextBackup(void); void ConfRestoreContextBackup(void); -ConfNode *ConfNodeLookupChild(ConfNode *node, const char *key); -const char *ConfNodeLookupChildValue(ConfNode *node, const char *key); +ConfNode *ConfNodeLookupChild(const ConfNode *node, const char *key); +const char *ConfNodeLookupChildValue(const ConfNode *node, const char *key); void ConfNodeRemove(ConfNode *); void ConfRegisterTests(); -int ConfNodeChildValueIsTrue(ConfNode *node, const char *key); +int ConfNodeChildValueIsTrue(const ConfNode *node, const char *key); int ConfValIsTrue(const char *val); int ConfValIsFalse(const char *val); void ConfNodePrune(ConfNode *node); -ConfNode *ConfNodeLookupKeyValue(ConfNode *base, const char *key, const char *value); -int ConfGetChildValue(ConfNode *base, char *name, char **vptr); -int ConfGetChildValueInt(ConfNode *base, char *name, intmax_t *val); -int ConfGetChildValueBool(ConfNode *base, char *name, int *val); -int ConfGetChildValueWithDefault(ConfNode *base, ConfNode *dflt, char *name, char **vptr); -int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, intmax_t *val); -int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val); -char *ConfLoadCompleteIncludePath(char *); +ConfNode *ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value); +int ConfGetChildValue(const ConfNode *base, const char *name, char **vptr); +int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val); +int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val); +int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, char **vptr); +int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val); +int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val); +char *ConfLoadCompleteIncludePath(const char *); +int ConfNodeIsSequence(const ConfNode *node); #endif /* ! __CONF_H__ */ diff --git a/src/counters.c b/src/counters.c index 9aae1fe52d9e..494f3a8f300b 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2015 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -19,8 +19,9 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien * - * Performance counters + * Engine stats API */ #include "suricata-common.h" @@ -35,22 +36,95 @@ #include "util-privs.h" #include "util-signal.h" #include "unix-manager.h" +#include "runmodes.h" + #include "output.h" +#include "output-stats.h" +#include "output-json-stats.h" + +/* Time interval for syncing the local counters with the global ones */ +#define STATS_WUT_TTS 3 + +/* Time interval at which the mgmt thread o/p the stats */ +#define STATS_MGMTT_TTS 8 + +/** + * \brief Different kinds of qualifier that can be used to modify the behaviour + * of the counter to be registered + */ +enum { + STATS_TYPE_NORMAL = 1, + STATS_TYPE_AVERAGE = 2, + STATS_TYPE_MAXIMUM = 3, + STATS_TYPE_FUNC = 4, + + STATS_TYPE_MAX = 5, +}; + +/** + * \brief per thread store of counters + */ +typedef struct StatsThreadStore_ { + /** thread name used in output */ + const char *name; + + StatsPublicThreadContext *ctx; -/** \todo Get the default log directory from some global resource. */ -#define SC_PERF_DEFAULT_LOG_FILENAME "stats.log" + StatsPublicThreadContext **head; + uint32_t size; -/* Used to parse the interval for Timebased counters */ -#define SC_PERF_PCRE_TIMEBASED_INTERVAL "^(?:(\\d+)([shm]))(?:(\\d+)([shm]))?(?:(\\d+)([shm]))?$" + struct StatsThreadStore_ *next; +} StatsThreadStore; -static SCPerfOPIfaceContext *sc_perf_op_ctx = NULL; -static time_t sc_start_time; +/** + * \brief Holds the output interface context for the counter api + */ +typedef struct StatsGlobalContext_ { + /** list of thread stores: one per thread plus one global */ + StatsThreadStore *sts; + SCMutex sts_lock; + int sts_cnt; + + HashTable *counters_id_hash; + + StatsPublicThreadContext global_counter_ctx; +} StatsGlobalContext; + +static void *stats_thread_data = NULL; +static StatsGlobalContext *stats_ctx = NULL; +static time_t stats_start_time; /** refresh interval in seconds */ -static uint32_t sc_counter_tts = SC_PERF_MGMTT_TTS; +static uint32_t stats_tts = STATS_MGMTT_TTS; /** is the stats counter enabled? */ -static char sc_counter_enabled = TRUE; -/** append or overwrite? 1: append, 0: overwrite */ -static char sc_counter_append = TRUE; +static char stats_enabled = TRUE; + +static int StatsOutput(ThreadVars *tv); +static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *); +void StatsReleaseCounters(StatsCounter *head); + +/** stats table is filled each interval and passed to the + * loggers. Initialized at first use. */ +static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}}; +static SCMutex stats_table_mutex = SCMUTEX_INITIALIZER; +static int stats_loggers_active = 1; + +static uint16_t counters_global_id = 0; + +static void StatsPublicThreadContextInit(StatsPublicThreadContext *t) +{ + SCMutexInit(&t->m, NULL); +} + +static void StatsPublicThreadContextCleanup(StatsPublicThreadContext *t) +{ + SCMutexLock(&t->m); + StatsReleaseCounters(t->head); + t->head = NULL; + t->perf_flag = 0; + t->curr_id = 0; + SCMutexUnlock(&t->m); + SCMutexDestroy(&t->m); +} /** * \brief Adds a value of type uint64_t to the local counter. @@ -59,17 +133,18 @@ static char sc_counter_append = TRUE; * \param pca Counter array that holds the local counter for this TM * \param x Value to add to this local counter */ -void SCPerfCounterAddUI64(uint16_t id, SCPerfCounterArray *pca, uint64_t x) +void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x) { - if (!pca) { - SCLogDebug("counterarray is NULL"); + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; +#ifdef UNITTESTS + if (pca->initialized == 0) return; - } +#endif #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - pca->head[id].ui64_cnt += x; - pca->head[id].syncs++; + pca->head[id].value += x; + pca->head[id].updates++; return; } @@ -79,19 +154,18 @@ void SCPerfCounterAddUI64(uint16_t id, SCPerfCounterArray *pca, uint64_t x) * \param id Index of the counter in the counter array * \param pca Counter array that holds the local counters for this TM */ -void SCPerfCounterIncr(uint16_t id, SCPerfCounterArray *pca) +void StatsIncr(ThreadVars *tv, uint16_t id) { - if (pca == NULL) { - SCLogDebug("counterarray is NULL"); + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; +#ifdef UNITTESTS + if (pca->initialized == 0) return; - } - +#endif #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - - pca->head[id].ui64_cnt++; - pca->head[id].syncs++; + pca->head[id].value++; + pca->head[id].updates++; return; } @@ -99,171 +173,90 @@ void SCPerfCounterIncr(uint16_t id, SCPerfCounterArray *pca) * \brief Sets a value of type double to the local counter * * \param id Index of the local counter in the counter array - * \param pca Pointer to the SCPerfCounterArray + * \param pca Pointer to the StatsPrivateThreadContext * \param x The value to set for the counter */ -void SCPerfCounterSetUI64(uint16_t id, SCPerfCounterArray *pca, - uint64_t x) +void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x) { - if (!pca) { - SCLogDebug("counterarray is NULL"); + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; +#ifdef UNITTESTS + if (pca->initialized == 0) return; - } - +#endif #ifdef DEBUG BUG_ON ((id < 1) || (id > pca->size)); #endif - if ((pca->head[id].pc->type == SC_PERF_TYPE_Q_MAXIMUM) && - (x > pca->head[id].ui64_cnt)) { - pca->head[id].ui64_cnt = x; - } else if (pca->head[id].pc->type == SC_PERF_TYPE_Q_NORMAL) { - pca->head[id].ui64_cnt = x; + if ((pca->head[id].pc->type == STATS_TYPE_MAXIMUM) && + (x > pca->head[id].value)) { + pca->head[id].value = x; + } else if (pca->head[id].pc->type == STATS_TYPE_NORMAL) { + pca->head[id].value = x; } - pca->head[id].syncs++; + pca->head[id].updates++; return; } -/** - * \brief Get the filename with path to the stats log file. - * - * This function returns a string containing the log filename. It uses - * allocated memory simply to drop into the existing code a little better - * where a SCStrdup was used. So as before, it is up to the caller to free - * the memory. - * - * \retval An allocated string containing the log filename on success or NULL on - * failure. - */ -static char *SCPerfGetLogFilename(ConfNode *stats) -{ - char *log_dir = NULL; - char *log_filename = NULL; - const char* filename = NULL; - - log_dir = ConfigGetLogDirectory(); - - if ( (log_filename = SCMalloc(PATH_MAX)) == NULL) { - return NULL; - } +static ConfNode *GetConfig(void) { + ConfNode *stats = ConfGetNode("stats"); + if (stats != NULL) + return stats; - if (stats != NULL) { - filename = ConfNodeLookupChildValue(stats, "filename"); - if (filename == NULL) { - filename = SC_PERF_DEFAULT_LOG_FILENAME; + ConfNode *root = ConfGetNode("outputs"); + ConfNode *node = NULL; + if (root != NULL) { + TAILQ_FOREACH(node, &root->head, next) { + if (strcmp(node->val, "stats") == 0) { + return node->head.tqh_first; + } } - } else { - filename = SC_PERF_DEFAULT_LOG_FILENAME; - } - - if (snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, - filename) < 0) { - SCLogError(SC_ERR_SPRINTF, "Sprintf Error"); - SCFree(log_filename); - return NULL; - } - - return log_filename; -} - -/** - * \brief Reopen the log file. - * - * \retval 1 if successful, otherwise 0. - */ -static int SCPerfFileReopen(SCPerfOPIfaceContext *sc_perf_op_ctx) -{ - fclose(sc_perf_op_ctx->fp); - if ((sc_perf_op_ctx->fp = fopen(sc_perf_op_ctx->file, "w+")) == NULL) { - SCLogError(SC_ERR_FOPEN, "Failed to reopen file \"%s\"." - "Stats logging will now be disabled.", - sc_perf_op_ctx->file); - return 0; } - return 1; + return NULL; } /** - * \brief Initializes the output interface context - * - * \todo Support multiple interfaces + * \brief Initializes stats context */ -static void SCPerfInitOPCtx(void) +static void StatsInitCtx(void) { SCEnter(); - - ConfNode *root = ConfGetNode("outputs"); - ConfNode *node = NULL; - ConfNode *stats = NULL; - if (root != NULL) { - TAILQ_FOREACH(node, &root->head, next) { - if (strncmp(node->val, "stats", 5) == 0) { - stats = node->head.tqh_first; - } - } - } - /* Check if the stats module is enabled or not */ +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + stats_enabled = FALSE; + SCReturn; +#endif + ConfNode *stats = GetConfig(); if (stats != NULL) { const char *enabled = ConfNodeLookupChildValue(stats, "enabled"); if (enabled != NULL && ConfValIsFalse(enabled)) { - sc_counter_enabled = FALSE; + stats_enabled = FALSE; SCLogDebug("Stats module has been disabled"); SCReturn; } const char *interval = ConfNodeLookupChildValue(stats, "interval"); if (interval != NULL) - sc_counter_tts = (uint32_t) atoi(interval); - - const char *append = ConfNodeLookupChildValue(stats, "append"); - if (append != NULL) - sc_counter_append = ConfValIsTrue(append); - } - - /* Store the engine start time */ - time(&sc_start_time); - - if ( (sc_perf_op_ctx = SCMalloc(sizeof(SCPerfOPIfaceContext))) == NULL) { - SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCPerfInitOPCtx. Exiting..."); - exit(EXIT_FAILURE); + stats_tts = (uint32_t) atoi(interval); } - memset(sc_perf_op_ctx, 0, sizeof(SCPerfOPIfaceContext)); - sc_perf_op_ctx->iface = SC_PERF_IFACE_FILE; + if (!OutputStatsLoggersRegistered()) { + stats_loggers_active = 0; - if ( (sc_perf_op_ctx->file = SCPerfGetLogFilename(stats)) == NULL) { - SCLogInfo("Error retrieving Perf Counter API output file path"); - } - - char *mode; - if (sc_counter_append) - mode = "a+"; - else - mode = "w+"; - - if ( (sc_perf_op_ctx->fp = fopen(sc_perf_op_ctx->file, mode)) == NULL) { - SCLogError(SC_ERR_FOPEN, "fopen error opening file \"%s\". Resorting " - "to using the standard output for output", - sc_perf_op_ctx->file); - - SCFree(sc_perf_op_ctx->file); - - /* Let us use the standard output for output */ - sc_perf_op_ctx->fp = stdout; - if ( (sc_perf_op_ctx->file = SCStrdup("stdout")) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + /* if the unix command socket is enabled we do the background + * stats sync just in case someone runs 'dump-counters' */ + if (!ConfUnixSocketIsEnable()) { + SCLogWarning(SC_WARN_NO_STATS_LOGGERS, "stats are enabled but no loggers are active"); + stats_enabled = FALSE; + SCReturn; } } - else { - /* File opened, register for rotation notification. */ - OutputRegisterFileRotationFlag(&sc_perf_op_ctx->rotation_flag); - } - /* init the lock used by SCPerfClubTMInst */ - if (SCMutexInit(&sc_perf_op_ctx->pctmi_lock, NULL) != 0) { - SCLogError(SC_ERR_INITIALIZATION, "error initializing pctmi mutex"); + /* Store the engine start time */ + time(&stats_start_time); + + /* init the lock used by StatsThreadStore */ + if (SCMutexInit(&stats_ctx->sts_lock, NULL) != 0) { + SCLogError(SC_ERR_INITIALIZATION, "error initializing sts mutex"); exit(EXIT_FAILURE); } @@ -271,55 +264,64 @@ static void SCPerfInitOPCtx(void) } /** - * \brief Releases the resources alloted to the output context of the Perf - * Counter API + * \brief Releases the resources alloted to the output context of the + * Stats API */ -static void SCPerfReleaseOPCtx() +static void StatsReleaseCtx() { - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return; } - SCPerfClubTMInst *pctmi = NULL; - SCPerfClubTMInst *temp = NULL; - pctmi = sc_perf_op_ctx->pctmi; - - OutputUnregisterFileRotationFlag(&sc_perf_op_ctx->rotation_flag); + StatsThreadStore *sts = NULL; + StatsThreadStore *temp = NULL; + sts = stats_ctx->sts; - if (sc_perf_op_ctx->fp != NULL) - fclose(sc_perf_op_ctx->fp); + while (sts != NULL) { + if (sts->head != NULL) + SCFree(sts->head); - if (sc_perf_op_ctx->file != NULL) - SCFree(sc_perf_op_ctx->file); + temp = sts->next; + SCFree(sts); + sts = temp; + } - while (pctmi != NULL) { - if (pctmi->tm_name != NULL) - SCFree(pctmi->tm_name); + if (stats_ctx->counters_id_hash != NULL) { + HashTableFree(stats_ctx->counters_id_hash); + stats_ctx->counters_id_hash = NULL; + counters_global_id = 0; + } - if (pctmi->head != NULL) - SCFree(pctmi->head); + StatsPublicThreadContextCleanup(&stats_ctx->global_counter_ctx); + SCFree(stats_ctx); + stats_ctx = NULL; - temp = pctmi->next; - SCFree(pctmi); - pctmi = temp; + SCMutexLock(&stats_table_mutex); + /* free stats table */ + if (stats_table.tstats != NULL) { + SCFree(stats_table.tstats); + stats_table.tstats = NULL; } - SCFree(sc_perf_op_ctx); - sc_perf_op_ctx = NULL; + if (stats_table.stats != NULL) { + SCFree(stats_table.stats); + stats_table.stats = NULL; + } + memset(&stats_table, 0, sizeof(stats_table)); + SCMutexUnlock(&stats_table_mutex); return; } /** - * \brief The management thread. This thread is responsible for writing the - * performance stats information. + * \brief management thread. This thread is responsible for writing the stats * - * \param arg is NULL always + * \param arg thread var * * \retval NULL This is the value that is always returned */ -static void *SCPerfMgmtThread(void *arg) +static void *StatsMgmtThread(void *arg) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); @@ -340,15 +342,25 @@ static void *SCPerfMgmtThread(void *arg) tv_local->cap_flags = 0; SCDropCaps(tv_local); - PacketPoolInit(); - if (sc_perf_op_ctx == NULL) { - SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" - "SCPerfInitCounterApi() has to be called first"); + if (stats_ctx == NULL) { + SCLogError(SC_ERR_STATS_NOT_INIT, "Stats API not init" + "StatsInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; } + TmModule *tm = &tmm_modules[TMM_STATSLOGGER]; + BUG_ON(tm->ThreadInit == NULL); + int r = tm->ThreadInit(tv_local, NULL, &stats_thread_data); + if (r != 0 || stats_thread_data == NULL) { + SCLogError(SC_ERR_THREAD_INIT, "Stats API " + "ThreadInit failed"); + TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); + return NULL; + } + SCLogDebug("stats_thread_data %p", &stats_thread_data); + TmThreadsSetFlag(tv_local, THV_INIT_DONE); while (run) { if (TmThreadsCheckFlag(tv_local, THV_PAUSE)) { @@ -357,14 +369,18 @@ static void *SCPerfMgmtThread(void *arg) TmThreadsUnsetFlag(tv_local, THV_PAUSED); } - cond_time.tv_sec = time(NULL) + sc_counter_tts; + cond_time.tv_sec = time(NULL) + stats_tts; cond_time.tv_nsec = 0; + /* wait for the set time, or until we are woken up by + * the shutdown procedure */ SCCtrlMutexLock(tv_local->ctrl_mutex); SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); - SCPerfOutputCounters(); + SCMutexLock(&stats_table_mutex); + StatsOutput(tv_local); + SCMutexUnlock(&stats_table_mutex); if (TmThreadsCheckFlag(tv_local, THV_KILL)) { run = 0; @@ -374,19 +390,25 @@ static void *SCPerfMgmtThread(void *arg) TmThreadsSetFlag(tv_local, THV_RUNNING_DONE); TmThreadWaitForFlag(tv_local, THV_DEINIT); + r = tm->ThreadDeinit(tv_local, stats_thread_data); + if (r != TM_ECODE_OK) { + SCLogError(SC_ERR_THREAD_DEINIT, "Stats Counter API " + "ThreadDeinit failed"); + } + TmThreadsSetFlag(tv_local, THV_CLOSED); return NULL; } /** * \brief Wake up thread. This thread wakes up every TTS(time to sleep) seconds - * and sets the flag for every ThreadVars' SCPerfContext + * and sets the flag for every ThreadVars' StatsPublicThreadContext * * \param arg is NULL always * * \retval NULL This is the value that is always returned */ -static void *SCPerfWakeupThread(void *arg) +static void *StatsWakeupThread(void *arg) { /* block usr2. usr2 to be handled by the main thread only */ UtilSignalBlock(SIGUSR2); @@ -409,11 +431,10 @@ static void *SCPerfWakeupThread(void *arg) tv_local->cap_flags = 0; SCDropCaps(tv_local); - PacketPoolInit(); - if (sc_perf_op_ctx == NULL) { - SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" - "SCPerfInitCounterApi() has to be called first"); + if (stats_ctx == NULL) { + SCLogError(SC_ERR_STATS_NOT_INIT, "Stats API not init" + "StatsInitCounterApi() has to be called first"); TmThreadsSetFlag(tv_local, THV_CLOSED | THV_RUNNING_DONE); return NULL; } @@ -426,23 +447,25 @@ static void *SCPerfWakeupThread(void *arg) TmThreadsUnsetFlag(tv_local, THV_PAUSED); } - cond_time.tv_sec = time(NULL) + SC_PERF_WUT_TTS; + cond_time.tv_sec = time(NULL) + STATS_WUT_TTS; cond_time.tv_nsec = 0; + /* wait for the set time, or until we are woken up by + * the shutdown procedure */ SCCtrlMutexLock(tv_local->ctrl_mutex); SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); SCCtrlMutexUnlock(tv_local->ctrl_mutex); tv = tv_root[TVT_PPT]; while (tv != NULL) { - if (tv->sc_perf_pctx.head == NULL) { + if (tv->perf_public_ctx.head == NULL) { tv = tv->next; continue; } /* assuming the assignment of an int to be atomic, and even if it's * not, it should be okay */ - tv->sc_perf_pctx.perf_flag = 1; + tv->perf_public_ctx.perf_flag = 1; if (tv->inq != NULL) { q = &trans_q[tv->inq->id]; @@ -455,14 +478,14 @@ static void *SCPerfWakeupThread(void *arg) /* mgt threads for flow manager */ tv = tv_root[TVT_MGMT]; while (tv != NULL) { - if (tv->sc_perf_pctx.head == NULL) { + if (tv->perf_public_ctx.head == NULL) { tv = tv->next; continue; } /* assuming the assignment of an int to be atomic, and even if it's * not, it should be okay */ - tv->sc_perf_pctx.perf_flag = 1; + tv->perf_public_ctx.perf_flag = 1; tv = tv->next; } @@ -480,23 +503,13 @@ static void *SCPerfWakeupThread(void *arg) } /** - * \brief Releases a perf counter. Used internally by - * SCPerfReleasePerfCounterS() + * \brief Releases a counter * - * \param pc Pointer to the SCPerfCounter to be freed + * \param pc Pointer to the StatsCounter to be freed */ -static void SCPerfReleaseCounter(SCPerfCounter *pc) +static void StatsReleaseCounter(StatsCounter *pc) { if (pc != NULL) { - if (pc->cname != NULL) - SCFree(pc->cname); - - if (pc->tm_name != NULL) - SCFree(pc->tm_name); - - if (pc->desc != NULL) - SCFree(pc->desc); - SCFree(pc); } @@ -504,36 +517,28 @@ static void SCPerfReleaseCounter(SCPerfCounter *pc) } /** - * \brief Registers a counter. Used internally by the Perf Counter API + * \brief Registers a counter. * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tm_name Thread module to which this counter belongs - * \param type Datatype of this counter variable - * \param desc Description of this counter - * \param pctx SCPerfContext for this tm-tv instance + * \param pctx StatsPublicThreadContext for this tm-tv instance * \param type_q Qualifier describing the type of counter to be registered * * \retval the counter id for the newly registered counter, or the already * present counter on success * \retval 0 on failure */ -static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, - int type, char *desc, - SCPerfContext *pctx, int type_q) +static uint16_t StatsRegisterQualifiedCounter(char *name, char *tm_name, + StatsPublicThreadContext *pctx, + int type_q, uint64_t (*Func)(void)) { - SCPerfCounter **head = &pctx->head; - SCPerfCounter *temp = NULL; - SCPerfCounter *prev = NULL; - SCPerfCounter *pc = NULL; + StatsCounter **head = &pctx->head; + StatsCounter *temp = NULL; + StatsCounter *prev = NULL; + StatsCounter *pc = NULL; - if (cname == NULL || tm_name == NULL || pctx == NULL) { - SCLogDebug("Counter name, tm name null or SCPerfContext NULL"); - return 0; - } - - if ((type >= SC_PERF_TYPE_MAX) || (type < 0)) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "Counters of type %" PRId32 " can't " - "be registered", type); + if (name == NULL || pctx == NULL) { + SCLogDebug("Counter name, StatsPublicThreadContext NULL"); return 0; } @@ -541,8 +546,7 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, while (temp != NULL) { prev = temp; - if (strcmp(cname, temp->cname) == 0 && - strcmp(tm_name, temp->tm_name) == 0) { + if (strcmp(name, temp->name) == 0) { break; } @@ -553,31 +557,17 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, if (temp != NULL) return(temp->id); - /* if we reach this point we don't have a counter registered by this cname */ - if ( (pc = SCMalloc(sizeof(SCPerfCounter))) == NULL) + /* if we reach this point we don't have a counter registered by this name */ + if ( (pc = SCMalloc(sizeof(StatsCounter))) == NULL) return 0; - memset(pc, 0, sizeof(SCPerfCounter)); - - if ( (pc->cname = SCStrdup(cname)) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - - if ( (pc->tm_name = SCStrdup(tm_name)) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } + memset(pc, 0, sizeof(StatsCounter)); - /* assign a unique id to this SCPerfCounter. The id is local to this - * PerfContext. Please note that the id start from 1, and not 0 */ + /* assign a unique id to this StatsCounter. The id is local to this + * thread context. Please note that the id start from 1, and not 0 */ pc->id = ++(pctx->curr_id); - - if (desc != NULL && (pc->desc = SCStrdup(desc)) == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - + pc->name = name; pc->type = type_q; + pc->Func = Func; /* we now add the counter to the list */ if (prev == NULL) @@ -589,273 +579,261 @@ static uint16_t SCPerfRegisterQualifiedCounter(char *cname, char *tm_name, } /** - * \brief Copies the SCPerfCounter value from the local counter present in the - * SCPerfCounterArray to its corresponding global counterpart. Used - * internally by SCPerfUpdateCounterArray() + * \brief Copies the StatsCounter value from the local counter present in the + * StatsPrivateThreadContext to its corresponding global counterpart. Used + * internally by StatsUpdateCounterArray() * - * \param pcae Pointer to the SCPerfCounterArray which holds the local + * \param pcae Pointer to the StatsPrivateThreadContext which holds the local * versions of the counters */ -static void SCPerfCopyCounterValue(SCPCAElem *pcae) +static void StatsCopyCounterValue(StatsLocalCounter *pcae) { - SCPerfCounter *pc = NULL; - uint64_t ui64_temp = 0; - - pc = pcae->pc; - ui64_temp = pcae->ui64_cnt; - - if (pc->type == SC_PERF_TYPE_Q_AVERAGE) { - if (pcae->syncs != 0) - ui64_temp /= pcae->syncs; - pc->value = ui64_temp; - } else { - pc->value = ui64_temp; - } + StatsCounter *pc = pcae->pc; + pc->value = pcae->value; + pc->updates = pcae->updates; return; } /** - * \brief Calculates counter value that should be sent as output - * - * If we aren't dealing with timebased counters, we just return the - * the counter value. In case of Timebased counters, if we haven't - * crossed the interval, we display the current value without any - * modifications. If we have crossed the limit, we calculate the counter - * value for the time period and also return 1, to indicate that the - * counter value can be reset after use - * - * \param pc Pointer to the PerfCounter for which the timebased counter has to - * be calculated - */ -static uint64_t SCPerfOutputCalculateCounterValue(SCPerfCounter *pc) -{ - return pc->value; -} - -/** - * \brief The file output interface for the Perf Counter api + * \brief The output interface for the Stats API */ -static int SCPerfOutputCounterFileIface() +static int StatsOutput(ThreadVars *tv) { - SCPerfClubTMInst *pctmi = NULL; - SCPerfCounter *pc = NULL; - SCPerfCounter **pc_heads = NULL; + const StatsThreadStore *sts = NULL; + const StatsCounter *pc = NULL; + void *td = stats_thread_data; - uint64_t ui64_temp = 0; - uint64_t ui64_result = 0; + if (counters_global_id == 0) + return -1; - struct timeval tval; - struct tm *tms; + if (stats_table.nstats == 0) { + StatsThreadRegister("Global", &stats_ctx->global_counter_ctx); - uint32_t u = 0; - int flag = 0; + uint32_t nstats = counters_global_id; - if (sc_perf_op_ctx->fp == NULL) { - SCLogDebug("perf_op_ctx->fp is NULL"); - return 0; - } - - if (sc_perf_op_ctx->rotation_flag) { - SCLogDebug("Rotating log file"); - sc_perf_op_ctx->rotation_flag = 0; - if (!SCPerfFileReopen(sc_perf_op_ctx)) { - /* Rotation failed, error already logged. */ - return 0; + stats_table.nstats = nstats; + stats_table.stats = SCCalloc(stats_table.nstats, sizeof(StatsRecord)); + if (stats_table.stats == NULL) { + stats_table.nstats = 0; + SCLogError(SC_ERR_MEM_ALLOC, "could not alloc memory for stats"); + return -1; } - } - memset(&tval, 0, sizeof(struct timeval)); - - gettimeofday(&tval, NULL); - struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); - - /* Calculate the Engine uptime */ - int up_time = (int)difftime(tval.tv_sec, sc_start_time); - int sec = up_time % 60; // Seconds in a minute - int in_min = up_time / 60; - int min = in_min % 60; // Minutes in a hour - int in_hours = in_min / 60; - int hours = in_hours % 24; // Hours in a day - int days = in_hours / 24; - - fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" - "---------------------\n"); - fprintf(sc_perf_op_ctx->fp, "Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", - tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, - tms->tm_min, tms->tm_sec, days, hours, min, sec); - fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" - "---------------------\n"); - fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %-s\n", "Counter", "TM Name", - "Value"); - fprintf(sc_perf_op_ctx->fp, "----------------------------------------------" - "---------------------\n"); - - pctmi = sc_perf_op_ctx->pctmi; - while (pctmi != NULL) { - if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) - return 0; - memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); - - for (u = 0; u < pctmi->size; u++) { - pc_heads[u] = pctmi->head[u]->head; - SCMutexLock(&pctmi->head[u]->m); + stats_table.ntstats = stats_ctx->sts_cnt; + uint32_t array_size = stats_table.nstats * sizeof(StatsRecord); + stats_table.tstats = SCCalloc(stats_table.ntstats, array_size); + if (stats_table.tstats == NULL) { + stats_table.ntstats = 0; + SCLogError(SC_ERR_MEM_ALLOC, "could not alloc memory for stats"); + return -1; } - flag = 1; - while (flag) { - ui64_result = 0; - if (pc_heads[0] == NULL) - break; - /* keep ptr to first pc to we can use it to print the cname */ - pc = pc_heads[0]; + stats_table.start_time = stats_start_time; + } - for (u = 0; u < pctmi->size; u++) { - ui64_temp = SCPerfOutputCalculateCounterValue(pc_heads[u]); - ui64_result += ui64_temp; + const uint16_t max_id = counters_global_id; + if (max_id == 0) + return -1; - if (pc_heads[u] != NULL) - pc_heads[u] = pc_heads[u]->next; - if (pc_heads[u] == NULL) - flag = 0; + /** temporary local table to merge the per thread counters, + * especially needed for the average counters */ + struct CountersMergeTable { + int type; + uint64_t value; + uint64_t updates; + } merge_table[max_id]; + memset(&merge_table, 0x00, + max_id * sizeof(struct CountersMergeTable)); + + int thread = stats_ctx->sts_cnt - 1; + StatsRecord *table = stats_table.stats; + + /* Loop through the thread counter stores. The global counters + * are in a separate store inside this list. */ + sts = stats_ctx->sts; + SCLogDebug("sts %p", sts); + while (sts != NULL) { + BUG_ON(thread < 0); + + SCLogDebug("Thread %d %s ctx %p", thread, sts->name, sts->ctx); + + /* temporay table for quickly storing the counters for this + * thread store, so that we can post process them outside + * of the thread store lock */ + struct CountersMergeTable thread_table[max_id]; + memset(&thread_table, 0x00, + max_id * sizeof(struct CountersMergeTable)); + + SCMutexLock(&sts->ctx->m); + pc = sts->ctx->head; + while (pc != NULL) { + SCLogDebug("Counter %s (%u:%u) value %"PRIu64, + pc->name, pc->id, pc->gid, pc->value); + + thread_table[pc->gid].type = pc->type; + switch (pc->type) { + case STATS_TYPE_FUNC: + if (pc->Func != NULL) + thread_table[pc->gid].value = pc->Func(); + break; + case STATS_TYPE_AVERAGE: + default: + thread_table[pc->gid].value = pc->value; + break; } + thread_table[pc->gid].updates = pc->updates; + table[pc->gid].name = pc->name; + + pc = pc->next; + } + SCMutexUnlock(&sts->ctx->m); + + /* update merge table */ + uint16_t c; + for (c = 0; c < max_id; c++) { + struct CountersMergeTable *e = &thread_table[c]; + /* thread only sets type if it has a counter + * of this type. */ + if (e->type == 0) + continue; - fprintf(sc_perf_op_ctx->fp, "%-25s | %-25s | %-" PRIu64 "\n", - pc->cname, pctmi->tm_name, ui64_result); + switch (e->type) { + case STATS_TYPE_MAXIMUM: + if (e->value > merge_table[c].value) + merge_table[c].value = e->value; + break; + case STATS_TYPE_FUNC: + merge_table[c].value = e->value; + break; + case STATS_TYPE_AVERAGE: + default: + merge_table[c].value += e->value; + break; + } + merge_table[c].updates += e->updates; + merge_table[c].type = e->type; } - for (u = 0; u < pctmi->size; u++) - SCMutexUnlock(&pctmi->head[u]->m); + /* update per thread stats table */ + for (c = 0; c < max_id; c++) { + struct CountersMergeTable *e = &thread_table[c]; + /* thread only sets type if it has a counter + * of this type. */ + if (e->type == 0) + continue; - pctmi = pctmi->next; + uint32_t offset = (thread * stats_table.nstats) + c; + StatsRecord *r = &stats_table.tstats[offset]; + /* xfer previous value to pvalue and reset value */ + r->pvalue = r->value; + r->value = 0; + r->name = table[c].name; + r->tm_name = sts->name; + + switch (e->type) { + case STATS_TYPE_AVERAGE: + if (e->value > 0 && e->updates > 0) { + r->value = (uint64_t)(e->value / e->updates); + } + break; + default: + r->value = e->value; + break; + } + } - SCFree(pc_heads); + sts = sts->next; + thread--; + } - fflush(sc_perf_op_ctx->fp); + /* transfer 'merge table' to final stats table */ + uint16_t x; + for (x = 0; x < max_id; x++) { + /* xfer previous value to pvalue and reset value */ + table[x].pvalue = table[x].value; + table[x].value = 0; + table[x].tm_name = "Total"; + + struct CountersMergeTable *m = &merge_table[x]; + switch (m->type) { + case STATS_TYPE_MAXIMUM: + if (m->value > table[x].value) + table[x].value = m->value; + break; + case STATS_TYPE_AVERAGE: + if (m->value > 0 && m->updates > 0) { + table[x].value = (uint64_t)(m->value / m->updates); + } + break; + default: + table[x].value += m->value; + break; + } } + /* invoke logger(s) */ + if (stats_loggers_active) { + OutputStatsLog(tv, td, &stats_table); + } return 1; } #ifdef BUILD_UNIX_SOCKET -/** - * \brief The file output interface for the Perf Counter api +/** \brief callback for getting stats into unix socket */ -TmEcode SCPerfOutputCounterSocket(json_t *cmd, +TmEcode StatsOutputCounterSocket(json_t *cmd, json_t *answer, void *data) { - SCPerfClubTMInst *pctmi = NULL; - SCPerfCounter *pc = NULL; - SCPerfCounter **pc_heads = NULL; - - uint64_t ui64_temp = 0; - uint64_t ui64_result = 0; - - uint32_t u = 0; - int flag = 0; - - if (sc_perf_op_ctx == NULL) { - json_object_set_new(answer, "message", - json_string("No performance counter context")); - return TM_ECODE_FAILED; - } - - json_t *tm_array; - - tm_array = json_object(); - if (tm_array == NULL) { - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - - pctmi = sc_perf_op_ctx->pctmi; - while (pctmi != NULL) { - json_t *jdata; - int filled = 0; - jdata = json_object(); - if (jdata == NULL) { - json_decref(tm_array); - json_object_set_new(answer, "message", - json_string("internal error at json object creation")); - return TM_ECODE_FAILED; - } - if ((pc_heads = SCMalloc(pctmi->size * sizeof(SCPerfCounter *))) == NULL) { - json_decref(tm_array); - json_object_set_new(answer, "message", - json_string("internal memory error")); - return TM_ECODE_FAILED; - } - memset(pc_heads, 0, pctmi->size * sizeof(SCPerfCounter *)); - - for (u = 0; u < pctmi->size; u++) { - pc_heads[u] = pctmi->head[u]->head; - - SCMutexLock(&pctmi->head[u]->m); - } - - flag = 1; - while(flag) { - ui64_result = 0; - if (pc_heads[0] == NULL) - break; - pc = pc_heads[0]; - - for (u = 0; u < pctmi->size; u++) { - ui64_temp = SCPerfOutputCalculateCounterValue(pc_heads[u]); - ui64_result += ui64_temp; - - if (pc_heads[u] != NULL) - pc_heads[u] = pc_heads[u]->next; - if (pc_heads[u] == NULL) - flag = 0; - } - - filled = 1; - json_object_set_new(jdata, pc->cname, json_integer(ui64_result)); - } - - for (u = 0; u < pctmi->size; u++) - SCMutexUnlock(&pctmi->head[u]->m); - - if (filled == 1) { - json_object_set_new(tm_array, pctmi->tm_name, jdata); - } - pctmi = pctmi->next; - - SCFree(pc_heads); + json_t *message = NULL; + TmEcode r = TM_ECODE_OK; + SCMutexLock(&stats_table_mutex); + if (stats_table.start_time == 0) { + r = TM_ECODE_FAILED; + message = json_string("stats not yet synchronized"); + } else { + message = StatsToJSON(&stats_table, JSON_STATS_TOTALS|JSON_STATS_THREADS); } + SCMutexUnlock(&stats_table_mutex); - json_object_set_new(answer, "message", tm_array); - - return TM_ECODE_OK; + json_object_set_new(answer, "message", message); + return r; } - #endif /* BUILD_UNIX_SOCKET */ /** * \brief Initializes the perf counter api. Things are hard coded currently. * More work to be done when we implement multiple interfaces */ -void SCPerfInitCounterApi(void) +void StatsInit(void) { - SCPerfInitOPCtx(); + BUG_ON(stats_ctx != NULL); + if ( (stats_ctx = SCMalloc(sizeof(StatsGlobalContext))) == NULL) { + SCLogError(SC_ERR_FATAL, "Fatal error encountered in StatsInitCtx. Exiting..."); + exit(EXIT_FAILURE); + } + memset(stats_ctx, 0, sizeof(StatsGlobalContext)); - return; + StatsPublicThreadContextInit(&stats_ctx->global_counter_ctx); +} + +void StatsSetupPostConfig(void) +{ + StatsInitCtx(); } /** - * \brief Spawns the wakeup, and the management thread used by the perf - * counter api + * \brief Spawns the wakeup, and the management thread used by the stats api + * + * The threads use the condition variable in the thread vars to control + * their wait loops to make sure the main thread can quickly kill them. */ -void SCPerfSpawnThreads(void) +void StatsSpawnThreads(void) { SCEnter(); - if (!sc_counter_enabled) { + if (!stats_enabled) { SCReturn; } @@ -863,8 +841,8 @@ void SCPerfSpawnThreads(void) ThreadVars *tv_mgmt = NULL; /* spawn the stats wakeup thread */ - tv_wakeup = TmThreadCreateMgmtThread("SCPerfWakeupThread", - SCPerfWakeupThread, 1); + tv_wakeup = TmThreadCreateMgmtThread(thread_name_counter_wakeup, + StatsWakeupThread, 1); if (tv_wakeup == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread " "failed"); @@ -873,13 +851,13 @@ void SCPerfSpawnThreads(void) if (TmThreadSpawn(tv_wakeup) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " - "SCPerfWakeupThread"); + "StatsWakeupThread"); exit(EXIT_FAILURE); } /* spawn the stats mgmt thread */ - tv_mgmt = TmThreadCreateMgmtThread("SCPerfMgmtThread", - SCPerfMgmtThread, 1); + tv_mgmt = TmThreadCreateMgmtThread(thread_name_counter_stats, + StatsMgmtThread, 1); if (tv_mgmt == NULL) { SCLogError(SC_ERR_THREAD_CREATE, "TmThreadCreateMgmtThread failed"); @@ -888,7 +866,7 @@ void SCPerfSpawnThreads(void) if (TmThreadSpawn(tv_mgmt) != 0) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " - "SCPerfWakeupThread"); + "StatsWakeupThread"); exit(EXIT_FAILURE); } @@ -898,23 +876,19 @@ void SCPerfSpawnThreads(void) /** * \brief Registers a normal, unqualified counter * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered - * \param type Datatype of this counter variable - * \param desc Description of this counter * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type, - char *desc) +uint16_t StatsRegisterCounter(char *name, struct ThreadVars_ *tv) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, desc, - &tv->sc_perf_pctx, - SC_PERF_TYPE_Q_NORMAL); + &tv->perf_public_ctx, + STATS_TYPE_NORMAL, NULL); return id; } @@ -923,23 +897,19 @@ uint16_t SCPerfTVRegisterCounter(char *cname, struct ThreadVars_ *tv, int type, * \brief Registers a counter, whose value holds the average of all the values * assigned to it. * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered - * \param type Datatype of this counter variable - * \param desc Description of this counter * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, - int type, char *desc) +uint16_t StatsRegisterAvgCounter(char *name, struct ThreadVars_ *tv) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, desc, - &tv->sc_perf_pctx, - SC_PERF_TYPE_Q_AVERAGE); + &tv->perf_public_ctx, + STATS_TYPE_AVERAGE, NULL); return id; } @@ -948,252 +918,197 @@ uint16_t SCPerfTVRegisterAvgCounter(char *cname, struct ThreadVars_ *tv, * \brief Registers a counter, whose value holds the maximum of all the values * assigned to it. * - * \param cname Name of the counter, to be registered + * \param name Name of the counter, to be registered * \param tv Pointer to the ThreadVars instance for which the counter would * be registered - * \param type Datatype of this counter variable - * \param desc Description of this counter * * \retval the counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfTVRegisterMaxCounter(char *cname, struct ThreadVars_ *tv, - int type, char *desc) +uint16_t StatsRegisterMaxCounter(char *name, struct ThreadVars_ *tv) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, + uint16_t id = StatsRegisterQualifiedCounter(name, (tv->thread_group_name != NULL) ? tv->thread_group_name : tv->name, - type, desc, - &tv->sc_perf_pctx, - SC_PERF_TYPE_Q_MAXIMUM); + &tv->perf_public_ctx, + STATS_TYPE_MAXIMUM, NULL); return id; } /** - * \brief Registers a normal, unqualified counter + * \brief Registers a counter, which represents a global value * - * \param cname Name of the counter, to be registered - * \param tm_name Name of the engine module under which the counter has to be - * registered - * \param type Datatype of this counter variable - * \param desc Description of this counter - * \param pctx SCPerfContext corresponding to the tm_name key under which the - * key has to be registered + * \param name Name of the counter, to be registered + * \param Func Function Pointer returning a uint64_t * * \retval id Counter id for the newly registered counter, or the already * present counter */ -uint16_t SCPerfRegisterCounter(char *cname, char *tm_name, int type, char *desc, - SCPerfContext *pctx) +uint16_t StatsRegisterGlobalCounter(char *name, uint64_t (*Func)(void)) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, - pctx, SC_PERF_TYPE_Q_NORMAL); - +#ifdef UNITTESTS + if (stats_ctx == NULL) + return 0; +#else + BUG_ON(stats_ctx == NULL); +#endif + uint16_t id = StatsRegisterQualifiedCounter(name, NULL, + &(stats_ctx->global_counter_ctx), + STATS_TYPE_FUNC, + Func); return id; } -/** - * \brief Registers a counter, whose value holds the average of all the values - * assigned to it. - * - * \param cname Name of the counter, to be registered - * \param tm_name Name of the engine module under which the counter has to be - * registered - * \param type Datatype of this counter variable - * \param desc Description of this counter - * \param pctx SCPerfContext corresponding to the tm_name key under which the - * key has to be registered - * - * \retval id Counter id for the newly registered counter, or the already - * present counter - */ -uint16_t SCPerfRegisterAvgCounter(char *cname, char *tm_name, int type, - char *desc, SCPerfContext *pctx) +typedef struct CountersIdType_ { + uint16_t id; + const char *string; +} CountersIdType; + +uint32_t CountersIdHashFunc(HashTable *ht, void *data, uint16_t datalen) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, - pctx, SC_PERF_TYPE_Q_AVERAGE); + CountersIdType *t = (CountersIdType *)data; + uint32_t hash = 0; + int i = 0; - return id; + int len = strlen(t->string); + + for (i = 0; i < len; i++) + hash += tolower((unsigned char)t->string[i]); + + hash = hash % ht->array_size; + + return hash; } -/** - * \brief Registers a counter, whose value holds the maximum of all the values - * assigned to it. - * - * \param cname Name of the counter, to be registered - * \param tm_name Name of the engine module under which the counter has to be - * registered - * \param type Datatype of this counter variable - * \param desc Description of this counter - * \param pctx SCPerfContext corresponding to the tm_name key under which the - * key has to be registered - * - * \retval id Counter id for the newly registered counter, or the already - * present counter - */ -uint16_t SCPerfRegisterMaxCounter(char *cname, char *tm_name, int type, - char *desc, SCPerfContext *pctx) +char CountersIdHashCompareFunc(void *data1, uint16_t datalen1, + void *data2, uint16_t datalen2) { - uint16_t id = SCPerfRegisterQualifiedCounter(cname, tm_name, type, desc, - pctx, SC_PERF_TYPE_Q_MAXIMUM); + CountersIdType *t1 = (CountersIdType *)data1; + CountersIdType *t2 = (CountersIdType *)data2; + int len1 = 0; + int len2 = 0; - return id; + if (t1 == NULL || t2 == NULL) + return 0; + + if (t1->string == NULL || t2->string == NULL) + return 0; + + len1 = strlen(t1->string); + len2 = strlen(t2->string); + + if (len1 == len2 && memcmp(t1->string, t2->string, len1) == 0) { + return 1; + } + + return 0; } -/** - * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM - * are stacked together in a PCTMI container. +void CountersIdHashFreeFunc(void *data) +{ + SCFree(data); +} + + +/** \internal + * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM + * are stacked together in a PCTMI container. * - * \param tm_name Name of the tm to be added to the table - * \param pctx SCPerfContext associated with the TM tm_name + * \param tm_name Name of the tm to be added to the table + * \param pctx StatsPublicThreadContext associated with the TM tm_name * - * \retval 1 on success, 0 on failure + * \retval 1 on success, 0 on failure */ -int SCPerfAddToClubbedTMTable(char *tm_name, SCPerfContext *pctx) +static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *pctx) { - void *ptmp; - if (sc_perf_op_ctx == NULL) { + if (stats_ctx == NULL) { SCLogDebug("Counter module has been disabled"); return 0; } - SCPerfClubTMInst *pctmi = NULL; - SCPerfClubTMInst *prev = NULL; - SCPerfClubTMInst *temp = NULL; - SCPerfContext **hpctx = NULL; - uint32_t u = 0; + StatsThreadStore *temp = NULL; - if (tm_name == NULL || pctx == NULL) { - SCLogDebug("supplied argument(s) to SCPerfAddToClubbedTMTable NULL"); + if (thread_name == NULL || pctx == NULL) { + SCLogDebug("supplied argument(s) to StatsThreadRegister NULL"); return 0; } - SCMutexLock(&sc_perf_op_ctx->pctmi_lock); - - pctmi = sc_perf_op_ctx->pctmi; - SCLogDebug("pctmi %p", pctmi); - prev = pctmi; - - while (pctmi != NULL) { - prev = pctmi; - if (strcmp(tm_name, pctmi->tm_name) != 0) { - pctmi = pctmi->next; - continue; - } - break; + SCMutexLock(&stats_ctx->sts_lock); + if (stats_ctx->counters_id_hash == NULL) { + stats_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc, + CountersIdHashCompareFunc, + CountersIdHashFreeFunc); + BUG_ON(stats_ctx->counters_id_hash == NULL); } - - /* get me the bugger who wrote this junk of a code :P */ - if (pctmi == NULL) { - if ( (temp = SCMalloc(sizeof(SCPerfClubTMInst))) == NULL) { - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; - } - memset(temp, 0, sizeof(SCPerfClubTMInst)); - - temp->size = 1; - temp->head = SCMalloc(sizeof(SCPerfContext **)); - if (temp->head == NULL) { - SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; - } - temp->head[0] = pctx; - temp->tm_name = SCStrdup(tm_name); - if (unlikely(temp->tm_name == NULL)) { - SCFree(temp->head); - SCFree(temp); - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 0; + StatsCounter *pc = pctx->head; + while (pc != NULL) { + CountersIdType t = { 0, pc->name }, *id = NULL; + id = HashTableLookup(stats_ctx->counters_id_hash, &t, sizeof(t)); + if (id == NULL) { + id = SCCalloc(1, sizeof(*id)); + BUG_ON(id == NULL); + id->id = counters_global_id++; + id->string = pc->name; + BUG_ON(HashTableAdd(stats_ctx->counters_id_hash, id, sizeof(*id)) < 0); } - - if (prev == NULL) - sc_perf_op_ctx->pctmi = temp; - else - prev->next = temp; - - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 1; + pc->gid = id->id; + pc = pc->next; } - /* see if the pctx is already part of this pctmi */ - hpctx = pctmi->head; - for (u = 0; u < pctmi->size; u++) { - if (hpctx[u] != pctx) - continue; - - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); - return 1; - } - ptmp = SCRealloc(pctmi->head, - (pctmi->size + 1) * sizeof(SCPerfContext **)); - if (ptmp == NULL) { - SCFree(pctmi->head); - pctmi->head = NULL; - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + if ( (temp = SCMalloc(sizeof(StatsThreadStore))) == NULL) { + SCMutexUnlock(&stats_ctx->sts_lock); return 0; } - pctmi->head = ptmp; - - hpctx = pctmi->head; + memset(temp, 0, sizeof(StatsThreadStore)); - hpctx[pctmi->size] = pctx; - for (u = pctmi->size - 1; u > 0; u--) { - if (pctx->curr_id <= hpctx[u]->curr_id) { - hpctx[u + 1] = hpctx[u]; - hpctx[u] = pctx; - continue; - } - break; - } - pctmi->size++; + temp->ctx = pctx; + temp->name = thread_name; - SCMutexUnlock(&sc_perf_op_ctx->pctmi_lock); + temp->next = stats_ctx->sts; + stats_ctx->sts = temp; + stats_ctx->sts_cnt++; + SCLogDebug("stats_ctx->sts %p", stats_ctx->sts); + SCMutexUnlock(&stats_ctx->sts_lock); return 1; } -/** - * \brief Returns a counter array for counters in this id range(s_id - e_id) +/** \internal + * \brief Returns a counter array for counters in this id range(s_id - e_id) * - * \param s_id Counter id of the first counter to be added to the array - * \param e_id Counter id of the last counter to be added to the array - * \param pctx Pointer to the tv's SCPerfContext + * \param s_id Counter id of the first counter to be added to the array + * \param e_id Counter id of the last counter to be added to the array + * \param pctx Pointer to the tv's StatsPublicThreadContext * - * \retval a counter-array in this(s_id-e_id) range for this TM instance + * \retval a counter-array in this(s_id-e_id) range for this TM instance */ -SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, - SCPerfContext *pctx) +static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id, + StatsPublicThreadContext *pctx, + StatsPrivateThreadContext *pca) { - SCPerfCounter *pc = NULL; - SCPerfCounterArray *pca = NULL; + StatsCounter *pc = NULL; uint32_t i = 0; - if (pctx == NULL) { - SCLogDebug("pctx is NULL"); - return NULL; + if (pctx == NULL || pca == NULL) { + SCLogDebug("pctx/pca is NULL"); + return -1; } if (s_id < 1 || e_id < 1 || s_id > e_id) { SCLogDebug("error with the counter ids"); - return NULL; + return -1; } if (e_id > pctx->curr_id) { SCLogDebug("end id is greater than the max id for this tv"); - return NULL; + return -1; } - if ( (pca = SCMalloc(sizeof(SCPerfCounterArray))) == NULL) - return NULL; - memset(pca, 0, sizeof(SCPerfCounterArray)); - - if ( (pca->head = SCMalloc(sizeof(SCPCAElem) * (e_id - s_id + 2))) == NULL) { - SCFree(pca); - return NULL; + if ( (pca->head = SCMalloc(sizeof(StatsLocalCounter) * (e_id - s_id + 2))) == NULL) { + return -1; } - memset(pca->head, 0, sizeof(SCPCAElem) * (e_id - s_id + 2)); + memset(pca->head, 0, sizeof(StatsLocalCounter) * (e_id - s_id + 2)); pc = pctx->head; while (pc->id != s_id) @@ -1208,67 +1123,61 @@ SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t s_id, uint16_t e_id, } pca->size = i - 1; - return pca; + pca->initialized = 1; + return 0; } -/** - * \brief Returns a counter array for all counters registered for this tm - * instance +/** \internal + * \brief Returns a counter array for all counters registered for this tm + * instance * - * \param pctx Pointer to the tv's SCPerfContext + * \param pctx Pointer to the tv's StatsPublicThreadContext * - * \retval pca Pointer to a counter-array for all counter of this tm instance - * on success; NULL on failure + * \retval pca Pointer to a counter-array for all counter of this tm instance + * on success; NULL on failure */ -SCPerfCounterArray *SCPerfGetAllCountersArray(SCPerfContext *pctx) +static int StatsGetAllCountersArray(StatsPublicThreadContext *pctx, StatsPrivateThreadContext *private) +{ + if (pctx == NULL || private == NULL) + return -1; + + return StatsGetCounterArrayRange(1, pctx->curr_id, pctx, private); +} + + +int StatsSetupPrivate(ThreadVars *tv) { - SCPerfCounterArray *pca = ((pctx)? - SCPerfGetCounterArrayRange(1, pctx->curr_id, pctx): - NULL); + StatsGetAllCountersArray(&(tv)->perf_public_ctx, &(tv)->perf_private_ctx); - return pca; + StatsThreadRegister(tv->name, &(tv)->perf_public_ctx); + return 0; } /** * \brief Syncs the counter array with the global counter variables * - * \param pca Pointer to the SCPerfCounterArray - * \param pctx Pointer the the tv's SCPerfContext - * \param reset_lc Indicates whether the local counter has to be reset or not + * \param pca Pointer to the StatsPrivateThreadContext + * \param pctx Pointer the the tv's StatsPublicThreadContext * * \retval 0 on success * \retval -1 on error */ -int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx) +int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx) { - SCPerfCounter *pc = NULL; - SCPCAElem *pcae = NULL; + StatsLocalCounter *pcae = NULL; uint32_t i = 0; if (pca == NULL || pctx == NULL) { - SCLogDebug("pca or pctx is NULL inside SCPerfUpdateCounterArray"); + SCLogDebug("pca or pctx is NULL inside StatsUpdateCounterArray"); return -1; } pcae = pca->head; SCMutexLock(&pctx->m); - pc = pctx->head; - for (i = 1; i <= pca->size; i++) { - while (pc != NULL) { - if (pc->id != pcae[i].id) { - pc = pc->next; - continue; - } - - SCPerfCopyCounterValue(&pcae[i]); - - pc = pc->next; - break; - } + StatsCopyCounterValue(&pcae[i]); } - SCMutexUnlock(&pctx->m); pctx->perf_flag = 0; @@ -1276,167 +1185,162 @@ int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx) return 1; } -/* +/** * \brief Get the value of the local copy of the counter that hold this id. * - * \param id The counter id. - * \param pca Pointer to the SCPerfCounterArray. + * \param tv threadvars + * \param id The counter id. * * \retval 0 on success. * \retval -1 on error. */ -double SCPerfGetLocalCounterValue(uint16_t id, SCPerfCounterArray *pca) +uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id) { + StatsPrivateThreadContext *pca = &tv->perf_private_ctx; #ifdef DEBUG - BUG_ON (pca == NULL); BUG_ON ((id < 1) || (id > pca->size)); #endif - return pca->head[id].ui64_cnt; -} - -/** - * \brief The output interface dispatcher for the counter api - */ -void SCPerfOutputCounters() -{ - switch (sc_perf_op_ctx->iface) { - case SC_PERF_IFACE_FILE: - SCPerfOutputCounterFileIface(); - - break; - case SC_PERF_IFACE_CONSOLE: - /* yet to be implemented */ - - break; - case SC_PERF_IFACE_SYSLOG: - /* yet to be implemented */ - - break; - } - - return; + return pca->head[id].value; } /** - * \brief Releases the resources alloted by the Perf Counter API + * \brief Releases the resources alloted by the Stats API */ -void SCPerfReleaseResources() +void StatsReleaseResources() { - SCPerfReleaseOPCtx(); + StatsReleaseCtx(); return; } /** - * \brief Releases a list of perf counters + * \brief Releases counters * * \param head Pointer to the head of the list of perf counters that have to * be freed */ -void SCPerfReleasePerfCounterS(SCPerfCounter *head) +void StatsReleaseCounters(StatsCounter *head) { - SCPerfCounter *pc = NULL; + StatsCounter *pc = NULL; while (head != NULL) { pc = head; head = head->next; - SCPerfReleaseCounter(pc); + StatsReleaseCounter(pc); } return; } /** - * \brief Releases the SCPerfCounterArray allocated by the user, for storing and + * \brief Releases the StatsPrivateThreadContext allocated by the user, for storing and * updating local counter values * - * \param pca Pointer to the SCPerfCounterArray + * \param pca Pointer to the StatsPrivateThreadContext */ -void SCPerfReleasePCA(SCPerfCounterArray *pca) +void StatsReleasePrivateThreadContext(StatsPrivateThreadContext *pca) { if (pca != NULL) { - if (pca->head != NULL) + if (pca->head != NULL) { SCFree(pca->head); - - SCFree(pca); + pca->head = NULL; + pca->size = 0; + } + pca->initialized = 0; } return; } +void StatsThreadCleanup(ThreadVars *tv) +{ + StatsPublicThreadContextCleanup(&tv->perf_public_ctx); + StatsReleasePrivateThreadContext(&tv->perf_private_ctx); +} + /*----------------------------------Unit_Tests--------------------------------*/ #ifdef UNITTESTS -static int SCPerfTestCounterReg01() +/** \internal + * \brief Registers a normal, unqualified counter + * + * \param name Name of the counter, to be registered + * \param tm_name Name of the engine module under which the counter has to be + * registered + * \param type Datatype of this counter variable + * \param pctx StatsPublicThreadContext corresponding to the tm_name key under which the + * key has to be registered + * + * \retval id Counter id for the newly registered counter, or the already + * present counter + */ +static uint16_t RegisterCounter(char *name, char *tm_name, + StatsPublicThreadContext *pctx) { - SCPerfContext pctx; - - memset(&pctx, 0, sizeof(SCPerfContext)); - - return SCPerfRegisterCounter("t1", "c1", 5, NULL, &pctx); + uint16_t id = StatsRegisterQualifiedCounter(name, tm_name, pctx, + STATS_TYPE_NORMAL, NULL); + return id; } -static int SCPerfTestCounterReg02() +static int StatsTestCounterReg02() { - SCPerfContext pctx; + StatsPublicThreadContext pctx; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(StatsPublicThreadContext)); - return SCPerfRegisterCounter(NULL, NULL, SC_PERF_TYPE_UINT64, NULL, &pctx); + return RegisterCounter(NULL, NULL, &pctx) == 0; } -static int SCPerfTestCounterReg03() +static int StatsTestCounterReg03() { - SCPerfContext pctx; + StatsPublicThreadContext pctx; int result; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(StatsPublicThreadContext)); - result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); + result = RegisterCounter("t1", "c1", &pctx); - SCPerfReleasePerfCounterS(pctx.head); + StatsReleaseCounters(pctx.head); return result; } -static int SCPerfTestCounterReg04() +static int StatsTestCounterReg04() { - SCPerfContext pctx; + StatsPublicThreadContext pctx; int result; - memset(&pctx, 0, sizeof(SCPerfContext)); + memset(&pctx, 0, sizeof(StatsPublicThreadContext)); - SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, &pctx); - SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, &pctx); + RegisterCounter("t1", "c1", &pctx); + RegisterCounter("t2", "c2", &pctx); + RegisterCounter("t3", "c3", &pctx); - result = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, &pctx); + result = RegisterCounter("t1", "c1", &pctx); - SCPerfReleasePerfCounterS(pctx.head); + StatsReleaseCounters(pctx.head); return result; } -static int SCPerfTestGetCntArray05() +static int StatsTestGetCntArray05() { ThreadVars tv; int id; memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); if (id != 1) { printf("id %d: ", id); return 0; } - tv.sc_perf_pca = SCPerfGetAllCountersArray(NULL); - - return (!tv.sc_perf_pca)?1:0; + int r = StatsGetAllCountersArray(NULL, &tv.perf_private_ctx); + return (r == -1) ? 1 : 0; } -static int SCPerfTestGetCntArray06() +static int StatsTestGetCntArray06() { ThreadVars tv; int id; @@ -1444,201 +1348,189 @@ static int SCPerfTestGetCntArray06() memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); if (id != 1) return 0; - tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + int r = StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); - result = (tv.sc_perf_pca)?1:0; + result = (r == 0) ? 1 : 0; - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); - SCPerfReleasePCA(tv.sc_perf_pca); + StatsReleaseCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(&tv.perf_private_ctx); return result; } -static int SCPerfTestCntArraySize07() +static int StatsTestCntArraySize07() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int result; memset(&tv, 0, sizeof(ThreadVars)); - //pca = (SCPerfCounterArray *)&tv.sc_perf_pca; + //pca = (StatsPrivateThreadContext *)&tv.perf_private_ctx; - SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + RegisterCounter("t1", "c1", &tv.perf_public_ctx); + RegisterCounter("t2", "c2", &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; - SCPerfCounterIncr(1, pca); - SCPerfCounterIncr(2, pca); + StatsIncr(&tv, 1); + StatsIncr(&tv, 2); result = pca->size; - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); - SCPerfReleasePCA(pca); + StatsReleaseCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); - return result; + PASS_IF(result == 2); } -static int SCPerfTestUpdateCounter08() +static int StatsTestUpdateCounter08() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int id; int result; memset(&tv, 0, sizeof(ThreadVars)); - id = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + id = RegisterCounter("t1", "c1", &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; - SCPerfCounterIncr(id, pca); - SCPerfCounterAddUI64(id, pca, 100); + StatsIncr(&tv, id); + StatsAddUI64(&tv, id, 100); - result = pca->head[id].ui64_cnt; + result = pca->head[id].value; - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); - SCPerfReleasePCA(pca); + StatsReleaseCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); - return result; + return result == 101; } -static int SCPerfTestUpdateCounter09() +static int StatsTestUpdateCounter09() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + StatsPrivateThreadContext *pca = NULL; uint16_t id1, id2; int result; memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - id2 = SCPerfRegisterCounter("t5", "c5", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + id1 = RegisterCounter("t1", "c1", &tv.perf_public_ctx); + RegisterCounter("t2", "c2", &tv.perf_public_ctx); + RegisterCounter("t3", "c3", &tv.perf_public_ctx); + RegisterCounter("t4", "c4", &tv.perf_public_ctx); + id2 = RegisterCounter("t5", "c5", &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; - SCPerfCounterIncr(id2, pca); - SCPerfCounterAddUI64(id2, pca, 100); + StatsIncr(&tv, id2); + StatsAddUI64(&tv, id2, 100); - result = (pca->head[id1].ui64_cnt == 0) && (pca->head[id2].ui64_cnt == 101); + result = (pca->head[id1].value == 0) && (pca->head[id2].value == 101); - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); - SCPerfReleasePCA(pca); + StatsReleaseCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } -static int SCPerfTestUpdateGlobalCounter10() +static int StatsTestUpdateGlobalCounter10() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int result = 1; uint16_t id1, id2, id3; memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + id1 = RegisterCounter("t1", "c1", &tv.perf_public_ctx); + id2 = RegisterCounter("t2", "c2", &tv.perf_public_ctx); + id3 = RegisterCounter("t3", "c3", &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; - SCPerfCounterIncr(id1, pca); - SCPerfCounterAddUI64(id2, pca, 100); - SCPerfCounterIncr(id3, pca); - SCPerfCounterAddUI64(id3, pca, 100); + StatsIncr(&tv, id1); + StatsAddUI64(&tv, id2, 100); + StatsIncr(&tv, id3); + StatsAddUI64(&tv, id3, 100); - SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx); + StatsUpdateCounterArray(pca, &tv.perf_public_ctx); - result = (1 == tv.sc_perf_pctx.head->value); - result &= (100 == tv.sc_perf_pctx.head->next->value); - result &= (101 == tv.sc_perf_pctx.head->next->next->value); + result = (1 == tv.perf_public_ctx.head->value); + result &= (100 == tv.perf_public_ctx.head->next->value); + result &= (101 == tv.perf_public_ctx.head->next->next->value); - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); - SCPerfReleasePCA(pca); + StatsReleaseCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } -static int SCPerfTestCounterValues11() +static int StatsTestCounterValues11() { ThreadVars tv; - SCPerfCounterArray *pca = NULL; + StatsPrivateThreadContext *pca = NULL; int result = 1; uint16_t id1, id2, id3, id4; memset(&tv, 0, sizeof(ThreadVars)); - id1 = SCPerfRegisterCounter("t1", "c1", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - id2 = SCPerfRegisterCounter("t2", "c2", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - id3 = SCPerfRegisterCounter("t3", "c3", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); - id4 = SCPerfRegisterCounter("t4", "c4", SC_PERF_TYPE_UINT64, NULL, - &tv.sc_perf_pctx); + id1 = RegisterCounter("t1", "c1", &tv.perf_public_ctx); + id2 = RegisterCounter("t2", "c2", &tv.perf_public_ctx); + id3 = RegisterCounter("t3", "c3", &tv.perf_public_ctx); + id4 = RegisterCounter("t4", "c4", &tv.perf_public_ctx); - pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); + StatsGetAllCountersArray(&tv.perf_public_ctx, &tv.perf_private_ctx); + pca = &tv.perf_private_ctx; - SCPerfCounterIncr(id1, pca); - SCPerfCounterAddUI64(id2, pca, 256); - SCPerfCounterAddUI64(id3, pca, 257); - SCPerfCounterAddUI64(id4, pca, 16843024); + StatsIncr(&tv, id1); + StatsAddUI64(&tv, id2, 256); + StatsAddUI64(&tv, id3, 257); + StatsAddUI64(&tv, id4, 16843024); - SCPerfUpdateCounterArray(pca, &tv.sc_perf_pctx); + StatsUpdateCounterArray(pca, &tv.perf_public_ctx); - result &= (1 == tv.sc_perf_pctx.head->value); + result &= (1 == tv.perf_public_ctx.head->value); - result &= (256 == tv.sc_perf_pctx.head->next->value); + result &= (256 == tv.perf_public_ctx.head->next->value); - result &= (257 == tv.sc_perf_pctx.head->next->next->value); + result &= (257 == tv.perf_public_ctx.head->next->next->value); - result &= (16843024 == tv.sc_perf_pctx.head->next->next->next->value); + result &= (16843024 == tv.perf_public_ctx.head->next->next->next->value); - SCPerfReleasePerfCounterS(tv.sc_perf_pctx.head); - SCPerfReleasePCA(pca); + StatsReleaseCounters(tv.perf_public_ctx.head); + StatsReleasePrivateThreadContext(pca); return result; } #endif -void SCPerfRegisterTests() +void StatsRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("SCPerfTestCounterReg01", SCPerfTestCounterReg01, 0); - UtRegisterTest("SCPerfTestCounterReg02", SCPerfTestCounterReg02, 0); - UtRegisterTest("SCPerfTestCounterReg03", SCPerfTestCounterReg03, 1); - UtRegisterTest("SCPerfTestCounterReg04", SCPerfTestCounterReg04, 1); - UtRegisterTest("SCPerfTestGetCntArray05", SCPerfTestGetCntArray05, 1); - UtRegisterTest("SCPerfTestGetCntArray06", SCPerfTestGetCntArray06, 1); - UtRegisterTest("SCPerfTestCntArraySize07", SCPerfTestCntArraySize07, 2); - UtRegisterTest("SCPerfTestUpdateCounter08", SCPerfTestUpdateCounter08, 101); - UtRegisterTest("SCPerfTestUpdateCounter09", SCPerfTestUpdateCounter09, 1); - UtRegisterTest("SCPerfTestUpdateGlobalCounter10", - SCPerfTestUpdateGlobalCounter10, 1); - UtRegisterTest("SCPerfTestCounterValues11", SCPerfTestCounterValues11, 1); + UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02); + UtRegisterTest("StatsTestCounterReg03", StatsTestCounterReg03); + UtRegisterTest("StatsTestCounterReg04", StatsTestCounterReg04); + UtRegisterTest("StatsTestGetCntArray05", StatsTestGetCntArray05); + UtRegisterTest("StatsTestGetCntArray06", StatsTestGetCntArray06); + UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07); + UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08); + UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09); + UtRegisterTest("StatsTestUpdateGlobalCounter10", + StatsTestUpdateGlobalCounter10); + UtRegisterTest("StatsTestCounterValues11", StatsTestCounterValues11); #endif } diff --git a/src/counters.h b/src/counters.h index 123a34f723c6..39fa0bc7f03f 100644 --- a/src/counters.h +++ b/src/counters.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2015 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -19,6 +19,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien */ #ifndef __COUNTERS_H__ @@ -27,194 +28,121 @@ /* forward declaration of the ThreadVars structure */ struct ThreadVars_; -/* Time interval for syncing the local counters with the global ones */ -#define SC_PERF_WUT_TTS 3 - -/* Time interval at which the mgmt thread o/p the stats */ -#define SC_PERF_MGMTT_TTS 8 - -/** - * \brief Data type for different kind of Perf counters that can be registered - */ -enum { - SC_PERF_TYPE_UINT64, - SC_PERF_TYPE_MAX, -}; - -/** - * \brief Different kinds of qualifier that can be used to modify the behaviour - * of the Perf counter to be registered - */ -enum { - SC_PERF_TYPE_Q_NORMAL = 1, - SC_PERF_TYPE_Q_AVERAGE = 2, - SC_PERF_TYPE_Q_MAXIMUM = 3, - SC_PERF_TYPE_Q_MAX = 4, -}; - -/** - * \brief Different output interfaces made available by the Perf counter API - */ -enum { - SC_PERF_IFACE_FILE, - SC_PERF_IFACE_CONSOLE, - SC_PERF_IFACE_SYSLOG, - SC_PERF_IFACE_MAX, -}; - /** * \brief Container to hold the counter variable */ -typedef struct SCPerfCounter_ { +typedef struct StatsCounter_ { int type; - /* local id for this counter in this tm */ + /* local id for this counter in this thread */ uint16_t id; - uint64_t value; + /* global id, used in output */ + uint16_t gid; + + /* counter value(s): copies from the 'private' counter */ + uint64_t value; /**< sum of updates/increments, or 'set' value */ + uint64_t updates; /**< number of updates (for avg) */ + + /* when using type STATS_TYPE_Q_FUNC this function is called once + * to get the counter value, regardless of how many threads there are. */ + uint64_t (*Func)(void); /* name of the counter */ - char *cname; - /* name of the thread module this counter is registered to */ - char *tm_name; + const char *name; /* the next perfcounter for this tv's tm instance */ - struct SCPerfCounter_ *next; - - /* description of this counter */ - char *desc; -} SCPerfCounter; + struct StatsCounter_ *next; +} StatsCounter; /** - * \brief Holds the Perf Context for a ThreadVars instance + * \brief Stats Context for a ThreadVars instance */ -typedef struct SCPerfContext_ { +typedef struct StatsPublicThreadContext_ { /* flag set by the wakeup thread, to inform the client threads to sync */ uint32_t perf_flag; /* pointer to the head of a list of counters assigned under this context */ - SCPerfCounter *head; + StatsCounter *head; /* holds the total no of counters already assigned for this perf context */ uint16_t curr_id; /* mutex to prevent simultaneous access during update_counter/output_stat */ SCMutex m; -} SCPerfContext; +} StatsPublicThreadContext; /** - * \brief Node elements used by the SCPerfCounterArray(PCA) Node + * \brief Storage for local counters, with a link to the public counter used + * for syncs */ -typedef struct SCPCAElem_ { - /* pointer to the PerfCounter that corresponds to this PCAElem */ - SCPerfCounter *pc; +typedef struct StatsLocalCounter_ { + /* pointer to the counter that corresponds to this local counter */ + StatsCounter *pc; - /* counter id of the above counter(pc) */ + /* local counter id of the above counter */ uint16_t id; - uint64_t ui64_cnt; + /* total value of the adds/increments, or exact value in case of 'set' */ + uint64_t value; /* no of times the local counter has been updated */ - uint64_t syncs; -} SCPCAElem; - -/** - * \brief The SCPerfCounterArray used to hold the local version of the counters - * registered - */ -typedef struct SCPerfCounterArray_ { - /* points to the array holding PCAElems */ - SCPCAElem *head; - - /* no of PCAElems in head */ - uint32_t size; -} SCPerfCounterArray; + uint64_t updates; +} StatsLocalCounter; /** - * \brief Holds multiple instances of the same TM together, used when the stats - * have to be clubbed based on TM, before being sent out + * \brief used to hold the private version of the counters registered */ -typedef struct SCPerfClubTMInst_ { - char *tm_name; +typedef struct StatsPrivateThreadContext_ { + /* points to the array holding local counters */ + StatsLocalCounter *head; - SCPerfContext **head; + /* size of head array in elements */ uint32_t size; - struct SCPerfClubTMInst_ *next; -} SCPerfClubTMInst; - -/** - * \brief Holds the output interface context for the counter api - */ -typedef struct SCPerfOPIfaceContext_ { - /* the iface to be used for output */ - uint32_t iface; - - /* the file to be used if the output interface used is SC_PERF_IFACE_FILE */ - char *file; - - /* more interfaces to be supported later. For now just a file */ - FILE *fp; - - SCPerfClubTMInst *pctmi; - SCMutex pctmi_lock; - - /* Flag set on file rotation notification. */ - int rotation_flag; - -} SCPerfOPIfaceContext; + int initialized; +} StatsPrivateThreadContext; /* the initialization functions */ -void SCPerfInitCounterApi(void); -void SCPerfSpawnThreads(void); +void StatsInit(void); +void StatsSetupPostConfig(void); +void StatsSpawnThreads(void); +void StatsRegisterTests(void); -/* the ThreadVars counter registration functions */ -uint16_t SCPerfTVRegisterCounter(char *, struct ThreadVars_ *, int, char *); -uint16_t SCPerfTVRegisterAvgCounter(char *, struct ThreadVars_ *, int, char *); -uint16_t SCPerfTVRegisterMaxCounter(char *, struct ThreadVars_ *, int, char *); +/* functions used to free the resources alloted by the Stats API */ +void StatsReleaseResources(void); -/* the non-ThreadVars counter registration functions */ -uint16_t SCPerfRegisterCounter(char *, char *, int, char *, SCPerfContext *); -uint16_t SCPerfRegisterAvgCounter(char *, char *, int, char *, SCPerfContext *); -uint16_t SCPerfRegisterMaxCounter(char *, char *, int, char *, SCPerfContext *); - -/* utility functions */ -int SCPerfAddToClubbedTMTable(char *, SCPerfContext *); -SCPerfCounterArray *SCPerfGetCounterArrayRange(uint16_t, uint16_t, SCPerfContext *); -SCPerfCounterArray * SCPerfGetAllCountersArray(SCPerfContext *); - -int SCPerfUpdateCounterArray(SCPerfCounterArray *, SCPerfContext *); -double SCPerfGetLocalCounterValue(uint16_t, SCPerfCounterArray *); - -void SCPerfOutputCounters(void); - -/* functions used to free the resources alloted by the Perf counter API */ -void SCPerfReleaseResources(void); -void SCPerfReleasePerfCounterS(SCPerfCounter *); -void SCPerfReleasePCA(SCPerfCounterArray *); - -void SCPerfCounterSetUI64(uint16_t, SCPerfCounterArray *, uint64_t); -void SCPerfCounterIncr(uint16_t, SCPerfCounterArray *); - -void SCPerfRegisterTests(void); +/* counter registration functions */ +uint16_t StatsRegisterCounter(char *, struct ThreadVars_ *); +uint16_t StatsRegisterAvgCounter(char *, struct ThreadVars_ *); +uint16_t StatsRegisterMaxCounter(char *, struct ThreadVars_ *); +uint16_t StatsRegisterGlobalCounter(char *cname, uint64_t (*Func)(void)); /* functions used to update local counter values */ -void SCPerfCounterAddUI64(uint16_t, SCPerfCounterArray *, uint64_t); +void StatsAddUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void StatsSetUI64(struct ThreadVars_ *, uint16_t, uint64_t); +void StatsIncr(struct ThreadVars_ *, uint16_t); + +/* utility functions */ +int StatsUpdateCounterArray(StatsPrivateThreadContext *, StatsPublicThreadContext *); +uint64_t StatsGetLocalCounterValue(struct ThreadVars_ *, uint16_t); +int StatsSetupPrivate(struct ThreadVars_ *); +void StatsThreadCleanup(struct ThreadVars_ *); -#define SCPerfSyncCounters(tv) \ - SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx); \ +#define StatsSyncCounters(tv) \ + StatsUpdateCounterArray(&(tv)->perf_private_ctx, &(tv)->perf_public_ctx); \ -#define SCPerfSyncCountersIfSignalled(tv) \ +#define StatsSyncCountersIfSignalled(tv) \ do { \ - if ((tv)->sc_perf_pctx.perf_flag == 1) { \ - SCPerfUpdateCounterArray((tv)->sc_perf_pca, &(tv)->sc_perf_pctx); \ + if ((tv)->perf_public_ctx.perf_flag == 1) { \ + StatsUpdateCounterArray(&(tv)->perf_private_ctx, \ + &(tv)->perf_public_ctx); \ } \ } while (0) #ifdef BUILD_UNIX_SOCKET -#include -TmEcode SCPerfOutputCounterSocket(json_t *cmd, - json_t *answer, void *data); +TmEcode StatsOutputCounterSocket(json_t *cmd, + json_t *answer, void *data); #endif #endif /* __COUNTERS_H__ */ diff --git a/src/decode-afl.c b/src/decode-afl.c new file mode 100644 index 000000000000..16b3ab87e478 --- /dev/null +++ b/src/decode-afl.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "conf.h" +#include "decode.h" +#include "util-debug.h" +#include "util-mem.h" +#include "app-layer-detect-proto.h" +#include "app-layer.h" +#include "tm-threads.h" +#include "util-error.h" +#include "util-print.h" +#include "tmqh-packetpool.h" +#include "util-profiling.h" +#include "pkt-var.h" +#include "util-mpm-ac.h" + +#include "output.h" +#include "output-flow.h" + +#include "defrag.h" +#include "flow.h" + +#ifdef AFLFUZZ_DECODER + +/* stateful processing of data as packets. Because AFL in case of a + * crash will only safe the last input, we dump all the inputs to a + * directory 'dump' with a unique timestamp for the serie and an + * incrementing 'id' so that we can 'replay' it in + * DecoderParseDataFromFileSerie(). + */ +int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) { + uint8_t buffer[65536]; + + struct timeval ts; + memset(&ts, 0, sizeof(ts)); + gettimeofday(&ts, NULL); + + uint32_t cnt = 0; + + DefragInit(); + FlowInitConfig(FLOW_QUIET); + + ThreadVars tv; + memset(&tv, 0, sizeof(tv)); + DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + StatsSetupPrivate(&tv); + PacketQueue pq; + memset(&pq, 0, sizeof(pq)); + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + char outfilename[256]; + snprintf(outfilename, sizeof(outfilename), "dump/%u-%u.%u", (uint)ts.tv_sec, (uint)ts.tv_usec, cnt); + FILE *out_fp = fopen(outfilename, "w"); + BUG_ON(out_fp == NULL); + (void)fwrite(buffer, size, 1, out_fp); + fclose(out_fp); + + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + PacketSetData(p, buffer, size); + (void) Decoder (&tv, dtv, p, buffer, size, &pq); + while (1) { + Packet *extra_p = PacketDequeue(&pq); + if (unlikely(extra_p == NULL)) + break; + PacketFree(extra_p); + } + PacketFree(p); + } + fclose(fp); + cnt++; + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + /* if we get here there was no crash, so we can remove our files */ + uint32_t x = 0; + for (x = 0; x < cnt; x++) { + char rmfilename[256]; + snprintf(rmfilename, sizeof(rmfilename), "dump/%u-%u.%u", (uint)ts.tv_sec, (uint)ts.tv_usec, x); + unlink(rmfilename); + } + + DecodeThreadVarsFree(&tv, dtv); + FlowShutdown(); + DefragDestroy(); + return 0; +} + +/* load a serie of files generated by DecoderParseDataFromFile() in + * the same order as it was produced. */ +int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder) +{ + uint8_t buffer[65536]; + uint32_t cnt = 0; + + DefragInit(); + FlowInitConfig(FLOW_QUIET); + ThreadVars tv; + memset(&tv, 0, sizeof(tv)); + DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + StatsSetupPrivate(&tv); + PacketQueue pq; + memset(&pq, 0, sizeof(pq)); + + char filename[256]; + snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); + FILE *fp; + while ((fp = fopen(filename, "r")) != NULL) + { + memset(buffer, 0, sizeof(buffer)); + + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + PacketSetData(p, buffer, size); + (void) Decoder (&tv, dtv, p, buffer, size, &pq); + while (1) { + Packet *extra_p = PacketDequeue(&pq); + if (unlikely(extra_p == NULL)) + break; + PacketFree(extra_p); + } + PacketFree(p); + } + fclose(fp); + cnt++; + snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt); + } + DecodeThreadVarsFree(&tv, dtv); + FlowShutdown(); + DefragDestroy(); + return 0; +} +#endif /* AFLFUZZ_DECODER */ + diff --git a/src/decode-erspan.c b/src/decode-erspan.c new file mode 100644 index 000000000000..f2fb0eb124fc --- /dev/null +++ b/src/decode-erspan.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup decode + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Decodes ERSPAN + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" +#include "decode-events.h" +#include "decode-erspan.h" + +#include "util-unittest.h" +#include "util-debug.h" + +/** + * \brief Function to decode ERSPAN packets + */ + +int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) +{ + StatsIncr(tv, dtv->counter_erspan); + + if (len < sizeof(ErspanHdr)) { + ENGINE_SET_EVENT(p,ERSPAN_HEADER_TOO_SMALL); + return TM_ECODE_FAILED; + } + + const ErspanHdr *ehdr = (const ErspanHdr *)pkt; + uint16_t version = ntohs(ehdr->ver_vlan) >> 12; + uint16_t vlan_id = ntohs(ehdr->ver_vlan) & 0x0fff; + + SCLogDebug("ERSPAN: version %u vlan %u", version, vlan_id); + + /* only v1 is tested at this time */ + if (version != 1) { + ENGINE_SET_EVENT(p,ERSPAN_UNSUPPORTED_VERSION); + return TM_ECODE_FAILED; + } + + if (vlan_id > 0 && dtv->vlan_disabled == 0) { + if (p->vlan_idx >= 2) { + ENGINE_SET_EVENT(p,ERSPAN_TOO_MANY_VLAN_LAYERS); + return TM_ECODE_FAILED; + } + p->vlan_id[p->vlan_idx] = vlan_id; + p->vlan_idx++; + } + + return DecodeEthernet(tv, dtv, p, pkt + sizeof(ErspanHdr), len - sizeof(ErspanHdr), pq); +} + +/** + * @} + */ diff --git a/src/decode-erspan.h b/src/decode-erspan.h new file mode 100644 index 000000000000..2f81d1e4a384 --- /dev/null +++ b/src/decode-erspan.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#ifndef __DECODE_ERSPAN_H__ +#define __DECODE_ERSPAN_H__ + +#include "decode.h" +#include "threadvars.h" + +typedef struct ErspanHdr_ { + uint16_t ver_vlan; + uint16_t flags_spanid; + uint32_t padding; +} __attribute__((__packed__)) ErspanHdr; + +#endif /* __DECODE_ERSPAN_H__ */ diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index e5a920d16932..1c5e83e97a5e 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -41,7 +41,7 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_eth, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_eth); if (unlikely(len < ETHERNET_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, ETHERNET_PKT_TOO_SMALL); @@ -85,6 +85,14 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, DecodeMPLS(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; + case ETHERNET_TYPE_DCE: + if (unlikely(len < ETHERNET_DCE_HEADER_LEN)) { + ENGINE_SET_INVALID_EVENT(p, DCE_PKT_TOO_SMALL); + } else { + DecodeEthernet(tv, dtv, p, pkt + ETHERNET_DCE_HEADER_LEN, + len - ETHERNET_DCE_HEADER_LEN, pq); + } + break; default: SCLogDebug("p %p pkt %p ether type %04x not supported", p, pkt, ntohs(p->ethh->eth_type)); @@ -132,7 +140,7 @@ static int DecodeEthernetTest01 (void) DecodeEthernet(&tv, &dtv, p, raw_eth, sizeof(raw_eth), NULL); SCFree(p); - return 0; + return 1; } #endif /* UNITTESTS */ @@ -144,7 +152,7 @@ static int DecodeEthernetTest01 (void) void DecodeEthernetRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01, 0); + UtRegisterTest("DecodeEthernetTest01", DecodeEthernetTest01); #endif /* UNITTESTS */ } /** diff --git a/src/decode-ethernet.h b/src/decode-ethernet.h index 2a6f86e936a4..33f443da84a3 100644 --- a/src/decode-ethernet.h +++ b/src/decode-ethernet.h @@ -26,10 +26,14 @@ #define ETHERNET_HEADER_LEN 14 +/* Cisco Fabric Path / DCE header length. */ +#define ETHERNET_DCE_HEADER_LEN ETHERNET_HEADER_LEN + 2 + /* Ethernet types -- taken from Snort and Libdnet */ #define ETHERNET_TYPE_PUP 0x0200 /* PUP protocol */ #define ETHERNET_TYPE_IP 0x0800 #define ETHERNET_TYPE_ARP 0x0806 +#define ETHERNET_TYPE_BRIDGE 0x6558 /* transparant ethernet bridge (GRE) */ #define ETHERNET_TYPE_REVARP 0x8035 #define ETHERNET_TYPE_EAPOL 0x888e #define ETHERNET_TYPE_IPV6 0x86dd @@ -40,6 +44,9 @@ #define ETHERNET_TYPE_8021Q 0x8100 #define ETHERNET_TYPE_LOOP 0x9000 #define ETHERNET_TYPE_8021QINQ 0x9100 +#define ETHERNET_TYPE_ERSPAN 0x88BE +#define ETHERNET_TYPE_DCE 0x8903 /* Data center ethernet, + * Cisco Fabric Path */ typedef struct EthernetHdr_ { uint8_t eth_dst[6]; diff --git a/src/decode-events.c b/src/decode-events.c index cecf77c54d5a..e6b330a76cf7 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -23,5 +23,223 @@ #include "suricata-common.h" +#include "decode-events.h" /* code moved to app-layer-events */ +const struct DecodeEvents_ DEvents[] = { + /* IPV4 EVENTS */ + { "decoder.ipv4.pkt_too_small", IPV4_PKT_TOO_SMALL, }, + { "decoder.ipv4.hlen_too_small", IPV4_HLEN_TOO_SMALL, }, + { "decoder.ipv4.iplen_smaller_than_hlen", IPV4_IPLEN_SMALLER_THAN_HLEN, }, + { "decoder.ipv4.trunc_pkt", IPV4_TRUNC_PKT, }, + + /* IPV4 OPTIONS */ + { "decoder.ipv4.opt_invalid", IPV4_OPT_INVALID, }, + { "decoder.ipv4.opt_invalid_len", IPV4_OPT_INVALID_LEN, }, + { "decoder.ipv4.opt_malformed", IPV4_OPT_MALFORMED, }, + { "decoder.ipv4.opt_pad_required", IPV4_OPT_PAD_REQUIRED, }, + { "decoder.ipv4.opt_eol_required", IPV4_OPT_EOL_REQUIRED, }, + { "decoder.ipv4.opt_duplicate", IPV4_OPT_DUPLICATE, }, + { "decoder.ipv4.opt_unknown", IPV4_OPT_UNKNOWN, }, + { "decoder.ipv4.wrong_ip_version", IPV4_WRONG_IP_VER, }, + { "decoder.ipv4.icmpv6", IPV4_WITH_ICMPV6, }, + + /* ICMP EVENTS */ + { "decoder.icmpv4.pkt_too_small", ICMPV4_PKT_TOO_SMALL, }, + { "decoder.icmpv4.unknown_type", ICMPV4_UNKNOWN_TYPE, }, + { "decoder.icmpv4.unknown_code", ICMPV4_UNKNOWN_CODE, }, + { "decoder.icmpv4.ipv4_trunc_pkt", ICMPV4_IPV4_TRUNC_PKT, }, + { "decoder.icmpv4.ipv4_unknown_ver", ICMPV4_IPV4_UNKNOWN_VER, }, + + /* ICMPv6 EVENTS */ + { "decoder.icmpv6.unknown_type", ICMPV6_UNKNOWN_TYPE,}, + { "decoder.icmpv6.unknown_code", ICMPV6_UNKNOWN_CODE,}, + { "decoder.icmpv6.pkt_too_small", ICMPV6_PKT_TOO_SMALL,}, + { "decoder.icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, + { "decoder.icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, + { "decoder.icmpv6.mld_message_with_invalid_hl", ICMPV6_MLD_MESSAGE_WITH_INVALID_HL,}, + { "decoder.icmpv6.unassigned_type", ICMPV6_UNASSIGNED_TYPE,}, + { "decoder.icmpv6.experimentation_type", ICMPV6_EXPERIMENTATION_TYPE,}, + + /* IPV6 EVENTS */ + { "decoder.ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, + { "decoder.ipv6.trunc_pkt", IPV6_TRUNC_PKT, }, + { "decoder.ipv6.trunc_exthdr", IPV6_TRUNC_EXTHDR, }, + { "decoder.ipv6.exthdr_dupl_fh", IPV6_EXTHDR_DUPL_FH, }, + { "decoder.ipv6.exthdr_useless_fh", IPV6_EXTHDR_USELESS_FH, }, + { "decoder.ipv6.exthdr_dupl_rh", IPV6_EXTHDR_DUPL_RH, }, + { "decoder.ipv6.exthdr_dupl_hh", IPV6_EXTHDR_DUPL_HH, }, + { "decoder.ipv6.exthdr_dupl_dh", IPV6_EXTHDR_DUPL_DH, }, + { "decoder.ipv6.exthdr_dupl_ah", IPV6_EXTHDR_DUPL_AH, }, + { "decoder.ipv6.exthdr_dupl_eh", IPV6_EXTHDR_DUPL_EH, }, + { "decoder.ipv6.exthdr_invalid_optlen", IPV6_EXTHDR_INVALID_OPTLEN, }, + { "decoder.ipv6.wrong_ip_version", IPV6_WRONG_IP_VER, }, + { "decoder.ipv6.exthdr_ah_res_not_null", IPV6_EXTHDR_AH_RES_NOT_NULL, }, + { "decoder.ipv6.hopopts_unknown_opt", IPV6_HOPOPTS_UNKNOWN_OPT, }, + { "decoder.ipv6.hopopts_only_padding", IPV6_HOPOPTS_ONLY_PADDING, }, + { "decoder.ipv6.dstopts_unknown_opt", IPV6_DSTOPTS_UNKNOWN_OPT, }, + { "decoder.ipv6.dstopts_only_padding", IPV6_DSTOPTS_ONLY_PADDING, }, + { "decoder.ipv6.rh_type_0", IPV6_EXTHDR_RH_TYPE_0, }, + { "decoder.ipv6.zero_len_padn", IPV6_EXTHDR_ZERO_LEN_PADN, }, + { "decoder.ipv6.fh_non_zero_reserved_field", IPV6_FH_NON_ZERO_RES_FIELD, }, + { "decoder.ipv6.data_after_none_header", IPV6_DATA_AFTER_NONE_HEADER, }, + { "decoder.ipv6.unknown_next_header", IPV6_UNKNOWN_NEXT_HEADER, }, + { "decoder.ipv6.icmpv4", IPV6_WITH_ICMPV4, }, + + /* TCP EVENTS */ + { "decoder.tcp.pkt_too_small", TCP_PKT_TOO_SMALL, }, + { "decoder.tcp.hlen_too_small", TCP_HLEN_TOO_SMALL, }, + { "decoder.tcp.invalid_optlen", TCP_INVALID_OPTLEN, }, + + /* TCP OPTIONS */ + { "decoder.tcp.opt_invalid_len", TCP_OPT_INVALID_LEN, }, + { "decoder.tcp.opt_duplicate", TCP_OPT_DUPLICATE, }, + + /* UDP EVENTS */ + { "decoder.udp.pkt_too_small", UDP_PKT_TOO_SMALL, }, + { "decoder.udp.hlen_too_small", UDP_HLEN_TOO_SMALL, }, + { "decoder.udp.hlen_invalid", UDP_HLEN_INVALID, }, + + /* SLL EVENTS */ + { "decoder.sll.pkt_too_small", SLL_PKT_TOO_SMALL, }, + + /* ETHERNET EVENTS */ + { "decoder.ethernet.pkt_too_small", ETHERNET_PKT_TOO_SMALL, }, + + /* PPP EVENTS */ + { "decoder.ppp.pkt_too_small", PPP_PKT_TOO_SMALL, }, + { "decoder.ppp.vju_pkt_too_small", PPPVJU_PKT_TOO_SMALL, }, + { "decoder.ppp.ip4_pkt_too_small", PPPIPV4_PKT_TOO_SMALL, }, + { "decoder.ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, }, + { "decoder.ppp.wrong_type", PPP_WRONG_TYPE, }, /** unknown & invalid protocol */ + { "decoder.ppp.unsup_proto", PPP_UNSUP_PROTO, }, /** unsupported but valid protocol */ + + /* PPPOE EVENTS */ + { "decoder.pppoe.pkt_too_small", PPPOE_PKT_TOO_SMALL, }, + { "decoder.pppoe.wrong_code", PPPOE_WRONG_CODE, }, + { "decoder.pppoe.malformed_tags", PPPOE_MALFORMED_TAGS, }, + + /* GRE EVENTS */ + { "decoder.gre.pkt_too_small", GRE_PKT_TOO_SMALL, }, + { "decoder.gre.wrong_version", GRE_WRONG_VERSION, }, + { "decoder.gre.version0_recur", GRE_VERSION0_RECUR, }, + { "decoder.gre.version0_flags", GRE_VERSION0_FLAGS, }, + { "decoder.gre.version0_hdr_too_big", GRE_VERSION0_HDR_TOO_BIG, }, + { "decoder.gre.version0_malformed_sre_hdr", GRE_VERSION0_MALFORMED_SRE_HDR, }, + { "decoder.gre.version1_chksum", GRE_VERSION1_CHKSUM, }, + { "decoder.gre.version1_route", GRE_VERSION1_ROUTE, }, + { "decoder.gre.version1_ssr", GRE_VERSION1_SSR, }, + { "decoder.gre.version1_recur", GRE_VERSION1_RECUR, }, + { "decoder.gre.version1_flags", GRE_VERSION1_FLAGS, }, + { "decoder.gre.version1_no_key", GRE_VERSION1_NO_KEY, }, + { "decoder.gre.version1_wrong_protocol", GRE_VERSION1_WRONG_PROTOCOL, }, + { "decoder.gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, }, + { "decoder.gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, }, + + /* VLAN EVENTS */ + { "decoder.vlan.header_too_small",VLAN_HEADER_TOO_SMALL, }, + { "decoder.vlan.unknown_type",VLAN_UNKNOWN_TYPE, }, + { "decoder.vlan.too_many_layers", VLAN_HEADER_TOO_MANY_LAYERS, }, + + /* RAW EVENTS */ + { "decoder.ipraw.invalid_ip_version",IPRAW_INVALID_IPV, }, + + /* LINKTYPE NULL EVENTS */ + { "decoder.ltnull.pkt_too_small", LTNULL_PKT_TOO_SMALL, }, + { "decoder.ltnull.unsupported_type", LTNULL_UNSUPPORTED_TYPE, }, + + /* SCTP EVENTS */ + { "decoder.sctp.pkt_too_small", SCTP_PKT_TOO_SMALL, }, + + /* Fragmentation reasembly events. */ + { "decoder.ipv4.frag_pkt_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, + { "decoder.ipv6.frag_pkt_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, + { "decoder.ipv4.frag_overlap", IPV4_FRAG_OVERLAP, }, + { "decoder.ipv6.frag_overlap", IPV6_FRAG_OVERLAP, }, + /* Fragment ignored due to internal error */ + { "decoder.ipv4.frag_ignored", IPV4_FRAG_IGNORED, }, + { "decoder.ipv6.frag_ignored", IPV6_FRAG_IGNORED, }, + + /* IPv4 in IPv6 events */ + { "decoder.ipv6.ipv4_in_ipv6_too_small", IPV4_IN_IPV6_PKT_TOO_SMALL, }, + { "decoder.ipv6.ipv4_in_ipv6_wrong_version", IPV4_IN_IPV6_WRONG_IP_VER, }, + /* IPv6 in IPv6 events */ + { "decoder.ipv6.ipv6_in_ipv6_too_small", IPV6_IN_IPV6_PKT_TOO_SMALL, }, + { "decoder.ipv6.ipv6_in_ipv6_wrong_version", IPV6_IN_IPV6_WRONG_IP_VER, }, + + /* MPLS events */ + { "decoder.mpls.header_too_small", MPLS_HEADER_TOO_SMALL, }, + { "decoder.mpls.bad_label_router_alert", MPLS_BAD_LABEL_ROUTER_ALERT, }, + { "decoder.mpls.bad_label_implicit_null", MPLS_BAD_LABEL_IMPLICIT_NULL, }, + { "decoder.mpls.bad_label_reserved", MPLS_BAD_LABEL_RESERVED, }, + { "decoder.mpls.unknown_payload_type", MPLS_UNKNOWN_PAYLOAD_TYPE, }, + + /* ERSPAN events */ + { "decoder.erspan.header_too_small", ERSPAN_HEADER_TOO_SMALL, }, + { "decoder.erspan.unsupported_version", ERSPAN_UNSUPPORTED_VERSION, }, + { "decoder.erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, }, + + /* Cisco Fabric Path/DCE events. */ + { "decoder.dce.pkt_too_small", DCE_PKT_TOO_SMALL, }, + + /* STREAM EVENTS */ + { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, + { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, + { "stream.3whs_right_seq_wrong_ack_evasion", STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, }, + { "stream.3whs_synack_in_wrong_direction", STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, }, + { "stream.3whs_synack_resend_with_different_ack", STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, + { "stream.3whs_synack_resend_with_diff_seq", STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, }, + { "stream.3whs_synack_toserver_on_syn_recv", STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, }, + { "stream.3whs_synack_with_wrong_ack", STREAM_3WHS_SYNACK_WITH_WRONG_ACK, }, + { "stream.3whs_synack_flood", STREAM_3WHS_SYNACK_FLOOD, }, + { "stream.3whs_syn_resend_diff_seq_on_syn_recv", STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, }, + { "stream.3whs_syn_toclient_on_syn_recv", STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, }, + { "stream.3whs_wrong_seq_wrong_ack", STREAM_3WHS_WRONG_SEQ_WRONG_ACK, }, + { "stream.4whs_synack_with_wrong_ack", STREAM_4WHS_SYNACK_WITH_WRONG_ACK, }, + { "stream.4whs_synack_with_wrong_syn", STREAM_4WHS_SYNACK_WITH_WRONG_SYN, }, + { "stream.4whs_wrong_seq", STREAM_4WHS_WRONG_SEQ, }, + { "stream.4whs_invalid_ack", STREAM_4WHS_INVALID_ACK, }, + { "stream.closewait_ack_out_of_window", STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, }, + { "stream.closewait_fin_out_of_window", STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, }, + { "stream.closewait_pkt_before_last_ack", STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, }, + { "stream.closewait_invalid_ack", STREAM_CLOSEWAIT_INVALID_ACK, }, + { "stream.closing_ack_wrong_seq", STREAM_CLOSING_ACK_WRONG_SEQ, }, + { "stream.closing_invalid_ack", STREAM_CLOSING_INVALID_ACK, }, + { "stream.est_packet_out_of_window", STREAM_EST_PACKET_OUT_OF_WINDOW, }, + { "stream.est_pkt_before_last_ack", STREAM_EST_PKT_BEFORE_LAST_ACK, }, + { "stream.est_synack_resend", STREAM_EST_SYNACK_RESEND, }, + { "stream.est_synack_resend_with_different_ack", STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, + { "stream.est_synack_resend_with_diff_seq", STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, }, + { "stream.est_synack_toserver", STREAM_EST_SYNACK_TOSERVER, }, + { "stream.est_syn_resend", STREAM_EST_SYN_RESEND, }, + { "stream.est_syn_resend_diff_seq", STREAM_EST_SYN_RESEND_DIFF_SEQ, }, + { "stream.est_syn_toclient", STREAM_EST_SYN_TOCLIENT, }, + { "stream.est_invalid_ack", STREAM_EST_INVALID_ACK, }, + { "stream.fin_invalid_ack", STREAM_FIN_INVALID_ACK, }, + { "stream.fin1_ack_wrong_seq", STREAM_FIN1_ACK_WRONG_SEQ, }, + { "stream.fin1_fin_wrong_seq", STREAM_FIN1_FIN_WRONG_SEQ, }, + { "stream.fin1_invalid_ack", STREAM_FIN1_INVALID_ACK, }, + { "stream.fin2_ack_wrong_seq", STREAM_FIN2_ACK_WRONG_SEQ, }, + { "stream.fin2_fin_wrong_seq", STREAM_FIN2_FIN_WRONG_SEQ, }, + { "stream.fin2_invalid_ack", STREAM_FIN2_INVALID_ACK, }, + { "stream.fin_but_no_session", STREAM_FIN_BUT_NO_SESSION, }, + { "stream.fin_out_of_window", STREAM_FIN_OUT_OF_WINDOW, }, + { "stream.lastack_ack_wrong_seq", STREAM_LASTACK_ACK_WRONG_SEQ, }, + { "stream.lastack_invalid_ack", STREAM_LASTACK_INVALID_ACK, }, + { "stream.rst_but_no_session", STREAM_RST_BUT_NO_SESSION, }, + { "stream.timewait_ack_wrong_seq", STREAM_TIMEWAIT_ACK_WRONG_SEQ, }, + { "stream.timewait_invalid_ack", STREAM_TIMEWAIT_INVALID_ACK, }, + { "stream.pkt_invalid_timestamp", STREAM_PKT_INVALID_TIMESTAMP, }, + { "stream.pkt_invalid_ack", STREAM_PKT_INVALID_ACK, }, + { "stream.pkt_broken_ack", STREAM_PKT_BROKEN_ACK, }, + { "stream.rst_invalid_ack", STREAM_RST_INVALID_ACK, }, + { "stream.shutdown_syn_resend", STREAM_SHUTDOWN_SYN_RESEND, }, + { "stream.pkt_retransmission", STREAM_PKT_RETRANSMISSION, }, + { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, }, + { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, }, + { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, }, + { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, }, + { "stream.pkt_bad_window_update", STREAM_PKT_BAD_WINDOW_UPDATE, }, + + { NULL, 0 }, +}; diff --git a/src/decode-events.h b/src/decode-events.h index 658b997312a6..048ac45571fb 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -28,7 +28,7 @@ /* packet decoder events */ enum { /* IPV4 EVENTS */ - IPV4_PKT_TOO_SMALL = 1, /**< ipv4 pkt smaller than minimum header size */ + IPV4_PKT_TOO_SMALL = 0, /**< ipv4 pkt smaller than minimum header size */ IPV4_HLEN_TOO_SMALL, /**< ipv4 header smaller than minimum size */ IPV4_IPLEN_SMALLER_THAN_HLEN, /**< ipv4 pkt len smaller than ip header size */ IPV4_TRUNC_PKT, /**< truncated ipv4 packet */ @@ -57,6 +57,9 @@ enum { ICMPV6_PKT_TOO_SMALL, /**< icmpv6 smaller than minimum size */ ICMPV6_IPV6_UNKNOWN_VER, /**< unknown version in icmpv6 packet */ ICMPV6_IPV6_TRUNC_PKT, /**< truncated icmpv6 packet */ + ICMPV6_MLD_MESSAGE_WITH_INVALID_HL, /**< invalid MLD that doesn't have HL 1 */ + ICMPV6_UNASSIGNED_TYPE, /**< unsassigned ICMPv6 type */ + ICMPV6_EXPERIMENTATION_TYPE, /**< uprivate experimentation ICMPv6 type */ /* IPV6 EVENTS */ IPV6_PKT_TOO_SMALL, /**< ipv6 packet smaller than minimum size */ @@ -145,6 +148,49 @@ enum { /* RAW EVENTS */ IPRAW_INVALID_IPV, /**< invalid ip version in ip raw */ + /* LINKTYPE NULL EVENTS */ + LTNULL_PKT_TOO_SMALL, /**< pkt too small for lt:null */ + LTNULL_UNSUPPORTED_TYPE, /**< pkt has a type that the decoder doesn't support */ + + /* SCTP EVENTS */ + SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */ + + /* Fragmentation reasembly events. */ + IPV4_FRAG_PKT_TOO_LARGE, + IPV6_FRAG_PKT_TOO_LARGE, + IPV4_FRAG_OVERLAP, + IPV6_FRAG_OVERLAP, + + /* Fragment ignored due to internal error */ + IPV4_FRAG_IGNORED, + IPV6_FRAG_IGNORED, + + /* IPv4 in IPv6 events */ + IPV4_IN_IPV6_PKT_TOO_SMALL, + IPV4_IN_IPV6_WRONG_IP_VER, + + /* IPv6 in IPv6 events */ + IPV6_IN_IPV6_PKT_TOO_SMALL, + IPV6_IN_IPV6_WRONG_IP_VER, + + /* MPLS decode events. */ + MPLS_HEADER_TOO_SMALL, + MPLS_BAD_LABEL_ROUTER_ALERT, + MPLS_BAD_LABEL_IMPLICIT_NULL, + MPLS_BAD_LABEL_RESERVED, + MPLS_UNKNOWN_PAYLOAD_TYPE, + + /* ERSPAN events */ + ERSPAN_HEADER_TOO_SMALL, + ERSPAN_UNSUPPORTED_VERSION, + ERSPAN_TOO_MANY_VLAN_LAYERS, + + /* Cisco Fabric Path/DCE events. */ + DCE_PKT_TOO_SMALL, + + /* END OF DECODE EVENTS ON SINGLE PACKET */ + DECODE_EVENT_PACKET_MAX, + /* STREAM EVENTS */ STREAM_3WHS_ACK_IN_WRONG_DIR, STREAM_3WHS_ASYNC_WRONG_SEQ, @@ -207,36 +253,19 @@ enum { STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, - /* SCTP EVENTS */ - SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */ - - /* Fragmentation reasembly events. */ - IPV4_FRAG_PKT_TOO_LARGE, - IPV6_FRAG_PKT_TOO_LARGE, - IPV4_FRAG_OVERLAP, - IPV6_FRAG_OVERLAP, - IPV4_FRAG_TOO_LARGE, - IPV6_FRAG_TOO_LARGE, - /* Fragment ignored due to internal error */ - IPV4_FRAG_IGNORED, - IPV6_FRAG_IGNORED, + /* should always be last! */ + DECODE_EVENT_MAX, +}; - /* IPv4 in IPv6 events */ - IPV4_IN_IPV6_PKT_TOO_SMALL, - IPV4_IN_IPV6_WRONG_IP_VER, - /* IPv6 in IPv6 events */ - IPV6_IN_IPV6_PKT_TOO_SMALL, - IPV6_IN_IPV6_WRONG_IP_VER, +#define EVENT_IS_DECODER_PACKET_ERROR(e) \ + ((e) < (DECODE_EVENT_PACKET_MAX)) - /* MPLS decode events. */ - MPLS_HEADER_TOO_SMALL, - MPLS_BAD_LABEL_ROUTER_ALERT, - MPLS_BAD_LABEL_IMPLICIT_NULL, - MPLS_BAD_LABEL_RESERVED, - MPLS_UNKNOWN_PAYLOAD_TYPE, +/* supported decoder events */ - /* should always be last! */ - DECODE_EVENT_MAX, +struct DecodeEvents_ { + char *event_name; + uint8_t code; }; +extern const struct DecodeEvents_ DEvents[DECODE_EVENT_MAX]; #endif /* __DECODE_EVENTS_H__ */ diff --git a/src/decode-gre.c b/src/decode-gre.c index cd9f47191b8f..da310bf350e0 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -48,7 +48,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; - SCPerfCounterIncr(dtv->counter_gre, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_gre); if(len < GRE_HDR_LEN) { ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); @@ -201,7 +201,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, IPPROTO_IP, pq); + len - header_len, DECODE_TUNNEL_IPV4, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -214,7 +214,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, PPP_OVER_GRE, pq); + len - header_len, DECODE_TUNNEL_PPP, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -227,7 +227,7 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, IPPROTO_IPV6, pq); + len - header_len, DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -240,7 +240,33 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, - len - header_len, VLAN_OVER_GRE, pq); + len - header_len, DECODE_TUNNEL_VLAN, pq); + if (tp != NULL) { + PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); + PacketEnqueue(pq,tp); + } + } + break; + } + + case ETHERNET_TYPE_ERSPAN: + { + if (pq != NULL) { + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, + len - header_len, DECODE_TUNNEL_ERSPAN, pq); + if (tp != NULL) { + PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); + PacketEnqueue(pq,tp); + } + } + break; + } + + case ETHERNET_TYPE_BRIDGE: + { + if (pq != NULL) { + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, + len - header_len, DECODE_TUNNEL_ETHERNET, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); @@ -377,9 +403,9 @@ static int DecodeGREtest03 (void) void DecodeGRERegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeGREtest01", DecodeGREtest01, 1); - UtRegisterTest("DecodeGREtest02", DecodeGREtest02, 1); - UtRegisterTest("DecodeGREtest03", DecodeGREtest03, 1); + UtRegisterTest("DecodeGREtest01", DecodeGREtest01); + UtRegisterTest("DecodeGREtest02", DecodeGREtest02); + UtRegisterTest("DecodeGREtest03", DecodeGREtest03); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 99ab99f231c6..1cfaf780780a 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -47,13 +47,13 @@ /** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ -void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) +int DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV4_HEADER_LEN) { SCLogDebug("DecodePartialIPV4: ICMPV4_IPV4_TRUNC_PKT"); ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); - return; + return -1; } IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; @@ -64,7 +64,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) SCLogDebug("DecodePartialIPV4: ICMPv4 contains Unknown IPV4 version " "ICMPV4_IPV4_UNKNOWN_VER"); ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); - return; + return -1; } /** We need to fill icmpv4vars */ @@ -125,12 +125,14 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) break; case IPPROTO_ICMP: - p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); - p->icmpv4vars.emb_sport = 0; - p->icmpv4vars.emb_dport = 0; - p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; + if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN ) { + p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); + p->icmpv4vars.emb_sport = 0; + p->icmpv4vars.emb_dport = 0; + p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; - SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); + SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); + } break; } @@ -144,8 +146,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) IPV4_GET_RAW_IPPROTO(icmp4_ip4h), IPV4_GET_RAW_IPID(icmp4_ip4h)); #endif - return; - + return 0; } /** DecodeICMPV4 @@ -153,7 +154,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) */ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_icmpv4, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_icmpv4); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); @@ -188,11 +189,13 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, } else { /* parse IP header plus 64 bytes */ if (len > ICMPV4_HEADER_PKT_OFFSET) { - DecodePartialIPV4( p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); - - /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ - if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { - FlowHandlePacket(tv, dtv, p); + if (DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), + len - ICMPV4_HEADER_PKT_OFFSET ) == 0) + { + /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ + if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { + FlowSetupPacket(p); + } } } } @@ -662,7 +665,7 @@ static int ICMPV4CalculateInvalidChecksumtest06(void) 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; csum = *( ((uint16_t *)raw_icmpv4) + 1); - return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); + return (csum != ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } static int ICMPV4InvalidType07(void) @@ -766,17 +769,17 @@ static int DecodeICMPV4test08(void) void DecodeICMPV4RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeICMPV4test01", DecodeICMPV4test01, 1); - UtRegisterTest("DecodeICMPV4test02", DecodeICMPV4test02, 1); - UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03, 1); - UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04, 1); - UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05, 1); + UtRegisterTest("DecodeICMPV4test01", DecodeICMPV4test01); + UtRegisterTest("DecodeICMPV4test02", DecodeICMPV4test02); + UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03); + UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04); + UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05); UtRegisterTest("ICMPV4CalculateValidChecksumtest05", - ICMPV4CalculateValidChecksumtest05, 1); + ICMPV4CalculateValidChecksumtest05); UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", - ICMPV4CalculateInvalidChecksumtest06, 0); - UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07, 1); - UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08, 1); + ICMPV4CalculateInvalidChecksumtest06); + UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07); + UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index f8cb97f4f0ab..d3ade18fac04 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -179,8 +179,6 @@ typedef struct ICMPV4Vars_ { uint16_t id; uint16_t seq; - uint32_t mtu; - uint32_t error_ptr; /** Pointers to the embedded packet headers */ IPV4Hdr *emb_ipv4h; @@ -200,22 +198,9 @@ typedef struct ICMPV4Vars_ } ICMPV4Vars; #define CLEAR_ICMPV4_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - (p)->icmpv4vars.id = 0; \ - (p)->icmpv4vars.seq = 0; \ - (p)->icmpv4vars.mtu = 0; \ - (p)->icmpv4vars.error_ptr = 0; \ - (p)->icmpv4vars.emb_ipv4h = NULL; \ - (p)->icmpv4vars.emb_tcph = NULL; \ - (p)->icmpv4vars.emb_udph = NULL; \ - (p)->icmpv4vars.emb_icmpv4h = NULL; \ - (p)->icmpv4vars.emb_ip4_src.s_addr = 0; \ - (p)->icmpv4vars.emb_ip4_dst.s_addr = 0; \ - (p)->icmpv4vars.emb_sport = 0; \ - (p)->icmpv4vars.emb_ip4_proto = 0; \ - (p)->icmpv4vars.emb_sport = 0; \ - (p)->icmpv4vars.emb_dport = 0; \ - (p)->icmpv4h = NULL; \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->icmpv4h = NULL; \ } while(0) #define ICMPV4_HEADER_PKT_OFFSET 8 @@ -225,7 +210,8 @@ typedef struct ICMPV4Vars_ /** macro for icmpv4 "code" access */ #define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /** macro for icmpv4 "csum" access */ -#define ICMPV4_GET_CSUM(p) (p)->icmpv4h->csum +#define ICMPV4_GET_RAW_CSUM(p) ntohs((p)->icmpv4h->checksum) +#define ICMPV4_GET_CSUM(p) (p)->icmpv4h->checksum /* If message is informational */ @@ -236,13 +222,6 @@ typedef struct ICMPV4Vars_ /* If message is Error */ -/** macro for icmpv4 "unused" access */ -#define ICMPV4_GET_UNUSED(p) (p)->icmpv4h->icmpv4b.icmpv4e.unused -/** macro for icmpv4 "error_ptr" access */ -#define ICMPV4_GET_ERROR_PTR(p) (p)->icmpv4h->icmpv4b.icmpv4e.error_ptr -/** macro for icmpv4 "mtu" access */ -#define ICMPV4_GET_MTU(p) (p)->icmpv4h->icmpv4b.icmpv4e.mtu - /** macro for icmpv4 embedded "protocol" access */ #define ICMPV4_GET_EMB_PROTO(p) (p)->icmpv4vars.emb_ip4_proto /** macro for icmpv4 embedded "ipv4h" header access */ @@ -259,7 +238,9 @@ typedef struct ICMPV4Vars_ * * \warning use only _after_ the decoder has processed the packet */ -#define ICMPV4_DEST_UNREACH_IS_VALID(p) (((p)->icmpv4h != NULL) && \ +#define ICMPV4_DEST_UNREACH_IS_VALID(p) ( \ + (!((p)->flags & PKT_IS_INVALID)) && \ + ((p)->icmpv4h != NULL) && \ (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH) && \ (ICMPV4_GET_EMB_IPV4((p)) != NULL) && \ ((ICMPV4_GET_EMB_TCP((p)) != NULL) || \ @@ -280,9 +261,6 @@ typedef struct ICMPV4Vars_ ICMPV4_GET_TYPE((p)) == ICMP_TIME_EXCEEDED || \ ICMPV4_GET_TYPE((p)) == ICMP_PARAMETERPROB) -typedef struct ICMPV4Cache_ { -} ICMPV4Cache; - void DecodeICMPV4RegisterTests(void); /** ------ Inline functions ------ */ diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 71623ab0403b..dc01d121c15b 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -168,7 +168,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int full_hdr = 0; - SCPerfCounterIncr(dtv->counter_icmpv6, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_icmpv6); if (len < ICMPV6_HEADER_LEN) { SCLogDebug("ICMPV6_PKT_TOO_SMALL"); @@ -254,7 +254,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("ICMP6_ECHO_REPLY id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.id = p->icmpv6h->icmpv6b.icmpv6i.id; @@ -265,56 +265,205 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, break; case ND_ROUTER_SOLICIT: SCLogDebug("ND_ROUTER_SOLICIT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_ROUTER_ADVERT: SCLogDebug("ND_ROUTER_ADVERT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_NEIGHBOR_SOLICIT: SCLogDebug("ND_NEIGHBOR_SOLICIT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_NEIGHBOR_ADVERT: SCLogDebug("ND_NEIGHBOR_ADVERT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case ND_REDIRECT: SCLogDebug("ND_REDIRECT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; case MLD_LISTENER_QUERY: SCLogDebug("MLD_LISTENER_QUERY"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } + if (IPV6_GET_HLIM(p) != 1) { + ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); + } break; case MLD_LISTENER_REPORT: SCLogDebug("MLD_LISTENER_REPORT"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } + if (IPV6_GET_HLIM(p) != 1) { + ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); + } break; case MLD_LISTENER_REDUCTION: SCLogDebug("MLD_LISTENER_REDUCTION"); - if (p->icmpv6h->code != 0) { + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + if (IPV6_GET_HLIM(p) != 1) { + ENGINE_SET_EVENT(p, ICMPV6_MLD_MESSAGE_WITH_INVALID_HL); + } + break; + case ICMP6_RR: + SCLogDebug("ICMP6_RR"); + if (ICMPV6_GET_CODE(p) > 2 && ICMPV6_GET_CODE(p) != 255) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ICMP6_NI_QUERY: + SCLogDebug("ICMP6_NI_QUERY"); + if (ICMPV6_GET_CODE(p) > 2) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ICMP6_NI_REPLY: + SCLogDebug("ICMP6_NI_REPLY"); + if (ICMPV6_GET_CODE(p) > 2) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ND_INVERSE_SOLICIT: + SCLogDebug("ND_INVERSE_SOLICIT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ND_INVERSE_ADVERT: + SCLogDebug("ND_INVERSE_ADVERT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MLD_V2_LIST_REPORT: + SCLogDebug("MLD_V2_LIST_REPORT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case HOME_AGENT_AD_REQUEST: + SCLogDebug("HOME_AGENT_AD_REQUEST"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case HOME_AGENT_AD_REPLY: + SCLogDebug("HOME_AGENT_AD_REPLY"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MOBILE_PREFIX_SOLICIT: + SCLogDebug("MOBILE_PREFIX_SOLICIT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MOBILE_PREFIX_ADVERT: + SCLogDebug("MOBILE_PREFIX_ADVERT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case CERT_PATH_SOLICIT: + SCLogDebug("CERT_PATH_SOLICIT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case CERT_PATH_ADVERT: + SCLogDebug("CERT_PATH_ADVERT"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case ICMP6_MOBILE_EXPERIMENTAL: + SCLogDebug("ICMP6_MOBILE_EXPERIMENTAL"); + break; + case MC_ROUTER_ADVERT: + SCLogDebug("MC_ROUTER_ADVERT"); + break; + case MC_ROUTER_SOLICIT: + SCLogDebug("MC_ROUTER_SOLICIT"); + break; + case MC_ROUTER_TERMINATE: + SCLogDebug("MC_ROUTER_TERMINATE"); + break; + case FMIPV6_MSG: + SCLogDebug("FMIPV6_MSG"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case RPL_CONTROL_MSG: + SCLogDebug("RPL_CONTROL_MSG"); + if (ICMPV6_GET_CODE(p) > 3 && ICMPV6_GET_CODE(p) < 128) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + if (ICMPV6_GET_CODE(p) > 132) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case LOCATOR_UDATE_MSG: + SCLogDebug("LOCATOR_UDATE_MSG"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case DUPL_ADDR_REQUEST: + SCLogDebug("DUPL_ADDR_REQUEST"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case DUPL_ADDR_CONFIRM: + SCLogDebug("DUPL_ADDR_CONFIRM"); + if (ICMPV6_GET_CODE(p) != 0) { + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); + } + break; + case MPL_CONTROL_MSG: + SCLogDebug("MPL_CONTROL_MSG"); + if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } break; default: - SCLogDebug("ICMPV6 Message type %" PRIu8 " not " - "implemented yet", ICMPV6_GET_TYPE(p)); - ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); + /* Various range taken from: + * http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2 + */ + if ((ICMPV6_GET_TYPE(p) > 4) && (ICMPV6_GET_TYPE(p) < 100)) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 100) && (ICMPV6_GET_TYPE(p) < 102)) { + ENGINE_SET_EVENT(p, ICMPV6_EXPERIMENTATION_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 102) && (ICMPV6_GET_TYPE(p) < 127)) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 160) && (ICMPV6_GET_TYPE(p) < 200)) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else if ((ICMPV6_GET_TYPE(p) >= 200) && (ICMPV6_GET_TYPE(p) < 202)) { + ENGINE_SET_EVENT(p, ICMPV6_EXPERIMENTATION_TYPE); + } else if (ICMPV6_GET_TYPE(p) >= 202) { + ENGINE_SET_EVENT(p, ICMPV6_UNASSIGNED_TYPE); + } else { + SCLogDebug("ICMPV6 Message type %" PRIu8 " not " + "implemented yet", ICMPV6_GET_TYPE(p)); + ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); + } } /* for a info message the header is just 4 bytes */ @@ -336,8 +485,7 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, SCLogDebug("Unknown Type, ICMPV6_UNKNOWN_TYPE"); #endif - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } @@ -368,8 +516,9 @@ static int ICMPV6CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)(raw_ipv6 + 56))); - return (csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(csum != ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); + PASS; } static int ICMPV6CalculateInvalidChecksumtest02(void) @@ -396,18 +545,17 @@ static int ICMPV6CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)(raw_ipv6 + 56))); - return (csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), + FAIL_IF(csum == ICMPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), (uint16_t *)(raw_ipv6 + 54), 68)); + PASS; } - /** \test icmpv6 message type: parameter problem, valid packet * * \retval retval 0 = Error ; 1 = ok */ static int ICMPV6ParamProbTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -423,8 +571,7 @@ static int ICMPV6ParamProbTest01(void) 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -441,37 +588,23 @@ static int ICMPV6ParamProbTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6h == NULL); - if (ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6) { - SCLogDebug("ICMPv6 not processed at all"); - retval = 0; - goto end; - } + /* ICMPv6 not processed at all? */ + FAIL_IF(ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0 || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_ICMPV6); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: packet too big, valid packet @@ -480,7 +613,6 @@ static int ICMPV6ParamProbTest01(void) */ static int ICMPV6PktTooBigTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -495,8 +627,7 @@ static int ICMPV6PktTooBigTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -513,39 +644,26 @@ static int ICMPV6PktTooBigTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6h == NULL); - /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - if (ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0 ) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } + /* Note: it has an embedded ipv6 packet but no protocol after ipv6 + * (IPPROTO_NONE) */ + /* Check if ICMPv6 header was processed at all. */ + FAIL_IF(ICMPV6_GET_TYPE(p) != 2 || ICMPV6_GET_CODE(p) != 0 ); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: time exceed, valid packet @@ -554,7 +672,6 @@ static int ICMPV6PktTooBigTest01(void) */ static int ICMPV6TimeExceedTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -569,8 +686,7 @@ static int ICMPV6TimeExceedTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -579,7 +695,6 @@ static int ICMPV6TimeExceedTest01(void) ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; - memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -588,40 +703,26 @@ static int ICMPV6TimeExceedTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - if (ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_IPV6(p)==NULL || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE ) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } + FAIL_IF(ICMPV6_GET_TYPE(p) != 3 || ICMPV6_GET_CODE(p) != 0 || + ICMPV6_GET_EMB_IPV6(p) == NULL || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } SCLogDebug("ICMPV6 IPV6 src and dst properly set"); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: destination unreach, valid packet @@ -630,7 +731,6 @@ static int ICMPV6TimeExceedTest01(void) */ static int ICMPV6DestUnreachTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -645,8 +745,7 @@ static int ICMPV6DestUnreachTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -655,7 +754,6 @@ static int ICMPV6DestUnreachTest01(void) ipv6src = (uint32_t*) &raw_ipv6[8]; ipv6dst = (uint32_t*) &raw_ipv6[24]; - memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); memset(&dtv, 0, sizeof(DecodeThreadVars)); @@ -664,38 +762,24 @@ static int ICMPV6DestUnreachTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); /* Note: it has an embedded ipv6 packet but no protocol after ipv6 (IPPROTO_NONE) */ - if (ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || - ICMPV6_GET_EMB_IPV6(p) == NULL || ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE ) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } + FAIL_IF(ICMPV6_GET_TYPE(p) != 1 || ICMPV6_GET_CODE(p) != 0 || + ICMPV6_GET_EMB_IPV6(p) == NULL || + ICMPV6_GET_EMB_PROTO(p) != IPPROTO_NONE); /* Let's check if we retrieved the embedded ipv6 addresses correctly */ uint32_t i=0; for (i = 0; i < 4; i++) { - if (p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || - p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]) { - SCLogDebug("ICMPv6 DecodePartialICMPV6 (Embedded ip6h) didn't set " - "the src and dest ip addresses correctly"); - retval = 0; - goto end; - } + FAIL_IF(p->icmpv6vars.emb_ip6_src[i] != ipv6src[i] || + p->icmpv6vars.emb_ip6_dst[i] != ipv6dst[i]); } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo request, valid packet @@ -703,7 +787,6 @@ static int ICMPV6DestUnreachTest01(void) */ static int ICMPV6EchoReqTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -713,8 +796,7 @@ static int ICMPV6EchoReqTest01(void) 0x80, 0x00, 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -727,10 +809,7 @@ static int ICMPV6EchoReqTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - goto end; - } + FAIL_IF_NULL(p->icmpv6h); SCLogDebug("ID: %u seq: %u", ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); @@ -739,15 +818,13 @@ static int ICMPV6EchoReqTest01(void) printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); - goto end; + FAIL; } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo reply, valid packet @@ -755,7 +832,6 @@ static int ICMPV6EchoReqTest01(void) */ static int ICMPV6EchoRepTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -766,8 +842,7 @@ static int ICMPV6EchoRepTest01(void) 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -780,10 +855,7 @@ static int ICMPV6EchoRepTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - goto end; - } + FAIL_IF_NULL(p->icmpv6h); SCLogDebug("type: %u code %u ID: %u seq: %u", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p),ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); @@ -793,15 +865,13 @@ static int ICMPV6EchoRepTest01(void) printf("ICMPv6 Echo reply decode failed TYPE %u CODE %u ID %04x(%u) SEQ %04x(%u): ", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ntohs(ICMPV6_GET_ID(p)), ICMPV6_GET_SEQ(p), ntohs(ICMPV6_GET_SEQ(p))); - goto end; + FAIL; } - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: parameter problem, invalid packet @@ -810,7 +880,6 @@ static int ICMPV6EchoRepTest01(void) */ static int ICMPV6ParamProbTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -826,8 +895,7 @@ static int ICMPV6ParamProbTest02(void) 0x80, 0x00, 0x08, 0xb5, 0x99, 0xc3, 0xde, 0x40 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -840,30 +908,14 @@ static int ICMPV6ParamProbTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); + FAIL_IF(ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0); + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER)); - if (ICMPV6_GET_TYPE(p) != 4 || ICMPV6_GET_CODE(p) != 0) { - SCLogDebug("ICMPv6 Not processed at all"); - retval = 0; - goto end; - } - - if (!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER)) { - SCLogDebug("ICMPv6 Error: Unknown embedded ipv6 version event not set"); - retval = 0; - goto end; - } - - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: packet too big, invalid packet @@ -872,7 +924,6 @@ static int ICMPV6ParamProbTest02(void) */ static int ICMPV6PktTooBigTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -887,8 +938,7 @@ static int ICMPV6PktTooBigTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -901,24 +951,13 @@ static int ICMPV6PktTooBigTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->icmpv6h == NULL) { - SCLogDebug("ICMPv6 Unable to detect icmpv6 layer from ipv6"); - retval = 0; - goto end; - } - - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event not set"); - retval = 0; - goto end; - } + FAIL_IF_NULL(p->icmpv6h); + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /** \test icmpv6 message type: time exceed, invalid packet @@ -927,7 +966,6 @@ static int ICMPV6PktTooBigTest02(void) */ static int ICMPV6TimeExceedTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -939,8 +977,7 @@ static int ICMPV6TimeExceedTest02(void) /* The icmpv6 header is broken in the checksum (so we dont have a complete header) */ Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -953,18 +990,12 @@ static int ICMPV6TimeExceedTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_PKT_TOO_SMALL)) { - SCLogDebug("ICMPv6 Error: event packet too small not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_PKT_TOO_SMALL)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: destination unreach, invalid packet @@ -973,7 +1004,6 @@ static int ICMPV6TimeExceedTest02(void) */ static int ICMPV6DestUnreachTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -988,8 +1018,7 @@ static int ICMPV6DestUnreachTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1002,18 +1031,12 @@ static int ICMPV6DestUnreachTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT)) { - SCLogDebug("ICMPv6 Error: embedded ipv6 truncated packet event not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo request, invalid packet @@ -1022,7 +1045,6 @@ static int ICMPV6DestUnreachTest02(void) */ static int ICMPV6EchoReqTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1033,8 +1055,7 @@ static int ICMPV6EchoReqTest02(void) 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1047,18 +1068,12 @@ static int ICMPV6EchoReqTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 message type: echo reply, invalid packet @@ -1067,7 +1082,6 @@ static int ICMPV6EchoReqTest02(void) */ static int ICMPV6EchoRepTest02(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1078,8 +1092,7 @@ static int ICMPV6EchoRepTest02(void) 0xe5, 0xa5, 0x25, 0xf0, 0x75, 0x23 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1092,18 +1105,12 @@ static int ICMPV6EchoRepTest02(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } /**\test icmpv6 packet decoding and setting up of payload_len and payload buufer @@ -1111,7 +1118,6 @@ static int ICMPV6EchoRepTest02(void) */ static int ICMPV6PayloadTest01(void) { - int retval = 0; static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1126,8 +1132,7 @@ static int ICMPV6PayloadTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1140,28 +1145,17 @@ static int ICMPV6PayloadTest01(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (p->payload == NULL) { - printf("payload == NULL, expected non-NULL: "); - goto end; - } + FAIL_IF_NULL(p->payload); + FAIL_IF(p->payload_len != 37); - if (p->payload_len != 37) { - printf("payload_len %"PRIu16", expected 37: ", p->payload_len); - goto end; - } - - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterSolicitTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1172,8 +1166,7 @@ static int ICMPV6RouterSolicitTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1186,24 +1179,16 @@ static int ICMPV6RouterSolicitTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterSolicitTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1214,8 +1199,7 @@ static int ICMPV6RouterSolicitTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1228,24 +1212,16 @@ static int ICMPV6RouterSolicitTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterAdvertTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1256,8 +1232,7 @@ static int ICMPV6RouterAdvertTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1270,24 +1245,16 @@ static int ICMPV6RouterAdvertTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RouterAdvertTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1298,8 +1265,7 @@ static int ICMPV6RouterAdvertTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1312,24 +1278,16 @@ static int ICMPV6RouterAdvertTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourSolicitTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1340,8 +1298,7 @@ static int ICMPV6NeighbourSolicitTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1354,24 +1311,16 @@ static int ICMPV6NeighbourSolicitTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourSolicitTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1382,8 +1331,7 @@ static int ICMPV6NeighbourSolicitTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1396,24 +1344,16 @@ static int ICMPV6NeighbourSolicitTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourAdvertTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1424,8 +1364,7 @@ static int ICMPV6NeighbourAdvertTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1438,24 +1377,16 @@ static int ICMPV6NeighbourAdvertTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6NeighbourAdvertTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1466,8 +1397,7 @@ static int ICMPV6NeighbourAdvertTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1480,24 +1410,16 @@ static int ICMPV6NeighbourAdvertTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RedirectTestKnownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1508,8 +1430,7 @@ static int ICMPV6RedirectTestKnownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1522,24 +1443,16 @@ static int ICMPV6RedirectTestKnownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is set"); - retval = 0; - goto end; - } + FAIL_IF(ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } static int ICMPV6RedirectTestUnknownCode(void) { - int retval = 0; - static uint8_t raw_ipv6[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1550,8 +1463,7 @@ static int ICMPV6RedirectTestUnknownCode(void) }; Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); IPV6Hdr ip6h; ThreadVars tv; DecodeThreadVars dtv; @@ -1564,18 +1476,67 @@ static int ICMPV6RedirectTestUnknownCode(void) FlowInitConfig(FLOW_QUIET); DecodeIPV6(&tv, &dtv, p, raw_ipv6, sizeof(raw_ipv6), NULL); - if (!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) { - SCLogDebug("ICMPv6 Error: Unknown code event is not set"); - retval = 0; - goto end; - } + FAIL_IF(!ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)); + + PACKET_RECYCLE(p); + FlowShutdown(); + SCFree(p); + PASS; +} + +/** + * \test Test for valid ICMPv6 checksum when the FCS is still attached. + * + * Tests that the packet is decoded with sufficient info to verify the + * checksum even if the packet has some trailing data like an ethernet + * FCS. + */ +static int ICMPV6CalculateValidChecksumWithFCS(void) +{ + /* IPV6/ICMPv6 packet with ethernet header. + * - IPv6 payload length: 36 + */ + uint8_t raw_ipv6[] = { + 0x33, 0x33, 0x00, 0x00, 0x00, 0x16, 0x00, 0x50, + 0x56, 0xa6, 0x6a, 0x7d, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0xfe, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x09, + 0xad, 0x44, 0x49, 0x38, 0x5f, 0xa9, 0xff, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x3a, 0x00, + 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, 0x8f, 0x00, + 0x24, 0xe0, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, /* Checksum: 0x24e0. */ + 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfb, 0x1f, 0x34, 0xf6, 0xa4 + }; + uint16_t csum = *(((uint16_t *)(raw_ipv6 + 64))); + + Packet *p = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p); + IPV6Hdr ip6h; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(p, 0, SIZE_OF_PACKET); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&ip6h, 0, sizeof(IPV6Hdr)); + + FlowInitConfig(FLOW_QUIET); + DecodeIPV6(&tv, &dtv, p, raw_ipv6 + 14, sizeof(raw_ipv6) - 14, NULL); + FAIL_IF_NULL(p->icmpv6h); + + uint16_t icmpv6_len = IPV6_GET_RAW_PLEN(p->ip6h) - + ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); + FAIL_IF(icmpv6_len != 28); + FAIL_IF(ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->icmpv6h, icmpv6_len) != csum); - retval = 1; -end: PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return retval; + PASS; } #endif /* UNITTESTS */ @@ -1586,46 +1547,51 @@ static int ICMPV6RedirectTestUnknownCode(void) void DecodeICMPV6RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ICMPV6CalculateValidChecksumtest01", ICMPV6CalculateValidChecksumtest01, 1); - UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", ICMPV6CalculateInvalidChecksumtest02, 0); - - UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01, 1); - UtRegisterTest("ICMPV6DestUnreachTest01 (Valid)", ICMPV6DestUnreachTest01, 1); - UtRegisterTest("ICMPV6PktTooBigTest01 (Valid)", ICMPV6PktTooBigTest01, 1); - UtRegisterTest("ICMPV6TimeExceedTest01 (Valid)", ICMPV6TimeExceedTest01, 1); - UtRegisterTest("ICMPV6EchoReqTest01 (Valid)", ICMPV6EchoReqTest01, 1); - UtRegisterTest("ICMPV6EchoRepTest01 (Valid)", ICMPV6EchoRepTest01, 1); - - UtRegisterTest("ICMPV6ParamProbTest02 (Invalid)", ICMPV6ParamProbTest02, 1); - UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", ICMPV6DestUnreachTest02, 1); - UtRegisterTest("ICMPV6PktTooBigTest02 (Invalid)", ICMPV6PktTooBigTest02, 1); - UtRegisterTest("ICMPV6TimeExceedTest02 (Invalid)", ICMPV6TimeExceedTest02, 1); - UtRegisterTest("ICMPV6EchoReqTest02 (Invalid)", ICMPV6EchoReqTest02, 1); - UtRegisterTest("ICMPV6EchoRepTest02 (Invalid)", ICMPV6EchoRepTest02, 1); - - UtRegisterTest("ICMPV6PayloadTest01", ICMPV6PayloadTest01, 1); + UtRegisterTest("ICMPV6CalculateValidChecksumtest01", + ICMPV6CalculateValidChecksumtest01); + UtRegisterTest("ICMPV6CalculateInValidChecksumtest02", + ICMPV6CalculateInvalidChecksumtest02); + + UtRegisterTest("ICMPV6ParamProbTest01 (Valid)", ICMPV6ParamProbTest01); + UtRegisterTest("ICMPV6DestUnreachTest01 (Valid)", ICMPV6DestUnreachTest01); + UtRegisterTest("ICMPV6PktTooBigTest01 (Valid)", ICMPV6PktTooBigTest01); + UtRegisterTest("ICMPV6TimeExceedTest01 (Valid)", ICMPV6TimeExceedTest01); + UtRegisterTest("ICMPV6EchoReqTest01 (Valid)", ICMPV6EchoReqTest01); + UtRegisterTest("ICMPV6EchoRepTest01 (Valid)", ICMPV6EchoRepTest01); + + UtRegisterTest("ICMPV6ParamProbTest02 (Invalid)", ICMPV6ParamProbTest02); + UtRegisterTest("ICMPV6DestUnreachTest02 (Invalid)", + ICMPV6DestUnreachTest02); + UtRegisterTest("ICMPV6PktTooBigTest02 (Invalid)", ICMPV6PktTooBigTest02); + UtRegisterTest("ICMPV6TimeExceedTest02 (Invalid)", ICMPV6TimeExceedTest02); + UtRegisterTest("ICMPV6EchoReqTest02 (Invalid)", ICMPV6EchoReqTest02); + UtRegisterTest("ICMPV6EchoRepTest02 (Invalid)", ICMPV6EchoRepTest02); + + UtRegisterTest("ICMPV6PayloadTest01", ICMPV6PayloadTest01); UtRegisterTest("ICMPV6RouterSolicitTestKnownCode", - ICMPV6RouterSolicitTestKnownCode, 1); + ICMPV6RouterSolicitTestKnownCode); UtRegisterTest("ICMPV6RouterSolicitTestUnknownCode", - ICMPV6RouterSolicitTestUnknownCode, 1); + ICMPV6RouterSolicitTestUnknownCode); UtRegisterTest("ICMPV6RouterAdvertTestKnownCode", - ICMPV6RouterAdvertTestKnownCode, 1); + ICMPV6RouterAdvertTestKnownCode); UtRegisterTest("ICMPV6RouterAdvertTestUnknownCode", - ICMPV6RouterAdvertTestUnknownCode, 1); + ICMPV6RouterAdvertTestUnknownCode); UtRegisterTest("ICMPV6NeighbourSolicitTestKnownCode", - ICMPV6NeighbourSolicitTestKnownCode, 1); + ICMPV6NeighbourSolicitTestKnownCode); UtRegisterTest("ICMPV6NeighbourSolicitTestUnknownCode", - ICMPV6NeighbourSolicitTestUnknownCode, 1); + ICMPV6NeighbourSolicitTestUnknownCode); UtRegisterTest("ICMPV6NeighbourAdvertTestKnownCode", - ICMPV6NeighbourAdvertTestKnownCode, 1); + ICMPV6NeighbourAdvertTestKnownCode); UtRegisterTest("ICMPV6NeighbourAdvertTestUnknownCode", - ICMPV6NeighbourAdvertTestUnknownCode, 1); + ICMPV6NeighbourAdvertTestUnknownCode); - UtRegisterTest("ICMPV6RedirectTestKnownCode", ICMPV6RedirectTestKnownCode, 1); + UtRegisterTest("ICMPV6RedirectTestKnownCode", ICMPV6RedirectTestKnownCode); UtRegisterTest("ICMPV6RedirectTestUnknownCode", - ICMPV6RedirectTestUnknownCode, 1); + ICMPV6RedirectTestUnknownCode); + UtRegisterTest("ICMPV6CalculateValidChecksumWithFCS", + ICMPV6CalculateValidChecksumWithFCS); #endif /* UNITTESTS */ } /** diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index af97500607f8..eb0b0fd691c8 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -53,6 +53,29 @@ #define ND_NEIGHBOR_ADVERT 136 #define ND_REDIRECT 137 +#define ICMP6_RR 138 +#define ICMP6_NI_QUERY 139 +#define ICMP6_NI_REPLY 140 +#define ND_INVERSE_SOLICIT 141 +#define ND_INVERSE_ADVERT 142 +#define MLD_V2_LIST_REPORT 143 +#define HOME_AGENT_AD_REQUEST 144 +#define HOME_AGENT_AD_REPLY 145 +#define MOBILE_PREFIX_SOLICIT 146 +#define MOBILE_PREFIX_ADVERT 147 +#define CERT_PATH_SOLICIT 148 +#define CERT_PATH_ADVERT 149 +#define ICMP6_MOBILE_EXPERIMENTAL 150 +#define MC_ROUTER_ADVERT 151 +#define MC_ROUTER_SOLICIT 152 +#define MC_ROUTER_TERMINATE 153 +#define FMIPV6_MSG 154 +#define RPL_CONTROL_MSG 155 +#define LOCATOR_UDATE_MSG 156 +#define DUPL_ADDR_REQUEST 157 +#define DUPL_ADDR_CONFIRM 158 +#define MPL_CONTROL_MSG 159 + /** Destination Unreachable Message (type=1) Code: */ #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ @@ -80,6 +103,7 @@ /** macro for icmpv6 "code" access */ #define ICMPV6_GET_CODE(p) (p)->icmpv6h->code /** macro for icmpv6 "csum" access */ +#define ICMPV6_GET_RAW_CSUM(p) ntohs((p)->icmpv6h->csum) #define ICMPV6_GET_CSUM(p) (p)->icmpv6h->csum /** If message is informational */ @@ -158,23 +182,9 @@ typedef struct ICMPV6Vars_ { #define CLEAR_ICMPV6_PACKET(p) do { \ - (p)->level4_comp_csum = -1; \ - (p)->icmpv6vars.id = 0; \ - (p)->icmpv6vars.seq = 0; \ - (p)->icmpv6vars.mtu = 0; \ - (p)->icmpv6vars.error_ptr = 0; \ - (p)->icmpv6vars.emb_ipv6h = NULL; \ - (p)->icmpv6vars.emb_tcph = NULL; \ - (p)->icmpv6vars.emb_udph = NULL; \ - (p)->icmpv6vars.emb_icmpv6h = NULL; \ - (p)->icmpv6vars.emb_ip6_src[0] = 0; \ - (p)->icmpv6vars.emb_ip6_src[1] = 0; \ - (p)->icmpv6vars.emb_ip6_src[2] = 0; \ - (p)->icmpv6vars.emb_ip6_src[3] = 0; \ - (p)->icmpv6vars.emb_ip6_proto_next = 0; \ - (p)->icmpv6vars.emb_sport = 0; \ - (p)->icmpv6vars.emb_dport = 0; \ - (p)->icmpv6h = NULL; \ + (p)->level4_comp_csum = -1; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->icmpv6h = NULL; \ } while(0) void DecodeICMPV6RegisterTests(void); diff --git a/src/decode-ipv4.c b/src/decode-ipv4.c index 5bfb228c8367..3b5ee6494214 100644 --- a/src/decode-ipv4.c +++ b/src/decode-ipv4.c @@ -59,27 +59,27 @@ static int IPV4OptValidateGeneric(Packet *p, const IPV4Opt *o) switch (o->type) { /* See: RFC 4782 */ case IPV4_OPT_QS: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len < IPV4_OPT_QS_MIN) { + if (o->len < IPV4_OPT_QS_MIN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } break; /* See: RFC 1108 */ case IPV4_OPT_SEC: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_SEC_LEN) { + if (o->len != IPV4_OPT_SEC_LEN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } break; case IPV4_OPT_SID: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_SID_LEN) { + if (o->len != IPV4_OPT_SID_LEN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } break; /* See: RFC 2113 */ case IPV4_OPT_RTRALT: - if (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len != IPV4_OPT_RTRALT_LEN) { + if (o->len != IPV4_OPT_RTRALT_LEN) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } @@ -284,15 +284,25 @@ static int IPV4OptValidateCIPSO(Packet *p, const IPV4Opt *o) return 0; } +typedef struct IPV4Options_ { + IPV4Opt o_rr; + IPV4Opt o_qs; + IPV4Opt o_ts; + IPV4Opt o_sec; + IPV4Opt o_lsrr; + IPV4Opt o_cipso; + IPV4Opt o_sid; + IPV4Opt o_ssrr; + IPV4Opt o_rtralt; +} IPV4Options; + /** * Decode/Validate IPv4 Options. */ -static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) +static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len, IPV4Options *opts) { uint16_t plen = len; - p->IPV4_OPTS_CNT = 0; - #ifdef DEBUG if (SCLogDebugEnabled()) { uint16_t i; @@ -314,11 +324,14 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) while (plen) { + p->ip4vars.opt_cnt++; + /* single byte options */ if (*pkt == IPV4_OPT_EOL) { /** \todo What if more data exist after EOL (possible covert channel or data leakage)? */ SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", *pkt, (len - plen), (len - 1)); + p->ip4vars.opts_set |= IPV4_OPT_FLAG_EOL; break; } else if (*pkt == IPV4_OPT_NOP) { SCLogDebug("IPV4OPT %" PRIu16 " len 1 @ %" PRIu16 "/%" PRIu16 "", @@ -326,6 +339,8 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) pkt++; plen--; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_NOP; + /* multibyte options */ } else { if (unlikely(plen < 2)) { @@ -341,133 +356,129 @@ static int DecodeIPV4Options(Packet *p, uint8_t *pkt, uint16_t len) return -1; } - p->IPV4_OPTS[p->IPV4_OPTS_CNT].type = *pkt; - p->IPV4_OPTS[p->IPV4_OPTS_CNT].len = *(pkt+1); - if (plen > 2) - p->IPV4_OPTS[p->IPV4_OPTS_CNT].data = (pkt+2); - else - p->IPV4_OPTS[p->IPV4_OPTS_CNT].data = NULL; - - SCLogDebug("IPV4OPT %" PRIu16 " len %" PRIu16 " @ %" PRIu16 "/%" PRIu16 "", - p->IPV4_OPTS[p->IPV4_OPTS_CNT].type, p->IPV4_OPTS[p->IPV4_OPTS_CNT].len, - (len - plen), (len - 1)); + IPV4Opt opt = {*pkt, *(pkt+1), plen > 2 ? (pkt + 2) : NULL }; /* we already know that the total options len is valid, * so here the len of the specific option must be bad. * Also check for invalid lengths 0 and 1. */ - if (unlikely(p->IPV4_OPTS[p->IPV4_OPTS_CNT].len > plen || - p->IPV4_OPTS[p->IPV4_OPTS_CNT].len < 2)) { + if (unlikely(opt.len > plen || opt.len < 2)) { ENGINE_SET_INVALID_EVENT(p, IPV4_OPT_INVALID_LEN); return -1; } - /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the * time. */ /** \todo Figure out which IP options are more common and list them first */ - switch (p->IPV4_OPTS[p->IPV4_OPTS_CNT].type) { + switch (opt.type) { case IPV4_OPT_TS: - if (p->ip4vars.o_ts != NULL) { + if (opts->o_ts.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateTimestamp(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateTimestamp(p, &opt)) { return -1; } - p->ip4vars.o_ts = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_ts = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_TS; break; case IPV4_OPT_RR: - if (p->ip4vars.o_rr != NULL) { + if (opts->o_rr.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateRoute(p, &opt) != 0) { return -1; } - p->ip4vars.o_rr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_rr = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_RR; break; case IPV4_OPT_QS: - if (p->ip4vars.o_qs != NULL) { + if (opts->o_qs.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_qs = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_qs = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_QS; break; case IPV4_OPT_SEC: - if (p->ip4vars.o_sec != NULL) { + if (opts->o_sec.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_sec = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_sec = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_SEC; break; case IPV4_OPT_LSRR: - if (p->ip4vars.o_lsrr != NULL) { + if (opts->o_lsrr.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateRoute(p, &opt) != 0) { return -1; } - p->ip4vars.o_lsrr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_lsrr = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_LSRR; break; case IPV4_OPT_CIPSO: - if (p->ip4vars.o_cipso != NULL) { + if (opts->o_cipso.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateCIPSO(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateCIPSO(p, &opt) != 0) { return -1; } - p->ip4vars.o_cipso = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_cipso = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_CIPSO; break; case IPV4_OPT_SID: - if (p->ip4vars.o_sid != NULL) { + if (opts->o_sid.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_sid = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_sid = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_SID; break; case IPV4_OPT_SSRR: - if (p->ip4vars.o_ssrr != NULL) { + if (opts->o_ssrr.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateRoute(p,&p->IPV4_OPTS[p->IPV4_OPTS_CNT]) != 0) { + } else if (IPV4OptValidateRoute(p, &opt) != 0) { return -1; } - p->ip4vars.o_ssrr = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_ssrr = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_SSRR; break; case IPV4_OPT_RTRALT: - if (p->ip4vars.o_rtralt != NULL) { + if (opts->o_rtralt.type != 0) { ENGINE_SET_EVENT(p,IPV4_OPT_DUPLICATE); /* Warn - we can keep going */ break; - } else if (IPV4OptValidateGeneric(p, &p->IPV4_OPTS[p->IPV4_OPTS_CNT])) { + } else if (IPV4OptValidateGeneric(p, &opt)) { return -1; } - p->ip4vars.o_rtralt = &p->IPV4_OPTS[p->IPV4_OPTS_CNT]; + opts->o_rtralt = opt; + p->ip4vars.opts_set |= IPV4_OPT_FLAG_RTRALT; break; default: - SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8 "", - p->IPV4_OPTS[p->IPV4_OPTS_CNT].type, - p->IPV4_OPTS[p->IPV4_OPTS_CNT].len); + SCLogDebug("IPV4OPT (%" PRIu8 ") len %" PRIu8, + opt.type, opt.len); ENGINE_SET_EVENT(p,IPV4_OPT_INVALID); /* Warn - we can keep going */ break; } - pkt += p->IPV4_OPTS[p->IPV4_OPTS_CNT].len; - plen -= (p->IPV4_OPTS[p->IPV4_OPTS_CNT].len); - p->IPV4_OPTS_CNT++; + pkt += opt.len; + plen -= opt.len; } } @@ -511,7 +522,9 @@ static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) /* save the options len */ uint8_t ip_opt_len = IPV4_GET_HLEN(p) - IPV4_HEADER_LEN; if (ip_opt_len > 0) { - DecodeIPV4Options(p, pkt + IPV4_HEADER_LEN, ip_opt_len); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + DecodeIPV4Options(p, pkt + IPV4_HEADER_LEN, ip_opt_len, &opts); } return 0; @@ -519,7 +532,7 @@ static int DecodeIPV4Packet(Packet *p, uint8_t *pkt, uint16_t len) int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_ipv4, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_ipv4); SCLogDebug("pkt %p len %"PRIu16"", pkt, len); @@ -583,7 +596,7 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u /* spawn off tunnel packet */ Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p), - IPV4_GET_IPPROTO(p), pq); + DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV4); PacketEnqueue(pq,tp); @@ -609,63 +622,20 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u /* UNITTESTS */ #ifdef UNITTESTS -void DecodeIPV4OptionsPrint(Packet *p) -{ - IPV4Vars *pv = &p->ip4vars; - - printf("DecodeIPV4Options: cnt=%" PRIu8 - ",rr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",qs={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",ts={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",sec={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",lsrr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",cipso={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",sid={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",ssrr={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - ",rtralt={t=%" PRIu8 ",l=%" PRIu8 ",d=%p}" - "}\n", - pv->ip_opt_cnt, - (pv->o_rr ? pv->o_rr->type : 0), (pv->o_rr ? pv->o_rr->len : 0), (pv->o_rr ? pv->o_rr->data : 0), - (pv->o_qs ? pv->o_qs->type : 0), (pv->o_qs ? pv->o_qs->len : 0), (pv->o_qs ? pv->o_qs->data : 0), - (pv->o_ts ? pv->o_ts->type : 0), (pv->o_ts ? pv->o_ts->len : 0), (pv->o_ts ? pv->o_ts->data : 0), - (pv->o_sec ? pv->o_sec->type : 0), (pv->o_sec ? pv->o_sec->len : 0), (pv->o_sec ? pv->o_sec->data : 0), - (pv->o_lsrr ? pv->o_lsrr->type : 0), (pv->o_lsrr ? pv->o_lsrr->len : 0), (pv->o_lsrr ? pv->o_lsrr->data : 0), - (pv->o_cipso ? pv->o_cipso->type : 0), (pv->o_cipso ? pv->o_cipso->len : 0), (pv->o_cipso ? pv->o_cipso->data : 0), - (pv->o_sid ? pv->o_sid->type : 0), (pv->o_sid ? pv->o_sid->len : 0), (pv->o_sid ? pv->o_sid->data : 0), - (pv->o_ssrr ? pv->o_ssrr->type : 0), (pv->o_ssrr ? pv->o_ssrr->len : 0), (pv->o_ssrr ? pv->o_ssrr->data : 0), - (pv->o_rtralt ? pv->o_rtralt->type : 0), (pv->o_rtralt ? pv->o_rtralt->len : 0), (pv->o_rtralt ? pv->o_rtralt->data : 0)); -} - /** \test IPV4 with no options. */ int DecodeIPV4OptionsNONETest01(void) { uint8_t raw_opts[] = { }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - uint8_t *data = (uint8_t *)p; - uint16_t i; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - if (rc != 0) { - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } + FAIL_IF(unlikely(p == NULL)); - for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { - if (*data) { - /* Should not have modified packet data */ - //printf("Data modified at offset %" PRIu16 "\n", i); - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - } + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); SCFree(p); - return 1; + PASS; } /** \test IPV4 with EOL option. */ @@ -675,31 +645,13 @@ int DecodeIPV4OptionsEOLTest01(void) IPV4_OPT_EOL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - uint8_t *data = (uint8_t *)p; - uint16_t i; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - if (rc != 0) { - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - - for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { - if (*data) { - /* Should not have modified packet data */ - //printf("Data modified at offset %" PRIu16 "\n", i); - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - } - + FAIL_IF(unlikely(p == NULL)); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF (rc != 0); SCFree(p); - return 1; + PASS; } /** \test IPV4 with NOP option. */ @@ -709,31 +661,13 @@ int DecodeIPV4OptionsNOPTest01(void) IPV4_OPT_NOP, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - uint8_t *data = (uint8_t *)p; - uint16_t i; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - if (rc != 0) { - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - - for (i = 0; i < (uint16_t)SIZE_OF_PACKET; i++) { - if (*data) { - /* Should not have modified packet data */ - //printf("Data modified at offset %" PRIu16 "\n", i); - DecodeIPV4OptionsPrint(p); - SCFree(p); - return 0; - } - } - + FAIL_IF(unlikely(p == NULL)); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF (rc != 0); SCFree(p); - return 1; + PASS; } /** \test IPV4 with RR option. */ @@ -747,25 +681,15 @@ int DecodeIPV4OptionsRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_RR) - && (p->IPV4_OPTS[0].len == 0x27) - && (p->ip4vars.o_rr == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_rr.type != IPV4_OPT_RR); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RR option (len too large). */ @@ -779,20 +703,15 @@ int DecodeIPV4OptionsRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RR option (ptr too large). */ @@ -806,20 +725,15 @@ int DecodeIPV4OptionsRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RR option (ptr not in 4 byte increment). */ @@ -833,20 +747,15 @@ int DecodeIPV4OptionsRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with QS option. */ @@ -856,25 +765,15 @@ int DecodeIPV4OptionsQSTest01(void) IPV4_OPT_QS, 0x08, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",qs=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_qs, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_QS) - && (p->IPV4_OPTS[0].len == 0x08) - && (p->ip4vars.o_qs == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_qs.type != IPV4_OPT_QS); SCFree(p); - return 0; + PASS; } /** \test IPV4 with QS option (len too small) */ @@ -884,20 +783,15 @@ int DecodeIPV4OptionsQSTest02(void) IPV4_OPT_QS, 0x07, 0x0d, 0x00, 0xbe, 0xef, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",qs=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_qs, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_qs.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option. */ @@ -911,25 +805,15 @@ int DecodeIPV4OptionsTSTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_TS) - && (p->IPV4_OPTS[0].len == 0x24) - && (p->ip4vars.o_ts == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_ts.type != IPV4_OPT_TS); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option (ptr too small). */ @@ -943,20 +827,15 @@ int DecodeIPV4OptionsTSTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ts.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option (ptr too large). */ @@ -970,20 +849,15 @@ int DecodeIPV4OptionsTSTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ts.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with TS option (ptr not valid). */ @@ -997,20 +871,15 @@ int DecodeIPV4OptionsTSTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ts=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ts, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ts.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SEC option. */ @@ -1021,25 +890,15 @@ int DecodeIPV4OptionsSECTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sec=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sec, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_SEC) - && (p->IPV4_OPTS[0].len == 0x0b) - && (p->ip4vars.o_sec == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_sec.type != IPV4_OPT_SEC); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SEC option (invalid length). */ @@ -1050,20 +909,15 @@ int DecodeIPV4OptionsSECTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sec=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sec, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_sec.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option. */ @@ -1077,25 +931,15 @@ int DecodeIPV4OptionsLSRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_LSRR) - && (p->IPV4_OPTS[0].len == 0x27) - && (p->ip4vars.o_lsrr == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_lsrr.type != IPV4_OPT_LSRR); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option (len too large). */ @@ -1109,20 +953,15 @@ int DecodeIPV4OptionsLSRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_lsrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option (ptr too large). */ @@ -1136,20 +975,15 @@ int DecodeIPV4OptionsLSRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_lsrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with LSRR option (ptr not in 4 byte increment). */ @@ -1163,20 +997,15 @@ int DecodeIPV4OptionsLSRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; + FAIL_IF(unlikely(p == NULL)); - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",lsrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_lsrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } - - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_lsrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with CIPSO option. */ @@ -1188,25 +1017,15 @@ int DecodeIPV4OptionsCIPSOTest01(void) 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_cipso, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_CIPSO) - && (p->IPV4_OPTS[0].len == 0x18) - && (p->ip4vars.o_cipso == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_cipso.type != IPV4_OPT_CIPSO); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SID option. */ @@ -1216,25 +1035,15 @@ int DecodeIPV4OptionsSIDTest01(void) IPV4_OPT_SID, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sid=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sid, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_SID) - && (p->IPV4_OPTS[0].len == 0x04) - && (p->ip4vars.o_sid == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_sid.type != IPV4_OPT_SID); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SID option (len invalid. */ @@ -1244,20 +1053,15 @@ int DecodeIPV4OptionsSIDTest02(void) IPV4_OPT_SID, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",sid=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_sid, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_sid.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option. */ @@ -1271,25 +1075,15 @@ int DecodeIPV4OptionsSSRRTest01(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_SSRR) - && (p->IPV4_OPTS[0].len == 0x27) - && (p->ip4vars.o_ssrr == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_ssrr.type != IPV4_OPT_SSRR); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option (len too large). */ @@ -1303,20 +1097,15 @@ int DecodeIPV4OptionsSSRRTest02(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ssrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option (ptr too large). */ @@ -1330,20 +1119,15 @@ int DecodeIPV4OptionsSSRRTest03(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ssrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with SSRR option (ptr not in 4 byte increment). */ @@ -1357,20 +1141,15 @@ int DecodeIPV4OptionsSSRRTest04(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",ssrr=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_ssrr, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_ssrr.type != 0); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RTRALT option. */ @@ -1380,25 +1159,15 @@ int DecodeIPV4OptionsRTRALTTest01(void) IPV4_OPT_RTRALT, 0x04, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rtralt=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rtralt, (uintmax_t)&p.IPV4_OPTS[0]); - if ( (rc == 0) - && (p->IPV4_OPTS_CNT == 1) - && (p->IPV4_OPTS[0].type == IPV4_OPT_RTRALT) - && (p->IPV4_OPTS[0].len == 0x04) - && (p->ip4vars.o_rtralt == &p->IPV4_OPTS[0])) - { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc != 0); + FAIL_IF(opts.o_rtralt.type != IPV4_OPT_RTRALT); SCFree(p); - return 0; + PASS; } /** \test IPV4 with RTRALT option (len invalid. */ @@ -1408,20 +1177,15 @@ int DecodeIPV4OptionsRTRALTTest02(void) IPV4_OPT_RTRALT, 0x05, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - int rc; - - rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts)); - //printf("rc=%d,cnt=%" PRIu16 ",type=%" PRIu8 ",len=%" PRIu8 ",rtralt=%" PRIuMAX "/%" PRIuMAX "\n", rc, p.IPV4_OPTS_CNT, p.IPV4_OPTS[0].type, p.IPV4_OPTS[0].len, (uintmax_t)p.ip4vars.o_rtralt, (uintmax_t)&p.IPV4_OPTS[0]); - if (rc != 0) { - SCFree(p); - return 1; - } + FAIL_IF(unlikely(p == NULL)); - DecodeIPV4OptionsPrint(p); + IPV4Options opts; + memset(&opts, 0x00, sizeof(opts)); + int rc = DecodeIPV4Options(p, raw_opts, sizeof(raw_opts), &opts); + FAIL_IF(rc == 0); + FAIL_IF(opts.o_rtralt.type != 0); SCFree(p); - return 0; + PASS; } static int IPV4CalculateValidChecksumtest01(void) @@ -1435,7 +1199,8 @@ static int IPV4CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_ipv4) + 5); - return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); + FAIL_IF(IPV4Checksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4), csum) != 0); + PASS; } static int IPV4CalculateInvalidChecksumtest02(void) @@ -1449,7 +1214,8 @@ static int IPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_ipv4) + 5); - return (csum == IPV4CalculateChecksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4))); + FAIL_IF(IPV4Checksum((uint16_t *)raw_ipv4, sizeof(raw_ipv4), csum) == 0); + PASS; } /** @@ -1754,7 +1520,6 @@ int DecodeIPV4DefragTest03(void) 0x80, 0x00, 0xb1, 0xa3, 0x00, 0x00 }; - Flow *f = NULL; Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; @@ -1778,12 +1543,11 @@ int DecodeIPV4DefragTest03(void) result = 0; goto end; } - if (p->flow == NULL) { + if (!(p->flags & PKT_WANTS_FLOW)) { printf("packet flow shouldn't be NULL\n"); result = 0; goto end; } - f = p->flow; PACKET_RECYCLE(p); PacketCopyData(p, pkt1, sizeof(pkt1)); @@ -1821,11 +1585,11 @@ int DecodeIPV4DefragTest03(void) result = 0; goto end; } - if (tp->flow == NULL) { + if (!(tp->flags & PKT_WANTS_FLOW)) { result = 0; goto end; } - if (tp->flow != f) { + if (tp->flow_hash != p->flow_hash) { result = 0; goto end; } @@ -1871,41 +1635,44 @@ int DecodeIPV4DefragTest03(void) void DecodeIPV4RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeIPV4OptionsNONETest01", DecodeIPV4OptionsNONETest01, 1); - UtRegisterTest("DecodeIPV4OptionsEOLTest01", DecodeIPV4OptionsEOLTest01, 1); - UtRegisterTest("DecodeIPV4OptionsNOPTest01", DecodeIPV4OptionsNOPTest01, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest01", DecodeIPV4OptionsRRTest01, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest02", DecodeIPV4OptionsRRTest02, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest03", DecodeIPV4OptionsRRTest03, 1); - UtRegisterTest("DecodeIPV4OptionsRRTest04", DecodeIPV4OptionsRRTest04, 1); - UtRegisterTest("DecodeIPV4OptionsQSTest01", DecodeIPV4OptionsQSTest01, 1); - UtRegisterTest("DecodeIPV4OptionsQSTest02", DecodeIPV4OptionsQSTest02, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest01", DecodeIPV4OptionsTSTest01, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest02", DecodeIPV4OptionsTSTest02, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest03", DecodeIPV4OptionsTSTest03, 1); - UtRegisterTest("DecodeIPV4OptionsTSTest04", DecodeIPV4OptionsTSTest04, 1); - UtRegisterTest("DecodeIPV4OptionsSECTest01", DecodeIPV4OptionsSECTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSECTest02", DecodeIPV4OptionsSECTest02, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest01", DecodeIPV4OptionsLSRRTest01, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest02", DecodeIPV4OptionsLSRRTest02, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest03", DecodeIPV4OptionsLSRRTest03, 1); - UtRegisterTest("DecodeIPV4OptionsLSRRTest04", DecodeIPV4OptionsLSRRTest04, 1); - UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", DecodeIPV4OptionsCIPSOTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSIDTest01", DecodeIPV4OptionsSIDTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSIDTest02", DecodeIPV4OptionsSIDTest02, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest01", DecodeIPV4OptionsSSRRTest01, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest02", DecodeIPV4OptionsSSRRTest02, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest03", DecodeIPV4OptionsSSRRTest03, 1); - UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04, 1); - UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", DecodeIPV4OptionsRTRALTTest01, 1); - UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", DecodeIPV4OptionsRTRALTTest02, 1); + UtRegisterTest("DecodeIPV4OptionsNONETest01", DecodeIPV4OptionsNONETest01); + UtRegisterTest("DecodeIPV4OptionsEOLTest01", DecodeIPV4OptionsEOLTest01); + UtRegisterTest("DecodeIPV4OptionsNOPTest01", DecodeIPV4OptionsNOPTest01); + UtRegisterTest("DecodeIPV4OptionsRRTest01", DecodeIPV4OptionsRRTest01); + UtRegisterTest("DecodeIPV4OptionsRRTest02", DecodeIPV4OptionsRRTest02); + UtRegisterTest("DecodeIPV4OptionsRRTest03", DecodeIPV4OptionsRRTest03); + UtRegisterTest("DecodeIPV4OptionsRRTest04", DecodeIPV4OptionsRRTest04); + UtRegisterTest("DecodeIPV4OptionsQSTest01", DecodeIPV4OptionsQSTest01); + UtRegisterTest("DecodeIPV4OptionsQSTest02", DecodeIPV4OptionsQSTest02); + UtRegisterTest("DecodeIPV4OptionsTSTest01", DecodeIPV4OptionsTSTest01); + UtRegisterTest("DecodeIPV4OptionsTSTest02", DecodeIPV4OptionsTSTest02); + UtRegisterTest("DecodeIPV4OptionsTSTest03", DecodeIPV4OptionsTSTest03); + UtRegisterTest("DecodeIPV4OptionsTSTest04", DecodeIPV4OptionsTSTest04); + UtRegisterTest("DecodeIPV4OptionsSECTest01", DecodeIPV4OptionsSECTest01); + UtRegisterTest("DecodeIPV4OptionsSECTest02", DecodeIPV4OptionsSECTest02); + UtRegisterTest("DecodeIPV4OptionsLSRRTest01", DecodeIPV4OptionsLSRRTest01); + UtRegisterTest("DecodeIPV4OptionsLSRRTest02", DecodeIPV4OptionsLSRRTest02); + UtRegisterTest("DecodeIPV4OptionsLSRRTest03", DecodeIPV4OptionsLSRRTest03); + UtRegisterTest("DecodeIPV4OptionsLSRRTest04", DecodeIPV4OptionsLSRRTest04); + UtRegisterTest("DecodeIPV4OptionsCIPSOTest01", + DecodeIPV4OptionsCIPSOTest01); + UtRegisterTest("DecodeIPV4OptionsSIDTest01", DecodeIPV4OptionsSIDTest01); + UtRegisterTest("DecodeIPV4OptionsSIDTest02", DecodeIPV4OptionsSIDTest02); + UtRegisterTest("DecodeIPV4OptionsSSRRTest01", DecodeIPV4OptionsSSRRTest01); + UtRegisterTest("DecodeIPV4OptionsSSRRTest02", DecodeIPV4OptionsSSRRTest02); + UtRegisterTest("DecodeIPV4OptionsSSRRTest03", DecodeIPV4OptionsSSRRTest03); + UtRegisterTest("DecodeIPV4OptionsSSRRTest04", DecodeIPV4OptionsSSRRTest04); + UtRegisterTest("DecodeIPV4OptionsRTRALTTest01", + DecodeIPV4OptionsRTRALTTest01); + UtRegisterTest("DecodeIPV4OptionsRTRALTTest02", + DecodeIPV4OptionsRTRALTTest02); UtRegisterTest("IPV4CalculateValidChecksumtest01", - IPV4CalculateValidChecksumtest01, 1); + IPV4CalculateValidChecksumtest01); UtRegisterTest("IPV4CalculateInvalidChecksumtest02", - IPV4CalculateInvalidChecksumtest02, 0); - UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01, 1); - UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02, 1); - UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03, 1); + IPV4CalculateInvalidChecksumtest02); + UtRegisterTest("DecodeIPV4DefragTest01", DecodeIPV4DefragTest01); + UtRegisterTest("DecodeIPV4DefragTest02", DecodeIPV4DefragTest02); + UtRegisterTest("DecodeIPV4DefragTest03", DecodeIPV4DefragTest03); #endif /* UNITTESTS */ } /** diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index be212bf2fadb..c8f268d054e5 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -151,61 +151,54 @@ typedef struct IPV4Hdr_ #define CLEAR_IPV4_PACKET(p) do { \ (p)->ip4h = NULL; \ (p)->level3_comp_csum = -1; \ - (p)->ip4vars.ip_src_u32 = 0; \ - (p)->ip4vars.ip_dst_u32 = 0; \ - (p)->ip4vars.ip_opt_cnt = 0; \ - (p)->ip4vars.o_rr = NULL; \ - (p)->ip4vars.o_qs = NULL; \ - (p)->ip4vars.o_ts = NULL; \ - (p)->ip4vars.o_sec = NULL; \ - (p)->ip4vars.o_lsrr = NULL; \ - (p)->ip4vars.o_cipso = NULL; \ - (p)->ip4vars.o_sid = NULL; \ - (p)->ip4vars.o_ssrr = NULL; \ - (p)->ip4vars.o_rtralt = NULL; \ + memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \ } while (0) +enum IPV4OptionFlags { + IPV4_OPT_FLAG_EOL = 0, + IPV4_OPT_FLAG_NOP, + IPV4_OPT_FLAG_RR, + IPV4_OPT_FLAG_TS, + IPV4_OPT_FLAG_QS, + IPV4_OPT_FLAG_LSRR, + IPV4_OPT_FLAG_SSRR, + IPV4_OPT_FLAG_SID, + IPV4_OPT_FLAG_SEC, + IPV4_OPT_FLAG_CIPSO, + IPV4_OPT_FLAG_RTRALT, +}; + /* helper structure with parsed ipv4 info */ typedef struct IPV4Vars_ { int32_t comp_csum; /* checksum computed over the ipv4 packet */ - uint32_t ip_src_u32; /* source IP */ - uint32_t ip_dst_u32; /* dest IP */ - - IPV4Opt ip_opts[IPV4_OPTMAX]; - uint8_t ip_opt_cnt; - - /* These are here for direct access and dup tracking */ - IPV4Opt *o_rr; - IPV4Opt *o_qs; - IPV4Opt *o_ts; - IPV4Opt *o_sec; - IPV4Opt *o_lsrr; - IPV4Opt *o_cipso; - IPV4Opt *o_sid; - IPV4Opt *o_ssrr; - IPV4Opt *o_rtralt; + + uint16_t opt_cnt; + uint16_t opts_set; } IPV4Vars; void DecodeIPV4RegisterTests(void); /** ----- Inline functions ----- */ -static inline uint16_t IPV4CalculateChecksum(uint16_t *, uint16_t); +static inline uint16_t IPV4Checksum(uint16_t *, uint16_t, uint16_t); + /** - * \brief Calculates the checksum for the IP packet + * \brief Calculateor validate the checksum for the IP packet * * \param pkt Pointer to the start of the IP packet * \param hlen Length of the IP header + * \param init The current checksum if validating, 0 if generating. * - * \retval csum Checksum for the IP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ -static inline uint16_t IPV4CalculateChecksum(uint16_t *pkt, uint16_t hlen) +static inline uint16_t IPV4Checksum(uint16_t *pkt, uint16_t hlen, uint16_t init) { - uint32_t csum = pkt[0]; + uint32_t csum = init; - csum += pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + pkt[8] + - pkt[9]; + csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + + pkt[8] + pkt[9]; hlen -= 20; pkt += 10; diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index 111810bd9766..ac0ad752ba2a 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -60,12 +60,12 @@ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, u } if (IP_GET_RAW_VER(pkt) == 4) { if (pq != NULL) { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, IPPROTO_IP, pq); + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV4, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_ipv4inipv6); return; } } @@ -88,11 +88,11 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint } if (IP_GET_RAW_VER(pkt) == 6) { if (unlikely(pq != NULL)) { - Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, IPPROTO_IPV6, pq); + Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_ipv6inipv6, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_ipv6inipv6); } } } else { @@ -101,6 +101,49 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint return TM_ECODE_OK; } +#ifndef UNITTESTS // ugly, but we need this in defrag tests +static inline +#endif +void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, + uint16_t hdrextlen, uint16_t plen, + uint16_t prev_hdrextlen) +{ + uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; + int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; + + p->ip6eh.fh_offset = frag_offset; + p->ip6eh.fh_more_frags_set = frag_morefrags ? TRUE : FALSE; + p->ip6eh.fh_nh = *pkt; + + uint32_t fh_id; + memcpy(&fh_id, pkt+4, 4); + p->ip6eh.fh_id = ntohl(fh_id); + + SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", + p->ip6eh.fh_offset, + p->ip6eh.fh_more_frags_set ? "true" : "false", + p->ip6eh.fh_nh, + p->ip6eh.fh_id, p->ip6eh.fh_id); + + // store header offset, data offset + uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p)); + uint16_t data_offset = (uint16_t)(frag_hdr_offset + hdrextlen); + uint16_t data_len = plen - hdrextlen; + + p->ip6eh.fh_header_offset = frag_hdr_offset; + p->ip6eh.fh_data_offset = data_offset; + p->ip6eh.fh_data_len = data_len; + + /* if we have a prev hdr, store the type and offset of it */ + if (prev_hdrextlen) { + p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - prev_hdrextlen; + } + + SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", + p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, + p->ip6eh.fh_data_len); +} + static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { @@ -108,10 +151,14 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt uint8_t *orig_pkt = pkt; uint8_t nh = 0; /* careful, 0 is actually a real type */ - uint16_t hdrextlen; + uint16_t hdrextlen = 0; uint16_t plen; char dstopts = 0; char exthdr_fh_done = 0; + int hh = 0; + int rh = 0; + int eh = 0; + int ah = 0; nh = IPV6_GET_NH(p); plen = len; @@ -161,16 +208,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if (p->IPV6_EH_CNT < IPV6_MAX_OPT) - { - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; - } - - if (IPV6_EXTHDR_ISSET_RH(p)) { + if (rh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH); /* skip past this extension so we can continue parsing the rest * of the packet */ @@ -180,26 +218,14 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - IPV6_EXTHDR_SET_RH(p, pkt); - - /** \todo move into own function and load on demand */ - if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) { -#if 0 // XXX usused and broken, original packet is modified in the memcpy - uint8_t i; - - uint8_t n = hdrextlen / 2; - /* because we devide the header len by 2 (as rfc 2460 tells us to) - * we devide the result by 8 and not 16 as the header fields are - * sized */ - for (i = 0; i < (n/8) && i < sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr)/sizeof(struct in6_addr); ++i) { - /* the address header fields are 16 bytes in size */ - /** \todo do this without memcpy since it's expensive */ - memcpy(&IPV6_EXTHDR_RH(p)->ip6rh0_addr[i], pkt+(i*16)+8, sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr[i])); - } - IPV6_EXTHDR_RH(p)->ip6rh0_num_addrs = i; -#endif + rh = 1; + IPV6_EXTHDR_SET_RH(p); + + uint8_t ip6rh_type = *(pkt + 2); + if (ip6rh_type == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_RH_TYPE_0); } + p->ip6eh.rh_type = ip6rh_type; nh = *pkt; pkt += hdrextlen; @@ -209,9 +235,9 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: { - IPV6OptHAO *hao = NULL; - IPV6OptRA *ra = NULL; - IPV6OptJumbo *jumbo = NULL; + IPV6OptHAO hao_s, *hao = &hao_s; + IPV6OptRA ra_s, *ra = &ra_s; + IPV6OptJumbo jumbo_s, *jumbo = &jumbo_s; uint16_t optslen = 0; IPV6_SET_L4PROTO(p,nh); @@ -221,21 +247,12 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if (p->IPV6_EH_CNT < IPV6_MAX_OPT) - { - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; - } - uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */ /* point the pointers to right structures * in Packet. */ if (nh == IPPROTO_HOPOPTS) { - if (IPV6_EXTHDR_ISSET_HH(p)) { + if (hh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH); /* skip past this extension so we can continue parsing the rest * of the packet */ @@ -245,28 +262,17 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - IPV6_EXTHDR_SET_HH(p, pkt); - hao = &IPV6_EXTHDR_HH_HAO(p); - ra = &IPV6_EXTHDR_HH_RA(p); - jumbo = &IPV6_EXTHDR_HH_JUMBO(p); + hh = 1; - optslen = ((IPV6_EXTHDR_HH(p)->ip6hh_len+1)<<3)-2; + optslen = ((*(pkt + 1) + 1 ) << 3) - 2; } else if (nh == IPPROTO_DSTOPTS) { if (dstopts == 0) { - IPV6_EXTHDR_SET_DH1(p, pkt); - hao = &IPV6_EXTHDR_DH1_HAO(p); - ra = &IPV6_EXTHDR_DH1_RA(p); - jumbo = &IPV6_EXTHDR_DH2_JUMBO(p); - optslen = ((IPV6_EXTHDR_DH1(p)->ip6dh_len+1)<<3)-2; + optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 1; } else if (dstopts == 1) { - IPV6_EXTHDR_SET_DH2(p, pkt); - hao = &IPV6_EXTHDR_DH2_HAO(p); - ra = &IPV6_EXTHDR_DH2_RA(p); - jumbo = &IPV6_EXTHDR_DH2_JUMBO(p); - optslen = ((IPV6_EXTHDR_DH2(p)->ip6dh_len+1)<<3)-2; + optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 2; } else { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH); @@ -403,6 +409,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt } case IPPROTO_FRAGMENT: + { IPV6_SET_L4PROTO(p,nh); /* store the offset of this extension into the packet * past the ipv6 header. We use it in defrag for creating @@ -412,6 +419,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt exthdr_fh_done = 1; } + uint16_t prev_hdrextlen = hdrextlen; hdrextlen = sizeof(IPV6FragHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); @@ -424,15 +432,6 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* non fatal, lets try to continue */ } - if(p->IPV6_EH_CNTIPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; - } - if (IPV6_EXTHDR_ISSET_FH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_FH); nh = *pkt; @@ -441,14 +440,17 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - /* set the header ptr first */ - IPV6_EXTHDR_SET_FH(p, pkt); + /* set the header flag first */ + IPV6_EXTHDR_SET_FH(p); + + /* parse the header and setup the vars */ + DecodeIPV6FragHeader(p, pkt, hdrextlen, plen, prev_hdrextlen); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ - if (IPV6_EXTHDR_GET_FH_FLAG(p) == 0 && IPV6_EXTHDR_GET_FH_OFFSET(p) == 0) { + if (p->ip6eh.fh_more_frags_set == 0 && p->ip6eh.fh_offset == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; @@ -460,7 +462,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* the rest is parsed upon reassembly */ p->flags |= PKT_IS_FRAGMENT; SCReturn; - + } case IPPROTO_ESP: { IPV6_SET_L4PROTO(p,nh); @@ -470,21 +472,12 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt SCReturn; } - if(p->IPV6_EH_CNTIPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = IPPROTO_NONE; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; - } - - if (IPV6_EXTHDR_ISSET_EH(p)) { + if (eh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); SCReturn; } - IPV6_EXTHDR_SET_EH(p, pkt); + eh = 1; nh = IPPROTO_NONE; pkt += hdrextlen; @@ -513,16 +506,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL); } - if(p->IPV6_EH_CNT < IPV6_MAX_OPT) - { - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; - p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; - p->IPV6_EH_CNT++; - } - - if (IPV6_EXTHDR_ISSET_AH(p)) { + if (ah) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH); nh = *pkt; pkt += hdrextlen; @@ -530,7 +514,7 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; } - IPV6_EXTHDR_SET_AH(p, pkt); + ah = 1; nh = *pkt; pkt += hdrextlen; @@ -601,7 +585,7 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { int ret; - SCPerfCounterIncr(dtv->counter_ipv6, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_ipv6); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); @@ -677,30 +661,6 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u } } -#ifdef DEBUG - if (IPV6_EXTHDR_ISSET_FH(p)) { - SCLogDebug("IPV6 FRAG - HDRLEN: %" PRIuMAX " NH: %" PRIu32 " OFFSET: %" PRIu32 " ID: %" PRIu32 "", - (uintmax_t)IPV6_EXTHDR_GET_FH_HDRLEN(p), IPV6_EXTHDR_GET_FH_NH(p), - IPV6_EXTHDR_GET_FH_OFFSET(p), IPV6_EXTHDR_GET_FH_ID(p)); - } - if (IPV6_EXTHDR_ISSET_RH(p)) { - SCLogDebug("IPV6 ROUTE - HDRLEN: %" PRIu32 " NH: %" PRIu32 " TYPE: %" PRIu32 "", - IPV6_EXTHDR_GET_RH_HDRLEN(p), IPV6_EXTHDR_GET_RH_NH(p), - IPV6_EXTHDR_GET_RH_TYPE(p)); - } - if (IPV6_EXTHDR_ISSET_HH(p)) { - SCLogDebug("IPV6 HOPOPT - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", - IPV6_EXTHDR_GET_HH_HDRLEN(p), IPV6_EXTHDR_GET_HH_NH(p)); - } - if (IPV6_EXTHDR_ISSET_DH1(p)) { - SCLogDebug("IPV6 DSTOPT1 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", - IPV6_EXTHDR_GET_DH1_HDRLEN(p), IPV6_EXTHDR_GET_DH1_NH(p)); - } - if (IPV6_EXTHDR_ISSET_DH2(p)) { - SCLogDebug("IPV6 DSTOPT2 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", - IPV6_EXTHDR_GET_DH2_HDRLEN(p), IPV6_EXTHDR_GET_DH2_NH(p)); - } -#endif return TM_ECODE_OK; } @@ -879,7 +839,6 @@ static int DecodeIPV6FragTest01 (void) */ static int DecodeIPV6RouteTest01 (void) { - uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x2b, 0x40, 0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00, @@ -893,11 +852,9 @@ static int DecodeIPV6RouteTest01 (void) 0xfa, 0x87, 0x00, 0x00, }; Packet *p1 = PacketGetFromAlloc(); - if (unlikely(p1 == NULL)) - return 0; + FAIL_IF(unlikely(p1 == NULL)); ThreadVars tv; DecodeThreadVars dtv; - int result = 0; PacketQueue pq; FlowInitConfig(FLOW_QUIET); @@ -910,22 +867,12 @@ static int DecodeIPV6RouteTest01 (void) DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1), &pq); - if (!(IPV6_EXTHDR_ISSET_RH(p1))) { - printf("ipv6 routing header not detected: "); - goto end; - } - - if (p1->ip6eh.ip6_exthdrs[0].len != 8) { - printf("ipv6 routing length incorrect: "); - goto end; - } - - result = 1; -end: + FAIL_IF (!(IPV6_EXTHDR_ISSET_RH(p1))); + FAIL_IF (p1->ip6eh.rh_type != 0); PACKET_RECYCLE(p1); SCFree(p1); FlowShutdown(); - return result; + PASS; } /** @@ -936,16 +883,15 @@ static int DecodeIPV6HopTest01 (void) uint8_t raw_pkt1[] = { 0x60,0x00,0x00,0x00,0x00,0x20,0x00,0x01,0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x0f,0xfe,0xff,0xfe,0x98,0x3d,0x01,0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x3a,0x00,0x05,0x02,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x3a,0x00,0xff, /* 0xff is a nonsene opt */ + 0x02,0x00,0x00,0x00,0x00, 0x82,0x00,0x1c,0x6f,0x27,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; Packet *p1 = PacketGetFromAlloc(); - if (unlikely(p1 == NULL)) - return 0; + FAIL_IF(unlikely(p1 == NULL)); ThreadVars tv; DecodeThreadVars dtv; - int result = 0; PacketQueue pq; FlowInitConfig(FLOW_QUIET); @@ -958,27 +904,12 @@ static int DecodeIPV6HopTest01 (void) DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1), &pq); - if (!(IPV6_EXTHDR_ISSET_HH(p1))) { - printf("ipv6 routing header not detected: "); - goto end; - } + FAIL_IF (!(ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT))); - if (p1->ip6eh.ip6_exthdrs[0].len != 8) { - printf("ipv6 routing length incorrect: "); - goto end; - } - - if (ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT)) { - printf("engine event IPV6_HOPOPTS_UNKNOWN_OPT set: "); - goto end; - } - - result = 1; -end: PACKET_RECYCLE(p1); SCFree(p1); FlowShutdown(); - return result; + PASS; } #endif /* UNITTESTS */ @@ -990,9 +921,9 @@ static int DecodeIPV6HopTest01 (void) void DecodeIPV6RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeIPV6FragTest01", DecodeIPV6FragTest01, 1); - UtRegisterTest("DecodeIPV6RouteTest01", DecodeIPV6RouteTest01, 1); - UtRegisterTest("DecodeIPV6HopTest01", DecodeIPV6HopTest01, 1); + UtRegisterTest("DecodeIPV6FragTest01", DecodeIPV6FragTest01); + UtRegisterTest("DecodeIPV6RouteTest01", DecodeIPV6RouteTest01); + UtRegisterTest("DecodeIPV6HopTest01", DecodeIPV6HopTest01); #endif /* UNITTESTS */ } diff --git a/src/decode-ipv6.h b/src/decode-ipv6.h index da58d9e2b384..c30580cbf4b1 100644 --- a/src/decode-ipv6.h +++ b/src/decode-ipv6.h @@ -109,14 +109,7 @@ typedef struct IPV6Vars_ (p)->ip6h = NULL; \ (p)->ip6vars.ip_opts_len = 0; \ (p)->ip6vars.l4proto = 0; \ - (p)->ip6eh.ip6fh = NULL; \ - (p)->ip6eh.fh_offset = 0; \ - (p)->ip6eh.ip6rh = NULL; \ - (p)->ip6eh.ip6eh = NULL; \ - (p)->ip6eh.ip6dh1 = NULL; \ - (p)->ip6eh.ip6dh2 = NULL; \ - (p)->ip6eh.ip6hh = NULL; \ - (p)->ip6eh.ip6_exthdrs_cnt = 0; \ + memset(&(p)->ip6eh, 0x00, sizeof((p)->ip6eh)); \ } while (0) /* Fragment header */ @@ -128,17 +121,10 @@ typedef struct IPV6FragHdr_ uint32_t ip6fh_ident; /* identification */ } __attribute__((__packed__)) IPV6FragHdr; -#define IPV6_EXTHDR_GET_RAW_FH_NH(p) ((p)->ip6eh.ip6fh->ip6fh_nxt) -#define IPV6_EXTHDR_GET_RAW_FH_HDRLEN(p) sizeof(IPV6FragHdr) -#define IPV6_EXTHDR_GET_RAW_FH_OFFSET(p) (ntohs((p)->ip6eh.ip6fh->ip6fh_offlg) & 0xFFF8) -#define IPV6_EXTHDR_GET_RAW_FH_FLAG(p) (ntohs((p)->ip6eh.ip6fh->ip6fh_offlg) & 0x0001) -#define IPV6_EXTHDR_GET_RAW_FH_ID(p) (ntohl((p)->ip6eh.ip6fh->ip6fh_ident)) - -#define IPV6_EXTHDR_GET_FH_NH(p) IPV6_EXTHDR_GET_RAW_FH_NH((p)) -#define IPV6_EXTHDR_GET_FH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_FH_HDRLEN((p)) -#define IPV6_EXTHDR_GET_FH_OFFSET(p) IPV6_EXTHDR_GET_RAW_FH_OFFSET((p)) -#define IPV6_EXTHDR_GET_FH_FLAG(p) IPV6_EXTHDR_GET_RAW_FH_FLAG((p)) -#define IPV6_EXTHDR_GET_FH_ID(p) IPV6_EXTHDR_GET_RAW_FH_ID((p)) +#define IPV6_EXTHDR_GET_FH_NH(p) (p)->ip6eh.fh_nh +#define IPV6_EXTHDR_GET_FH_OFFSET(p) (p)->ip6eh.fh_offset +#define IPV6_EXTHDR_GET_FH_FLAG(p) (p)->ip6eh.fh_more_frags_set +#define IPV6_EXTHDR_GET_FH_ID(p) (p)->ip6eh.fh_id /* rfc 1826 */ typedef struct IPV6AuthHdr_ @@ -164,24 +150,8 @@ typedef struct IPV6RouteHdr_ including first 8 bytes. */ uint8_t ip6rh_type; /* routing type */ uint8_t ip6rh_segsleft; /* segments left */ -#if 0 - struct in6_addr ip6rh0_addr[23]; /* type 0 addresses */ - uint8_t ip6rh0_num_addrs; /* number of actual addresses in the - array/packet. The array is guarranteed - to be filled up to this number. */ -#endif } __attribute__((__packed__)) IPV6RouteHdr; -#define IPV6_EXTHDR_GET_RAW_RH_NH(p) ((p)->ip6eh.ip6rh->ip6rh_nxt) -#define IPV6_EXTHDR_GET_RAW_RH_HDRLEN(p) ((p)->ip6eh.ip6rh->ip6rh_len) -#define IPV6_EXTHDR_GET_RAW_RH_TYPE(p) (ntohs((p)->ip6eh.ip6rh->ip6rh_type)) -/* XXX */ - -#define IPV6_EXTHDR_GET_RH_NH(p) IPV6_EXTHDR_GET_RAW_RH_NH((p)) -#define IPV6_EXTHDR_GET_RH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_RH_HDRLEN((p)) -#define IPV6_EXTHDR_GET_RH_TYPE(p) IPV6_EXTHDR_GET_RAW_RH_TYPE((p)) -/* XXX */ - /* Hop-by-Hop header and Destination Options header use options that are * defined here. */ @@ -223,14 +193,6 @@ typedef struct IPV6HopOptsHdr_ including first 8 bytes. */ } __attribute__((__packed__)) IPV6HopOptsHdr; -#define IPV6_EXTHDR_GET_RAW_HH_NH(p) ((p)->ip6eh.ip6hh->ip6hh_nxt) -#define IPV6_EXTHDR_GET_RAW_HH_HDRLEN(p) ((p)->ip6eh.ip6hh->ip6hh_len) -/* XXX */ - -#define IPV6_EXTHDR_GET_HH_NH(p) IPV6_EXTHDR_GET_RAW_HH_NH((p)) -#define IPV6_EXTHDR_GET_HH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_HH_HDRLEN((p)) -/* XXX */ - typedef struct IPV6DstOptsHdr_ { uint8_t ip6dh_nxt; /* next header */ @@ -238,22 +200,6 @@ typedef struct IPV6DstOptsHdr_ including first 8 bytes. */ } __attribute__((__packed__)) IPV6DstOptsHdr; -#define IPV6_EXTHDR_GET_RAW_DH1_NH(p) ((p)->ip6eh.ip6dh1->ip6dh_nxt) -#define IPV6_EXTHDR_GET_RAW_DH1_HDRLEN(p) ((p)->ip6eh.ip6dh1->ip6dh_len) -/* XXX */ - -#define IPV6_EXTHDR_GET_DH1_NH(p) IPV6_EXTHDR_GET_RAW_DH1_NH((p)) -#define IPV6_EXTHDR_GET_DH1_HDRLEN(p) IPV6_EXTHDR_GET_RAW_DH1_HDRLEN((p)) -/* XXX */ - -#define IPV6_EXTHDR_GET_RAW_DH2_NH(p) ((p)->ip6eh.ip6dh2->ip6dh_nxt) -#define IPV6_EXTHDR_GET_RAW_DH2_HDRLEN(p) ((p)->ip6eh.ip6dh2->ip6dh_len) -/* XXX */ - -#define IPV6_EXTHDR_GET_DH2_NH(p) IPV6_EXTHDR_GET_RAW_DH2_NH((p)) -#define IPV6_EXTHDR_GET_DH2_HDRLEN(p) IPV6_EXTHDR_GET_RAW_DH2_HDRLEN((p)) -/* XXX */ - typedef struct IPV6GenOptHdr_ { uint8_t type; @@ -264,69 +210,32 @@ typedef struct IPV6GenOptHdr_ typedef struct IPV6ExtHdrs_ { - const IPV6FragHdr *ip6fh; + _Bool rh_set; + uint8_t rh_type; + + _Bool fh_set; + _Bool fh_more_frags_set; + uint8_t fh_nh; + + uint8_t fh_prev_nh; + uint16_t fh_prev_hdr_offset; + + uint16_t fh_header_offset; + uint16_t fh_data_offset; + uint16_t fh_data_len; + /* In fh_offset we store the offset of this extension into the packet past * the ipv6 header. We use it in defrag for creating a defragmented packet * without the frag header */ - uint16_t fh_offset; - - const IPV6RouteHdr *ip6rh; - const IPV6AuthHdr *ip6ah; - const IPV6EspHdr *ip6eh; - const IPV6DstOptsHdr *ip6dh1; - const IPV6DstOptsHdr *ip6dh2; - const IPV6HopOptsHdr *ip6hh; - - /* Hop-By-Hop options */ - IPV6OptHAO ip6hh_opt_hao; - IPV6OptRA ip6hh_opt_ra; - IPV6OptJumbo ip6hh_opt_jumbo; - /* Dest Options 1 */ - IPV6OptHAO ip6dh1_opt_hao; - IPV6OptRA ip6dh1_opt_ra; - IPV6OptJumbo ip6dh1_opt_jumbo; - /* Dest Options 2 */ - IPV6OptHAO ip6dh2_opt_hao; - IPV6OptRA ip6dh2_opt_ra; - IPV6OptJumbo ip6dh2_opt_jumbo; - - IPV6GenOptHdr ip6_exthdrs[IPV6_MAX_OPT]; - uint8_t ip6_exthdrs_cnt; + uint16_t fh_offset; + uint32_t fh_id; } IPV6ExtHdrs; -#define IPV6_EXTHDR_FH(p) (p)->ip6eh.ip6fh -#define IPV6_EXTHDR_RH(p) (p)->ip6eh.ip6rh -#define IPV6_EXTHDR_AH(p) (p)->ip6eh.ip6ah -#define IPV6_EXTHDR_EH(p) (p)->ip6eh.ip6eh -#define IPV6_EXTHDR_DH1(p) (p)->ip6eh.ip6dh1 -#define IPV6_EXTHDR_DH2(p) (p)->ip6eh.ip6dh2 -#define IPV6_EXTHDR_HH(p) (p)->ip6eh.ip6hh - -#define IPV6_EXTHDR_HH_HAO(p) (p)->ip6eh.ip6hh_opt_hao -#define IPV6_EXTHDR_DH1_HAO(p) (p)->ip6eh.ip6dh1_opt_hao -#define IPV6_EXTHDR_DH2_HAO(p) (p)->ip6eh.ip6dh2_opt_hao -#define IPV6_EXTHDR_HH_RA(p) (p)->ip6eh.ip6hh_opt_ra -#define IPV6_EXTHDR_DH1_RA(p) (p)->ip6eh.ip6dh1_opt_ra -#define IPV6_EXTHDR_DH2_RA(p) (p)->ip6eh.ip6dh2_opt_ra -#define IPV6_EXTHDR_HH_JUMBO(p) (p)->ip6eh.ip6hh_opt_jumbo -#define IPV6_EXTHDR_DH1_JUMBO(p) (p)->ip6eh.ip6dh1_opt_jumbo -#define IPV6_EXTHDR_DH2_JUMBO(p) (p)->ip6eh.ip6dh2_opt_jumbo - -#define IPV6_EXTHDR_SET_FH(p,pkt) IPV6_EXTHDR_FH((p)) = (IPV6FragHdr *)pkt -#define IPV6_EXTHDR_ISSET_FH(p) (IPV6_EXTHDR_FH((p)) != NULL) -#define IPV6_EXTHDR_SET_RH(p,pkt) IPV6_EXTHDR_RH((p)) = (IPV6RouteHdr *)pkt -#define IPV6_EXTHDR_ISSET_RH(p) (IPV6_EXTHDR_RH((p)) != NULL) -#define IPV6_EXTHDR_SET_AH(p,pkt) IPV6_EXTHDR_AH((p)) = (IPV6AuthHdr *)pkt -#define IPV6_EXTHDR_ISSET_AH(p) (IPV6_EXTHDR_AH((p)) != NULL) -#define IPV6_EXTHDR_SET_EH(p,pkt) IPV6_EXTHDR_EH((p)) = (IPV6EspHdr *)pkt -#define IPV6_EXTHDR_ISSET_EH(p) (IPV6_EXTHDR_EH((p)) != NULL) -#define IPV6_EXTHDR_SET_DH1(p,pkt) IPV6_EXTHDR_DH1((p)) = (IPV6DstOptsHdr *)pkt -#define IPV6_EXTHDR_ISSET_DH1(p) (IPV6_EXTHDR_DH1((p)) != NULL) -#define IPV6_EXTHDR_SET_DH2(p,pkt) IPV6_EXTHDR_DH2((p)) = (IPV6DstOptsHdr *)pkt -#define IPV6_EXTHDR_ISSET_DH2(p) (IPV6_EXTHDR_DH2((p)) != NULL) -#define IPV6_EXTHDR_SET_HH(p,pkt) IPV6_EXTHDR_HH((p)) = (IPV6HopOptsHdr *)pkt -#define IPV6_EXTHDR_ISSET_HH(p) (IPV6_EXTHDR_HH((p)) != NULL) +#define IPV6_EXTHDR_SET_FH(p) (p)->ip6eh.fh_set = TRUE +#define IPV6_EXTHDR_ISSET_FH(p) (p)->ip6eh.fh_set +#define IPV6_EXTHDR_SET_RH(p) (p)->ip6eh.rh_set = TRUE +#define IPV6_EXTHDR_ISSET_RH(p) (p)->ip6eh.rh_set void DecodeIPV6RegisterTests(void); diff --git a/src/decode-mpls.c b/src/decode-mpls.c index 86188502031b..815592e1ff58 100644 --- a/src/decode-mpls.c +++ b/src/decode-mpls.c @@ -51,7 +51,7 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, int label; int event = 0; - SCPerfCounterIncr(dtv->counter_mpls, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { @@ -312,14 +312,14 @@ void DecodeMPLSRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DecodeMPLSTestHeaderTooSmall", - DecodeMPLSTestHeaderTooSmall, 1); + DecodeMPLSTestHeaderTooSmall); UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert", - DecodeMPLSTestBadLabelRouterAlert, 1); + DecodeMPLSTestBadLabelRouterAlert); UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull", - DecodeMPLSTestBadLabelImplicitNull, 1); + DecodeMPLSTestBadLabelImplicitNull); UtRegisterTest("DecodeMPLSTestBadLabelReserved", - DecodeMPLSTestBadLabelReserved, 1); + DecodeMPLSTestBadLabelReserved); UtRegisterTest("DecodeMPLSTestUnknownPayloadType", - DecodeMPLSTestUnknownPayloadType, 1); + DecodeMPLSTestUnknownPayloadType); #endif /* UNITTESTS */ } diff --git a/src/decode-null.c b/src/decode-null.c new file mode 100644 index 000000000000..b3bcb0667c21 --- /dev/null +++ b/src/decode-null.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup decode + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Decode linkype null: + * http://www.tcpdump.org/linktypes.html + */ + +#include "suricata-common.h" +#include "decode.h" +#include "decode-raw.h" +#include "decode-events.h" + +#include "util-unittest.h" +#include "util-debug.h" + +#include "pkt-var.h" +#include "util-profiling.h" +#include "host.h" + +#define HDR_SIZE 4 + +int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) +{ + StatsIncr(tv, dtv->counter_null); + + if (unlikely(len < HDR_SIZE)) { + ENGINE_SET_INVALID_EVENT(p, LTNULL_PKT_TOO_SMALL); + return TM_ECODE_FAILED; + } + + uint32_t type = *((uint32_t *)pkt); + switch(type) { + case AF_INET: + SCLogDebug("IPV4 Packet"); + DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p)+HDR_SIZE, GET_PKT_LEN(p)-HDR_SIZE, pq); + break; + case AF_INET6: + SCLogDebug("IPV6 Packet"); + DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p)+HDR_SIZE, GET_PKT_LEN(p)-HDR_SIZE, pq); + break; + default: + SCLogDebug("Unknown Null packet type version %" PRIu32 "", type); + ENGINE_SET_EVENT(p, LTNULL_UNSUPPORTED_TYPE); + break; + } + return TM_ECODE_OK; +} + +#ifdef UNITTESTS + +#endif /* UNITTESTS */ + +/** + * \brief Registers Null unit tests + */ +void DecodeNullRegisterTests(void) +{ +#ifdef UNITTESTS +#endif /* UNITTESTS */ +} +/** + * @} + */ diff --git a/src/decode-null.h b/src/decode-null.h new file mode 100644 index 000000000000..22d988c72481 --- /dev/null +++ b/src/decode-null.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DECODE_NULL_H__ +#define __DECODE_NULL_H__ +void DecodeNullRegisterTests(void); +#endif /* __DECODE_NULL_H__ */ diff --git a/src/decode-ppp.c b/src/decode-ppp.c index 0d15c0c450ed..6fff62cd174c 100644 --- a/src/decode-ppp.c +++ b/src/decode-ppp.c @@ -42,7 +42,7 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_ppp, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_ppp); if (unlikely(len < PPP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL); @@ -300,10 +300,10 @@ static int DecodePPPtest04 (void) void DecodePPPRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodePPPtest01", DecodePPPtest01, 1); - UtRegisterTest("DecodePPPtest02", DecodePPPtest02, 1); - UtRegisterTest("DecodePPPtest03", DecodePPPtest03, 1); - UtRegisterTest("DecodePPPtest04", DecodePPPtest04, 1); + UtRegisterTest("DecodePPPtest01", DecodePPPtest01); + UtRegisterTest("DecodePPPtest02", DecodePPPtest02); + UtRegisterTest("DecodePPPtest03", DecodePPPtest03); + UtRegisterTest("DecodePPPtest04", DecodePPPtest04); #endif /* UNITTESTS */ } diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index 57df28f5e54b..ae2e8127b76c 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -49,7 +49,7 @@ */ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_pppoe); if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); @@ -128,7 +128,7 @@ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8 */ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_pppoe); if (len < PPPOE_SESSION_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); @@ -446,12 +446,12 @@ static int DecodePPPOEtest06 (void) void DecodePPPOERegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01, 1); - UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02, 1); - UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03, 1); - UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04, 1); - UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05, 1); - UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06, 1); + UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01); + UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02); + UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03); + UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04); + UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05); + UtRegisterTest("DecodePPPOEtest06", DecodePPPOEtest06); #endif /* UNITTESTS */ } diff --git a/src/decode-raw.c b/src/decode-raw.c index caa806873842..d174ab376617 100644 --- a/src/decode-raw.c +++ b/src/decode-raw.c @@ -45,7 +45,7 @@ int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_raw, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_raw); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (unlikely(len < IPV4_HEADER_LEN)) { @@ -100,7 +100,7 @@ static int DecodeRawTest01 (void) if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); - return 1; + return 0; } FlowInitConfig(FLOW_QUIET); @@ -110,13 +110,13 @@ static int DecodeRawTest01 (void) printf("expected a valid ipv6 header but it was NULL: "); FlowShutdown(); SCFree(p); - return 1; + return 0; } PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 0; + return 1; } /** DecodeRawtest02 @@ -146,7 +146,7 @@ static int DecodeRawTest02 (void) if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); - return 1; + return 0; } FlowInitConfig(FLOW_QUIET); @@ -157,13 +157,13 @@ static int DecodeRawTest02 (void) PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 1; + return 0; } PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 0; + return 1; } /** DecodeRawtest03 * \brief Valid Raw packet @@ -194,18 +194,17 @@ static int DecodeRawTest03 (void) if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) { SCFree(p); - return 1; + return 0; } FlowInitConfig(FLOW_QUIET); DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL); - if (ENGINE_ISSET_EVENT(p,IPRAW_INVALID_IPV)) { + if (!ENGINE_ISSET_EVENT(p,IPRAW_INVALID_IPV)) { + printf("expected IPRAW_INVALID_IPV to be set but it wasn't: "); FlowShutdown(); SCFree(p); return 0; - } else { - printf("expected IPRAW_INVALID_IPV to be set but it wasn't: "); } PACKET_RECYCLE(p); FlowShutdown(); @@ -222,9 +221,9 @@ static int DecodeRawTest03 (void) void DecodeRawRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeRawTest01", DecodeRawTest01, 0); - UtRegisterTest("DecodeRawTest02", DecodeRawTest02, 0); - UtRegisterTest("DecodeRawTest03", DecodeRawTest03, 0); + UtRegisterTest("DecodeRawTest01", DecodeRawTest01); + UtRegisterTest("DecodeRawTest02", DecodeRawTest02); + UtRegisterTest("DecodeRawTest03", DecodeRawTest03); #endif /* UNITTESTS */ } /** diff --git a/src/decode-sctp.c b/src/decode-sctp.c index 6fd8be8d616d..f787933ebd9d 100644 --- a/src/decode-sctp.c +++ b/src/decode-sctp.c @@ -61,7 +61,7 @@ static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t le int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_sctp, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_sctp); if (unlikely(DecodeSCTPPacket(tv, p,pkt,len) < 0)) { p->sctph = NULL; @@ -73,8 +73,7 @@ int DecodeSCTP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u SCTP_GET_SRC_PORT(p), SCTP_GET_DST_PORT(p)); #endif - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } diff --git a/src/decode-sll.c b/src/decode-sll.c index 5bfc63cf56fd..eed61a4c39fe 100644 --- a/src/decode-sll.c +++ b/src/decode-sll.c @@ -38,7 +38,7 @@ int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_sll, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_sll); if (unlikely(len < SLL_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, SLL_PKT_TOO_SMALL); diff --git a/src/decode-tcp.c b/src/decode-tcp.c index 47c066160d0b..1ff16e0a7f7e 100644 --- a/src/decode-tcp.c +++ b/src/decode-tcp.c @@ -42,8 +42,16 @@ #include "pkt-var.h" #include "host.h" +#define SET_OPTS(dst, src) \ + (dst).type = (src).type; \ + (dst).len = (src).len; \ + (dst).data = (src).data + static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) { + uint8_t tcp_opt_cnt = 0; + TCPOpt tcp_opts[TCP_OPTMAX]; + uint16_t plen = len; while (plen) { @@ -68,81 +76,85 @@ static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) return -1; } - p->TCP_OPTS[p->TCP_OPTS_CNT].type = *pkt; - p->TCP_OPTS[p->TCP_OPTS_CNT].len = *(pkt+1); + tcp_opts[tcp_opt_cnt].type = *pkt; + tcp_opts[tcp_opt_cnt].len = *(pkt+1); if (plen > 2) - p->TCP_OPTS[p->TCP_OPTS_CNT].data = (pkt+2); + tcp_opts[tcp_opt_cnt].data = (pkt+2); else - p->TCP_OPTS[p->TCP_OPTS_CNT].data = NULL; + tcp_opts[tcp_opt_cnt].data = NULL; /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the * time. */ - switch (p->TCP_OPTS[p->TCP_OPTS_CNT].type) { + switch (tcp_opts[tcp_opt_cnt].type) { case TCP_OPT_WS: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_WS_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_WS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.ws != NULL) { + if (p->tcpvars.ws.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.ws = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.ws, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_MSS: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_MSS_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_MSS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.mss != NULL) { + if (p->tcpvars.mss.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.mss = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.mss, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_SACKOK: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_SACKOK_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_SACKOK_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.sackok != NULL) { + if (p->tcpvars.sackok.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.sackok = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.sackok, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_TS: - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_TS_LEN) { + if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_TS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.ts != NULL) { + if (p->tcpvars.ts_set) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.ts = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + uint32_t values[2]; + memcpy(&values, tcp_opts[tcp_opt_cnt].data, sizeof(values)); + p->tcpvars.ts_val = ntohl(values[0]); + p->tcpvars.ts_ecr = ntohl(values[1]); + p->tcpvars.ts_set = TRUE; } } break; case TCP_OPT_SACK: - SCLogDebug("SACK option, len %u", p->TCP_OPTS[p->TCP_OPTS_CNT].len); - if (p->TCP_OPTS[p->TCP_OPTS_CNT].len < TCP_OPT_SACK_MIN_LEN || - p->TCP_OPTS[p->TCP_OPTS_CNT].len > TCP_OPT_SACK_MAX_LEN || - !((p->TCP_OPTS[p->TCP_OPTS_CNT].len - 2) % 8 == 0)) + SCLogDebug("SACK option, len %u", tcp_opts[tcp_opt_cnt].len); + if (tcp_opts[tcp_opt_cnt].len < TCP_OPT_SACK_MIN_LEN || + tcp_opts[tcp_opt_cnt].len > TCP_OPT_SACK_MAX_LEN || + !((tcp_opts[tcp_opt_cnt].len - 2) % 8 == 0)) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { - if (p->tcpvars.sack != NULL) { + if (p->tcpvars.sack.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { - p->tcpvars.sack = &p->TCP_OPTS[p->TCP_OPTS_CNT]; + SET_OPTS(p->tcpvars.sack, tcp_opts[tcp_opt_cnt]); } } break; } - pkt += p->TCP_OPTS[p->TCP_OPTS_CNT].len; - plen -= (p->TCP_OPTS[p->TCP_OPTS_CNT].len); - p->TCP_OPTS_CNT++; + pkt += tcp_opts[tcp_opt_cnt].len; + plen -= (tcp_opts[tcp_opt_cnt].len); + tcp_opt_cnt++; } } return 0; @@ -186,7 +198,7 @@ static int DecodeTCPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_tcp, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_tcp); if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) { SCLogDebug("invalid TCP packet"); @@ -197,13 +209,12 @@ int DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui #ifdef DEBUG SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s", GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len, - p->tcpvars.sackok ? "SACKOK " : "", p->tcpvars.sack ? "SACK " : "", - p->tcpvars.ws ? "WS " : "", p->tcpvars.ts ? "TS " : "", - p->tcpvars.mss ? "MSS " : ""); + TCP_HAS_SACKOK(p) ? "SACKOK " : "", TCP_HAS_SACK(p) ? "SACK " : "", + TCP_HAS_WSCALE(p) ? "WS " : "", TCP_HAS_TS(p) ? "TS " : "", + TCP_HAS_MSS(p) ? "MSS " : ""); #endif - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } @@ -225,8 +236,9 @@ static int TCPCalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_tcp) + 8); - return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_tcp, sizeof(raw_tcp))); + FAIL_IF(TCPChecksum((uint16_t *)raw_ipshdr, + (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) != 0); + PASS; } static int TCPCalculateInvalidChecksumtest02(void) @@ -245,8 +257,9 @@ static int TCPCalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_tcp) + 8); - return (csum == TCPCalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_tcp, sizeof(raw_tcp))); + FAIL_IF(TCPChecksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_tcp, sizeof(raw_tcp), csum) == 0); + PASS; } static int TCPV6CalculateValidChecksumtest03(void) @@ -268,8 +281,9 @@ static int TCPV6CalculateValidChecksumtest03(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - return (csum == TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 32)); + FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 32, csum) != 0); + PASS; } static int TCPV6CalculateInvalidChecksumtest04(void) @@ -291,8 +305,9 @@ static int TCPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 70))); - return (csum == TCPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 32)); + FAIL_IF(TCPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 32, csum) == 0); + PASS; } /** \test Get the wscale of 2 */ @@ -468,7 +483,7 @@ static int TCPGetSackTest01(void) goto end; } - if (p->tcpvars.sack == NULL) { + if (!TCP_HAS_SACK(p)) { printf("tcp packet sack not decoded: "); goto end; } @@ -503,17 +518,17 @@ void DecodeTCPRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("TCPCalculateValidChecksumtest01", - TCPCalculateValidChecksumtest01, 1); + TCPCalculateValidChecksumtest01); UtRegisterTest("TCPCalculateInvalidChecksumtest02", - TCPCalculateInvalidChecksumtest02, 0); + TCPCalculateInvalidChecksumtest02); UtRegisterTest("TCPV6CalculateValidChecksumtest03", - TCPV6CalculateValidChecksumtest03, 1); + TCPV6CalculateValidChecksumtest03); UtRegisterTest("TCPV6CalculateInvalidChecksumtest04", - TCPV6CalculateInvalidChecksumtest04, 0); - UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01, 1); - UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02, 1); - UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03, 1); - UtRegisterTest("TCPGetSackTest01", TCPGetSackTest01, 1); + TCPV6CalculateInvalidChecksumtest04); + UtRegisterTest("TCPGetWscaleTest01", TCPGetWscaleTest01); + UtRegisterTest("TCPGetWscaleTest02", TCPGetWscaleTest02); + UtRegisterTest("TCPGetWscaleTest03", TCPGetWscaleTest03); + UtRegisterTest("TCPGetSackTest01", TCPGetSackTest01); #endif /* UNITTESTS */ } /** diff --git a/src/decode-tcp.h b/src/decode-tcp.h index 152d5103f42f..0621d7ef6176 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -62,11 +62,8 @@ /** Max valid wscale value. */ #define TCP_WSCALE_MAX 14 -#define TCP_OPTS tcpvars.tcp_opts -#define TCP_OPTS_CNT tcpvars.tcp_opt_cnt - #define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4) -#define TCP_GET_RAW_X2(tcph) ((tcph)->th_offx2 & 0x0f) +#define TCP_GET_RAW_X2(tcph) (unsigned char)((tcph)->th_offx2 & 0x0f) #define TCP_GET_RAW_SRC_PORT(tcph) ntohs((tcph)->th_sport) #define TCP_GET_RAW_DST_PORT(tcph) ntohs((tcph)->th_dport) @@ -78,25 +75,31 @@ #define TCP_GET_RAW_WINDOW(tcph) ntohs((tcph)->th_win) #define TCP_GET_RAW_URG_POINTER(tcph) ntohs((tcph)->th_urp) +#define TCP_GET_RAW_SUM(tcph) ntohs((tcph)->th_sum) + +/** macro for getting the first timestamp from the packet in host order */ +#define TCP_GET_TSVAL(p) ((p)->tcpvars.ts_val) -/** macro for getting the first timestamp from the packet. Timestamp is in host - * order and either returned from the cache or from the packet directly. */ -#define TCP_GET_TSVAL(p) \ - (uint32_t)ntohl((*(uint32_t *)(p)->tcpvars.ts->data)) +/** macro for getting the second timestamp from the packet in host order. */ +#define TCP_GET_TSECR(p) ((p)->tcpvars.ts_ecr) -/** macro for getting the second timestamp from the packet. Timestamp is in - * host order and either returned from the cache or from the packet directly. */ -#define TCP_GET_TSECR(p) \ - (uint32_t)ntohl((*(uint32_t *)((p)->tcpvars.ts->data+4))) +#define TCP_HAS_WSCALE(p) ((p)->tcpvars.ws.type == TCP_OPT_WS) +#define TCP_HAS_SACK(p) ((p)->tcpvars.sack.type == TCP_OPT_SACK) +#define TCP_HAS_SACKOK(p) ((p)->tcpvars.sackok.type == TCP_OPT_SACKOK) +#define TCP_HAS_TS(p) ((p)->tcpvars.ts_set == TRUE) +#define TCP_HAS_MSS(p) ((p)->tcpvars.mss.type == TCP_OPT_MSS) /** macro for getting the wscale from the packet. */ -#define TCP_GET_WSCALE(p) ((p)->tcpvars.ws ? (((*(uint8_t *)(p)->tcpvars.ws->data) <= TCP_WSCALE_MAX) ? (*(uint8_t *)((p)->tcpvars.ws->data)) : 0) : 0) +#define TCP_GET_WSCALE(p) (TCP_HAS_WSCALE((p)) ? \ + (((*(uint8_t *)(p)->tcpvars.ws.data) <= TCP_WSCALE_MAX) ? \ + (*(uint8_t *)((p)->tcpvars.ws.data)) : 0) : 0) -#define TCP_GET_SACKOK(p) ((p)->tcpvars.sackok ? 1 : 0) -#define TCP_GET_SACK_PTR(p) (p)->tcpvars.sack ? (p)->tcpvars.sack->data : NULL -#define TCP_GET_SACK_CNT(p) ((p)->tcpvars.sack ? (((p)->tcpvars.sack->len - 2) / 8) : 0) +#define TCP_GET_SACKOK(p) (TCP_HAS_SACKOK((p)) ? 1 : 0) +#define TCP_GET_SACK_PTR(p) TCP_HAS_SACK((p)) ? (p)->tcpvars.sack.data : NULL +#define TCP_GET_SACK_CNT(p) (TCP_HAS_SACK((p)) ? (((p)->tcpvars.sack.len - 2) / 8) : 0) #define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET((p)->tcph) +#define TCP_GET_X2(p) TCP_GET_RAW_X2((p)->tcph) #define TCP_GET_HLEN(p) (TCP_GET_OFFSET((p)) << 2) #define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT((p)->tcph) #define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT((p)->tcph) @@ -104,6 +107,8 @@ #define TCP_GET_ACK(p) TCP_GET_RAW_ACK((p)->tcph) #define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW((p)->tcph) #define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER((p)->tcph) +#define TCP_GET_SUM(p) TCP_GET_RAW_SUM((p)->tcph) +#define TCP_GET_FLAGS(p) (p)->tcph->th_flags #define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN) #define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN) @@ -140,51 +145,47 @@ typedef struct TCPHdr_ typedef struct TCPVars_ { - uint8_t tcp_opt_cnt; - TCPOpt tcp_opts[TCP_OPTMAX]; - - /* ptrs to commonly used and needed opts */ - TCPOpt *ts; - TCPOpt *sack; - TCPOpt *sackok; - TCPOpt *ws; - TCPOpt *mss; + /* commonly used and needed opts */ + _Bool ts_set; + uint32_t ts_val; /* host-order */ + uint32_t ts_ecr; /* host-order */ + TCPOpt sack; + TCPOpt sackok; + TCPOpt ws; + TCPOpt mss; } TCPVars; -#define CLEAR_TCP_PACKET(p) { \ - (p)->tcph = NULL; \ +#define CLEAR_TCP_PACKET(p) { \ (p)->level4_comp_csum = -1; \ - (p)->tcpvars.tcp_opt_cnt = 0; \ - (p)->tcpvars.ts = NULL; \ - (p)->tcpvars.sack = NULL; \ - (p)->tcpvars.sackok = NULL; \ - (p)->tcpvars.ws = NULL; \ - (p)->tcpvars.mss = NULL; \ + PACKET_CLEAR_L4VARS((p)); \ + (p)->tcph = NULL; \ } void DecodeTCPRegisterTests(void); /** -------- Inline functions ------- */ -static inline uint16_t TCPCalculateChecksum(uint16_t *, uint16_t *, uint16_t); -static inline uint16_t TCPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); +static inline uint16_t TCPChecksum(uint16_t *, uint16_t *, uint16_t, uint16_t); +static inline uint16_t TCPV6Checksum(uint16_t *, uint16_t *, uint16_t, uint16_t); /** - * \brief Calculates the checksum for the TCP packet + * \brief Calculate or validate the checksum for the TCP packet * * \param shdr Pointer to source address field from the IP packet. Used as a * part of the pseudoheader for computing the checksum * \param pkt Pointer to the start of the TCP packet * \param tlen Total length of the TCP packet(header + payload) + * \param init The current checksum if validating, 0 if generating. * - * \retval csum Checksum for the TCP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ -static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) +static inline uint16_t TCPChecksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + htons(6) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; @@ -194,7 +195,9 @@ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, while (tlen >= 32) { csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + - pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + + pkt[7] + + pkt[8] + + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] + pkt[14] + pkt[15]; tlen -= 32; pkt += 16; @@ -230,24 +233,26 @@ static inline uint16_t TCPCalculateChecksum(uint16_t *shdr, uint16_t *pkt, } /** - * \brief Calculates the checksum for the TCP packet + * \brief Calculate or validate the checksum for the TCP packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the TCP packet * \param tlen Total length of the TCP packet(header + payload) + * \param init The current checksum if validating, 0 if generating. * - * \retval csum Checksum for the TCP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ -static inline uint16_t TCPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) +static inline uint16_t TCPV6Checksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + - shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + - shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(6) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] + pkt[7] + pkt[9]; diff --git a/src/decode-template.c b/src/decode-template.c new file mode 100644 index 000000000000..2673a2cdff56 --- /dev/null +++ b/src/decode-template.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup decode + * + * @{ + */ + + +/** + * \file + * + * \author XXX Your Name + * + * Decodes XXX describe the protocol + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" +#include "decode-events.h" +#include "decode-template.h" + +#include "util-unittest.h" +#include "util-debug.h" + +/** + * \brief Function to decode XXX packets + * \param tv thread vars + * \param dtv decoder thread vars + * \param p packet + * \param pkt raw packet data + * \param len length in bytes of pkt array + * \retval TM_ECODE_OK or TM_ECODE_FAILED on serious error + */ + +int DecodeTEMPLATE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, + const uint8_t *pkt, uint16_t len, PacketQueue *pq) +{ + /* TODO add counter for your type of packet to DecodeThreadVars, + * and register it in DecodeRegisterPerfCounters */ + //StatsIncr(tv, dtv->counter_template); + + /* Validation: make sure that the input data is big enough to hold + * the header */ + if (len < sizeof(TemplateHdr)) { + /* in case of errors, we set events. Events are defined in + * decode-events.h, and are then exposed to the detection + * engine through detect-engine-events.h */ + //ENGINE_SET_EVENT(p,TEMPLATE_HEADER_TOO_SMALL); + return TM_ECODE_FAILED; + } + + /* Now we can access the header */ + const TemplateHdr *hdr = (const TemplateHdr *)pkt; + + /* lets assume we have UDP encapsulated */ + if (hdr->proto == 17) { + /* we need to pass on the pkt and it's length minus the current + * header */ + size_t hdr_len = sizeof(TemplateHdr); + + /* in this example it's clear that hdr_len can't be bigger than + * 'len', but in more complex cases checking that we can't underflow + * len is very important + if (hdr_len < len) { + */ + + /* invoke the next decoder on the remainder of the data */ + return DecodeUDP(tv, dtv, p, (uint8_t *)pkt + hdr_len, len - hdr_len, pq); + //} + } else { + //ENGINE_SET_EVENT(p,TEMPLATE_UNSUPPORTED_PROTOCOL); + return TM_ECODE_FAILED; + } + + return TM_ECODE_OK; +} + +/** + * @} + */ diff --git a/src/decode-template.h b/src/decode-template.h new file mode 100644 index 000000000000..b6a976e0e4f1 --- /dev/null +++ b/src/decode-template.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author XXX + * + */ + +#ifndef __DECODE_TEMPLATE_H__ +#define __DECODE_TEMPLATE_H__ + +#include "decode.h" +#include "threadvars.h" + +typedef struct TemplateHdr_ { + uint8_t proto; + uint8_t pad0; + uint16_t pad1; +} __attribute__((__packed__)) TemplateHdr; + +#endif /* __DECODE_TEMPLATE_H__ */ diff --git a/src/decode-teredo.c b/src/decode-teredo.c index bea132e3b652..208760277d0e 100644 --- a/src/decode-teredo.c +++ b/src/decode-teredo.c @@ -91,12 +91,12 @@ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, int blen = len - (start - pkt); /* spawn off tunnel packet */ Packet *tp = PacketTunnelPktSetup(tv, dtv, p, start, blen, - IPPROTO_IPV6, pq); + DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); - SCPerfCounterIncr(dtv->counter_teredo, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_teredo); return TM_ECODE_OK; } } diff --git a/src/decode-udp.c b/src/decode-udp.c index 5b83768f9e6f..d84f96919206 100644 --- a/src/decode-udp.c +++ b/src/decode-udp.c @@ -72,7 +72,7 @@ static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - SCPerfCounterIncr(dtv->counter_udp, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_udp); if (unlikely(DecodeUDPPacket(tv, p,pkt,len) < 0)) { p->udph = NULL; @@ -85,17 +85,11 @@ int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, ui if (unlikely(DecodeTeredo(tv, dtv, p, p->payload, p->payload_len, pq) == TM_ECODE_OK)) { /* Here we have a Teredo packet and don't need to handle app * layer */ - FlowHandlePacket(tv, dtv, p); + FlowSetupPacket(p); return TM_ECODE_OK; } - /* Flow is an integral part of us */ - FlowHandlePacket(tv, dtv, p); - - /* handle the app layer part of the UDP packet payload */ - if (unlikely(p->flow != NULL)) { - AppLayerHandleUdp(tv, dtv->app_tctx, p, p->flow); - } + FlowSetupPacket(p); return TM_ECODE_OK; } @@ -123,9 +117,9 @@ static int UDPV4CalculateValidChecksumtest01(void) csum = *( ((uint16_t *)raw_udp) + 3); - return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_udp, - sizeof(raw_udp))); + FAIL_IF(UDPV4Checksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_udp, sizeof(raw_udp), csum) != 0); + PASS; } static int UDPV4CalculateInvalidChecksumtest02(void) @@ -150,9 +144,9 @@ static int UDPV4CalculateInvalidChecksumtest02(void) csum = *( ((uint16_t *)raw_udp) + 3); - return (csum == UDPV4CalculateChecksum((uint16_t *) raw_ipshdr, - (uint16_t *)raw_udp, - sizeof(raw_udp))); + FAIL_IF(UDPV4Checksum((uint16_t *) raw_ipshdr, + (uint16_t *)raw_udp, sizeof(raw_udp), csum) == 0); + PASS; } static int UDPV6CalculateValidChecksumtest03(void) @@ -173,8 +167,9 @@ static int UDPV6CalculateValidChecksumtest03(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - return (csum == UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 20)); + FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 20, csum) != 0); + PASS; } static int UDPV6CalculateInvalidChecksumtest04(void) @@ -195,8 +190,9 @@ static int UDPV6CalculateInvalidChecksumtest04(void) csum = *( ((uint16_t *)(raw_ipv6 + 60))); - return (csum == UDPV6CalculateChecksum((uint16_t *)(raw_ipv6 + 14 + 8), - (uint16_t *)(raw_ipv6 + 54), 20)); + FAIL_IF(UDPV6Checksum((uint16_t *)(raw_ipv6 + 14 + 8), + (uint16_t *)(raw_ipv6 + 54), 20, csum) == 0); + PASS; } #endif /* UNITTESTS */ @@ -204,13 +200,13 @@ void DecodeUDPV4RegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("UDPV4CalculateValidChecksumtest01", - UDPV4CalculateValidChecksumtest01, 1); + UDPV4CalculateValidChecksumtest01); UtRegisterTest("UDPV4CalculateInvalidChecksumtest02", - UDPV4CalculateInvalidChecksumtest02, 0); + UDPV4CalculateInvalidChecksumtest02); UtRegisterTest("UDPV6CalculateValidChecksumtest03", - UDPV6CalculateValidChecksumtest03, 1); + UDPV6CalculateValidChecksumtest03); UtRegisterTest("UDPV6CalculateInvalidChecksumtest04", - UDPV6CalculateInvalidChecksumtest04, 0); + UDPV6CalculateInvalidChecksumtest04); #endif /* UNITTESTS */ } /** diff --git a/src/decode-udp.h b/src/decode-udp.h index 5636c32b0f42..cfbdc7f23a4b 100644 --- a/src/decode-udp.h +++ b/src/decode-udp.h @@ -30,10 +30,12 @@ #define UDP_GET_RAW_LEN(udph) ntohs((udph)->uh_len) #define UDP_GET_RAW_SRC_PORT(udph) ntohs((udph)->uh_sport) #define UDP_GET_RAW_DST_PORT(udph) ntohs((udph)->uh_dport) +#define UDP_GET_RAW_SUM(udph) ntohs((udph)->uh_sum) #define UDP_GET_LEN(p) UDP_GET_RAW_LEN(p->udph) #define UDP_GET_SRC_PORT(p) UDP_GET_RAW_SRC_PORT(p->udph) #define UDP_GET_DST_PORT(p) UDP_GET_RAW_DST_PORT(p->udph) +#define UDP_GET_SUM(p) UDP_GET_RAW_SUM(p->udph) /* UDP header structure */ typedef struct UDPHdr_ @@ -44,38 +46,37 @@ typedef struct UDPHdr_ uint16_t uh_sum; /* checksum */ } __attribute__((__packed__)) UDPHdr; -typedef struct UDPVars_ -{ -} UDPVars; - -#define CLEAR_UDP_PACKET(p) do { \ - (p)->udph = NULL; \ - (p)->level4_comp_csum = -1; \ +#define CLEAR_UDP_PACKET(p) do { \ + (p)->level4_comp_csum = -1; \ + (p)->udph = NULL; \ } while (0) void DecodeUDPV4RegisterTests(void); /** ------ Inline function ------ */ -static inline uint16_t UDPV4CalculateChecksum(uint16_t *, uint16_t *, uint16_t); -static inline uint16_t UDPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t); +static inline uint16_t UDPV4Checksum(uint16_t *, uint16_t *, uint16_t, uint16_t); +static inline uint16_t UDPV6Checksum(uint16_t *, uint16_t *, uint16_t, uint16_t); /** - * \brief Calculates the checksum for the UDP packet + * \brief Calculate or valid the checksum for the UDP packet * * \param shdr Pointer to source address field from the IP packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the UDP packet * \param hlen Total length of the UDP packet(header + payload) + * \param init For validation this is the UDP checksum, for calculation this + * value should be set to 0. * - * \retval csum Checksum for the UDP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ -static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) +static inline uint16_t UDPV4Checksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + htons(17) + htons(tlen); + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + htons(17) + htons(tlen); csum += pkt[0] + pkt[1] + pkt[2]; @@ -117,29 +118,32 @@ static inline uint16_t UDPV4CalculateChecksum(uint16_t *shdr, uint16_t *pkt, csum += (csum >> 16); uint16_t csum_u16 = (uint16_t)~csum; - if (csum_u16 == 0) + if (init == 0 && csum_u16 == 0) return 0xFFFF; else return csum_u16; } /** - * \brief Calculates the checksum for the UDP packet + * \brief Calculate or valid the checksum for the UDP packet * * \param shdr Pointer to source address field from the IPV6 packet. Used as a * part of the psuedoheader for computing the checksum * \param pkt Pointer to the start of the UDP packet * \param tlen Total length of the UDP packet(header + payload) + * \param init For validation this is the UDP checksum, for calculation this + * value should be set to 0. * - * \retval csum Checksum for the UDP packet + * \retval csum For validation 0 will be returned for success, for calculation + * this will be the checksum. */ -static inline uint16_t UDPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, - uint16_t tlen) +static inline uint16_t UDPV6Checksum(uint16_t *shdr, uint16_t *pkt, + uint16_t tlen, uint16_t init) { uint16_t pad = 0; - uint32_t csum = shdr[0]; + uint32_t csum = init; - csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + + csum += shdr[0] + shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] + shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] + shdr[13] + shdr[14] + shdr[15] + htons(17) + htons(tlen); @@ -183,7 +187,7 @@ static inline uint16_t UDPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt, csum += (csum >> 16); uint16_t csum_u16 = (uint16_t)~csum; - if (csum_u16 == 0) + if (init == 0 && csum_u16 == 0) return 0xFFFF; else return csum_u16; diff --git a/src/decode-vlan.c b/src/decode-vlan.c index d84262e606c8..dc07a6851902 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -61,9 +61,9 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u uint32_t proto; if (p->vlan_idx == 0) - SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_vlan); else if (p->vlan_idx == 1) - SCPerfCounterIncr(dtv->counter_vlan_qinq, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_vlan_qinq); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); @@ -240,7 +240,7 @@ static int DecodeVLANtest03 (void) DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan), NULL); - if(p->vlanh == NULL) { + if(p->vlanh[0] == NULL) { goto error; } @@ -268,9 +268,9 @@ static int DecodeVLANtest03 (void) void DecodeVLANRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01, 1); - UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02, 1); - UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03, 1); + UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01); + UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02); + UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03); #endif /* UNITTESTS */ } diff --git a/src/decode.c b/src/decode.c index 8ad78bcf3212..4b064c8300d6 100644 --- a/src/decode.c +++ b/src/decode.c @@ -67,17 +67,21 @@ #include "output-flow.h" int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, - uint8_t *pkt, uint16_t len, PacketQueue *pq, uint8_t proto) + uint8_t *pkt, uint16_t len, PacketQueue *pq, enum DecodeTunnelProto proto) { switch (proto) { - case PPP_OVER_GRE: + case DECODE_TUNNEL_PPP: return DecodePPP(tv, dtv, p, pkt, len, pq); - case IPPROTO_IP: + case DECODE_TUNNEL_IPV4: return DecodeIPV4(tv, dtv, p, pkt, len, pq); - case IPPROTO_IPV6: + case DECODE_TUNNEL_IPV6: return DecodeIPV6(tv, dtv, p, pkt, len, pq); - case VLAN_OVER_GRE: + case DECODE_TUNNEL_VLAN: return DecodeVLAN(tv, dtv, p, pkt, len, pq); + case DECODE_TUNNEL_ETHERNET: + return DecodeEthernet(tv, dtv, p, pkt, len, pq); + case DECODE_TUNNEL_ERSPAN: + return DecodeERSPAN(tv, dtv, p, pkt, len, pq); default: SCLogInfo("FIXME: DecodeTunnel: protocol %" PRIu32 " not supported.", proto); break; @@ -105,9 +109,15 @@ void PacketFree(Packet *p) void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { - if (p->flags & PKT_IS_INVALID) - SCPerfCounterIncr(dtv->counter_invalid, tv->sc_perf_pca); - + if (p->flags & PKT_IS_INVALID) { + StatsIncr(tv, dtv->counter_invalid); + int i = 0; + for (i = 0; i < p->events.cnt; i++) { + if (EVENT_IS_DECODER_PACKET_ERROR(p->events.events[i])) { + StatsIncr(tv, dtv->counter_invalid_events[p->events.events[i]]); + } + } + } #ifdef __SC_CUDA_SUPPORT__ if (dtv->cuda_vars.mpm_is_cuda) CudaBufferPacket(&dtv->cuda_vars, p); @@ -171,6 +181,18 @@ Packet *PacketGetFromQueueOrAlloc(void) return p; } +inline int PacketCallocExtPkt(Packet *p, int datalen) +{ + if (! p->ext_pkt) { + p->ext_pkt = SCCalloc(1, datalen); + if (unlikely(p->ext_pkt == NULL)) { + SET_PKT_LEN(p, 0); + return -1; + } + } + return 0; +} + /** * \brief Copy data to Packet payload at given offset * @@ -239,7 +261,8 @@ inline int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen) * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, - uint8_t *pkt, uint16_t len, uint8_t proto, PacketQueue *pq) + uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto, + PacketQueue *pq) { int ret; @@ -257,6 +280,7 @@ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *pare p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; + p->tenant_id = parent->tenant_id; /* set the root ptr to the lowest layer */ if (parent->root != NULL) @@ -323,11 +347,14 @@ Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t p->root = parent; /* copy packet and set lenght, proto */ - PacketCopyData(p, pkt, len); + if (pkt && len) { + PacketCopyData(p, pkt, len); + } p->recursion_level = parent->recursion_level; /* NOT incremented */ p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; + p->tenant_id = parent->tenant_id; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); p->vlan_id[0] = parent->vlan_id[0]; @@ -355,83 +382,89 @@ void PacketDefragPktSetupParent(Packet *parent) DecodeSetNoPayloadInspectionFlag(parent); } +void PacketBypassCallback(Packet *p) +{ + /* Don't try to bypass if flow is already out or + * if we have failed to do it once */ + int state = SC_ATOMIC_GET(p->flow->flow_state); + if ((state == FLOW_STATE_LOCAL_BYPASSED) || + (state == FLOW_STATE_CAPTURE_BYPASSED)) { + return; + } + + if (p->BypassPacketsFlow && p->BypassPacketsFlow(p)) { + FlowUpdateState(p->flow, FLOW_STATE_CAPTURE_BYPASSED); + } else { + FlowUpdateState(p->flow, FLOW_STATE_LOCAL_BYPASSED); + } +} + void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) { /* register counters */ - dtv->counter_pkts = SCPerfTVRegisterCounter("decoder.pkts", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_bytes = SCPerfTVRegisterCounter("decoder.bytes", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_invalid = SCPerfTVRegisterCounter("decoder.invalid", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_ipv4 = SCPerfTVRegisterCounter("decoder.ipv4", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_ipv6 = SCPerfTVRegisterCounter("decoder.ipv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_eth = SCPerfTVRegisterCounter("decoder.ethernet", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_raw = SCPerfTVRegisterCounter("decoder.raw", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_sll = SCPerfTVRegisterCounter("decoder.sll", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_tcp = SCPerfTVRegisterCounter("decoder.tcp", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_udp = SCPerfTVRegisterCounter("decoder.udp", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_sctp = SCPerfTVRegisterCounter("decoder.sctp", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_icmpv4 = SCPerfTVRegisterCounter("decoder.icmpv4", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_icmpv6 = SCPerfTVRegisterCounter("decoder.icmpv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_ppp = SCPerfTVRegisterCounter("decoder.ppp", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_pppoe = SCPerfTVRegisterCounter("decoder.pppoe", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_gre = SCPerfTVRegisterCounter("decoder.gre", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_vlan = SCPerfTVRegisterCounter("decoder.vlan", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_vlan_qinq = SCPerfTVRegisterCounter("decoder.vlan_qinq", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_teredo = SCPerfTVRegisterCounter("decoder.teredo", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_ipv4inipv6 = SCPerfTVRegisterCounter("decoder.ipv4_in_ipv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_ipv6inipv6 = SCPerfTVRegisterCounter("decoder.ipv6_in_ipv6", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_mpls = SCPerfTVRegisterCounter("decoder.mpls", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_avg_pkt_size = SCPerfTVRegisterAvgCounter("decoder.avg_pkt_size", tv, - SC_PERF_TYPE_UINT64, "NULL"); - dtv->counter_max_pkt_size = SCPerfTVRegisterMaxCounter("decoder.max_pkt_size", tv, - SC_PERF_TYPE_UINT64, "NULL"); + dtv->counter_pkts = StatsRegisterCounter("decoder.pkts", tv); + dtv->counter_bytes = StatsRegisterCounter("decoder.bytes", tv); + dtv->counter_invalid = StatsRegisterCounter("decoder.invalid", tv); + dtv->counter_ipv4 = StatsRegisterCounter("decoder.ipv4", tv); + dtv->counter_ipv6 = StatsRegisterCounter("decoder.ipv6", tv); + dtv->counter_eth = StatsRegisterCounter("decoder.ethernet", tv); + dtv->counter_raw = StatsRegisterCounter("decoder.raw", tv); + dtv->counter_null = StatsRegisterCounter("decoder.null", tv); + dtv->counter_sll = StatsRegisterCounter("decoder.sll", tv); + dtv->counter_tcp = StatsRegisterCounter("decoder.tcp", tv); + dtv->counter_udp = StatsRegisterCounter("decoder.udp", tv); + dtv->counter_sctp = StatsRegisterCounter("decoder.sctp", tv); + dtv->counter_icmpv4 = StatsRegisterCounter("decoder.icmpv4", tv); + dtv->counter_icmpv6 = StatsRegisterCounter("decoder.icmpv6", tv); + dtv->counter_ppp = StatsRegisterCounter("decoder.ppp", tv); + dtv->counter_pppoe = StatsRegisterCounter("decoder.pppoe", tv); + dtv->counter_gre = StatsRegisterCounter("decoder.gre", tv); + dtv->counter_vlan = StatsRegisterCounter("decoder.vlan", tv); + dtv->counter_vlan_qinq = StatsRegisterCounter("decoder.vlan_qinq", tv); + dtv->counter_teredo = StatsRegisterCounter("decoder.teredo", tv); + dtv->counter_ipv4inipv6 = StatsRegisterCounter("decoder.ipv4_in_ipv6", tv); + dtv->counter_ipv6inipv6 = StatsRegisterCounter("decoder.ipv6_in_ipv6", tv); + dtv->counter_mpls = StatsRegisterCounter("decoder.mpls", tv); + dtv->counter_avg_pkt_size = StatsRegisterAvgCounter("decoder.avg_pkt_size", tv); + dtv->counter_max_pkt_size = StatsRegisterMaxCounter("decoder.max_pkt_size", tv); + dtv->counter_erspan = StatsRegisterMaxCounter("decoder.erspan", tv); + dtv->counter_flow_memcap = StatsRegisterCounter("flow.memcap", tv); dtv->counter_defrag_ipv4_fragments = - SCPerfTVRegisterCounter("defrag.ipv4.fragments", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.ipv4.fragments", tv); dtv->counter_defrag_ipv4_reassembled = - SCPerfTVRegisterCounter("defrag.ipv4.reassembled", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.ipv4.reassembled", tv); dtv->counter_defrag_ipv4_timeouts = - SCPerfTVRegisterCounter("defrag.ipv4.timeouts", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.ipv4.timeouts", tv); dtv->counter_defrag_ipv6_fragments = - SCPerfTVRegisterCounter("defrag.ipv6.fragments", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.ipv6.fragments", tv); dtv->counter_defrag_ipv6_reassembled = - SCPerfTVRegisterCounter("defrag.ipv6.reassembled", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.ipv6.reassembled", tv); dtv->counter_defrag_ipv6_timeouts = - SCPerfTVRegisterCounter("defrag.ipv6.timeouts", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.ipv6.timeouts", tv); dtv->counter_defrag_max_hit = - SCPerfTVRegisterCounter("defrag.max_frag_hits", tv, - SC_PERF_TYPE_UINT64, "NULL"); + StatsRegisterCounter("defrag.max_frag_hits", tv); + + int i = 0; + for (i = 0; i < DECODE_EVENT_PACKET_MAX; i++) { + BUG_ON(i != (int)DEvents[i].code); + dtv->counter_invalid_events[i] = StatsRegisterCounter( + DEvents[i].event_name, tv); + } return; } +void DecodeUpdatePacketCounters(ThreadVars *tv, + const DecodeThreadVars *dtv, const Packet *p) +{ + StatsIncr(tv, dtv->counter_pkts); + //StatsIncr(tv, dtv->counter_pkts_per_sec); + StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); + StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); + StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); +} + /** * \brief Debug print function for printing addresses * @@ -539,16 +572,34 @@ const char *PktSrcToString(enum PktSrcEnum pkt_src) case PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO: pkt_src_str = "stream"; break; - case PKT_SRC_FFR_V2: + case PKT_SRC_FFR: pkt_src_str = "stream (flow timeout)"; break; - case PKT_SRC_FFR_SHUTDOWN: - pkt_src_str = "stream (engine shutdown)"; - break; } return pkt_src_str; } +void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p) +{ + if (unlikely(PACKET_TEST_ACTION(p, (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)))) { + StatsIncr(tv, s->counter_ips_rejected); + } else if (unlikely(PACKET_TEST_ACTION(p, ACTION_DROP))) { + StatsIncr(tv, s->counter_ips_blocked); + } else if (unlikely(p->flags & PKT_STREAM_MODIFIED)) { + StatsIncr(tv, s->counter_ips_replaced); + } else { + StatsIncr(tv, s->counter_ips_accepted); + } +} + +void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s) +{ + s->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); + s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); + s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); + s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); +} + /** * @} */ diff --git a/src/decode.h b/src/decode.h index 98839be6bcdb..d732ce9038b3 100644 --- a/src/decode.h +++ b/src/decode.h @@ -30,6 +30,7 @@ #include "suricata-common.h" #include "threadvars.h" #include "decode-events.h" +#include "flow-worker.h" #ifdef __SC_CUDA_SUPPORT__ #include "util-cuda-buffer.h" @@ -52,8 +53,7 @@ enum PktSrcEnum { PKT_SRC_DECODER_TEREDO, PKT_SRC_DEFRAG, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO, - PKT_SRC_FFR_V2, - PKT_SRC_FFR_SHUTDOWN, + PKT_SRC_FFR, }; #include "source-nflog.h" @@ -62,9 +62,11 @@ enum PktSrcEnum { #include "source-pcap.h" #include "source-af-packet.h" #include "source-mpipe.h" +#include "source-netmap.h" #include "action-globals.h" +#include "decode-erspan.h" #include "decode-ethernet.h" #include "decode-gre.h" #include "decode-ppp.h" @@ -78,6 +80,7 @@ enum PktSrcEnum { #include "decode-udp.h" #include "decode-sctp.h" #include "decode-raw.h" +#include "decode-null.h" #include "decode-vlan.h" #include "decode-mpls.h" @@ -255,10 +258,9 @@ typedef uint16_t Port; * found in this packet */ typedef struct PacketAlert_ { SigIntId num; /* Internal num, used for sorting */ - SigIntId order_id; /* Internal num, used for sorting */ uint8_t action; /* Internal num, used for sorting */ uint8_t flags; - struct Signature_ *s; + const struct Signature_ *s; uint64_t tx_id; } PacketAlert; @@ -272,12 +274,17 @@ typedef struct PacketAlert_ { #define PACKET_ALERT_FLAG_STREAM_MATCH 0x04 /** alert is in a tx, tx_id set */ #define PACKET_ALERT_FLAG_TX 0x08 +/** action was changed by rate_filter */ +#define PACKET_ALERT_RATE_FILTER_MODIFIED 0x10 #define PACKET_ALERT_MAX 15 typedef struct PacketAlerts_ { uint16_t cnt; PacketAlert alerts[PACKET_ALERT_MAX]; + /* single pa used when we're dropping, + * so we can log it out in the drop log. */ + PacketAlert drop; } PacketAlerts; /** number of decoder events we support per packet. Power of 2 minus 1 @@ -291,12 +298,14 @@ typedef struct PacketEngineEvents_ { } PacketEngineEvents; typedef struct PktVar_ { - char *name; + uint32_t id; struct PktVar_ *next; /* right now just implement this as a list, * in the long run we have thing of something * faster. */ - uint8_t *value; + uint16_t key_len; uint16_t value_len; + uint8_t *key; + uint8_t *value; } PktVar; #ifdef PROFILING @@ -321,6 +330,11 @@ typedef struct PktProfilingTmmData_ { #endif } PktProfilingTmmData; +typedef struct PktProfilingData_ { + uint64_t ticks_start; + uint64_t ticks_end; +} PktProfilingData; + typedef struct PktProfilingDetectData_ { uint64_t ticks_start; uint64_t ticks_end; @@ -331,14 +345,32 @@ typedef struct PktProfilingAppData_ { uint64_t ticks_spent; } PktProfilingAppData; +typedef struct PktProfilingLoggerData_ { + uint64_t ticks_start; + uint64_t ticks_end; + uint64_t ticks_spent; +} PktProfilingLoggerData; + +typedef struct PktProfilingPrefilterEngine_ { + uint64_t ticks_spent; +} PktProfilingPrefilterEngine; + +typedef struct PktProfilingPrefilterData_ { + PktProfilingPrefilterEngine *engines; + uint32_t size; /**< array size */ +} PktProfilingPrefilterData; + /** \brief Per pkt stats storage */ typedef struct PktProfiling_ { uint64_t ticks_start; uint64_t ticks_end; PktProfilingTmmData tmm[TMM_SIZE]; + PktProfilingData flowworker[PROFILE_FLOWWORKER_SIZE]; PktProfilingAppData app[ALPROTO_MAX]; PktProfilingDetectData detect[PROF_DETECT_SIZE]; + PktProfilingLoggerData logger[LOGGER_SIZE]; + PktProfilingPrefilterData prefilter; uint64_t proto_detect; } PktProfiling; @@ -395,6 +427,10 @@ typedef struct Packet_ struct Flow_ *flow; + /* raw hash value for looking up the flow, will need to modulated to the + * hash size still */ + uint32_t flow_hash; + struct timeval ts; union { @@ -415,6 +451,9 @@ typedef struct Packet_ /* tilegx mpipe stuff */ MpipePacketVars mpipe_v; #endif +#ifdef HAVE_NETMAP + NetmapPacketVars netmap_v; +#endif /** libpcap vars: shared by Pcap Live mode and Pcap File mode */ PcapPacketVars pcap_v; @@ -422,6 +461,9 @@ typedef struct Packet_ /** The release function for packet structure and data */ void (*ReleasePacket)(struct Packet_ *); + /** The function triggering bypass the flow in the capture method. + * Return 1 for success and 0 on error */ + int (*BypassPacketsFlow)(struct Packet_ *); /* pkt vars */ PktVar *pktvar; @@ -449,10 +491,12 @@ typedef struct Packet_ /* Can only be one of TCP, UDP, ICMP at any given time */ union { TCPVars tcpvars; - UDPVars udpvars; ICMPV4Vars icmpv4vars; ICMPV6Vars icmpv6vars; - }; + } l4vars; +#define tcpvars l4vars.tcpvars +#define icmpv4vars l4vars.icmpv4vars +#define icmpv6vars l4vars.icmpv6vars TCPHdr *tcph; @@ -510,10 +554,6 @@ typedef struct Packet_ /** data linktype in host order */ int datalink; - /* used to hold flowbits only if debuglog is enabled */ - int debuglog_flowbits_names_len; - const char **debuglog_flowbits_names; - /* tunnel/encapsulation handling */ struct Packet_ *root; /* in case of tunnel this is a ptr * to the 'real' packet, the one we @@ -531,6 +571,9 @@ typedef struct Packet_ /* tunnel packet ref count */ uint16_t tunnel_tpr_cnt; + /** tenant id for this packet, if any. If 0 then no tenant was assigned. */ + uint32_t tenant_id; + /* The Packet pool from which this packet was allocated. Used when returning * the packet to its owner's stack. If NULL, then allocated with malloc. */ @@ -549,7 +592,12 @@ typedef struct Packet_ #endif Packet; -#define DEFAULT_PACKET_SIZE (1500 + ETHERNET_HEADER_LEN) +/** highest mtu of the interfaces we monitor */ +extern int g_default_mtu; +#define DEFAULT_MTU 1500 +#define MINIMUM_MTU 68 /**< ipv4 minimum: rfc791 */ + +#define DEFAULT_PACKET_SIZE (DEFAULT_MTU + ETHERNET_HEADER_LEN) /* storage: maximum ip packet size + link header */ #define MAX_PAYLOAD_SIZE (IPV6_HEADER_LEN + 65536 + 28) uint32_t default_packet_size; @@ -574,23 +622,26 @@ typedef struct DecodeThreadVars_ int vlan_disabled; - /* thread data for flow logging api */ - void *output_flow_thread_data; - /** stats/counters */ uint16_t counter_pkts; uint16_t counter_bytes; + uint16_t counter_avg_pkt_size; + uint16_t counter_max_pkt_size; + uint16_t counter_invalid; + + uint16_t counter_eth; uint16_t counter_ipv4; uint16_t counter_ipv6; - uint16_t counter_eth; - uint16_t counter_sll; - uint16_t counter_raw; uint16_t counter_tcp; uint16_t counter_udp; - uint16_t counter_sctp; uint16_t counter_icmpv4; uint16_t counter_icmpv6; + + uint16_t counter_sll; + uint16_t counter_raw; + uint16_t counter_null; + uint16_t counter_sctp; uint16_t counter_ppp; uint16_t counter_gre; uint16_t counter_vlan; @@ -600,8 +651,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_mpls; uint16_t counter_ipv4inipv6; uint16_t counter_ipv6inipv6; - uint16_t counter_avg_pkt_size; - uint16_t counter_max_pkt_size; + uint16_t counter_erspan; /** frag stats - defrag runs in the context of the decoder. */ uint16_t counter_defrag_ipv4_fragments; @@ -612,11 +662,34 @@ typedef struct DecodeThreadVars_ uint16_t counter_defrag_ipv6_timeouts; uint16_t counter_defrag_max_hit; + uint16_t counter_flow_memcap; + + uint16_t counter_invalid_events[DECODE_EVENT_PACKET_MAX]; + /* thread data for flow logging api: only used at forced + * flow recycle during lookups */ + void *output_flow_thread_data; + #ifdef __SC_CUDA_SUPPORT__ CudaThreadVars cuda_vars; #endif } DecodeThreadVars; +typedef struct CaptureStats_ { + + uint16_t counter_ips_accepted; + uint16_t counter_ips_blocked; + uint16_t counter_ips_rejected; + uint16_t counter_ips_replaced; + +} CaptureStats; + +void CaptureStatsUpdate(ThreadVars *tv, CaptureStats *s, const Packet *p); +void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s); + +#define PACKET_CLEAR_L4VARS(p) do { \ + memset(&(p)->l4vars, 0x00, sizeof((p)->l4vars)); \ + } while (0) + /** * \brief reset these to -1(indicates that the packet is fresh from the queue) */ @@ -719,8 +792,10 @@ typedef struct DecodeThreadVars_ (p)->vlanh[1] = NULL; \ (p)->payload = NULL; \ (p)->payload_len = 0; \ + (p)->BypassPacketsFlow = NULL; \ (p)->pktlen = 0; \ (p)->alerts.cnt = 0; \ + (p)->alerts.drop.action = 0; \ (p)->pcap_cnt = 0; \ (p)->tunnel_rtv_cnt = 0; \ (p)->tunnel_tpr_cnt = 0; \ @@ -732,6 +807,7 @@ typedef struct DecodeThreadVars_ (p)->livedev = NULL; \ PACKET_RESET_CHECKSUMS((p)); \ PACKET_PROFILING_RESET((p)); \ + p->tenant_id = 0; \ } while (0) #define PACKET_RECYCLE(p) do { \ @@ -821,24 +897,36 @@ typedef struct DecodeThreadVars_ #define IS_TUNNEL_PKT_VERDICTED(p) (((p)->flags & PKT_TUNNEL_VERDICTED)) #define SET_TUNNEL_PKT_VERDICTED(p) ((p)->flags |= PKT_TUNNEL_VERDICTED) +enum DecodeTunnelProto { + DECODE_TUNNEL_ETHERNET, + DECODE_TUNNEL_ERSPAN, + DECODE_TUNNEL_VLAN, + DECODE_TUNNEL_IPV4, + DECODE_TUNNEL_IPV6, + DECODE_TUNNEL_PPP, +}; -void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, - uint8_t *pkt, uint16_t len, uint8_t proto, PacketQueue *pq); + uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto, PacketQueue *pq); Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto); void PacketDefragPktSetupParent(Packet *parent); +void DecodeRegisterPerfCounters(DecodeThreadVars *, ThreadVars *); Packet *PacketGetFromQueueOrAlloc(void); Packet *PacketGetFromAlloc(void); void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p); void PacketFree(Packet *p); void PacketFreeOrRelease(Packet *p); +int PacketCallocExtPkt(Packet *p, int datalen); int PacketCopyData(Packet *p, uint8_t *pktdata, int pktlen); int PacketSetData(Packet *p, uint8_t *pktdata, int pktlen); int PacketCopyDataOffset(Packet *p, int offset, uint8_t *data, int datalen); const char *PktSrcToString(enum PktSrcEnum pkt_src); +void PacketBypassCallback(Packet *p); DecodeThreadVars *DecodeThreadVarsAlloc(ThreadVars *); void DecodeThreadVarsFree(ThreadVars *, DecodeThreadVars *); +void DecodeUpdatePacketCounters(ThreadVars *tv, + const DecodeThreadVars *dtv, const Packet *p); /* decoder functions */ int DecodeEthernet(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); @@ -846,7 +934,8 @@ int DecodeSll(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, P int DecodePPP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodePPPOESession(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); -int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *, uint8_t) __attribute__ ((warn_unused_result)); +int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *, enum DecodeTunnelProto) __attribute__ ((warn_unused_result)); +int DecodeNull(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeIPV6(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); @@ -858,9 +947,18 @@ int DecodeSCTP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, int DecodeGRE(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeVLAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int DecodeMPLS(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); +int DecodeERSPAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void AddressDebugPrint(Address *); +#ifdef AFLFUZZ_DECODER +typedef int (*DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, + uint8_t *pkt, uint16_t len, PacketQueue *pq); + +int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); +int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder); +#endif + /** \brief Set the No payload inspection Flag for the packet. * * \param p Packet to set the flag in @@ -869,6 +967,10 @@ void AddressDebugPrint(Address *); (p)->flags |= PKT_NOPAYLOAD_INSPECTION; \ } while (0) +#define DecodeUnsetNoPayloadInspectionFlag(p) do { \ + (p)->flags &= ~PKT_NOPAYLOAD_INSPECTION; \ + } while (0) + /** \brief Set the No packet inspection Flag for the packet. * * \param p Packet to set the flag in @@ -876,6 +978,9 @@ void AddressDebugPrint(Address *); #define DecodeSetNoPacketInspectionFlag(p) do { \ (p)->flags |= PKT_NOPACKET_INSPECTION; \ } while (0) +#define DecodeUnsetNoPacketInspectionFlag(p) do { \ + (p)->flags &= ~PKT_NOPACKET_INSPECTION; \ + } while (0) #define ENGINE_SET_EVENT(p, e) do { \ @@ -905,6 +1010,10 @@ void AddressDebugPrint(Address *); r; \ }) +#ifndef IPPROTO_IPIP +#define IPPROTO_IPIP 4 +#endif + /* older libcs don't contain a def for IPPROTO_DCCP * inside of * if it isn't defined let's define it here. @@ -948,8 +1057,13 @@ void AddressDebugPrint(Address *); #endif #endif +#ifndef DLT_NULL +#define DLT_NULL 0 +#endif + /** libpcap shows us the way to linktype codes * \todo we need more & maybe put them in a separate file? */ +#define LINKTYPE_NULL DLT_NULL #define LINKTYPE_ETHERNET DLT_EN10MB #define LINKTYPE_LINUX_SLL 113 #define LINKTYPE_PPP 9 @@ -984,6 +1098,17 @@ void AddressDebugPrint(Address *); #define PKT_IS_INVALID (1<<20) #define PKT_PROFILE (1<<21) +/** indication by decoder that it feels the packet should be handled by + * flow engine: Packet::flow_hash will be set */ +#define PKT_WANTS_FLOW (1<<22) + +/** protocol detection done */ +#define PKT_PROTO_DETECT_TS_DONE (1<<23) +#define PKT_PROTO_DETECT_TC_DONE (1<<24) + +#define PKT_REBUILT_FRAGMENT (1<<25) /**< Packet is rebuilt from + * fragments. */ + /** \brief return 1 if the packet is a pseudo packet */ #define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END) diff --git a/src/defrag-config.c b/src/defrag-config.c index 5bc4be36b67a..a1e1b4f94a94 100644 --- a/src/defrag-config.c +++ b/src/defrag-config.c @@ -160,3 +160,11 @@ void DefragPolicyLoadFromConfig(void) } } } + +void DefragTreeDestroy(void) +{ + if (defrag_tree != NULL) { + SCRadixReleaseRadixTree(defrag_tree); + } + defrag_tree = NULL; +} diff --git a/src/defrag-config.h b/src/defrag-config.h index a6c086ff0313..08abd00b9c16 100644 --- a/src/defrag-config.h +++ b/src/defrag-config.h @@ -28,5 +28,6 @@ void DefragSetDefaultTimeout(intmax_t timeout); void DefragPolicyLoadFromConfig(void); int DefragPolicyGetHostTimeout(Packet *p); +void DefragTreeDestroy(void); #endif /* DEFRAG_CONFIG_H_ */ diff --git a/src/defrag-hash.c b/src/defrag-hash.c index 9cb377e5b3f2..54206b2c73cc 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -92,28 +92,18 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p) dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p); dt->af = AF_INET6; } + dt->proto = IP_GET_IPPROTO(p); dt->vlan_id[0] = p->vlan_id[0]; dt->vlan_id[1] = p->vlan_id[1]; dt->policy = DefragGetOsPolicy(p); dt->host_timeout = DefragPolicyGetHostTimeout(p); + dt->remove = 0; + dt->seen_last = 0; TAILQ_INIT(&dt->frags); (void) DefragTrackerIncrUsecnt(dt); } -static DefragTracker *DefragTrackerNew(Packet *p) -{ - DefragTracker *dt = DefragTrackerAlloc(); - if (dt == NULL) - goto error; - - DefragTrackerInit(dt, p); - return dt; - -error: - return NULL; -} - void DefragTrackerRelease(DefragTracker *t) { (void) DefragTrackerDecrUsecnt(t); @@ -143,10 +133,11 @@ void DefragInitConfig(char quiet) SC_ATOMIC_INIT(defragtracker_prune_idx); DefragTrackerQueueInit(&defragtracker_spare_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ defrag_config.hash_rand = (int)(DEFRAG_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif defrag_config.hash_size = DEFRAG_DEFAULT_HASHSIZE; defrag_config.memcap = DEFRAG_DEFAULT_MEMCAP; defrag_config.prealloc = DEFRAG_DEFAULT_PREALLOC; @@ -214,7 +205,7 @@ void DefragInitConfig(char quiet) (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the defrag hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size, (uintmax_t)sizeof(DefragTrackerHashRow)); @@ -241,14 +232,14 @@ void DefragInitConfig(char quiet) DefragTrackerEnqueue(&defragtracker_spare_q,h); } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "", + SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "", defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker)); } } } if (quiet == FALSE) { - SCLogInfo("defrag memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(defrag_memuse), defrag_config.memcap); } @@ -416,6 +407,7 @@ static inline uint32_t DefragHashGetKey(Packet *p) CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \ CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ + (d1)->proto == IP_GET_IPPROTO(d2) && \ (d1)->id == (id) && \ (d1)->vlan_id[0] == (d2)->vlan_id[0] && \ (d1)->vlan_id[1] == (d2)->vlan_id[1]) @@ -467,7 +459,7 @@ static DefragTracker *DefragTrackerGetNew(Packet *p) /* freed a tracker, but it's unlocked */ } else { /* now see if we can alloc a new tracker */ - dt = DefragTrackerNew(p); + dt = DefragTrackerAlloc(); if (dt == NULL) { return NULL; } @@ -526,7 +518,7 @@ DefragTracker *DefragGetTrackerFromHash (Packet *p) dt = hb->head; /* see if this is the tracker we are looking for */ - if (DefragTrackerCompare(dt, p) == 0) { + if (dt->remove || DefragTrackerCompare(dt, p) == 0) { DefragTracker *pdt = NULL; /* previous tracker */ while (dt) { diff --git a/src/defrag-hash.h b/src/defrag-hash.h index 2d48393a77c4..5697fdb9582c 100644 --- a/src/defrag-hash.h +++ b/src/defrag-hash.h @@ -85,7 +85,7 @@ typedef struct DefragConfig_ { ((((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)(size)) <= defrag_config.memcap)) DefragConfig defrag_config; -SC_ATOMIC_DECLARE(unsigned long long int,defrag_memuse); +SC_ATOMIC_DECLARE(uint64_t,defrag_memuse); SC_ATOMIC_DECLARE(unsigned int,defragtracker_counter); SC_ATOMIC_DECLARE(unsigned int,defragtracker_prune_idx); diff --git a/src/defrag.c b/src/defrag.c index 7d38dec1c9e5..11cda60e991a 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -256,8 +256,9 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) Packet *rp = NULL; /* Should not be here unless we have seen the last fragment. */ - if (!tracker->seen_last) + if (!tracker->seen_last) { return NULL; + } /* Check that we have all the data. Relies on the fact that * fragments are inserted if frag_offset order. */ @@ -291,9 +292,10 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (rp == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for " "fragmentation re-assembly, dumping fragments."); - goto remove_tracker; + goto error_remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); + rp->flags |= PKT_REBUILT_FRAGMENT; rp->recursion_level = p->recursion_level; int fragmentable_offset = 0; @@ -311,7 +313,7 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (frag->offset == 0) { if (PacketCopyData(rp, frag->pkt, frag->len) == -1) - goto remove_tracker; + goto error_remove_tracker; hlen = frag->hlen; ip_hdr_offset = frag->ip_hdr_offset; @@ -327,16 +329,21 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (pkt_end > (int)MAX_PAYLOAD_SIZE) { SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble " "fragmented packet, exceeds size of packet buffer."); - goto remove_tracker; + goto error_remove_tracker; } - if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, - frag->pkt + frag->data_offset + frag->ltrim, - frag->data_len - frag->ltrim) == -1) { - goto remove_tracker; + if (PacketCopyDataOffset(rp, + fragmentable_offset + frag->offset + frag->ltrim, + frag->pkt + frag->data_offset + frag->ltrim, + frag->data_len - frag->ltrim) == -1) { + goto error_remove_tracker; } if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } + + if (!frag->more_frags) { + break; + } } SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u", @@ -350,12 +357,17 @@ Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) old, rp->ip4h->ip_len + rp->ip4h->ip_off); SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len); -remove_tracker: - /** \todo check locking */ tracker->remove = 1; DefragTrackerFreeFrags(tracker); done: return rp; + +error_remove_tracker: + tracker->remove = 1; + DefragTrackerFreeFrags(tracker); + if (rp != NULL) + PacketFreeOrRelease(rp); + return NULL; } /** @@ -405,7 +417,7 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) if (rp == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for " "fragmentation re-assembly, dumping fragments."); - goto remove_tracker; + goto error_remove_tracker; } PKT_SET_SRC(rp, PKT_SRC_DEFRAG); @@ -428,11 +440,11 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * IPv6 headers. We also copy in its data, but remove the * fragmentation header. */ if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1) - goto remove_tracker; + goto error_remove_tracker; if (PacketCopyDataOffset(rp, frag->frag_hdr_offset, frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr), frag->data_len) == -1) - goto remove_tracker; + goto error_remove_tracker; ip_hdr_offset = frag->ip_hdr_offset; /* This is the start of the fragmentable portion of the @@ -445,16 +457,20 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) * and the frag header. */ unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN; if (unfragmentable_len >= fragmentable_offset) - goto remove_tracker; + goto error_remove_tracker; } else { if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim, frag->pkt + frag->data_offset + frag->ltrim, frag->data_len - frag->ltrim) == -1) - goto remove_tracker; + goto error_remove_tracker; if (frag->offset + frag->data_len > fragmentable_len) fragmentable_len = frag->offset + frag->data_len; } + + if (!frag->more_frags) { + break; + } } rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset); @@ -468,12 +484,17 @@ Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p) SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) + unfragmentable_len + fragmentable_len); -remove_tracker: - /** \todo check locking */ tracker->remove = 1; DefragTrackerFreeFrags(tracker); done: return rp; + +error_remove_tracker: + tracker->remove = 1; + DefragTrackerFreeFrags(tracker); + if (rp != NULL) + PacketFreeOrRelease(rp); + return NULL; } /** @@ -541,26 +562,27 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, else if (tracker->af == AF_INET6) { more_frags = IPV6_EXTHDR_GET_FH_FLAG(p); frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p); - data_offset = (uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr) - GET_PKT_DATA(p); - data_len = IPV6_GET_PLEN(p) - ( - ((uint8_t *)p->ip6eh.ip6fh + sizeof(IPV6FragHdr)) - - ((uint8_t *)p->ip6h + sizeof(IPV6Hdr))); + data_offset = p->ip6eh.fh_data_offset; + data_len = p->ip6eh.fh_data_len; frag_end = frag_offset + data_len; ip_hdr_offset = (uint8_t *)p->ip6h - GET_PKT_DATA(p); - frag_hdr_offset = (uint8_t *)p->ip6eh.ip6fh - GET_PKT_DATA(p); + frag_hdr_offset = p->ip6eh.fh_header_offset; + + SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, " + "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u", + more_frags ? "true" : "false", frag_offset, data_offset, + data_len, frag_end, ip_hdr_offset, frag_hdr_offset); /* handle unfragmentable exthdrs */ if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) { - SCLogDebug("we have exthdrs before fraghdr %u bytes (%u hdrs total)", - (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)), - p->ip6eh.ip6_exthdrs_cnt); + SCLogDebug("we have exthdrs before fraghdr %u bytes", + (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN))); /* get the offset of the 'next' field in exthdr before the FH, * relative to the buffer start */ - int t_offset = (int)((p->ip6eh.ip6_exthdrs[p->ip6eh.ip6_exthdrs_cnt - 2].data - 2) - GET_PKT_DATA(p)); /* store offset and FH 'next' value for updating frag buffer below */ - ip6_nh_set_offset = (int)t_offset; + ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset; ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p); SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value); } @@ -584,9 +606,12 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Frag *prev = NULL, *next; int overlap = 0; + ltrim = 0; if (!TAILQ_EMPTY(&tracker->frags)) { TAILQ_FOREACH(prev, &tracker->frags, next) { - ltrim = 0; + if (prev->skip) { + continue; + } next = TAILQ_NEXT(prev, next); switch (tracker->policy) { @@ -609,34 +634,81 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } break; case DEFRAG_POLICY_LINUX: - if (frag_offset < prev->offset + prev->data_len) { - if (frag_offset > prev->offset) { - ltrim = prev->offset + prev->data_len - frag_offset; - overlap++; - } - if ((next != NULL) && (frag_end > next->offset)) { - next->ltrim = frag_end - next->offset; - overlap++; - } - if ((frag_offset < prev->offset) && - (frag_end >= prev->offset + prev->data_len)) { - prev->skip = 1; - overlap++; - } - goto insert; + /* Check if new fragment overlaps the end of previous + * fragment, if it does, trim the new fragment. + * + * Old: AAAAAAAA AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB + */ + if (prev->offset + prev->ltrim < frag_offset + ltrim && + prev->offset + prev->data_len > frag_offset + ltrim) { + ltrim += prev->offset + prev->data_len - frag_offset; + overlap++; + } + + /* Check if new fragment overlaps the beginning of + * previous fragment, if it does, tim the previous + * fragment. + * + * Old: AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: BBBBBBBB BBBBBBBB BBBBBBBB + */ + if (frag_offset + ltrim < prev->offset + prev->ltrim && + frag_end > prev->offset + prev->ltrim) { + prev->ltrim += frag_end - (prev->offset + prev->ltrim); + overlap++; + } + + /* If the new fragment completely overlaps the + * previous fragment, mark the previous to be + * skipped. Re-assembly would succeed without doing + * this, but this will prevent the bytes from being + * copied just to be overwritten. */ + if (frag_offset + ltrim <= prev->offset + prev->ltrim && + frag_end >= prev->offset + prev->data_len) { + prev->skip = 1; } break; case DEFRAG_POLICY_WINDOWS: - if (frag_offset < prev->offset + prev->data_len) { - if (frag_offset >= prev->offset) { - ltrim = prev->offset + prev->data_len - frag_offset; - overlap++; - } - if ((frag_offset < prev->offset) && - (frag_end > prev->offset + prev->data_len)) { - prev->skip = 1; - overlap++; - } + /* If new fragment fits inside a previous fragment, drop it. */ + if (frag_offset + ltrim >= prev->offset + ltrim && + frag_end <= prev->offset + prev->data_len) { + overlap++; + goto done; + } + + /* If new fragment starts before and ends after + * previous fragment, drop the previous fragment. */ + if (frag_offset + ltrim < prev->offset + ltrim && + frag_end > prev->offset + prev->data_len) { + prev->skip = 1; + overlap++; + goto insert; + } + + /* Check if new fragment overlaps the end of previous + * fragment, if it does, trim the new fragment. + * + * Old: AAAAAAAA AAAAAAAA AAAAAAAA + * New: BBBBBBBB BBBBBBBB BBBBBBBB + * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB + */ + if (frag_offset + ltrim > prev->offset + prev->ltrim && + frag_offset + ltrim < prev->offset + prev->data_len) { + ltrim += prev->offset + prev->data_len - frag_offset; + overlap++; + goto insert; + } + + /* If new fragment starts at same offset as an + * existing fragment, but ends after it, trim the new + * fragment. */ + if (frag_offset + ltrim == prev->offset + ltrim && + frag_end > prev->offset + prev->data_len) { + ltrim += prev->offset + prev->data_len - frag_offset; + overlap++; goto insert; } break; @@ -685,12 +757,9 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, } insert: - if (data_len - ltrim <= 0) { - if (af == AF_INET) { - ENGINE_SET_EVENT(p, IPV4_FRAG_TOO_LARGE); - } else { - ENGINE_SET_EVENT(p, IPV6_FRAG_TOO_LARGE); - } + if (ltrim > data_len) { + /* Full packet has been trimmed due to the overlap policy. Overlap + * already set. */ goto done; } @@ -737,6 +806,7 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, new->data_len = data_len - ltrim; new->ip_hdr_offset = ip_hdr_offset; new->frag_hdr_offset = frag_hdr_offset; + new->more_frags = more_frags; #ifdef DEBUG new->pcap_cnt = pcap_cnt; #endif @@ -761,11 +831,14 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, if (tracker->af == AF_INET) { r = Defrag4Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { - SCPerfCounterIncr(dtv->counter_defrag_ipv4_reassembled, - tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled); if (pq && DecodeIPV4(tv, dtv, r, (void *)r->ip4h, IPV4_GET_IPLEN(r), pq) != TM_ECODE_OK) { + + UNSET_TUNNEL_PKT(r); + r->root = NULL; TmqhOutputPacketpool(tv, r); + r = NULL; } else { PacketDefragPktSetupParent(p); } @@ -774,12 +847,15 @@ DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, else if (tracker->af == AF_INET6) { r = Defrag6Reassemble(tv, tracker, p); if (r != NULL && tv != NULL && dtv != NULL) { - SCPerfCounterIncr(dtv->counter_defrag_ipv6_reassembled, - tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled); if (pq && DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h, IPV6_GET_PLEN(r) + IPV6_HEADER_LEN, pq) != TM_ECODE_OK) { + + UNSET_TUNNEL_PKT(r); + r->root = NULL; TmqhOutputPacketpool(tv, r); + r = NULL; } else { PacketDefragPktSetupParent(p); } @@ -915,12 +991,10 @@ Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, PacketQueue *pq) if (tv != NULL && dtv != NULL) { if (af == AF_INET) { - SCPerfCounterIncr(dtv->counter_defrag_ipv4_fragments, - tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_defrag_ipv4_fragments); } else if (af == AF_INET6) { - SCPerfCounterIncr(dtv->counter_defrag_ipv6_fragments, - tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_defrag_ipv6_fragments); } } @@ -963,6 +1037,7 @@ void DefragDestroy(void) DefragHashShutdown(); DefragContextDestroy(defrag_context); defrag_context = NULL; + DefragTreeDestroy(); } #ifdef UNITTESTS @@ -972,9 +1047,8 @@ void DefragDestroy(void) * Allocate a test packet. Nothing to fancy, just a simple IP packet * with some payload of no particular protocol. */ -static Packet * -BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, - int content_len) +static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf, + const char content, int content_len) { Packet *p = NULL; int hlen = 20; @@ -994,13 +1068,12 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, ip4h.ip_verhl |= hlen >> 2; ip4h.ip_len = htons(hlen + content_len); ip4h.ip_id = htons(id); - ip4h.ip_off = htons(off); if (mf) ip4h.ip_off = htons(IP_MF | off); else ip4h.ip_off = htons(off); ip4h.ip_ttl = ttl; - ip4h.ip_proto = IPPROTO_ICMP; + ip4h.ip_proto = proto; ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */ ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */ @@ -1019,7 +1092,7 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, SET_PKT_LEN(p, hlen + content_len); SCFree(pcontent); - p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)GET_PKT_DATA(p), hlen); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0); /* Self test. */ if (IPV4_GET_VER(p) != 4) @@ -1036,7 +1109,7 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, goto error; if (IPV4_GET_IPTTL(p) != ttl) goto error; - if (IPV4_GET_IPPROTO(p) != IPPROTO_ICMP) + if (IPV4_GET_IPPROTO(p) != proto) goto error; return p; @@ -1046,9 +1119,12 @@ BuildTestPacket(uint16_t id, uint16_t off, int mf, const char content, return NULL; } -static Packet * -IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, - int content_len) +void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, + uint16_t hdrextlen, uint16_t plen, + uint16_t prev_hdrextlen); + +static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off, + int mf, const char content, int content_len) { Packet *p = NULL; uint8_t *pcontent; @@ -1082,10 +1158,11 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, IPV6_SET_RAW_VER(p->ip6h, 6); /* Fragmentation header. */ IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr)); - fh->ip6fh_nxt = IPPROTO_ICMP; + fh->ip6fh_nxt = proto; fh->ip6fh_ident = htonl(id); fh->ip6fh_offlg = htons((off << 3) | mf); - p->ip6eh.ip6fh = fh; + + DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0); pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) @@ -1110,7 +1187,6 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, return p; error: - fprintf(stderr, "Error building test packet.\n"); if (p != NULL) SCFree(p); return NULL; @@ -1120,294 +1196,212 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, * Test the simplest possible re-assembly scenario. All packet in * order and no overlaps. */ -static int -DefragInOrderSimpleTest(void) +static int DefragInOrderSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); - p1 = BuildTestPacket(id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; - p2 = BuildTestPacket(id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; - p3 = BuildTestPacket(id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; - - if (Defrag(NULL, NULL, p1, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8); + FAIL_IF_NULL(p2); + p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); + FAIL_IF_NULL(p3); + + FAIL_IF(Defrag(NULL, NULL, p1, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p3, NULL); - if (reassembled == NULL) { - goto end; - } + FAIL_IF_NULL(reassembled); - if (IPV4_GET_HLEN(reassembled) != 20) { - goto end; - } - if (IPV4_GET_IPLEN(reassembled) != 39) { - goto end; - } + FAIL_IF(IPV4_GET_HLEN(reassembled) != 20); + FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39); /* 20 bytes in we should find 8 bytes of A. */ for (i = 20; i < 20 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') { - goto end; - } + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 28; i < 28 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') { - goto end; - } + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 36; i < 36 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; - -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } /** * Simple fragmented packet in reverse order. */ -static int -DefragReverseSimpleTest(void) +static int DefragReverseSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); - p1 = BuildTestPacket(id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; - p2 = BuildTestPacket(id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; - p3 = BuildTestPacket(id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; - - if (Defrag(NULL, NULL, p3, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8); + FAIL_IF_NULL(p2); + p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); + FAIL_IF_NULL(p3); + + FAIL_IF(Defrag(NULL, NULL, p3, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p1, NULL); - if (reassembled == NULL) - goto end; + FAIL_IF_NULL(reassembled); - if (IPV4_GET_HLEN(reassembled) != 20) - goto end; - if (IPV4_GET_IPLEN(reassembled) != 39) - goto end; + FAIL_IF(IPV4_GET_HLEN(reassembled) != 20); + FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39); /* 20 bytes in we should find 8 bytes of A. */ for (i = 20; i < 20 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 28; i < 28 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 36; i < 36 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } /** * Test the simplest possible re-assembly scenario. All packet in * order and no overlaps. */ -static int -IPV6DefragInOrderSimpleTest(void) +static int IPV6DefragInOrderSimpleTest(void) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); - p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; - p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; - p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; - - if (Defrag(NULL, NULL, p1, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8); + FAIL_IF_NULL(p2); + p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3); + FAIL_IF_NULL(p3); + + FAIL_IF(Defrag(NULL, NULL, p1, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p3, NULL); - if (reassembled == NULL) - goto end; + FAIL_IF_NULL(reassembled); - if (IPV6_GET_PLEN(reassembled) != 19) - goto end; + FAIL_IF(IPV6_GET_PLEN(reassembled) != 19); /* 40 bytes in we should find 8 bytes of A. */ for (i = 40; i < 40 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 48; i < 48 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 56; i < 56 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } -static int -IPV6DefragReverseSimpleTest(void) +static int IPV6DefragReverseSimpleTest(void) { DefragContext *dc = NULL; Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; Packet *reassembled = NULL; int id = 12; int i; - int ret = 0; DefragInit(); dc = DefragContextNew(); - if (dc == NULL) - goto end; - - p1 = IPV6BuildTestPacket(id, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; - p2 = IPV6BuildTestPacket(id, 1, 1, 'B', 8); - if (p2 == NULL) - goto end; - p3 = IPV6BuildTestPacket(id, 2, 0, 'C', 3); - if (p3 == NULL) - goto end; - - if (Defrag(NULL, NULL, p3, NULL) != NULL) - goto end; - if (Defrag(NULL, NULL, p2, NULL) != NULL) - goto end; + FAIL_IF_NULL(dc); + + p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8); + FAIL_IF_NULL(p2); + p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3); + FAIL_IF_NULL(p3); + + FAIL_IF(Defrag(NULL, NULL, p3, NULL) != NULL); + FAIL_IF(Defrag(NULL, NULL, p2, NULL) != NULL); reassembled = Defrag(NULL, NULL, p1, NULL); - if (reassembled == NULL) - goto end; + FAIL_IF_NULL(reassembled); /* 40 bytes in we should find 8 bytes of A. */ for (i = 40; i < 40 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'A') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A'); } /* 28 bytes in we should find 8 bytes of B. */ for (i = 48; i < 48 + 8; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'B') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B'); } /* And 36 bytes in we should find 3 bytes of C. */ for (i = 56; i < 56 + 3; i++) { - if (GET_PKT_DATA(reassembled)[i] != 'C') - goto end; + FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C'); } - ret = 1; -end: - if (dc != NULL) - DefragContextDestroy(dc); - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); - if (p3 != NULL) - SCFree(p3); - if (reassembled != NULL) - SCFree(reassembled); + DefragContextDestroy(dc); + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(reassembled); DefragDestroy(); - return ret; + PASS; } -static int -DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) +static int DefragDoSturgesNovakTest(int policy, u_char *expected, + size_t expected_len) { int i; - int ret = 0; DefragInit(); @@ -1424,125 +1418,102 @@ DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) */ /* A*24 at 0. */ - packets[0] = BuildTestPacket(id, 0, 1, 'A', 24); + packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24); /* B*15 at 32. */ - packets[1] = BuildTestPacket(id, 32 >> 3, 1, 'B', 16); + packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16); /* C*24 at 48. */ - packets[2] = BuildTestPacket(id, 48 >> 3, 1, 'C', 24); + packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24); /* D*8 at 80. */ - packets[3] = BuildTestPacket(id, 80 >> 3, 1, 'D', 8); + packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8); /* E*16 at 104. */ - packets[4] = BuildTestPacket(id, 104 >> 3, 1, 'E', 16); + packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16); /* F*24 at 120. */ - packets[5] = BuildTestPacket(id, 120 >> 3, 1, 'F', 24); + packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24); /* G*16 at 144. */ - packets[6] = BuildTestPacket(id, 144 >> 3, 1, 'G', 16); + packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16); /* H*16 at 160. */ - packets[7] = BuildTestPacket(id, 160 >> 3, 1, 'H', 16); + packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16); /* I*8 at 176. */ - packets[8] = BuildTestPacket(id, 176 >> 3, 1, 'I', 8); + packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8); /* * Overlapping subsequent fragments. */ /* J*32 at 8. */ - packets[9] = BuildTestPacket(id, 8 >> 3, 1, 'J', 32); + packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32); /* K*24 at 48. */ - packets[10] = BuildTestPacket(id, 48 >> 3, 1, 'K', 24); + packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24); /* L*24 at 72. */ - packets[11] = BuildTestPacket(id, 72 >> 3, 1, 'L', 24); + packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24); /* M*24 at 96. */ - packets[12] = BuildTestPacket(id, 96 >> 3, 1, 'M', 24); + packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24); /* N*8 at 128. */ - packets[13] = BuildTestPacket(id, 128 >> 3, 1, 'N', 8); + packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8); /* O*8 at 152. */ - packets[14] = BuildTestPacket(id, 152 >> 3, 1, 'O', 8); + packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8); /* P*8 at 160. */ - packets[15] = BuildTestPacket(id, 160 >> 3, 1, 'P', 8); + packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8); /* Q*16 at 176. */ - packets[16] = BuildTestPacket(id, 176 >> 3, 0, 'Q', 16); + packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16); default_policy = policy; /* Send all but the last. */ for (i = 0; i < 9; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } - if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) { - goto end; - } + FAIL_IF_NOT_NULL(tp); + FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)); } int overlap = 0; for (; i < 16; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) { overlap++; } } - if (!overlap) { - goto end; - } + FAIL_IF_NOT(overlap); /* And now the last one. */ Packet *reassembled = Defrag(NULL, NULL, packets[16], NULL); - if (reassembled == NULL) { - goto end; - } + FAIL_IF_NULL(reassembled); - if (IPV4_GET_HLEN(reassembled) != 20) { - goto end; - } - if (IPV4_GET_IPLEN(reassembled) != 20 + 192) { - goto end; - } + FAIL_IF(IPV4_GET_HLEN(reassembled) != 20); + FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192); - if (memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0) { - goto end; - } + FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0); SCFree(reassembled); /* Make sure all frags were returned back to the pool. */ - if (defrag_context->frag_pool->outstanding != 0) { - goto end; - } + FAIL_IF(defrag_context->frag_pool->outstanding != 0); - ret = 1; -end: for (i = 0; i < 17; i++) { SCFree(packets[i]); } DefragDestroy(); - return ret; + PASS; } -static int -IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) +static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, + size_t expected_len) { int i; - int ret = 0; DefragInit(); @@ -1559,113 +1530,95 @@ IPV6DefragDoSturgesNovakTest(int policy, u_char *expected, size_t expected_len) */ /* A*24 at 0. */ - packets[0] = IPV6BuildTestPacket(id, 0, 1, 'A', 24); + packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24); /* B*15 at 32. */ - packets[1] = IPV6BuildTestPacket(id, 32 >> 3, 1, 'B', 16); + packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16); /* C*24 at 48. */ - packets[2] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'C', 24); + packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24); /* D*8 at 80. */ - packets[3] = IPV6BuildTestPacket(id, 80 >> 3, 1, 'D', 8); + packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8); /* E*16 at 104. */ - packets[4] = IPV6BuildTestPacket(id, 104 >> 3, 1, 'E', 16); + packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16); /* F*24 at 120. */ - packets[5] = IPV6BuildTestPacket(id, 120 >> 3, 1, 'F', 24); + packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24); /* G*16 at 144. */ - packets[6] = IPV6BuildTestPacket(id, 144 >> 3, 1, 'G', 16); + packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16); /* H*16 at 160. */ - packets[7] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'H', 16); + packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16); /* I*8 at 176. */ - packets[8] = IPV6BuildTestPacket(id, 176 >> 3, 1, 'I', 8); + packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8); /* * Overlapping subsequent fragments. */ /* J*32 at 8. */ - packets[9] = IPV6BuildTestPacket(id, 8 >> 3, 1, 'J', 32); + packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32); /* K*24 at 48. */ - packets[10] = IPV6BuildTestPacket(id, 48 >> 3, 1, 'K', 24); + packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24); /* L*24 at 72. */ - packets[11] = IPV6BuildTestPacket(id, 72 >> 3, 1, 'L', 24); + packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24); /* M*24 at 96. */ - packets[12] = IPV6BuildTestPacket(id, 96 >> 3, 1, 'M', 24); + packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24); /* N*8 at 128. */ - packets[13] = IPV6BuildTestPacket(id, 128 >> 3, 1, 'N', 8); + packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8); /* O*8 at 152. */ - packets[14] = IPV6BuildTestPacket(id, 152 >> 3, 1, 'O', 8); + packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8); /* P*8 at 160. */ - packets[15] = IPV6BuildTestPacket(id, 160 >> 3, 1, 'P', 8); + packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8); /* Q*16 at 176. */ - packets[16] = IPV6BuildTestPacket(id, 176 >> 3, 0, 'Q', 16); + packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16); default_policy = policy; /* Send all but the last. */ for (i = 0; i < 9; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } - if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) { - goto end; - } + FAIL_IF_NOT_NULL(tp); + FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)); } int overlap = 0; for (; i < 16; i++) { Packet *tp = Defrag(NULL, NULL, packets[i], NULL); - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) { overlap++; } } - if (!overlap) - goto end; + FAIL_IF_NOT(overlap); /* And now the last one. */ Packet *reassembled = Defrag(NULL, NULL, packets[16], NULL); - if (reassembled == NULL) - goto end; - if (memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0) - goto end; + FAIL_IF_NULL(reassembled); + FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0); - if (IPV6_GET_PLEN(reassembled) != 192) - goto end; + FAIL_IF(IPV6_GET_PLEN(reassembled) != 192); SCFree(reassembled); /* Make sure all frags were returned to the pool. */ - if (defrag_context->frag_pool->outstanding != 0) { - printf("defrag_context->frag_pool->outstanding %u: ", defrag_context->frag_pool->outstanding); - goto end; - } - - ret = 1; + FAIL_IF(defrag_context->frag_pool->outstanding != 0); -end: for (i = 0; i < 17; i++) { SCFree(packets[i]); } DefragDestroy(); - return ret; + PASS; } static int @@ -1699,11 +1652,12 @@ DefragSturgesNovakBsdTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakBsdTest(void) +static int IPV6DefragSturgesNovakBsdTest(void) { /* Expected data. */ u_char expected[] = { @@ -1733,11 +1687,12 @@ IPV6DefragSturgesNovakBsdTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakLinuxTest(void) +static int DefragSturgesNovakLinuxIpv4Test(void) { /* Expected data. */ u_char expected[] = { @@ -1767,11 +1722,12 @@ DefragSturgesNovakLinuxTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakLinuxTest(void) +static int IPV6DefragSturgesNovakLinuxTest(void) { /* Expected data. */ u_char expected[] = { @@ -1801,12 +1757,12 @@ IPV6DefragSturgesNovakLinuxTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakWindowsTest(void) +static int DefragSturgesNovakWindowsIpv4Test(void) { /* Expected data. */ u_char expected[] = { @@ -1836,11 +1792,12 @@ DefragSturgesNovakWindowsTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakWindowsTest(void) +static int IPV6DefragSturgesNovakWindowsTest(void) { /* Expected data. */ u_char expected[] = { @@ -1870,12 +1827,12 @@ IPV6DefragSturgesNovakWindowsTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakSolarisTest(void) +static int DefragSturgesNovakSolarisTest(void) { /* Expected data. */ u_char expected[] = { @@ -1905,11 +1862,12 @@ DefragSturgesNovakSolarisTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakSolarisTest(void) +static int IPV6DefragSturgesNovakSolarisTest(void) { /* Expected data. */ u_char expected[] = { @@ -1939,12 +1897,12 @@ IPV6DefragSturgesNovakSolarisTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected, + sizeof(expected))); + PASS; } -static int -DefragSturgesNovakFirstTest(void) +static int DefragSturgesNovakFirstTest(void) { /* Expected data. */ u_char expected[] = { @@ -1974,11 +1932,12 @@ DefragSturgesNovakFirstTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakFirstTest(void) +static int IPV6DefragSturgesNovakFirstTest(void) { /* Expected data. */ u_char expected[] = { @@ -2043,11 +2002,12 @@ DefragSturgesNovakLastTest(void) "QQQQQQQQ" }; - return DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, sizeof(expected)); + FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, + sizeof(expected))); + PASS; } -static int -IPV6DefragSturgesNovakLastTest(void) +static int IPV6DefragSturgesNovakLastTest(void) { /* Expected data. */ u_char expected[] = { @@ -2077,67 +2037,48 @@ IPV6DefragSturgesNovakLastTest(void) "QQQQQQQQ" }; - return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, - sizeof(expected)); + FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected, + sizeof(expected))); + PASS; } -static int -DefragTimeoutTest(void) +static int DefragTimeoutTest(void) { int i; - int ret = 0; /* Setup a small numberr of trackers. */ - if (ConfSet("defrag.trackers", "16") != 1) { - printf("ConfSet failed: "); - goto end; - } + FAIL_IF_NOT(ConfSet("defrag.trackers", "16")); DefragInit(); /* Load in 16 packets. */ for (i = 0; i < 16; i++) { - Packet *p = BuildTestPacket(i, 0, 1, 'A' + i, 16); - if (p == NULL) - goto end; + Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16); + FAIL_IF_NULL(p); Packet *tp = Defrag(NULL, NULL, p, NULL); - SCFree(p); - - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); } /* Build a new packet but push the timestamp out by our timeout. * This should force our previous fragments to be timed out. */ - Packet *p = BuildTestPacket(99, 0, 1, 'A' + i, 16); - if (p == NULL) - goto end; + Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16); + FAIL_IF_NULL(p); p->ts.tv_sec += (defrag_context->timeout + 1); Packet *tp = Defrag(NULL, NULL, p, NULL); - - if (tp != NULL) { - SCFree(tp); - goto end; - } + FAIL_IF_NOT_NULL(tp); DefragTracker *tracker = DefragLookupTrackerFromHash(p); - if (tracker == NULL) - goto end; + FAIL_IF_NULL(tracker); - if (tracker->id != 99) - goto end; + FAIL_IF(tracker->id != 99); SCFree(p); - ret = 1; -end: DefragDestroy(); - return ret; + PASS; } /** @@ -2146,84 +2087,65 @@ DefragTimeoutTest(void) * fail. The fix was simple, but this unit test is just to make sure * its not introduced. */ -static int -DefragIPv4NoDataTest(void) +static int DefragIPv4NoDataTest(void) { DefragContext *dc = NULL; Packet *p = NULL; int id = 12; - int ret = 0; DefragInit(); dc = DefragContextNew(); - if (dc == NULL) - goto end; + FAIL_IF_NULL(dc); /* This packet has an offset > 0, more frags set to 0 and no data. */ - p = BuildTestPacket(id, 1, 0, 'A', 0); - if (p == NULL) - goto end; + p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0); + FAIL_IF_NULL(p); /* We do not expect a packet returned. */ - if (Defrag(NULL, NULL, p, NULL) != NULL) - goto end; + FAIL_IF(Defrag(NULL, NULL, p, NULL) != NULL); /* The fragment should have been ignored so no fragments should * have been allocated from the pool. */ - if (dc->frag_pool->outstanding != 0) - return 0; + FAIL_IF(dc->frag_pool->outstanding != 0); - ret = 1; -end: - if (dc != NULL) - DefragContextDestroy(dc); - if (p != NULL) - SCFree(p); + DefragContextDestroy(dc); + SCFree(p); DefragDestroy(); - return ret; + PASS; } -static int -DefragIPv4TooLargeTest(void) +static int DefragIPv4TooLargeTest(void) { DefragContext *dc = NULL; Packet *p = NULL; - int ret = 0; DefragInit(); dc = DefragContextNew(); - if (dc == NULL) - goto end; + FAIL_IF_NULL(dc); /* Create a fragment that would extend past the max allowable size * for an IPv4 packet. */ - p = BuildTestPacket(1, 8183, 0, 'A', 71); - if (p == NULL) - goto end; + p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71); + FAIL_IF_NULL(p); /* We do not expect a packet returned. */ - if (Defrag(NULL, NULL, p, NULL) != NULL) - goto end; - if (!ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE)) - goto end; + FAIL_IF(Defrag(NULL, NULL, p, NULL) != NULL); + + /* We do expect an event. */ + FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE)); /* The fragment should have been ignored so no fragments should have * been allocated from the pool. */ - if (dc->frag_pool->outstanding != 0) - return 0; + FAIL_IF(dc->frag_pool->outstanding != 0); - ret = 1; -end: - if (dc != NULL) - DefragContextDestroy(dc); - if (p != NULL) - SCFree(p); + DefragContextDestroy(dc); + SCFree(p); DefragDestroy(); - return ret; + PASS; } /** @@ -2231,72 +2153,52 @@ DefragIPv4TooLargeTest(void) * re-assembled, are not re-assembled. Just use simple in-order * fragments. */ -static int -DefragVlanTest(void) +static int DefragVlanTest(void) { Packet *p1 = NULL, *p2 = NULL, *r = NULL; - int ret = 0; DefragInit(); - p1 = BuildTestPacket(1, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; - p2 = BuildTestPacket(1, 1, 0, 'B', 8); - if (p2 == NULL) - goto end; + p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); + FAIL_IF_NULL(p2); /* With no VLAN IDs set, packets should re-assemble. */ - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) == NULL) - goto end; + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) == NULL); SCFree(r); /* With mismatched VLANs, packets should not re-assemble. */ p1->vlan_id[0] = 1; p2->vlan_id[0] = 2; - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) != NULL) - goto end; - - /* Pass. */ - ret = 1; - -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) != NULL); + + SCFree(p1); + SCFree(p2); DefragDestroy(); - return ret; + PASS; } /** * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID. */ -static int -DefragVlanQinQTest(void) +static int DefragVlanQinQTest(void) { Packet *p1 = NULL, *p2 = NULL, *r = NULL; - int ret = 0; DefragInit(); - p1 = BuildTestPacket(1, 0, 1, 'A', 8); - if (p1 == NULL) - goto end; - p2 = BuildTestPacket(1, 1, 0, 'B', 8); - if (p2 == NULL) - goto end; + p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); + FAIL_IF_NULL(p2); /* With no VLAN IDs set, packets should re-assemble. */ - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) == NULL) - goto end; + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) == NULL); SCFree(r); /* With mismatched VLANs, packets should not re-assemble. */ @@ -2304,72 +2206,271 @@ DefragVlanQinQTest(void) p2->vlan_id[0] = 1; p1->vlan_id[1] = 1; p2->vlan_id[1] = 2; - if ((r = Defrag(NULL, NULL, p1, NULL)) != NULL) - goto end; - if ((r = Defrag(NULL, NULL, p2, NULL)) != NULL) - goto end; - - /* Pass. */ - ret = 1; - -end: - if (p1 != NULL) - SCFree(p1); - if (p2 != NULL) - SCFree(p2); + FAIL_IF((r = Defrag(NULL, NULL, p1, NULL)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2, NULL)) != NULL); + + SCFree(p1); + SCFree(p2); + DefragDestroy(); + + PASS; +} + +static int DefragTrackerReuseTest(void) +{ + int id = 1; + Packet *p1 = NULL; + DefragTracker *tracker1 = NULL, *tracker2 = NULL; + + DefragInit(); + + /* Build a packet, its not a fragment but shouldn't matter for + * this test. */ + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8); + FAIL_IF_NULL(p1); + + /* Get a tracker. It shouldn't look like its already in use. */ + tracker1 = DefragGetTracker(NULL, NULL, p1); + FAIL_IF_NULL(tracker1); + FAIL_IF(tracker1->seen_last); + FAIL_IF(tracker1->remove); + DefragTrackerRelease(tracker1); + + /* Get a tracker again, it should be the same one. */ + tracker2 = DefragGetTracker(NULL, NULL, p1); + FAIL_IF_NULL(tracker2); + FAIL_IF(tracker2 != tracker1); + DefragTrackerRelease(tracker1); + + /* Now mark the tracker for removal. It should not be returned + * when we get a tracker for a packet that may have the same + * attributes. */ + tracker1->remove = 1; + + tracker2 = DefragGetTracker(NULL, NULL, p1); + FAIL_IF_NULL(tracker2); + FAIL_IF(tracker2 == tracker1); + FAIL_IF(tracker2->remove); + + SCFree(p1); DefragDestroy(); + PASS; +} + +/** + * IPV4: Test the case where you have a packet fragmented in 3 parts + * and send like: + * - Offset: 2; MF: 1 + * - Offset: 0; MF: 1 + * - Offset: 1; MF: 0 + * + * Only the fragments with offset 0 and 1 should be reassembled. + */ +static int DefragMfIpv4Test(void) +{ + int ip_id = 9; + Packet *p = NULL; + + DefragInit(); - return ret; + Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8); + Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8); + Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8); + FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL); + + p = Defrag(NULL, NULL, p1, NULL); + FAIL_IF_NOT_NULL(p); + + p = Defrag(NULL, NULL, p2, NULL); + FAIL_IF_NOT_NULL(p); + + /* This should return a packet as MF=0. */ + p = Defrag(NULL, NULL, p3, NULL); + FAIL_IF_NULL(p); + + /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the + * fragments should be in the re-assembled packet. */ + FAIL_IF(IPV4_GET_IPLEN(p) != 36); + + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(p); + DefragDestroy(); + PASS; +} + +/** + * IPV6: Test the case where you have a packet fragmented in 3 parts + * and send like: + * - Offset: 2; MF: 1 + * - Offset: 0; MF: 1 + * - Offset: 1; MF: 0 + * + * Only the fragments with offset 0 and 1 should be reassembled. + */ +static int DefragMfIpv6Test(void) +{ + int ip_id = 9; + Packet *p = NULL; + + DefragInit(); + + Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8); + Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8); + Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8); + FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL); + + p = Defrag(NULL, NULL, p1, NULL); + FAIL_IF_NOT_NULL(p); + + p = Defrag(NULL, NULL, p2, NULL); + FAIL_IF_NOT_NULL(p); + + /* This should return a packet as MF=0. */ + p = Defrag(NULL, NULL, p3, NULL); + FAIL_IF_NULL(p); + + /* For IPv6 the expected length is just the length of the payload + * of 2 fragments, so 16. */ + FAIL_IF(IPV6_GET_PLEN(p) != 16); + + SCFree(p1); + SCFree(p2); + SCFree(p3); + SCFree(p); + DefragDestroy(); + PASS; +} + +/** + * \brief Test that fragments that match other than the proto don't + * actually get matched. + */ +static int DefragTestBadProto(void) +{ + Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; + int id = 12; + + DefragInit(); + + p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8); + FAIL_IF_NULL(p2); + p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3); + FAIL_IF_NULL(p3); + + FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1, NULL)); + FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2, NULL)); + FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3, NULL)); + + SCFree(p1); + SCFree(p2); + SCFree(p3); + + DefragDestroy(); + PASS; +} + +/** + * \test Test a report Linux overlap issue that doesn't appear to be + * covered by the Sturges/Novak tests above. + */ +static int DefragTestJeremyLinux(void) +{ + char expected[] = "AAAAAAAA" + "AAAAAAAA" + "AAAAAAAA" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "CCCCCCCC" + "BBBBBBBB" + "BBBBBBBB" + "DDDDDDDD" + "DDDDDD"; + + DefragInit(); + default_policy = DEFRAG_POLICY_LINUX; + + int id = 1; + Packet *packets[4]; + int i = 0; + + packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24); + packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48); + packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48); + packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14); + + Packet *r = Defrag(NULL, NULL, packets[0], NULL); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[1], NULL); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[2], NULL); + FAIL_IF_NOT_NULL(r); + + r = Defrag(NULL, NULL, packets[3], NULL); + FAIL_IF_NULL(r); + + FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0); + + for (i = 0; i < 4; i++) { + SCFree(packets[i]); + } + SCFree(r); + + DefragDestroy(); + PASS; } #endif /* UNITTESTS */ -void -DefragRegisterTests(void) +void DefragRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DefragInOrderSimpleTest", - DefragInOrderSimpleTest, 1); - UtRegisterTest("DefragReverseSimpleTest", - DefragReverseSimpleTest, 1); - UtRegisterTest("DefragSturgesNovakBsdTest", - DefragSturgesNovakBsdTest, 1); - UtRegisterTest("DefragSturgesNovakLinuxTest", - DefragSturgesNovakLinuxTest, 1); - UtRegisterTest("DefragSturgesNovakWindowsTest", - DefragSturgesNovakWindowsTest, 1); + UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest); + UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest); + UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest); + UtRegisterTest("DefragSturgesNovakLinuxIpv4Test", + DefragSturgesNovakLinuxIpv4Test); + UtRegisterTest("DefragSturgesNovakWindowsIpv4Test", + DefragSturgesNovakWindowsIpv4Test); UtRegisterTest("DefragSturgesNovakSolarisTest", - DefragSturgesNovakSolarisTest, 1); - UtRegisterTest("DefragSturgesNovakFirstTest", - DefragSturgesNovakFirstTest, 1); - UtRegisterTest("DefragSturgesNovakLastTest", - DefragSturgesNovakLastTest, 1); - - UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest, 1); - UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest, 1); - - UtRegisterTest("IPV6DefragInOrderSimpleTest", - IPV6DefragInOrderSimpleTest, 1); - UtRegisterTest("IPV6DefragReverseSimpleTest", - IPV6DefragReverseSimpleTest, 1); + DefragSturgesNovakSolarisTest); + UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest); + UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest); + + UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest); + UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest); + + UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest); + UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest); UtRegisterTest("IPV6DefragSturgesNovakBsdTest", - IPV6DefragSturgesNovakBsdTest, 1); + IPV6DefragSturgesNovakBsdTest); UtRegisterTest("IPV6DefragSturgesNovakLinuxTest", - IPV6DefragSturgesNovakLinuxTest, 1); + IPV6DefragSturgesNovakLinuxTest); UtRegisterTest("IPV6DefragSturgesNovakWindowsTest", - IPV6DefragSturgesNovakWindowsTest, 1); + IPV6DefragSturgesNovakWindowsTest); UtRegisterTest("IPV6DefragSturgesNovakSolarisTest", - IPV6DefragSturgesNovakSolarisTest, 1); + IPV6DefragSturgesNovakSolarisTest); UtRegisterTest("IPV6DefragSturgesNovakFirstTest", - IPV6DefragSturgesNovakFirstTest, 1); + IPV6DefragSturgesNovakFirstTest); UtRegisterTest("IPV6DefragSturgesNovakLastTest", - IPV6DefragSturgesNovakLastTest, 1); + IPV6DefragSturgesNovakLastTest); - UtRegisterTest("DefragVlanTest", DefragVlanTest, 1); - UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest, 1); + UtRegisterTest("DefragVlanTest", DefragVlanTest); + UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest); + UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest); + UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest); + UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test); + UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test); + UtRegisterTest("DefragTestBadProto", DefragTestBadProto); - UtRegisterTest("DefragTimeoutTest", - DefragTimeoutTest, 1); + UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux); #endif /* UNITTESTS */ } - diff --git a/src/defrag.h b/src/defrag.h index 8bd0325a341f..c3a0c693733a 100644 --- a/src/defrag.h +++ b/src/defrag.h @@ -71,20 +71,6 @@ typedef struct Frag_ { TAILQ_ENTRY(Frag_) next; /**< Pointer to next fragment for tailq. */ } Frag; -/** \brief Reset tracker fields except "lock" */ -#define DEFRAG_TRACKER_RESET(t) { \ - (t)->timeout = 0; \ - (t)->id = 0; \ - (t)->policy = 0; \ - (t)->af = 0; \ - (t)->seen_last = 0; \ - (t)->remove = 0; \ - CLEAR_ADDR(&(t)->src_addr); \ - CLEAR_ADDR(&(t)->dst_addr); \ - (t)->frags.tqh_first = NULL; \ - (t)->frags.tqh_last = NULL; \ -} - /** * A defragmentation tracker. Used to track fragments that make up a * single packet. @@ -98,6 +84,8 @@ typedef struct DefragTracker_ { uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16 * for IPv4. */ + uint8_t proto; /**< IP protocol for this tracker. */ + uint8_t policy; /**< Reassembly policy this tracker will use. */ uint8_t af; /**< Address family for this tracker, AF_INET or diff --git a/src/detect-ack.c b/src/detect-ack.c index 89d87131afc7..0d36096a4d98 100644 --- a/src/detect-ack.c +++ b/src/detect-ack.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -19,6 +19,7 @@ * \file * * \author Brian Rectanus + * \author Victor Julien * * Implements the "ack" keyword. */ @@ -31,6 +32,8 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "detect-ack.h" @@ -42,18 +45,24 @@ /* prototypes */ static int DetectAckSetup(DetectEngineCtx *, Signature *, char *); static int DetectAckMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); + Packet *, const Signature *, const SigMatchCtx *); static void DetectAckRegisterTests(void); static void DetectAckFree(void *); +static int PrefilterSetupTcpAck(SigGroupHead *sgh); +static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s); void DetectAckRegister(void) { sigmatch_table[DETECT_ACK].name = "ack"; sigmatch_table[DETECT_ACK].desc = "check for a specific TCP acknowledgement number"; - sigmatch_table[DETECT_ACK].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ack"; + sigmatch_table[DETECT_ACK].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ack"; sigmatch_table[DETECT_ACK].Match = DetectAckMatch; sigmatch_table[DETECT_ACK].Setup = DetectAckSetup; sigmatch_table[DETECT_ACK].Free = DetectAckFree; + + sigmatch_table[DETECT_ACK].SupportsPrefilter = PrefilterTcpAckIsPrefilterable; + sigmatch_table[DETECT_ACK].SetupPrefilter = PrefilterSetupTcpAck; + sigmatch_table[DETECT_ACK].RegisterTests = DetectAckRegisterTests; } @@ -70,9 +79,9 @@ void DetectAckRegister(void) * \retval 1 match */ static int DetectAckMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectAckData *data = (DetectAckData *)m->ctx; + const DetectAckData *data = (const DetectAckData *)ctx; /* This is only needed on TCP packets */ if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { @@ -112,7 +121,7 @@ static int DetectAckSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (-1 == ByteExtractStringUint32(&data->ack, 10, 0, optstr)) { goto error; } - sm->ctx = data; + sm->ctx = (SigMatchCtx*)data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -140,13 +149,66 @@ static void DetectAckFree(void *ptr) SCFree(data); } +/* prefilter code */ + +static void +PrefilterPacketAckMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && + (p->tcph != NULL) && (TCP_GET_ACK(p) == ctx->v1.u32[0])) + { + SCLogDebug("packet matches TCP ack %u", ctx->v1.u32[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketAckSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectAckData *a = smctx; + v->u32[0] = a->ack; +} + +static _Bool +PrefilterPacketAckCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectAckData *a = smctx; + if (v.u32[0] == a->ack) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTcpAck(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ACK, + PrefilterPacketAckSet, + PrefilterPacketAckCompare, + PrefilterPacketAckMatch); +} + +static _Bool PrefilterTcpAckIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ACK: + return TRUE; + } + } + return FALSE; +} #ifdef UNITTESTS /** * \internal * \brief This test tests sameip success and failure. */ -static int DetectAckSigTest01Real(int mpm_type) +static int DetectAckSigTest01(void) { Packet *p1 = NULL; Packet *p2 = NULL; @@ -173,7 +235,6 @@ static int DetectAckSigTest01Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; /* These three are crammed in here as there is no Parse */ @@ -261,30 +322,6 @@ static int DetectAckSigTest01Real(int mpm_type) return result; } -/** - * \test DetectAckSigTest01B2g tests sameip under B2g MPM - */ -static int DetectAckSigTest01B2g(void) -{ - return DetectAckSigTest01Real(MPM_B2G); -} - -/** - * \test DetectAckSigTest01B2g tests sameip under B3g MPM - */ -static int DetectAckSigTest01B3g(void) -{ - return DetectAckSigTest01Real(MPM_B3G); -} - -/** - * \test DetectAckSigTest01B2g tests sameip under WuManber MPM - */ -static int DetectAckSigTest01Wm(void) -{ - return DetectAckSigTest01Real(MPM_WUMANBER); -} - #endif /* UNITTESTS */ /** @@ -294,9 +331,7 @@ static int DetectAckSigTest01Wm(void) static void DetectAckRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectAckSigTest01B2g", DetectAckSigTest01B2g, 1); - UtRegisterTest("DetectAckSigTest01B3g", DetectAckSigTest01B3g, 1); - UtRegisterTest("DetectAckSigTest01Wm", DetectAckSigTest01Wm, 1); + UtRegisterTest("DetectAckSigTest01", DetectAckSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 2cabeef1f402..8658d3955e78 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -44,15 +44,22 @@ #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" +#include "stream-tcp-util.h" +#define MAX_ALPROTO_NAME 50 static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m); -static int DetectAppLayerEventAppMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); + Packet *p, const Signature *s, const SigMatchCtx *ctx); static int DetectAppLayerEventSetupP1(DetectEngineCtx *, Signature *, char *); static void DetectAppLayerEventRegisterTests(void); static void DetectAppLayerEventFree(void *); +static int DetectEngineAptEventInspect(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); +static void DetectAppLayerEventSetupCallback(Signature *s); +static int g_applayer_events_list_id = 0; /** * \brief Registers the keyword handlers for the "app-layer-event" keyword. @@ -62,44 +69,113 @@ void DetectAppLayerEventRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_EVENT].name = "app-layer-event"; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match = DetectAppLayerEventPktMatch; - sigmatch_table[DETECT_AL_APP_LAYER_EVENT].AppLayerMatch = - DetectAppLayerEventAppMatch; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Setup = DetectAppLayerEventSetupP1; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Free = DetectAppLayerEventFree; sigmatch_table[DETECT_AL_APP_LAYER_EVENT].RegisterTests = DetectAppLayerEventRegisterTests; - return; + DetectAppLayerInspectEngineRegister("app-layer-events", + ALPROTO_UNKNOWN, SIG_FLAG_TOSERVER, + DetectEngineAptEventInspect); + DetectAppLayerInspectEngineRegister("app-layer-events", + ALPROTO_UNKNOWN, SIG_FLAG_TOCLIENT, + DetectEngineAptEventInspect); + + DetectBufferTypeRegisterSetupCallback("app-layer-events", + DetectAppLayerEventSetupCallback); + + g_applayer_events_list_id = DetectBufferTypeGetByName("app-layer-events"); +} + +static int DetectEngineAptEventInspect(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id) +{ + AppLayerDecoderEvents *decoder_events = NULL; + int r = 0; + AppProto alproto; + DetectAppLayerEventData *aled = NULL; + + alproto = f->alproto; + decoder_events = AppLayerParserGetEventsByTx(f->proto, alproto, alstate, tx_id); + if (decoder_events == NULL) + goto end; + + while (1) { + aled = (DetectAppLayerEventData *)smd->ctx; + KEYWORD_PROFILING_START; + + if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + + if (smd->is_last) + break; + smd++; + continue; + } + + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + goto end; + } + + r = 1; + + end: + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) == + AppLayerParserGetStateProgressCompletionStatus(alproto, flags)) + { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + } } static int DetectAppLayerEventPktMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectAppLayerEventData *aled = (DetectAppLayerEventData *)m->ctx; + const DetectAppLayerEventData *aled = (const DetectAppLayerEventData *)ctx; return AppLayerDecoderEventsIsEventSet(p->app_layer_events, aled->event_id); } -static int DetectAppLayerEventAppMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, - SigMatch *m) +static void DetectAppLayerEventSetupCallback(Signature *s) { - SCEnter(); - AppLayerDecoderEvents *decoder_events = NULL; - int r = 0; - DetectAppLayerEventData *aled = (DetectAppLayerEventData *)m->ctx; - - if (r == 0) { - decoder_events = AppLayerParserGetDecoderEvents(f->alparser); - if (decoder_events != NULL && - AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { - r = 1; + SigMatch *sm; + for (sm = s->init_data->smlists[g_applayer_events_list_id] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_AL_APP_LAYER_EVENT: + { + DetectAppLayerEventData *aed = (DetectAppLayerEventData *)sm->ctx; + switch (aed->alproto) { + case ALPROTO_HTTP: + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + SCLogDebug("sig %u requires http app state (http event)", s->id); + break; + case ALPROTO_SMTP: + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + SCLogDebug("sig %u requires smtp app state (smtp event)", s->id); + break; + case ALPROTO_DNS: + s->mask |= SIG_MASK_REQUIRE_DNS_STATE; + SCLogDebug("sig %u requires dns app state (dns event)", s->id); + break; + case ALPROTO_TLS: + s->mask |= SIG_MASK_REQUIRE_TLS_STATE; + SCLogDebug("sig %u requires tls app state (tls event)", s->id); + break; + } + break; + } } } - - SCReturnInt(r); } static DetectAppLayerEventData *DetectAppLayerEventParsePkt(const char *arg, @@ -135,10 +211,14 @@ static int DetectAppLayerEventParseAppP2(DetectAppLayerEventData *data, int event_id = 0; const char *p_idx; uint8_t ipproto; - char alproto_name[50]; + char alproto_name[MAX_ALPROTO_NAME]; int r = 0; p_idx = strchr(data->arg, '.'); + if (strlen(data->arg) > MAX_ALPROTO_NAME) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-event keyword is too long or malformed"); + return -1; + } strlcpy(alproto_name, data->arg, p_idx - data->arg + 1); if (ipproto_bitarray[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8)) { @@ -169,9 +249,13 @@ static DetectAppLayerEventData *DetectAppLayerEventParseAppP1(const char *arg) DetectAppLayerEventData *aled; AppProto alproto; const char *p_idx; - char alproto_name[50]; + char alproto_name[MAX_ALPROTO_NAME]; p_idx = strchr(arg, '.'); + if (strlen(arg) > MAX_ALPROTO_NAME) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-event keyword is too long or malformed"); + return NULL; + } /* + 1 for trailing \0 */ strlcpy(alproto_name, arg, p_idx - arg + 1); @@ -223,15 +307,12 @@ static int DetectAppLayerEventSetupP2(Signature *s, { AppLayerEventType event_type = 0; - if (DetectAppLayerEventParseAppP2(sm->ctx, s->proto.proto, + if (DetectAppLayerEventParseAppP2((DetectAppLayerEventData *)sm->ctx, s->proto.proto, &event_type) < 0) { /* DetectAppLayerEventParseAppP2 prints errors */ return -1; } - if (event_type == APP_LAYER_EVENT_TYPE_GENERAL) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_APP_EVENT); + SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); /* We should have set this flag already in SetupP1 */ s->flags |= SIG_FLAG_APPLAYER; @@ -253,25 +334,15 @@ static int DetectAppLayerEventSetupP1(DetectEngineCtx *de_ctx, Signature *s, cha goto error; sm->type = DETECT_AL_APP_LAYER_EVENT; - sm->ctx = (void *)data; - - if (s->alproto != ALPROTO_UNKNOWN) { - if (s->alproto != data->alproto) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " - "conflicting keywords needing different alprotos"); - goto error; - } - } else { - s->alproto = data->alproto; - } + sm->ctx = (SigMatchCtx *)data; if (event_type == APP_LAYER_EVENT_TYPE_PACKET) { SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); } else { - /* We push it to this list temporarily. We deal with - * these in DetectAppLayerEventPrepare(). */ - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_APP_EVENT); - s->flags |= SIG_FLAG_APPLAYER; + if (DetectSignatureSetAppProto(s, data->alproto) != 0) + goto error; + + SigMatchAppendSMToList(s, sm, g_applayer_events_list_id); } return 0; @@ -299,9 +370,9 @@ static void DetectAppLayerEventFree(void *ptr) int DetectAppLayerEventPrepare(Signature *s) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT]; - s->sm_lists[DETECT_SM_LIST_APP_EVENT] = NULL; - s->sm_lists_tail[DETECT_SM_LIST_APP_EVENT] = NULL; + SigMatch *sm = s->init_data->smlists[g_applayer_events_list_id]; + s->init_data->smlists[g_applayer_events_list_id] = NULL; + s->init_data->smlists_tail[g_applayer_events_list_id] = NULL; while (sm != NULL) { sm->next = sm->prev = NULL; @@ -316,11 +387,9 @@ int DetectAppLayerEventPrepare(Signature *s) /**********************************Unittests***********************************/ #ifdef UNITTESTS /* UNITTESTS */ - #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" -#include "app-layer.h" #define APP_LAYER_EVENT_TEST_MAP_EVENT1 0 #define APP_LAYER_EVENT_TEST_MAP_EVENT2 1 @@ -350,7 +419,7 @@ static int DetectAppLayerEventTestGetEventInfo(const char *event_name, return -1; } - *event_type = APP_LAYER_EVENT_TYPE_GENERAL; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; return 0; } @@ -491,7 +560,6 @@ int DetectAppLayerEventTest02(void) int DetectAppLayerEventTest03(void) { - int result = 0; ThreadVars tv; TcpReassemblyThreadCtx *ra_ctx = NULL; Packet *p = NULL; @@ -532,70 +600,53 @@ int DetectAppLayerEventTest03(void) ssn.data_first_seen_dir = STREAM_TOSERVER; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(app-layer-event: applayer_mismatch_protocol_both_directions; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); - if (f == NULL) - goto end; + FAIL_IF(f == NULL); FLOW_INITIALIZE(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->flags |= FLOW_IPV4; p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - goto end; + FAIL_IF(unlikely(p == NULL)); p->flow = f; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; - ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); - if (ra_ctx == NULL) - goto end; - StreamTcpInitConfig(TRUE); + StreamTcpUTInit(&ra_ctx); p->flowflags = FLOW_PKT_TOSERVER; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, - sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF(AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, + sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0); + SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + + FAIL_IF (PacketAlertCheck(p, 1)); p->flowflags = FLOW_PKT_TOCLIENT; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, - sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, + sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0); + SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - result = 1; - end: - return result; + FAIL_IF(PacketAlertCheck(p, 1)); + + StreamTcpUTDeinit(ra_ctx); + PASS; } int DetectAppLayerEventTest04(void) { - int result = 0; ThreadVars tv; TcpReassemblyThreadCtx *ra_ctx = NULL; Packet *p = NULL; @@ -636,70 +687,49 @@ int DetectAppLayerEventTest04(void) ssn.data_first_seen_dir = STREAM_TOSERVER; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF (de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(app-layer-event: applayer_detect_protocol_only_one_direction; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); - if (f == NULL) - goto end; + FAIL_IF (f == NULL); FLOW_INITIALIZE(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->flags |= FLOW_IPV4; p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - goto end; + FAIL_IF(unlikely(p == NULL)); p->flow = f; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; - ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); - if (ra_ctx == NULL) - goto end; - StreamTcpInitConfig(TRUE); + StreamTcpUTInit(&ra_ctx); p->flowflags = FLOW_PKT_TOSERVER; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, - sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF(AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, + sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + FAIL_IF (PacketAlertCheck(p, 1)); p->flowflags = FLOW_PKT_TOCLIENT; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, - sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, + sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match but should have\n"); - goto end; - } + FAIL_IF (!PacketAlertCheck(p, 1)); - result = 1; - end: - return result; + StreamTcpUTDeinit(ra_ctx); + PASS; } int DetectAppLayerEventTest05(void) { - int result = 0; ThreadVars tv; TcpReassemblyThreadCtx *ra_ctx = NULL; Packet *p = NULL; @@ -756,65 +786,45 @@ int DetectAppLayerEventTest05(void) ssn.data_first_seen_dir = STREAM_TOSERVER; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF (de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(app-layer-event: applayer_mismatch_protocol_both_directions; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF (de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); - if (f == NULL) - goto end; + FAIL_IF (f == NULL); FLOW_INITIALIZE(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->flags |= FLOW_IPV4; p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - goto end; + FAIL_IF (unlikely(p == NULL)); p->flow = f; p->src.family = AF_INET; p->dst.family = AF_INET; p->proto = IPPROTO_TCP; - ra_ctx = StreamTcpReassembleInitThreadCtx(&tv); - if (ra_ctx == NULL) - goto end; - StreamTcpInitConfig(TRUE); + StreamTcpUTInit(&ra_ctx); p->flowflags = FLOW_PKT_TOSERVER; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, - sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_ts, buf_ts, + sizeof(buf_ts), STREAM_TOSERVER | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + FAIL_IF (PacketAlertCheck(p, 1)); p->flowflags = FLOW_PKT_TOCLIENT; - if (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, - sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0) { - printf("AppLayerHandleTCPData failure\n"); - goto end; - } + FAIL_IF (AppLayerHandleTCPData(&tv, ra_ctx, p, f, &ssn, &stream_tc, buf_tc, + sizeof(buf_tc), STREAM_TOCLIENT | STREAM_START) < 0); SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match but should have\n"); - goto end; - } + FAIL_IF (!PacketAlertCheck(p, 1)); - result = 1; - end: - return result; + StreamTcpUTDeinit(ra_ctx); + PASS; } #endif /* UNITTESTS */ @@ -825,11 +835,11 @@ int DetectAppLayerEventTest05(void) void DetectAppLayerEventRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectAppLayerEventTest01", DetectAppLayerEventTest01, 1); - UtRegisterTest("DetectAppLayerEventTest02", DetectAppLayerEventTest02, 1); - UtRegisterTest("DetectAppLayerEventTest03", DetectAppLayerEventTest03, 1); - UtRegisterTest("DetectAppLayerEventTest04", DetectAppLayerEventTest04, 1); - UtRegisterTest("DetectAppLayerEventTest05", DetectAppLayerEventTest05, 1); + UtRegisterTest("DetectAppLayerEventTest01", DetectAppLayerEventTest01); + UtRegisterTest("DetectAppLayerEventTest02", DetectAppLayerEventTest02); + UtRegisterTest("DetectAppLayerEventTest03", DetectAppLayerEventTest03); + UtRegisterTest("DetectAppLayerEventTest04", DetectAppLayerEventTest04); + UtRegisterTest("DetectAppLayerEventTest05", DetectAppLayerEventTest05); #endif /* UNITTESTS */ return; diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 92285d5d3abf..5761d2b87ddd 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -23,6 +23,8 @@ #include "suricata-common.h" #include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "detect-parse.h" #include "detect-app-layer-protocol.h" #include "app-layer.h" @@ -31,19 +33,57 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -void DetectAppLayerProtocolRegisterTests(void); +static void DetectAppLayerProtocolRegisterTests(void); -int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, - Signature *s, SigMatch *m) +static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { + SCEnter(); + int r = 0; - DetectAppLayerProtocolData *data = (DetectAppLayerProtocolData *)m->ctx; + const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)ctx; + + /* if the sig is PD-only we only match when PD packet flags are set */ + if ((s->flags & SIG_FLAG_PDONLY) && + (p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) + { + SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt); + SCReturnInt(0); + } + + const Flow *f = p->flow; + if (f == NULL) { + SCLogDebug("packet %"PRIu64": no flow", p->pcap_cnt); + SCReturnInt(0); + } + + /* unknown means protocol detection isn't ready yet */ + + if ((f->alproto_ts != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOSERVER)) + { + SCLogDebug("toserver packet %"PRIu64": looking for %u/neg %u, got %u", + p->pcap_cnt, data->alproto, data->negated, f->alproto_ts); + + r = (data->negated) ? (f->alproto_ts != data->alproto) : + (f->alproto_ts == data->alproto); - r = (data->negated) ? (f->alproto != data->alproto) : - (f->alproto == data->alproto); + } else if ((f->alproto_tc != ALPROTO_UNKNOWN) && (p->flowflags & FLOW_PKT_TOCLIENT)) + { + SCLogDebug("toclient packet %"PRIu64": looking for %u/neg %u, got %u", + p->pcap_cnt, data->alproto, data->negated, f->alproto_tc); - return r; + r = (data->negated) ? (f->alproto_tc != data->alproto) : + (f->alproto_tc == data->alproto); + } + else { + SCLogDebug("packet %"PRIu64": default case: direction %02x, approtos %u/%u/%u", + p->pcap_cnt, + p->flowflags & (FLOW_PKT_TOCLIENT|FLOW_PKT_TOSERVER), + f->alproto, f->alproto_ts, f->alproto_tc); + } + + SCReturnInt(r); } static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) @@ -70,11 +110,15 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) while (*arg != '\0' && isspace((unsigned char)*arg)) arg++; - alproto = AppLayerGetProtoByName((char *)arg); - if (alproto == ALPROTO_UNKNOWN) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol " - "keyword supplied with unknown protocol \"%s\"", arg); - return NULL; + if (strcmp(arg, "failed") == 0) { + alproto = ALPROTO_FAILED; + } else { + alproto = AppLayerGetProtoByName((char *)arg); + if (alproto == ALPROTO_UNKNOWN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol " + "keyword supplied with unknown protocol \"%s\"", arg); + return NULL; + } } data = SCMalloc(sizeof(DetectAppLayerProtocolData)); @@ -86,8 +130,25 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) return data; } -int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, - char *arg) +static _Bool HasConflicts(const DetectAppLayerProtocolData *us, + const DetectAppLayerProtocolData *them) +{ + /* mixing negated and non negated is illegal */ + if (them->negated ^ us->negated) + return TRUE; + /* multiple non-negated is illegal */ + if (!us->negated) + return TRUE; + /* duplicate option */ + if (us->alproto == them->alproto) + return TRUE; + + /* all good */ + return FALSE; +} + +static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, + Signature *s, char *arg) { DetectAppLayerProtocolData *data = NULL; SigMatch *sm = NULL; @@ -104,8 +165,19 @@ int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, if (data == NULL) goto error; - if (!data->negated) - s->alproto = data->alproto; + SigMatch *tsm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; + for ( ; tsm != NULL; tsm = tsm->next) { + if (tsm->type == DETECT_AL_APP_LAYER_PROTOCOL) { + const DetectAppLayerProtocolData *them = (const DetectAppLayerProtocolData *)tsm->ctx; + + if (HasConflicts(data, them)) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "can't mix " + "positive app-layer-protocol match with negated " + "match or match for 'failed'."); + goto error; + } + } + } sm = SigMatchAlloc(); if (sm == NULL) @@ -114,9 +186,7 @@ int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, sm->type = DETECT_AL_APP_LAYER_PROTOCOL; sm->ctx = (void *)data; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - s->flags |= SIG_FLAG_APPLAYER; - + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: @@ -125,19 +195,90 @@ int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, return -1; } -void DetectAppLayerProtocolFree(void *ptr) +static void DetectAppLayerProtocolFree(void *ptr) { SCFree(ptr); - return; } +/** \internal + * \brief prefilter function for protocol detect matching + */ +static void +PrefilterPacketAppProtoMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) { + SCLogDebug("packet %"PRIu64": extra match failed", p->pcap_cnt); + SCReturn; + } + + if (p->flow == NULL) { + SCLogDebug("packet %"PRIu64": no flow, no alproto", p->pcap_cnt); + SCReturn; + } + + if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) { + SCLogDebug("packet %"PRIu64": flags not set", p->pcap_cnt); + SCReturn; + } + + if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) + { + int r = (ctx->v1.u16[0] == p->flow->alproto_ts) ^ ctx->v1.u8[2]; + if (r) { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } + } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) + { + int r = (ctx->v1.u16[0] == p->flow->alproto_tc) ^ ctx->v1.u8[2]; + if (r) { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } + } +} + +static void +PrefilterPacketAppProtoSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectAppLayerProtocolData *a = smctx; + v->u16[0] = a->alproto; + v->u8[2] = (uint8_t)a->negated; +} + +static _Bool +PrefilterPacketAppProtoCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectAppLayerProtocolData *a = smctx; + if (v.u16[0] == a->alproto && + v.u8[2] == (uint8_t)a->negated) + return TRUE; + return FALSE; +} + +static int PrefilterSetupAppProto(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_AL_APP_LAYER_PROTOCOL, + PrefilterPacketAppProtoSet, + PrefilterPacketAppProtoCompare, + PrefilterPacketAppProtoMatch); +} + +static _Bool PrefilterAppProtoIsPrefilterable(const Signature *s) +{ + if (s->flags & SIG_FLAG_PDONLY) { + SCLogDebug("prefilter on PD %u", s->id); + return TRUE; + } + return FALSE; +} + void DetectAppLayerProtocolRegister(void) { sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol"; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = NULL; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].AppLayerMatch = - DetectAppLayerProtocolMatch; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = + DetectAppLayerProtocolPacketMatch; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup = DetectAppLayerProtocolSetup; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Free = @@ -145,6 +286,10 @@ void DetectAppLayerProtocolRegister(void) sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].RegisterTests = DetectAppLayerProtocolRegisterTests; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SetupPrefilter = + PrefilterSetupAppProto; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].SupportsPrefilter = + PrefilterAppProtoIsPrefilterable; return; } @@ -152,255 +297,301 @@ void DetectAppLayerProtocolRegister(void) #ifdef UNITTESTS -int DetectAppLayerProtocolTest01(void) +static int DetectAppLayerProtocolTest01(void) { - int result = 0; - DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("http"); - if (data == NULL) - goto end; - if (data->alproto != ALPROTO_HTTP || data->negated) { - printf("test failure. Holding wrong state\n"); - goto end; - } - - result = 1; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated != 0); + DetectAppLayerProtocolFree(data); + PASS; +} - end: - if (data != NULL) - DetectAppLayerProtocolFree(data); - return result; +static int DetectAppLayerProtocolTest02(void) +{ + DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("!http"); + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated == 0); + DetectAppLayerProtocolFree(data); + PASS; } -int DetectAppLayerProtocolTest02(void) +static int DetectAppLayerProtocolTest03(void) { - int result = 0; + Signature *s = NULL; + DetectAppLayerProtocolData *data = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; - DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("!http"); - if (data == NULL) - goto end; - if (data->alproto != ALPROTO_HTTP || !data->negated) { - printf("test failure. Holding wrong state\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; sid:1;)"); + FAIL_IF_NULL(s); - result = 1; + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); - end: - if (data != NULL) - DetectAppLayerProtocolFree(data); - return result; + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + + data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + DetectEngineCtxFree(de_ctx); + PASS; } -int DetectAppLayerProtocolTest03(void) +static int DetectAppLayerProtocolTest04(void) { - int result = 0; Signature *s = NULL; DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; sid:1;)"); - if (s->alproto != ALPROTO_HTTP) { - printf("signature alproto should be http\n"); - goto end; - } - data = s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; - if (data->alproto != ALPROTO_HTTP || data->negated) { - printf("if (data->alproto != ALPROTO_HTTP || data->negated)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:!http; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); + FAIL_IF(s->flags & SIG_FLAG_APPLAYER); + + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); - result = 1; + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated == 0); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest04(void) +static int DetectAppLayerProtocolTest05(void) { - int result = 0; Signature *s = NULL; DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!http; sid:1;)"); - if (s->alproto != ALPROTO_UNKNOWN) { - printf("signature alproto should be unknown\n"); - goto end; - } - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - printf("if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL)\n"); - goto end; - } - data = s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx; - if (data == NULL) { - printf("if (data == NULL)\n"); - goto end; - } - if (data->alproto != ALPROTO_HTTP || !data->negated) { - printf("if (data->alproto != ALPROTO_HTTP || !data->negated)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); + FAIL_IF(s->flags & SIG_FLAG_APPLAYER); + + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); - result = 1; + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated == 0); + + data = (DetectAppLayerProtocolData*)s->sm_lists[DETECT_SM_LIST_MATCH]->next->ctx; + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_SMTP); + FAIL_IF(data->negated == 0); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest05(void) +static int DetectAppLayerProtocolTest06(void) { - int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)"); - if (s->alproto != ALPROTO_UNKNOWN) { - printf("signature alproto should be unknown\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(app-layer-protocol:smtp; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); + PASS; +} - result = 1; +static int DetectAppLayerProtocolTest07(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(app-layer-protocol:!smtp; sid:1;)"); + FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest06(void) +static int DetectAppLayerProtocolTest08(void) { - int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert http any any -> any any " - "(app-layer-protocol:smtp; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); + PASS; +} - result = 1; +static int DetectAppLayerProtocolTest09(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)"); + FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest07(void) +static int DetectAppLayerProtocolTest10(void) { - int result = 0; Signature *s = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert http any any -> any any " - "(app-layer-protocol:!smtp; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:smtp; app-layer-protocol:!http; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); + PASS; +} - result = 1; +static int DetectAppLayerProtocolTest11(void) +{ + DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("failed"); + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_FAILED); + FAIL_IF(data->negated != 0); + DetectAppLayerProtocolFree(data); + PASS; +} - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - return result; +static int DetectAppLayerProtocolTest12(void) +{ + DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("!failed"); + FAIL_IF_NULL(data); + FAIL_IF(data->alproto != ALPROTO_FAILED); + FAIL_IF(data->negated == 0); + DetectAppLayerProtocolFree(data); + PASS; } -int DetectAppLayerProtocolTest08(void) +static int DetectAppLayerProtocolTest13(void) { - int result = 0; Signature *s = NULL; + DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:failed; sid:1;)"); + FAIL_IF_NULL(s); + + FAIL_IF(s->alproto != ALPROTO_UNKNOWN); - result = 1; + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s->sm_lists[DETECT_SM_LIST_MATCH]->ctx); - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + data = (DetectAppLayerProtocolData *)s->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_FAILED); + FAIL_IF(data->negated); DetectEngineCtxFree(de_ctx); - return result; + PASS; } -int DetectAppLayerProtocolTest09(void) +static int DetectAppLayerProtocolTest14(void) { - int result = 0; - Signature *s = NULL; + DetectAppLayerProtocolData *data = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = SigInit(de_ctx, "alert tcp any any -> any any " - "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)"); - if (s != NULL) { - printf("if (s != NULL)\n"); - goto end; - } - - result = 1; + Signature *s1 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flowbits:set,blah; sid:1;)"); + FAIL_IF_NULL(s1); + FAIL_IF(s1->alproto != ALPROTO_UNKNOWN); + FAIL_IF_NULL(s1->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s1->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + data = (DetectAppLayerProtocolData *)s1->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + + Signature *s2 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flow:to_client; sid:2;)"); + FAIL_IF_NULL(s2); + FAIL_IF(s2->alproto != ALPROTO_UNKNOWN); + FAIL_IF_NULL(s2->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s2->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + data = (DetectAppLayerProtocolData *)s2->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + + /* flow:established and other options not supported for PD-only */ + Signature *s3 = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(app-layer-protocol:http; flow:to_client,established; sid:3;)"); + FAIL_IF_NULL(s3); + FAIL_IF(s3->alproto != ALPROTO_UNKNOWN); + FAIL_IF_NULL(s3->sm_lists[DETECT_SM_LIST_MATCH]); + FAIL_IF_NULL(s3->sm_lists[DETECT_SM_LIST_MATCH]->ctx); + data = (DetectAppLayerProtocolData *)s3->sm_lists[DETECT_SM_LIST_MATCH]->ctx; + FAIL_IF(data->alproto != ALPROTO_HTTP); + FAIL_IF(data->negated); + + SigGroupBuild(de_ctx); + FAIL_IF_NOT(s1->flags & SIG_FLAG_PDONLY); + FAIL_IF_NOT(s2->flags & SIG_FLAG_PDONLY); + FAIL_IF(s3->flags & SIG_FLAG_PDONLY); // failure now - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } #endif /* UNITTESTS */ -void DetectAppLayerProtocolRegisterTests(void) +static void DetectAppLayerProtocolRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectAppLayerProtocolTest01", DetectAppLayerProtocolTest01, 1); - UtRegisterTest("DetectAppLayerProtocolTest02", DetectAppLayerProtocolTest02, 1); - UtRegisterTest("DetectAppLayerProtocolTest03", DetectAppLayerProtocolTest03, 1); - UtRegisterTest("DetectAppLayerProtocolTest04", DetectAppLayerProtocolTest04, 1); - UtRegisterTest("DetectAppLayerProtocolTest05", DetectAppLayerProtocolTest05, 1); - UtRegisterTest("DetectAppLayerProtocolTest06", DetectAppLayerProtocolTest06, 1); - UtRegisterTest("DetectAppLayerProtocolTest07", DetectAppLayerProtocolTest07, 1); - UtRegisterTest("DetectAppLayerProtocolTest08", DetectAppLayerProtocolTest08, 1); - UtRegisterTest("DetectAppLayerProtocolTest09", DetectAppLayerProtocolTest09, 1); + UtRegisterTest("DetectAppLayerProtocolTest01", + DetectAppLayerProtocolTest01); + UtRegisterTest("DetectAppLayerProtocolTest02", + DetectAppLayerProtocolTest02); + UtRegisterTest("DetectAppLayerProtocolTest03", + DetectAppLayerProtocolTest03); + UtRegisterTest("DetectAppLayerProtocolTest04", + DetectAppLayerProtocolTest04); + UtRegisterTest("DetectAppLayerProtocolTest05", + DetectAppLayerProtocolTest05); + UtRegisterTest("DetectAppLayerProtocolTest06", + DetectAppLayerProtocolTest06); + UtRegisterTest("DetectAppLayerProtocolTest07", + DetectAppLayerProtocolTest07); + UtRegisterTest("DetectAppLayerProtocolTest08", + DetectAppLayerProtocolTest08); + UtRegisterTest("DetectAppLayerProtocolTest09", + DetectAppLayerProtocolTest09); + UtRegisterTest("DetectAppLayerProtocolTest10", + DetectAppLayerProtocolTest10); + UtRegisterTest("DetectAppLayerProtocolTest11", + DetectAppLayerProtocolTest11); + UtRegisterTest("DetectAppLayerProtocolTest12", + DetectAppLayerProtocolTest12); + UtRegisterTest("DetectAppLayerProtocolTest13", + DetectAppLayerProtocolTest13); + UtRegisterTest("DetectAppLayerProtocolTest14", + DetectAppLayerProtocolTest14); #endif /* UNITTESTS */ return; diff --git a/src/detect-asn1.c b/src/detect-asn1.c index b88885d78da7..7bdc57957abb 100644 --- a/src/detect-asn1.c +++ b/src/detect-asn1.c @@ -42,11 +42,11 @@ /* delimiters for functions/arguments */ const char *ASN_DELIM = " \t,\n"; -int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectAsn1Match(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectAsn1Setup (DetectEngineCtx *, Signature *, char *); -void DetectAsn1RegisterTests(void); -void DetectAsn1Free(void *); +static void DetectAsn1RegisterTests(void); +static void DetectAsn1Free(void *); /** * \brief Registration function for asn1 @@ -76,7 +76,7 @@ void DetectAsn1Register(void) * checks that we want to perform, and the lenght of oversize check * \retval 1 if any of the options match, 0 if not */ -static uint8_t DetectAsn1Checks(Asn1Node *node, DetectAsn1Data *ad) +static uint8_t DetectAsn1Checks(Asn1Node *node, const DetectAsn1Data *ad) { /* oversize_length will check if a node has a length greater than @@ -137,8 +137,8 @@ static uint8_t DetectAsn1Checks(Asn1Node *node, DetectAsn1Data *ad) * \retval 0 no match * \retval 1 match */ -int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, SigMatch *m) +static int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { uint8_t ret = 0; @@ -147,7 +147,7 @@ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, return 0; } - DetectAsn1Data *ad = (DetectAsn1Data *)m->ctx; + const DetectAsn1Data *ad = (const DetectAsn1Data *)ctx; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -197,7 +197,7 @@ int DetectAsn1Match(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, * \retval fd pointer to DetectAsn1Data on success * \retval NULL on failure */ -DetectAsn1Data *DetectAsn1Parse(char *asn1str) +static DetectAsn1Data *DetectAsn1Parse(char *asn1str) { DetectAsn1Data *fd = NULL; char *tok = NULL; @@ -205,8 +205,9 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) uint32_t abs_off = 0; int32_t rel_off = 0; uint8_t flags = 0; + char *saveptr = NULL; - tok = strtok(asn1str, ASN_DELIM); + tok = strtok_r(asn1str, ASN_DELIM, &saveptr); if (tok == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Malformed asn1 argument: %s", asn1str); @@ -223,7 +224,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) } else if (strcasecmp("oversize_length", tok) == 0) { flags |= ASN1_OVERSIZE_LEN; /* get the param */ - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); if ( tok == NULL || ByteExtractStringUint32(&ov_len, 10, 0, tok) <= 0) { @@ -234,7 +235,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) } else if (strcasecmp("absolute_offset", tok) == 0) { flags |= ASN1_ABSOLUTE_OFFSET; /* get the param */ - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); if (tok == NULL || ByteExtractStringUint32(&abs_off, 10, 0, tok) <= 0) { @@ -245,7 +246,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) } else if (strcasecmp("relative_offset",tok) == 0) { flags |= ASN1_RELATIVE_OFFSET; /* get the param */ - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); if (tok == NULL || ByteExtractStringInt32(&rel_off, 10, 0, tok) <= 0) { @@ -258,7 +259,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) asn1str); return NULL; } - tok = strtok(NULL, ASN_DELIM); + tok = strtok_r(NULL, ASN_DELIM, &saveptr); } fd = SCMalloc(sizeof(DetectAsn1Data)); @@ -288,7 +289,7 @@ DetectAsn1Data *DetectAsn1Parse(char *asn1str) * \retval 0 on Success * \retval -1 on Failure */ -int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) +static int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) { DetectAsn1Data *ad = NULL; SigMatch *sm = NULL; @@ -303,15 +304,17 @@ int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) goto error; sm->type = DETECT_ASN1; - sm->ctx = (void *)ad; + sm->ctx = (SigMatchCtx *)ad; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; error: - if (ad != NULL) DetectAsn1Free(ad); - if (sm != NULL) SCFree(sm); + if (ad != NULL) + DetectAsn1Free(ad); + if (sm != NULL) + SCFree(sm); return -1; } @@ -321,7 +324,7 @@ int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, char *asn1str) * * \param ad pointer to DetectAsn1Data */ -void DetectAsn1Free(void *ptr) +static void DetectAsn1Free(void *ptr) { DetectAsn1Data *ad = (DetectAsn1Data *)ptr; SCFree(ad); @@ -332,7 +335,7 @@ void DetectAsn1Free(void *ptr) /** * \test DetectAsn1TestParse01 check that we parse oversize_length correctly */ -int DetectAsn1TestParse01(void) +static int DetectAsn1TestParse01(void) { int result = 0; char str[] = "oversize_length 1024"; @@ -352,7 +355,7 @@ int DetectAsn1TestParse01(void) /** * \test DetectAsn1TestParse02 check that we parse absolute_offset correctly */ -int DetectAsn1TestParse02(void) +static int DetectAsn1TestParse02(void) { int result = 0; DetectAsn1Data *ad = NULL; @@ -371,7 +374,7 @@ int DetectAsn1TestParse02(void) /** * \test DetectAsn1TestParse03 check that we parse relative_offset correctly */ -int DetectAsn1TestParse03(void) +static int DetectAsn1TestParse03(void) { int result = 0; char str[] = "relative_offset 1024"; @@ -390,7 +393,7 @@ int DetectAsn1TestParse03(void) /** * \test DetectAsn1TestParse04 check that we parse bitstring_overflow correctly */ -int DetectAsn1TestParse04(void) +static int DetectAsn1TestParse04(void) { int result = 0; char str[] = "bitstring_overflow"; @@ -408,7 +411,7 @@ int DetectAsn1TestParse04(void) /** * \test DetectAsn1TestParse05 check that we parse double_overflow correctly */ -int DetectAsn1TestParse05(void) +static int DetectAsn1TestParse05(void) { int result = 0; char str[] = "double_overflow"; @@ -426,7 +429,7 @@ int DetectAsn1TestParse05(void) /** * \test DetectAsn1TestParse06 check that we fail if a needed arg is not given */ -int DetectAsn1TestParse06(void) +static int DetectAsn1TestParse06(void) { int result = 1; char str[] = "absolute_offset"; @@ -444,7 +447,7 @@ int DetectAsn1TestParse06(void) /** * \test DetectAsn1TestParse07 check that we fail if a needed arg is not given */ -int DetectAsn1TestParse07(void) +static int DetectAsn1TestParse07(void) { int result = 1; char str[] = "relative_offset"; @@ -462,7 +465,7 @@ int DetectAsn1TestParse07(void) /** * \test DetectAsn1TestParse08 check that we fail if a needed arg is not given */ -int DetectAsn1TestParse08(void) +static int DetectAsn1TestParse08(void) { int result = 1; char str[] = "oversize_length"; @@ -482,7 +485,7 @@ int DetectAsn1TestParse08(void) /** * \test DetectAsn1TestParse09 test that we break on invalid options */ -int DetectAsn1TestParse09(void) +static int DetectAsn1TestParse09(void) { int result = 1; DetectAsn1Data *fd = NULL; @@ -500,7 +503,7 @@ int DetectAsn1TestParse09(void) /** * \test DetectAsn1TestParse10 test that we break with a empty string */ -int DetectAsn1TestParse10(void) +static int DetectAsn1TestParse10(void) { int result = 1; DetectAsn1Data *fd = NULL; @@ -518,7 +521,7 @@ int DetectAsn1TestParse10(void) /** * \test DetectAsn1TestParse11 check for combinations of keywords */ -int DetectAsn1TestParse11(void) +static int DetectAsn1TestParse11(void) { int result = 0; char str[] = "oversize_length 1024, relative_offset 10"; @@ -540,7 +543,7 @@ int DetectAsn1TestParse11(void) /** * \test DetectAsn1TestParse12 check for combinations of keywords */ -int DetectAsn1TestParse12(void) +static int DetectAsn1TestParse12(void) { int result = 0; char str[] = "oversize_length 1024 absolute_offset 10"; @@ -562,7 +565,7 @@ int DetectAsn1TestParse12(void) /** * \test DetectAsn1TestParse13 check for combinations of keywords */ -int DetectAsn1TestParse13(void) +static int DetectAsn1TestParse13(void) { int result = 0; char str[] = "oversize_length 1024 absolute_offset 10, bitstring_overflow"; @@ -585,7 +588,7 @@ int DetectAsn1TestParse13(void) /** * \test DetectAsn1TestParse14 check for combinations of keywords */ -int DetectAsn1TestParse14(void) +static int DetectAsn1TestParse14(void) { int result = 0; char str[] = "double_overflow, oversize_length 1024 absolute_offset 10," @@ -610,7 +613,7 @@ int DetectAsn1TestParse14(void) /** * \test DetectAsn1TestParse15 check for combinations of keywords */ -int DetectAsn1TestParse15(void) +static int DetectAsn1TestParse15(void) { int result = 0; char str[] = "double_overflow, oversize_length 1024 relative_offset 10," @@ -635,73 +638,65 @@ int DetectAsn1TestParse15(void) /** * \test DetectAsn1Test01 Ensure that the checks work when they should */ -int DetectAsn1Test01(void) +static int DetectAsn1Test01(void) { - int result = 0; /* Match if any of the nodes after offset 0 has greater length than 10 */ char str[] = "oversize_length 132 absolute_offset 0"; - DetectAsn1Data *ad = NULL; - ad = DetectAsn1Parse(str); - if (ad != NULL && ad->oversize_length == 132 - && (ad->flags & ASN1_OVERSIZE_LEN) - && ad->absolute_offset == 0 - && (ad->flags & ASN1_ABSOLUTE_OFFSET)) - { - // Example from the specification X.690-0207 Appendix A.3 - uint8_t *str = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" - "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" - "\x42\x01\x33\xA1\x0A\x43\x08""19710917" - "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" - "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" - "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" - "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" - "Jones""\xA0\x0A\x43\x08""19590717"; + DetectAsn1Data *ad = DetectAsn1Parse(str); + FAIL_IF_NULL(ad); + FAIL_IF_NOT(ad->oversize_length == 132); + FAIL_IF_NOT(ad->flags & ASN1_OVERSIZE_LEN); + FAIL_IF_NOT(ad->absolute_offset == 0); + FAIL_IF_NOT(ad->flags & ASN1_ABSOLUTE_OFFSET); + + // Example from the specification X.690-0207 Appendix A.3 + char buf[] = "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" + "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" + "\x42\x01\x33\xA1\x0A\x43\x08""19710917" + "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" + "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01" + "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111" + "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05" + "Jones""\xA0\x0A\x43\x08""19590717"; - Asn1Ctx *ac = SCAsn1CtxNew(); - if (ac == NULL) - return 0; - - uint16_t len = strlen((char *)str)-1; - - SCAsn1CtxInit(ac, str, len); - - SCAsn1Decode(ac, ac->cur_frame); + Asn1Ctx *ac = SCAsn1CtxNew(); + FAIL_IF_NULL(ac); - /* The first node has length 133, so it should match the oversize */ - if (ac->cur_frame > 0) { - /* We spect at least one node */ - uint16_t n_iter = 0; + uint16_t len = strlen((char *)buf)-1; - for (; n_iter <= ac->cur_frame; n_iter++) { - Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); + SCAsn1CtxInit(ac, (uint8_t *)buf, len); + SCAsn1Decode(ac, ac->cur_frame); - if (node == NULL || node->id.ptr == NULL) - continue; /* Should not happen */ + /* The first node has length 133, so it should match the oversize */ + FAIL_IF_NOT(ac->cur_frame > 0); - result = DetectAsn1Checks(node, ad); - /* Got a match? */ - if (result == 1) - break; - } - } + /* We spect at least one node */ + uint16_t n_iter = 0; + int result = 0; + for (; n_iter <= ac->cur_frame; n_iter++) { + Asn1Node *node = ASN1CTX_GET_NODE(ac, n_iter); - SCAsn1CtxDestroy(ac); - DetectAsn1Free(ad); + if (node == NULL || node->id.ptr == NULL) + continue; /* Should not happen */ + result = DetectAsn1Checks(node, ad); + /* Got a match? */ + if (result == 1) + break; } + FAIL_IF(result != 1); - if (result == 0) { - printf("Error, oversize_length should match the first node: "); - } + SCAsn1CtxDestroy(ac); + DetectAsn1Free(ad); - return result; + PASS; } /** * \test DetectAsn1Test02 Ensure that the checks work when they should */ -int DetectAsn1Test02(void) +static int DetectAsn1Test02(void) { int result = 0; /* Match if any of the nodes has the bitstring overflow condition */ @@ -715,7 +710,7 @@ int DetectAsn1Test02(void) && (ad->flags & ASN1_ABSOLUTE_OFFSET)) { // Example from the specification X.690-0207 Appendix A.3 - uint8_t *str = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" + uint8_t *buf = (uint8_t*) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director" "\x42\x01\x33\xA1\x0A\x43\x08""19710917" "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05" @@ -728,9 +723,9 @@ int DetectAsn1Test02(void) if (ac == NULL) return 0; - uint16_t len = strlen((char *)str)-1; + uint16_t len = strlen((char *)buf)-1; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -769,7 +764,7 @@ int DetectAsn1Test02(void) /** * \test DetectAsn1Test03 Ensure that the checks work when they should */ -int DetectAsn1Test03(void) +static int DetectAsn1Test03(void) { int result = 0; /* Match if any of the nodes after offset 0 has a bitstring overflow */ @@ -784,7 +779,7 @@ int DetectAsn1Test03(void) /* Let's say tagnum bitstring, primitive, and as universal tag, * and then length = 1 octet, but the next octet specify to ignore * the last 256 bits... (let's match!) */ - uint8_t *str = (uint8_t*) "\x03\x01\xFF"; + uint8_t *buf = (uint8_t*) "\x03\x01\xFF"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -792,7 +787,7 @@ int DetectAsn1Test03(void) uint16_t len = 3; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -828,7 +823,7 @@ int DetectAsn1Test03(void) /** * \test DetectAsn1Test04 Ensure that the checks work when they should */ -int DetectAsn1Test04(void) +static int DetectAsn1Test04(void) { int result = 0; /* Match if any of the nodes after offset 0 has a bitstring overflow */ @@ -843,7 +838,7 @@ int DetectAsn1Test04(void) /* Let's say tagnum bitstring, primitive, and as universal tag, * and then length = 1 octet, but the next octet specify to ignore * the last 7 bits... (should not match) */ - uint8_t *str = (uint8_t*) "\x03\x01\x07"; + uint8_t *buf = (uint8_t*) "\x03\x01\x07"; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -851,7 +846,7 @@ int DetectAsn1Test04(void) uint16_t len = 3; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -890,7 +885,7 @@ int DetectAsn1Test04(void) /** * \test DetectAsn1Test05 Ensure that the checks work when they should */ -int DetectAsn1Test05(void) +static int DetectAsn1Test05(void) { int result = 0; /* Match if any of the nodes after offset 0 has a double overflow */ @@ -904,19 +899,19 @@ int DetectAsn1Test05(void) { /* Let's say tag num 9 (type Real), and encoded as ASCII, with length * 257, then we must match */ - uint8_t str[261]; + uint8_t buf[261]; /* universal class, primitive type, tag_num = 9 (Data type Real) */ - str[0] = '\x09'; + buf[0] = '\x09'; /* length, definite form, 2 octets */ - str[1] = '\x82'; + buf[1] = '\x82'; /* length is the sum of the following octets (257): */ - str[2] = '\xFE'; - str[3] = '\x03'; + buf[2] = '\xFE'; + buf[3] = '\x03'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 257;i++) - str[i] = '\x05'; + buf[i] = '\x05'; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -924,7 +919,7 @@ int DetectAsn1Test05(void) uint16_t len = 261; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -960,7 +955,7 @@ int DetectAsn1Test05(void) /** * \test DetectAsn1Test06 Ensure that the checks work when they should */ -int DetectAsn1Test06(void) +static int DetectAsn1Test06(void) { int result = 0; /* Match if any of the nodes after offset 0 has a double overflow */ @@ -974,19 +969,19 @@ int DetectAsn1Test06(void) { /* Let's say tag num 9 (type Real), and encoded as ASCII, with length * 256, which fit in the buffer, so it should not match */ - uint8_t str[260]; + uint8_t buf[260]; /* universal class, primitive type, tag_num = 9 (Data type Real) */ - str[0] = '\x09'; + buf[0] = '\x09'; /* length, definite form, 2 octets */ - str[1] = '\x82'; + buf[1] = '\x82'; /* length is the sum of the following octets (256): */ - str[2] = '\xFE'; - str[3] = '\x02'; + buf[2] = '\xFE'; + buf[3] = '\x02'; /* Fill the content of the number */ uint16_t i = 4; for (; i < 256;i++) - str[i] = '\x05'; + buf[i] = '\x05'; Asn1Ctx *ac = SCAsn1CtxNew(); if (ac == NULL) @@ -994,7 +989,7 @@ int DetectAsn1Test06(void) uint16_t len = 260; - SCAsn1CtxInit(ac, str, len); + SCAsn1CtxInit(ac, buf, len); SCAsn1Decode(ac, ac->cur_frame); @@ -1033,7 +1028,7 @@ int DetectAsn1Test06(void) /** * \test DetectAsn1TestReal01 Ensure that all works together */ -int DetectAsn1TestReal01(void) +static int DetectAsn1TestReal01(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" @@ -1112,7 +1107,7 @@ int DetectAsn1TestReal01(void) /** * \test DetectAsn1TestReal02 Ensure that all works together */ -int DetectAsn1TestReal02(void) +static int DetectAsn1TestReal02(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" @@ -1189,7 +1184,7 @@ int DetectAsn1TestReal02(void) /** * \test DetectAsn1TestReal03 Ensure that all works together */ -int DetectAsn1TestReal03(void) +static int DetectAsn1TestReal03(void) { int result = 0; uint8_t buf[261] = ""; @@ -1250,7 +1245,7 @@ int DetectAsn1TestReal03(void) * relative offset to check negative offset values, in this case * start decoding from -7 bytes respect the content match "John" */ -int DetectAsn1TestReal04(void) +static int DetectAsn1TestReal04(void) { int result = 0; uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01" @@ -1329,37 +1324,37 @@ int DetectAsn1TestReal04(void) /** * \brief this function registers unit tests for DetectAsn1 */ -void DetectAsn1RegisterTests(void) +static void DetectAsn1RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectAsn1TestParse01", DetectAsn1TestParse01, 1); - UtRegisterTest("DetectAsn1TestParse02", DetectAsn1TestParse02, 1); - UtRegisterTest("DetectAsn1TestParse03", DetectAsn1TestParse03, 1); - - UtRegisterTest("DetectAsn1TestParse04", DetectAsn1TestParse04, 1); - UtRegisterTest("DetectAsn1TestParse05", DetectAsn1TestParse05, 1); - UtRegisterTest("DetectAsn1TestParse06", DetectAsn1TestParse06, 1); - - UtRegisterTest("DetectAsn1TestParse07", DetectAsn1TestParse07, 1); - UtRegisterTest("DetectAsn1TestParse08", DetectAsn1TestParse08, 1); - UtRegisterTest("DetectAsn1TestParse09", DetectAsn1TestParse09, 1); - - UtRegisterTest("DetectAsn1TestParse10", DetectAsn1TestParse10, 1); - UtRegisterTest("DetectAsn1TestParse11", DetectAsn1TestParse11, 1); - UtRegisterTest("DetectAsn1TestParse12", DetectAsn1TestParse12, 1); - UtRegisterTest("DetectAsn1TestParse13", DetectAsn1TestParse13, 1); - UtRegisterTest("DetectAsn1TestParse14", DetectAsn1TestParse14, 1); - UtRegisterTest("DetectAsn1TestParse15", DetectAsn1TestParse15, 1); - UtRegisterTest("DetectAsn1Test01 - oversize_len", DetectAsn1Test01, 1); - UtRegisterTest("DetectAsn1Test02 - oversize_len", DetectAsn1Test02, 1); - UtRegisterTest("DetectAsn1Test03 - bitstring_ovf", DetectAsn1Test03, 1); - UtRegisterTest("DetectAsn1Test04 - bitstring_ovf", DetectAsn1Test04, 1); - UtRegisterTest("DetectAsn1Test05 - double_ovf", DetectAsn1Test05, 1); - UtRegisterTest("DetectAsn1Test06 - double_ovf", DetectAsn1Test06, 1); - UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01, 1); - UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02, 1); - UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03, 1); - UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04, 1); + UtRegisterTest("DetectAsn1TestParse01", DetectAsn1TestParse01); + UtRegisterTest("DetectAsn1TestParse02", DetectAsn1TestParse02); + UtRegisterTest("DetectAsn1TestParse03", DetectAsn1TestParse03); + + UtRegisterTest("DetectAsn1TestParse04", DetectAsn1TestParse04); + UtRegisterTest("DetectAsn1TestParse05", DetectAsn1TestParse05); + UtRegisterTest("DetectAsn1TestParse06", DetectAsn1TestParse06); + + UtRegisterTest("DetectAsn1TestParse07", DetectAsn1TestParse07); + UtRegisterTest("DetectAsn1TestParse08", DetectAsn1TestParse08); + UtRegisterTest("DetectAsn1TestParse09", DetectAsn1TestParse09); + + UtRegisterTest("DetectAsn1TestParse10", DetectAsn1TestParse10); + UtRegisterTest("DetectAsn1TestParse11", DetectAsn1TestParse11); + UtRegisterTest("DetectAsn1TestParse12", DetectAsn1TestParse12); + UtRegisterTest("DetectAsn1TestParse13", DetectAsn1TestParse13); + UtRegisterTest("DetectAsn1TestParse14", DetectAsn1TestParse14); + UtRegisterTest("DetectAsn1TestParse15", DetectAsn1TestParse15); + UtRegisterTest("DetectAsn1Test01 - oversize_len", DetectAsn1Test01); + UtRegisterTest("DetectAsn1Test02 - oversize_len", DetectAsn1Test02); + UtRegisterTest("DetectAsn1Test03 - bitstring_ovf", DetectAsn1Test03); + UtRegisterTest("DetectAsn1Test04 - bitstring_ovf", DetectAsn1Test04); + UtRegisterTest("DetectAsn1Test05 - double_ovf", DetectAsn1Test05); + UtRegisterTest("DetectAsn1Test06 - double_ovf", DetectAsn1Test06); + UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01); + UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02); + UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03); + UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04); #endif /* UNITTESTS */ } diff --git a/src/detect-base64-data.c b/src/detect-base64-data.c new file mode 100644 index 000000000000..97fd2e09b708 --- /dev/null +++ b/src/detect-base64-data.c @@ -0,0 +1,261 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" +#include "detect-parse.h" + +#include "util-unittest.h" + +static int DetectBase64DataSetup(DetectEngineCtx *, Signature *, char *); +static void DetectBase64DataRegisterTests(void); + +void DetectBase64DataRegister(void) +{ + sigmatch_table[DETECT_BASE64_DATA].name = "base64_data"; + sigmatch_table[DETECT_BASE64_DATA].desc = + "Content match base64 decoded data."; + sigmatch_table[DETECT_BASE64_DATA].url = + DOC_URL DOC_VERSION "/rules/payload-keywords.html#base64-data"; + sigmatch_table[DETECT_BASE64_DATA].Setup = DetectBase64DataSetup; + sigmatch_table[DETECT_BASE64_DATA].RegisterTests = + DetectBase64DataRegisterTests; + + sigmatch_table[DETECT_BASE64_DATA].flags |= SIGMATCH_NOOPT; +} + +static int DetectBase64DataSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + SigMatch *pm = NULL; + + /* Check for a preceding base64_decode. */ + pm = DetectGetLastSMFromLists(s, DETECT_BASE64_DECODE, -1); + if (pm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "\"base64_data\" keyword seen without preceding base64_decode."); + return -1; + } + + s->init_data->list = DETECT_SM_LIST_BASE64_DATA; + return 0; +} + +int DetectBase64DataDoMatch(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f) +{ + if (det_ctx->base64_decoded_len) { + return DetectEngineContentInspection(de_ctx, det_ctx, s, + s->sm_arrays[DETECT_SM_LIST_BASE64_DATA], f, det_ctx->base64_decoded, + det_ctx->base64_decoded_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + } + + return 0; +} + +#ifdef UNITTESTS + +#include "detect-engine.h" + +static int g_file_data_buffer_id = 0; + +static int DetectBase64DataSetupTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any (msg:\"DetectBase64DataSetupTest\"; " + "base64_decode; base64_data; content:\"content\"; sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + printf("SigInit failed: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; + if (sm == NULL) { + printf("DETECT_SM_LIST_PMATCH should not be NULL: "); + goto end; + } + if (sm->type != DETECT_BASE64_DECODE) { + printf("sm->type should be DETECT_BASE64_DECODE: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_BASE64_DATA] == NULL) { + printf("DETECT_SM_LIST_BASE64_DATA should not be NULL: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +static int DetectBase64DataSetupTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any ( " + "msg:\"DetectBase64DataSetupTest\"; " + "file_data; " + "content:\"SGV\"; " + "base64_decode: bytes 16; " + "base64_data; " + "content:\"content\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + printf("SigInit failed: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; + if (sm != NULL) { + printf("DETECT_SM_LIST_PMATCH is not NULL: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; + if (sm == NULL) { + printf("DETECT_SM_LIST_FILEDATA is NULL: "); + goto end; + } + + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_BASE64_DATA]; + if (sm == NULL) { + printf("DETECT_SM_LIST_BASE64_DATA is NULL: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +/** + * \test Test that the rule fails to load if the detection list is + * changed after base64_data. + */ +static int DetectBase64DataSetupTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any ( " + "msg:\"DetectBase64DataSetupTest\"; " + "base64_decode: bytes 16; " + "base64_data; " + "content:\"content\"; " + "file_data; " + "content:\"SGV\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list != NULL) { + printf("SigInit should have failed: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +/** + * \test Test that the list can be changed to post-detection lists + * after the base64 keyword. + */ +static int DetectBase64DataSetupTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"some b64thing\"; flow:established,from_server; file_data; content:\"sometext\"; fast_pattern; base64_decode:relative; base64_data; content:\"foobar\"; nocase; tag:session,120,seconds; sid:1111111; rev:1;)"); + if (de_ctx->sig_list == NULL) { + printf("SigInit failed: "); + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +#endif + +static void DetectBase64DataRegisterTests(void) +{ +#ifdef UNITTESTS + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + + UtRegisterTest("DetectBase64DataSetupTest01", DetectBase64DataSetupTest01); + UtRegisterTest("DetectBase64DataSetupTest02", DetectBase64DataSetupTest02); + UtRegisterTest("DetectBase64DataSetupTest03", DetectBase64DataSetupTest03); + UtRegisterTest("DetectBase64DataSetupTest04", DetectBase64DataSetupTest04); +#endif /* UNITTESTS */ +} diff --git a/src/detect-base64-data.h b/src/detect-base64-data.h new file mode 100644 index 000000000000..38bb93fc0691 --- /dev/null +++ b/src/detect-base64-data.h @@ -0,0 +1,25 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_BASE64_DATA_H__ +#define __DETECT_BASE64_DATA_H__ + +void DetectBase64DataRegister(void); +int DetectBase64DataDoMatch(DetectEngineCtx *, DetectEngineThreadCtx *, + const Signature *, Flow *); + +#endif /* __DETECT_BASE64_DATA_H__ */ diff --git a/src/detect-base64-decode.c b/src/detect-base64-decode.c new file mode 100644 index 000000000000..354b85dd99ea --- /dev/null +++ b/src/detect-base64-decode.c @@ -0,0 +1,681 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-base64-decode.h" +#include "util-base64.h" +#include "util-byte.h" +#include "util-print.h" + +/* Arbitrary maximum buffer size for decoded base64 data. */ +#define BASE64_DECODE_MAX 65535 + +static const char decode_pattern[] = "\\s*(bytes\\s+(\\d+),?)?" + "\\s*(offset\\s+(\\d+),?)?" + "\\s*(\\w+)?"; +static pcre *decode_pcre = NULL; +static pcre_extra *decode_pcre_study = NULL; + +static int DetectBase64DecodeSetup(DetectEngineCtx *, Signature *, char *); +static void DetectBase64DecodeFree(void *); +static void DetectBase64DecodeRegisterTests(void); + +void DetectBase64DecodeRegister(void) +{ + sigmatch_table[DETECT_BASE64_DECODE].name = "base64_decode"; + sigmatch_table[DETECT_BASE64_DECODE].desc = + "Decodes base64 encoded data."; + sigmatch_table[DETECT_BASE64_DECODE].url = + DOC_URL DOC_VERSION "/rules/payload-keywords.html#base64-decode"; + sigmatch_table[DETECT_BASE64_DECODE].Setup = DetectBase64DecodeSetup; + sigmatch_table[DETECT_BASE64_DECODE].Free = DetectBase64DecodeFree; + sigmatch_table[DETECT_BASE64_DECODE].RegisterTests = + DetectBase64DecodeRegisterTests; + + sigmatch_table[DETECT_BASE64_DECODE].flags |= SIGMATCH_OPTIONAL_OPT; + + DetectSetupParseRegexes(decode_pattern, &decode_pcre, &decode_pcre_study); +} + +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, + const SigMatchData *smd, uint8_t *payload, uint32_t payload_len) +{ + DetectBase64Decode *data = (DetectBase64Decode *)smd->ctx; + int decode_len; + +#if 0 + printf("Input data:\n"); + PrintRawDataFp(stdout, payload, payload_len); +#endif + + if (data->relative) { + payload += det_ctx->buffer_offset; + payload_len -= det_ctx->buffer_offset; + } + + if (data->offset) { + if (data->offset >= payload_len) { + return 0; + } + payload = payload + data->offset; + payload_len -= data->offset; + } + + decode_len = MIN(payload_len, data->bytes); + +#if 0 + printf("Decoding:\n"); + PrintRawDataFp(stdout, payload, decode_len); +#endif + + det_ctx->base64_decoded_len = DecodeBase64(det_ctx->base64_decoded, + payload, decode_len, 0); + SCLogDebug("Decoded %d bytes from base64 data.", + det_ctx->base64_decoded_len); +#if 0 + if (det_ctx->base64_decoded_len) { + printf("Decoded data:\n"); + PrintRawDataFp(stdout, det_ctx->base64_decoded, + det_ctx->base64_decoded_len); + } +#endif + + return det_ctx->base64_decoded_len > 0; +} + +static int DetectBase64DecodeParse(const char *str, uint32_t *bytes, + uint32_t *offset, uint8_t *relative) +{ + static const int max = 30; + int ov[max]; + int pcre_rc; + const char *bytes_str = NULL; + const char *offset_str = NULL; + const char *relative_str = NULL; + int retval = 0; + + *bytes = 0; + *offset = 0; + *relative = 0; + + pcre_rc = pcre_exec(decode_pcre, decode_pcre_study, str, strlen(str), 0, 0, + ov, max); + if (pcre_rc < 3) { + goto error; + } + + if (pcre_rc >= 3) { + if (pcre_get_substring((char *)str, ov, max, 2, &bytes_str) > 0) { + if (ByteExtractStringUint32(bytes, 10, 0, bytes_str) <= 0) { + SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, + "Bad value for bytes: \"%s\"", bytes_str); + goto error; + } + } + } + + if (pcre_rc >= 5) { + if (pcre_get_substring((char *)str, ov, max, 4, &offset_str)) { + if (ByteExtractStringUint32(offset, 10, 0, offset_str) <= 0) { + SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, + "Bad value for offset: \"%s\"", offset_str); + goto error; + } + } + } + + if (pcre_rc >= 6) { + if (pcre_get_substring((char *)str, ov, max, 5, &relative_str)) { + if (strcmp(relative_str, "relative") == 0) { + *relative = 1; + } + else { + SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, + "Invalid argument: \"%s\"", relative_str); + goto error; + } + } + } + + retval = 1; +error: + if (bytes_str != NULL) { + pcre_free_substring(bytes_str); + } + if (offset_str != NULL) { + pcre_free_substring(offset_str); + } + if (relative_str != NULL) { + pcre_free_substring(relative_str); + } + return retval; +} + +static int DetectBase64DecodeSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + uint32_t bytes = 0; + uint32_t offset = 0; + uint8_t relative = 0; + DetectBase64Decode *data = NULL; + int sm_list; + SigMatch *sm = NULL; + SigMatch *pm = NULL; + + if (str != NULL) { + if (!DetectBase64DecodeParse(str, &bytes, &offset, &relative)) { + goto error; + } + } + data = SCCalloc(1, sizeof(DetectBase64Decode)); + if (unlikely(data == NULL)) { + goto error; + } + data->bytes = bytes; + data->offset = offset; + data->relative = relative; + + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->init_data->list; +#if 0 + if (data->relative) { + pm = SigMatchGetLastSMFromLists(s, 4, + DETECT_CONTENT, s->sm_lists_tail[sm_list], + DETECT_PCRE, s->sm_lists_tail[sm_list]); + } +#endif + } + else { + pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); + if (pm == NULL) { + sm_list = DETECT_SM_LIST_PMATCH; + } + else { + sm_list = SigMatchListSMBelongsTo(s, pm); + if (sm_list < 0) { + goto error; + } + } + } + + sm = SigMatchAlloc(); + if (sm == NULL) { + goto error; + } + sm->type = DETECT_BASE64_DECODE; + sm->ctx = (SigMatchCtx *)data; + SigMatchAppendSMToList(s, sm, sm_list); + + if (!data->bytes) { + data->bytes = BASE64_DECODE_MAX; + } + if (data->bytes > de_ctx->base64_decode_max_len) { + de_ctx->base64_decode_max_len = data->bytes; + } + + return 0; +error: + if (data != NULL) { + SCFree(data); + } + return -1; +} + +static void DetectBase64DecodeFree(void *ptr) +{ + DetectBase64Decode *data = ptr; + SCFree(data); +} + + +#ifdef UNITTESTS +#include "detect-engine.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int g_http_header_buffer_id = 0; + +static int DetectBase64TestDecodeParse(void) +{ + int retval = 0; + uint32_t bytes = 0; + uint32_t offset = 0; + uint8_t relative = 0; + + if (!DetectBase64DecodeParse("bytes 1", &bytes, &offset, &relative)) { + goto end; + } + if (bytes != 1 || offset != 0 || relative != 0) { + goto end; + } + + if (!DetectBase64DecodeParse("offset 9", &bytes, &offset, &relative)) { + goto end; + } + if (bytes != 0 || offset != 9 || relative != 0) { + goto end; + } + + if (!DetectBase64DecodeParse("relative", &bytes, &offset, &relative)) { + goto end; + } + if (bytes != 0 || offset != 0 || relative != 1) { + goto end; + } + + if (!DetectBase64DecodeParse("bytes 1, offset 2", &bytes, &offset, + &relative)) { + goto end; + } + if (bytes != 1 || offset != 2 || relative != 0) { + goto end; + } + + if (!DetectBase64DecodeParse("bytes 1, offset 2, relative", &bytes, &offset, + &relative)) { + goto end; + } + if (bytes != 1 || offset != 2 || relative != 1) { + goto end; + } + + if (!DetectBase64DecodeParse("offset 2, relative", &bytes, &offset, + &relative)) { + goto end; + } + if (bytes != 0 || offset != 2 || relative != 1) { + goto end; + } + + /* Misspelled relative. */ + if (DetectBase64DecodeParse("bytes 1, offset 2, relatve", &bytes, &offset, + &relative)) { + goto end; + } + + /* Misspelled bytes. */ + if (DetectBase64DecodeParse("byts 1, offset 2, relatve", &bytes, &offset, + &relative)) { + goto end; + } + + /* Misspelled offset. */ + if (DetectBase64DecodeParse("bytes 1, offst 2, relatve", &bytes, &offset, + &relative)) { + goto end; + } + + /* Misspelled empty string. */ + if (DetectBase64DecodeParse("", &bytes, &offset, &relative)) { + goto end; + } + + retval = 1; +end: + return retval; +} + +/** + * Test keyword setup on basic content. + */ +static int DetectBase64DecodeTestSetup(void) +{ + DetectEngineCtx *de_ctx = NULL; + Signature *s; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (" + "msg:\"DetectBase64DecodeTestSetup\"; " + "base64_decode; content:\"content\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + s = de_ctx->sig_list; + if (s == NULL) { + goto end; + } + if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +/** + * Test keyword setup when the prior rule has a content modifier on + * it. + */ +static int DetectBase64DecodeHttpHeaderTestSetup(void) +{ + DetectEngineCtx *de_ctx = NULL; + Signature *s; + int retval = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (" + "msg:\"DetectBase64DecodeTestSetup\"; " + "content:\"Authorization: basic \"; http_header; " + "base64_decode; content:\"content\"; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + s = de_ctx->sig_list; + if (s == NULL) { + goto end; + } + + /* I'm not complete sure if this list should not be NULL. */ + if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + goto end; + } + + /* Test that the http header list is not NULL. */ + if (s->sm_lists_tail[g_http_header_buffer_id] == NULL) { + goto end; + } + + retval = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } + return retval; +} + +static int DetectBase64DecodeTestDecode(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len == 0) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +static int DetectBase64DecodeTestDecodeWithOffset(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + char decoded[] = "Hello World"; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode: offset 8; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len != (int)strlen(decoded)) { + goto end; + } + if (memcmp(det_ctx->base64_decoded, decoded, strlen(decoded))) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +static int DetectBase64DecodeTestDecodeLargeOffset(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + /* Offset is out of range. */ + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "base64_decode: bytes 16, offset 32; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len != 0) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +static int DetectBase64DecodeTestDecodeRelative(void) +{ + ThreadVars tv; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + Packet *p = NULL; + int retval = 0; + + uint8_t payload[] = { + 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 'S', 'G', 'V', 's', 'b', 'G', '8', 'g', + 'V', '2', '9', 'y', 'b', 'G', 'Q', '=', + }; + char decoded[] = "Hello World"; + + memset(&tv, 0, sizeof(tv)); + + if ((de_ctx = DetectEngineCtxInit()) == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any (msg:\"base64 test\"; " + "content:\"aaaaaaaa\"; " + "base64_decode: relative; " + "sid:1; rev:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + if (p == NULL) { + goto end; + } + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + if (det_ctx->base64_decoded_len != (int)strlen(decoded)) { + goto end; + } + if (memcmp(det_ctx->base64_decoded, decoded, strlen(decoded))) { + goto end; + } + + retval = 1; +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&tv, det_ctx); + } + if (de_ctx != NULL) { + SigCleanSignatures(de_ctx); + SigGroupCleanup(de_ctx); + DetectEngineCtxFree(de_ctx); + } + if (p != NULL) { + UTHFreePacket(p); + } + return retval; +} + +#endif + +static void DetectBase64DecodeRegisterTests(void) +{ +#ifdef UNITTESTS + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + + UtRegisterTest("DetectBase64TestDecodeParse", DetectBase64TestDecodeParse); + UtRegisterTest("DetectBase64DecodeTestSetup", DetectBase64DecodeTestSetup); + UtRegisterTest("DetectBase64DecodeHttpHeaderTestSetup", + DetectBase64DecodeHttpHeaderTestSetup); + UtRegisterTest("DetectBase64DecodeTestDecode", + DetectBase64DecodeTestDecode); + UtRegisterTest("DetectBase64DecodeTestDecodeWithOffset", + DetectBase64DecodeTestDecodeWithOffset); + UtRegisterTest("DetectBase64DecodeTestDecodeLargeOffset", + DetectBase64DecodeTestDecodeLargeOffset); + UtRegisterTest("DetectBase64DecodeTestDecodeRelative", + DetectBase64DecodeTestDecodeRelative); +#endif /* UNITTESTS */ +} diff --git a/src/detect-base64-decode.h b/src/detect-base64-decode.h new file mode 100644 index 000000000000..4ae19cd93d6b --- /dev/null +++ b/src/detect-base64-decode.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_BASE64_DECODE_H__ +#define __DETECT_BASE64_DECODE_H__ + +#include "app-layer-template.h" + +typedef struct DetectBase64Decode_ { + uint32_t bytes; + uint32_t offset; + uint8_t relative; +} DetectBase64Decode; + +void DetectBase64DecodeRegister(void); +int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *, const Signature *, + const SigMatchData *, uint8_t *, uint32_t); + +#endif /* __DETECT_BASE64_DECODE_H__ */ diff --git a/src/detect-bypass.c b/src/detect-bypass.c new file mode 100644 index 000000000000..6d77fbefa451 --- /dev/null +++ b/src/detect-bypass.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Giuseppe Longo + * + */ + +#include "suricata-common.h" +#include "threads.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "debug.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-sigorder.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "stream-tcp.h" + +#include "util-debug.h" +#include "util-spm-bm.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-device.h" + +static int DetectBypassMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); +static int DetectBypassSetup(DetectEngineCtx *, Signature *, char *); +static void DetectBypassRegisterTests(void); + +/** + * \brief Registration function for keyword: bypass + */ +void DetectBypassRegister(void) +{ + sigmatch_table[DETECT_BYPASS].name = "bypass"; + sigmatch_table[DETECT_BYPASS].desc = "call the bypass callback when the match of a sig is complete"; + sigmatch_table[DETECT_BYPASS].url = ""; + sigmatch_table[DETECT_BYPASS].Match = DetectBypassMatch; + sigmatch_table[DETECT_BYPASS].Setup = DetectBypassSetup; + sigmatch_table[DETECT_BYPASS].Free = NULL; + sigmatch_table[DETECT_BYPASS].RegisterTests = DetectBypassRegisterTests; + sigmatch_table[DETECT_BYPASS].flags = SIGMATCH_NOOPT; +} + +static int DetectBypassSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SigMatch *sm = NULL; + + if (s->flags & SIG_FLAG_FILESTORE) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "bypass can't work with filestore keyword"); + return -1; + } + s->flags |= SIG_FLAG_BYPASS; + + sm = SigMatchAlloc(); + if (sm == NULL) + return -1; + + sm->type = DETECT_BYPASS; + sm->ctx = NULL; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + + return 0; +} + +static int DetectBypassMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) +{ + PacketBypassCallback(p); + + return 1; +} + +#ifdef UNITTESTS +static int callback_var = 0; + +static int BypassCallback() +{ + callback_var = 1; + return 1; +} + +static void ResetCallbackVar() +{ + callback_var = 0; +} + +static int DetectBypassTestSig01(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This is dummy message body\r\n" + "User-Agent: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len1 = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + LiveDevice *livedev = SCMalloc(sizeof(LiveDevice)); + FAIL_IF(livedev == NULL); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(p1 == NULL); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF(p2 == NULL); + + p1->BypassPacketsFlow = BypassCallback; + p2->BypassPacketsFlow = BypassCallback; + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p1->livedev = livedev; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->livedev = livedev; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + de_ctx->flags |= DE_QUIET; + + char *sigs[3]; + sigs[0] = "alert tcp any any -> any any (bypass; content:\"GET \"; sid:1;)"; + sigs[1] = "alert http any any -> any any " + "(bypass; content:\"message\"; http_server_body; " + "sid:2;)"; + sigs[2] = "alert http any any -> any any " + "(bypass; content:\"message\"; http_host; " + "sid:3;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 3) == 0); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + FAIL_IF(http_state == NULL); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, + http_buf2, http_len2); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + FAIL_IF(!(PacketAlertCheck(p2, 2))); + FAIL_IF(!(PacketAlertCheck(p1, 3))); + + FAIL_IF(callback_var == 0); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + ResetCallbackVar(); + SCFree(livedev); + PASS; +} +#endif /* UNITTESTS */ + +static void DetectBypassRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectBypassTestSig01", DetectBypassTestSig01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-bypass.h b/src/detect-bypass.h new file mode 100644 index 000000000000..7afc4c9a323d --- /dev/null +++ b/src/detect-bypass.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Giuseppe Longo + */ + +#ifndef __DETECT_BYPASS_H__ +#define __DETECT_BYPASS_H__ + +void DetectBypassRegister(void); + +#endif /* __DETECT_BYPASS_H__ */ diff --git a/src/detect-byte-extract.c b/src/detect-byte-extract.c index 8dda193aa00f..0b0f4734777c 100644 --- a/src/detect-byte-extract.c +++ b/src/detect-byte-extract.c @@ -89,54 +89,30 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); -int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); -void DetectByteExtractRegisterTests(void); -void DetectByteExtractFree(void *); +static int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); +static void DetectByteExtractRegisterTests(void); +static void DetectByteExtractFree(void *); /** * \brief Registers the keyword handlers for the "byte_extract" keyword. */ void DetectByteExtractRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_BYTE_EXTRACT].name = "byte_extract"; sigmatch_table[DETECT_BYTE_EXTRACT].Match = NULL; - sigmatch_table[DETECT_BYTE_EXTRACT].AppLayerMatch = NULL; sigmatch_table[DETECT_BYTE_EXTRACT].Setup = DetectByteExtractSetup; sigmatch_table[DETECT_BYTE_EXTRACT].Free = DetectByteExtractFree; sigmatch_table[DETECT_BYTE_EXTRACT].RegisterTests = DetectByteExtractRegisterTests; - sigmatch_table[DETECT_BYTE_EXTRACT].flags |= SIGMATCH_PAYLOAD; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed " - "at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, SigMatch *sm, - Signature *s, uint8_t *payload, +int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, const SigMatchData *smd, + const Signature *s, uint8_t *payload, uint16_t payload_len, uint64_t *value, uint8_t endian) { - DetectByteExtractData *data = (DetectByteExtractData *)sm->ctx; + DetectByteExtractData *data = (DetectByteExtractData *)smd->ctx; uint8_t *ptr = NULL; int32_t len = 0; uint64_t val = 0; @@ -221,15 +197,6 @@ int DetectByteExtractDoMatch(DetectEngineThreadCtx *det_ctx, SigMatch *sm, return 1; } - -int DetectByteExtractMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) -{ - goto end; - end: - return 1; -} - /** * \internal * \brief Used to parse byte_extract arg. @@ -465,11 +432,8 @@ static inline DetectByteExtractData *DetectByteExtractParse(char *arg) if (bed->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) { if (bed->base == DETECT_BYTE_EXTRACT_BASE_NONE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Base not specified for " - "byte_extract, though string was specified. " - "The right options are (string, hex), (string, oct) " - "or (string, dec)"); - goto error; + /* Default to decimal if base not specified. */ + bed->base = DETECT_BYTE_EXTRACT_BASE_DEC; } if (bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE) { SCLogError(SC_ERR_INVALID_SIGNATURE, "byte_extract can't have " @@ -540,7 +504,7 @@ static inline DetectByteExtractData *DetectByteExtractParse(char *arg) * \retval 0 On success. * \retval -1 On failure. */ -int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; @@ -552,31 +516,17 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) goto error; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { - if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "dce byte_extract specified " - "with file_data option set."); - goto error; - } - AppLayerHtpEnableResponseBodyCallback(); - } - sm_list = s->list; - s->flags |= SIG_FLAG_APPLAYER; + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->init_data->list; + if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -592,96 +542,10 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) s->flags |= SIG_FLAG_APPLAYER; } else if (data->flags & DETECT_BYTE_EXTRACT_FLAG_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -697,12 +561,9 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) } if (data->endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " - "byte_extract with dce enabled"); + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) goto error; - } - s->alproto = ALPROTO_DCERPC; + if ((data->flags & DETECT_BYTE_EXTRACT_FLAG_STRING) || (data->base == DETECT_BYTE_EXTRACT_BASE_DEC) || (data->base == DETECT_BYTE_EXTRACT_BASE_HEX) || @@ -713,8 +574,8 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) } } - SigMatch *prev_bed_sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_BYTE_EXTRACT, s->sm_lists_tail[sm_list]); + SigMatch *prev_bed_sm = DetectGetLastSMByListId(s, sm_list, + DETECT_BYTE_EXTRACT, -1); if (prev_bed_sm == NULL) data->local_id = 0; else @@ -758,7 +619,7 @@ int DetectByteExtractSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) * * \param ptr Instance of DetectByteExtractData to be freed. */ -void DetectByteExtractFree(void *ptr) +static void DetectByteExtractFree(void *ptr) { if (ptr != NULL) { DetectByteExtractData *bed = ptr; @@ -778,13 +639,14 @@ void DetectByteExtractFree(void *ptr) * * \retval A pointer to the SigMatch if found, otherwise NULL. */ -SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, Signature *s) +SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, const Signature *s) { DetectByteExtractData *bed = NULL; int list; + const int nlists = DetectBufferTypeMaxId(); - for (list = 0; list < DETECT_SM_LIST_MAX; list++) { - SigMatch *sm = s->sm_lists[list]; + for (list = 0; list < nlists; list++) { + SigMatch *sm = s->init_data->smlists[list]; while (sm != NULL) { if (sm->type == DETECT_BYTE_EXTRACT) { bed = (DetectByteExtractData *)sm->ctx; @@ -803,7 +665,10 @@ SigMatch *DetectByteExtractRetrieveSMVar(const char *arg, Signature *s) #ifdef UNITTESTS -int DetectByteExtractTest01(void) +static int g_file_data_buffer_id = 0; +static int g_http_uri_buffer_id = 0; + +static int DetectByteExtractTest01(void) { int result = 0; @@ -829,7 +694,7 @@ int DetectByteExtractTest01(void) return result; } -int DetectByteExtractTest02(void) +static int DetectByteExtractTest02(void) { int result = 0; @@ -855,7 +720,7 @@ int DetectByteExtractTest02(void) return result; } -int DetectByteExtractTest03(void) +static int DetectByteExtractTest03(void) { int result = 0; @@ -881,7 +746,7 @@ int DetectByteExtractTest03(void) return result; } -int DetectByteExtractTest04(void) +static int DetectByteExtractTest04(void) { int result = 0; @@ -908,7 +773,7 @@ int DetectByteExtractTest04(void) return result; } -int DetectByteExtractTest05(void) +static int DetectByteExtractTest05(void) { int result = 0; @@ -934,7 +799,7 @@ int DetectByteExtractTest05(void) return result; } -int DetectByteExtractTest06(void) +static int DetectByteExtractTest06(void) { int result = 0; @@ -960,7 +825,7 @@ int DetectByteExtractTest06(void) return result; } -int DetectByteExtractTest07(void) +static int DetectByteExtractTest07(void) { int result = 0; @@ -986,7 +851,7 @@ int DetectByteExtractTest07(void) return result; } -int DetectByteExtractTest08(void) +static int DetectByteExtractTest08(void) { int result = 0; @@ -1012,7 +877,7 @@ int DetectByteExtractTest08(void) return result; } -int DetectByteExtractTest09(void) +static int DetectByteExtractTest09(void) { int result = 0; @@ -1038,7 +903,7 @@ int DetectByteExtractTest09(void) return result; } -int DetectByteExtractTest10(void) +static int DetectByteExtractTest10(void) { int result = 0; @@ -1064,7 +929,7 @@ int DetectByteExtractTest10(void) return result; } -int DetectByteExtractTest11(void) +static int DetectByteExtractTest11(void) { int result = 0; @@ -1090,7 +955,7 @@ int DetectByteExtractTest11(void) return result; } -int DetectByteExtractTest12(void) +static int DetectByteExtractTest12(void) { int result = 0; @@ -1117,7 +982,7 @@ int DetectByteExtractTest12(void) return result; } -int DetectByteExtractTest13(void) +static int DetectByteExtractTest13(void) { int result = 0; @@ -1145,7 +1010,7 @@ int DetectByteExtractTest13(void) return result; } -int DetectByteExtractTest14(void) +static int DetectByteExtractTest14(void) { int result = 0; @@ -1173,7 +1038,7 @@ int DetectByteExtractTest14(void) return result; } -int DetectByteExtractTest15(void) +static int DetectByteExtractTest15(void) { int result = 0; @@ -1201,7 +1066,7 @@ int DetectByteExtractTest15(void) return result; } -int DetectByteExtractTest16(void) +static int DetectByteExtractTest16(void) { int result = 0; @@ -1230,7 +1095,7 @@ int DetectByteExtractTest16(void) return result; } -int DetectByteExtractTest17(void) +static int DetectByteExtractTest17(void) { int result = 0; @@ -1247,7 +1112,7 @@ int DetectByteExtractTest17(void) return result; } -int DetectByteExtractTest18(void) +static int DetectByteExtractTest18(void) { int result = 0; @@ -1265,7 +1130,7 @@ int DetectByteExtractTest18(void) return result; } -int DetectByteExtractTest19(void) +static int DetectByteExtractTest19(void) { int result = 0; @@ -1283,7 +1148,7 @@ int DetectByteExtractTest19(void) return result; } -int DetectByteExtractTest20(void) +static int DetectByteExtractTest20(void) { int result = 0; @@ -1301,7 +1166,7 @@ int DetectByteExtractTest20(void) return result; } -int DetectByteExtractTest21(void) +static int DetectByteExtractTest21(void) { int result = 0; @@ -1319,7 +1184,7 @@ int DetectByteExtractTest21(void) return result; } -int DetectByteExtractTest22(void) +static int DetectByteExtractTest22(void) { int result = 0; @@ -1337,7 +1202,7 @@ int DetectByteExtractTest22(void) return result; } -int DetectByteExtractTest23(void) +static int DetectByteExtractTest23(void) { int result = 0; @@ -1355,7 +1220,7 @@ int DetectByteExtractTest23(void) return result; } -int DetectByteExtractTest24(void) +static int DetectByteExtractTest24(void) { int result = 0; @@ -1372,7 +1237,7 @@ int DetectByteExtractTest24(void) return result; } -int DetectByteExtractTest25(void) +static int DetectByteExtractTest25(void) { int result = 0; @@ -1389,7 +1254,7 @@ int DetectByteExtractTest25(void) return result; } -int DetectByteExtractTest26(void) +static int DetectByteExtractTest26(void) { int result = 0; @@ -1407,7 +1272,7 @@ int DetectByteExtractTest26(void) return result; } -int DetectByteExtractTest27(void) +static int DetectByteExtractTest27(void) { int result = 0; @@ -1425,7 +1290,7 @@ int DetectByteExtractTest27(void) return result; } -int DetectByteExtractTest28(void) +static int DetectByteExtractTest28(void) { int result = 0; @@ -1440,7 +1305,7 @@ int DetectByteExtractTest28(void) return result; } -int DetectByteExtractTest29(void) +static int DetectByteExtractTest29(void) { int result = 0; @@ -1455,7 +1320,7 @@ int DetectByteExtractTest29(void) return result; } -int DetectByteExtractTest30(void) +static int DetectByteExtractTest30(void) { int result = 0; @@ -1470,7 +1335,7 @@ int DetectByteExtractTest30(void) return result; } -int DetectByteExtractTest31(void) +static int DetectByteExtractTest31(void) { int result = 0; @@ -1485,7 +1350,7 @@ int DetectByteExtractTest31(void) return result; } -int DetectByteExtractTest32(void) +static int DetectByteExtractTest32(void) { int result = 0; @@ -1500,7 +1365,7 @@ int DetectByteExtractTest32(void) return result; } -int DetectByteExtractTest33(void) +static int DetectByteExtractTest33(void) { int result = 0; @@ -1515,7 +1380,7 @@ int DetectByteExtractTest33(void) return result; } -int DetectByteExtractTest34(void) +static int DetectByteExtractTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1591,7 +1456,7 @@ int DetectByteExtractTest34(void) return result; } -int DetectByteExtractTest35(void) +static int DetectByteExtractTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1679,7 +1544,7 @@ int DetectByteExtractTest35(void) return result; } -int DetectByteExtractTest36(void) +static int DetectByteExtractTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1767,7 +1632,7 @@ int DetectByteExtractTest36(void) return result; } -int DetectByteExtractTest37(void) +static int DetectByteExtractTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1821,7 +1686,7 @@ int DetectByteExtractTest37(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -1868,7 +1733,7 @@ int DetectByteExtractTest37(void) return result; } -int DetectByteExtractTest38(void) +static int DetectByteExtractTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -1934,7 +1799,7 @@ int DetectByteExtractTest38(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -1968,7 +1833,7 @@ int DetectByteExtractTest38(void) return result; } -int DetectByteExtractTest39(void) +static int DetectByteExtractTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2022,7 +1887,7 @@ int DetectByteExtractTest39(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -2069,7 +1934,7 @@ int DetectByteExtractTest39(void) return result; } -int DetectByteExtractTest40(void) +static int DetectByteExtractTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2135,7 +2000,7 @@ int DetectByteExtractTest40(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -2169,7 +2034,7 @@ int DetectByteExtractTest40(void) return result; } -int DetectByteExtractTest41(void) +static int DetectByteExtractTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2270,7 +2135,7 @@ int DetectByteExtractTest41(void) return result; } -int DetectByteExtractTest42(void) +static int DetectByteExtractTest42(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2367,7 +2232,7 @@ int DetectByteExtractTest42(void) if (sm->next != NULL) goto end; - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -2421,7 +2286,7 @@ int DetectByteExtractTest42(void) return result; } -int DetectByteExtractTest43(void) +static int DetectByteExtractTest43(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2519,7 +2384,7 @@ int DetectByteExtractTest43(void) return result; } -int DetectByteExtractTest44(void) +static int DetectByteExtractTest44(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2642,7 +2507,7 @@ int DetectByteExtractTest44(void) return result; } -int DetectByteExtractTest45(void) +static int DetectByteExtractTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2741,7 +2606,7 @@ int DetectByteExtractTest45(void) return result; } -int DetectByteExtractTest46(void) +static int DetectByteExtractTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2864,7 +2729,7 @@ int DetectByteExtractTest46(void) return result; } -int DetectByteExtractTest47(void) +static int DetectByteExtractTest47(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2964,7 +2829,7 @@ int DetectByteExtractTest47(void) return result; } -int DetectByteExtractTest48(void) +static int DetectByteExtractTest48(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3092,7 +2957,7 @@ int DetectByteExtractTest48(void) return result; } -int DetectByteExtractTest49(void) +static int DetectByteExtractTest49(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3193,7 +3058,7 @@ int DetectByteExtractTest49(void) return result; } -int DetectByteExtractTest50(void) +static int DetectByteExtractTest50(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3323,7 +3188,7 @@ int DetectByteExtractTest50(void) return result; } -int DetectByteExtractTest51(void) +static int DetectByteExtractTest51(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3421,7 +3286,7 @@ int DetectByteExtractTest51(void) return result; } -int DetectByteExtractTest52(void) +static int DetectByteExtractTest52(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3542,7 +3407,7 @@ int DetectByteExtractTest52(void) return result; } -int DetectByteExtractTest53(void) +static int DetectByteExtractTest53(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3639,7 +3504,7 @@ int DetectByteExtractTest53(void) return result; } -int DetectByteExtractTest54(void) +static int DetectByteExtractTest54(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3757,7 +3622,7 @@ int DetectByteExtractTest54(void) return result; } -int DetectByteExtractTest55(void) +static int DetectByteExtractTest55(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3871,7 +3736,7 @@ int DetectByteExtractTest55(void) return result; } -int DetectByteExtractTest56(void) +static int DetectByteExtractTest56(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -3906,7 +3771,7 @@ int DetectByteExtractTest56(void) goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4019,7 +3884,7 @@ int DetectByteExtractTest56(void) return result; } -int DetectByteExtractTest57(void) +static int DetectByteExtractTest57(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4078,7 +3943,7 @@ int DetectByteExtractTest57(void) if (sm->next != NULL) goto end; - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4184,7 +4049,7 @@ int DetectByteExtractTest57(void) return result; } -int DetectByteExtractTest58(void) +static int DetectByteExtractTest58(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4317,7 +4182,7 @@ int DetectByteExtractTest58(void) return result; } -int DetectByteExtractTest59(void) +static int DetectByteExtractTest59(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4451,7 +4316,7 @@ int DetectByteExtractTest59(void) return result; } -int DetectByteExtractTest60(void) +static int DetectByteExtractTest60(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4541,12 +4406,12 @@ int DetectByteExtractTest60(void) if (sm->next != NULL) goto end; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { + if (s->sm_lists_tail[g_http_uri_buffer_id] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4594,7 +4459,7 @@ int DetectByteExtractTest60(void) return result; } -int DetectByteExtractTest61(void) +static int DetectByteExtractTest61(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -4671,12 +4536,12 @@ int DetectByteExtractTest61(void) if (sm->next != NULL) goto end; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { + if (s->sm_lists_tail[g_http_uri_buffer_id] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = s->sm_lists[g_http_uri_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -4758,11 +4623,11 @@ static int DetectByteExtractTest62(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[g_file_data_buffer_id] == NULL) { goto end; } - sm = s->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = s->sm_lists[g_file_data_buffer_id]; if (sm->type != DETECT_BYTE_EXTRACT) { result = 0; goto end; @@ -4789,7 +4654,7 @@ static int DetectByteExtractTest62(void) return result; } -int DetectByteExtractTest63(void) +static int DetectByteExtractTest63(void) { int result = 0; @@ -4815,82 +4680,128 @@ int DetectByteExtractTest63(void) return result; } +static int DetectByteExtractTestParseNoBase(void) +{ + int result = 0; + + DetectByteExtractData *bed = DetectByteExtractParse("4, 2, one, string"); + if (bed == NULL) + goto end; + + if (bed->nbytes != 4) { + goto end; + } + if (bed->offset != 2) { + goto end; + } + if (strcmp(bed->name, "one") != 0) { + goto end; + } + if (bed->flags != DETECT_BYTE_EXTRACT_FLAG_STRING) { + goto end; + } + if (bed->endian != DETECT_BYTE_EXTRACT_ENDIAN_NONE) { + goto end; + } + if (bed->base != DETECT_BYTE_EXTRACT_BASE_DEC) { + goto end; + } + if (bed->align_value != 0) { + goto end; + } + if (bed->multiplier_value != DETECT_BYTE_EXTRACT_MULTIPLIER_DEFAULT) { + goto end; + } + + result = 1; + end: + if (bed != NULL) + DetectByteExtractFree(bed); + return result; +} + #endif /* UNITTESTS */ -void DetectByteExtractRegisterTests(void) +static void DetectByteExtractRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01, 1); - UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02, 1); - UtRegisterTest("DetectByteExtractTest03", DetectByteExtractTest03, 1); - UtRegisterTest("DetectByteExtractTest04", DetectByteExtractTest04, 1); - UtRegisterTest("DetectByteExtractTest05", DetectByteExtractTest05, 1); - UtRegisterTest("DetectByteExtractTest06", DetectByteExtractTest06, 1); - UtRegisterTest("DetectByteExtractTest07", DetectByteExtractTest07, 1); - UtRegisterTest("DetectByteExtractTest08", DetectByteExtractTest08, 1); - UtRegisterTest("DetectByteExtractTest09", DetectByteExtractTest09, 1); - UtRegisterTest("DetectByteExtractTest10", DetectByteExtractTest10, 1); - UtRegisterTest("DetectByteExtractTest11", DetectByteExtractTest11, 1); - UtRegisterTest("DetectByteExtractTest12", DetectByteExtractTest12, 1); - UtRegisterTest("DetectByteExtractTest13", DetectByteExtractTest13, 1); - UtRegisterTest("DetectByteExtractTest14", DetectByteExtractTest14, 1); - UtRegisterTest("DetectByteExtractTest15", DetectByteExtractTest15, 1); - UtRegisterTest("DetectByteExtractTest16", DetectByteExtractTest16, 1); - UtRegisterTest("DetectByteExtractTest17", DetectByteExtractTest17, 1); - UtRegisterTest("DetectByteExtractTest18", DetectByteExtractTest18, 1); - UtRegisterTest("DetectByteExtractTest19", DetectByteExtractTest19, 1); - UtRegisterTest("DetectByteExtractTest20", DetectByteExtractTest20, 1); - UtRegisterTest("DetectByteExtractTest21", DetectByteExtractTest21, 1); - UtRegisterTest("DetectByteExtractTest22", DetectByteExtractTest22, 1); - UtRegisterTest("DetectByteExtractTest23", DetectByteExtractTest23, 1); - UtRegisterTest("DetectByteExtractTest24", DetectByteExtractTest24, 1); - UtRegisterTest("DetectByteExtractTest25", DetectByteExtractTest25, 1); - UtRegisterTest("DetectByteExtractTest26", DetectByteExtractTest26, 1); - UtRegisterTest("DetectByteExtractTest27", DetectByteExtractTest27, 1); - UtRegisterTest("DetectByteExtractTest28", DetectByteExtractTest28, 1); - UtRegisterTest("DetectByteExtractTest29", DetectByteExtractTest29, 1); - UtRegisterTest("DetectByteExtractTest30", DetectByteExtractTest30, 1); - UtRegisterTest("DetectByteExtractTest31", DetectByteExtractTest31, 1); - UtRegisterTest("DetectByteExtractTest32", DetectByteExtractTest32, 1); - UtRegisterTest("DetectByteExtractTest33", DetectByteExtractTest33, 1); - UtRegisterTest("DetectByteExtractTest34", DetectByteExtractTest34, 1); - UtRegisterTest("DetectByteExtractTest35", DetectByteExtractTest35, 1); - UtRegisterTest("DetectByteExtractTest36", DetectByteExtractTest36, 1); - UtRegisterTest("DetectByteExtractTest37", DetectByteExtractTest37, 1); - UtRegisterTest("DetectByteExtractTest38", DetectByteExtractTest38, 1); - UtRegisterTest("DetectByteExtractTest39", DetectByteExtractTest39, 1); - UtRegisterTest("DetectByteExtractTest40", DetectByteExtractTest40, 1); - UtRegisterTest("DetectByteExtractTest41", DetectByteExtractTest41, 1); - UtRegisterTest("DetectByteExtractTest42", DetectByteExtractTest42, 1); - - UtRegisterTest("DetectByteExtractTest43", DetectByteExtractTest43, 1); - UtRegisterTest("DetectByteExtractTest44", DetectByteExtractTest44, 1); - - UtRegisterTest("DetectByteExtractTest45", DetectByteExtractTest45, 1); - UtRegisterTest("DetectByteExtractTest46", DetectByteExtractTest46, 1); - - UtRegisterTest("DetectByteExtractTest47", DetectByteExtractTest47, 1); - UtRegisterTest("DetectByteExtractTest48", DetectByteExtractTest48, 1); - - UtRegisterTest("DetectByteExtractTest49", DetectByteExtractTest49, 1); - UtRegisterTest("DetectByteExtractTest50", DetectByteExtractTest50, 1); - - UtRegisterTest("DetectByteExtractTest51", DetectByteExtractTest51, 1); - UtRegisterTest("DetectByteExtractTest52", DetectByteExtractTest52, 1); - - UtRegisterTest("DetectByteExtractTest53", DetectByteExtractTest53, 1); - UtRegisterTest("DetectByteExtractTest54", DetectByteExtractTest54, 1); - - UtRegisterTest("DetectByteExtractTest55", DetectByteExtractTest55, 1); - UtRegisterTest("DetectByteExtractTest56", DetectByteExtractTest56, 1); - UtRegisterTest("DetectByteExtractTest57", DetectByteExtractTest57, 1); - - UtRegisterTest("DetectByteExtractTest58", DetectByteExtractTest58, 1); - UtRegisterTest("DetectByteExtractTest59", DetectByteExtractTest59, 1); - UtRegisterTest("DetectByteExtractTest60", DetectByteExtractTest60, 1); - UtRegisterTest("DetectByteExtractTest61", DetectByteExtractTest61, 1); - UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62, 1); - UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); + + UtRegisterTest("DetectByteExtractTest01", DetectByteExtractTest01); + UtRegisterTest("DetectByteExtractTest02", DetectByteExtractTest02); + UtRegisterTest("DetectByteExtractTest03", DetectByteExtractTest03); + UtRegisterTest("DetectByteExtractTest04", DetectByteExtractTest04); + UtRegisterTest("DetectByteExtractTest05", DetectByteExtractTest05); + UtRegisterTest("DetectByteExtractTest06", DetectByteExtractTest06); + UtRegisterTest("DetectByteExtractTest07", DetectByteExtractTest07); + UtRegisterTest("DetectByteExtractTest08", DetectByteExtractTest08); + UtRegisterTest("DetectByteExtractTest09", DetectByteExtractTest09); + UtRegisterTest("DetectByteExtractTest10", DetectByteExtractTest10); + UtRegisterTest("DetectByteExtractTest11", DetectByteExtractTest11); + UtRegisterTest("DetectByteExtractTest12", DetectByteExtractTest12); + UtRegisterTest("DetectByteExtractTest13", DetectByteExtractTest13); + UtRegisterTest("DetectByteExtractTest14", DetectByteExtractTest14); + UtRegisterTest("DetectByteExtractTest15", DetectByteExtractTest15); + UtRegisterTest("DetectByteExtractTest16", DetectByteExtractTest16); + UtRegisterTest("DetectByteExtractTest17", DetectByteExtractTest17); + UtRegisterTest("DetectByteExtractTest18", DetectByteExtractTest18); + UtRegisterTest("DetectByteExtractTest19", DetectByteExtractTest19); + UtRegisterTest("DetectByteExtractTest20", DetectByteExtractTest20); + UtRegisterTest("DetectByteExtractTest21", DetectByteExtractTest21); + UtRegisterTest("DetectByteExtractTest22", DetectByteExtractTest22); + UtRegisterTest("DetectByteExtractTest23", DetectByteExtractTest23); + UtRegisterTest("DetectByteExtractTest24", DetectByteExtractTest24); + UtRegisterTest("DetectByteExtractTest25", DetectByteExtractTest25); + UtRegisterTest("DetectByteExtractTest26", DetectByteExtractTest26); + UtRegisterTest("DetectByteExtractTest27", DetectByteExtractTest27); + UtRegisterTest("DetectByteExtractTest28", DetectByteExtractTest28); + UtRegisterTest("DetectByteExtractTest29", DetectByteExtractTest29); + UtRegisterTest("DetectByteExtractTest30", DetectByteExtractTest30); + UtRegisterTest("DetectByteExtractTest31", DetectByteExtractTest31); + UtRegisterTest("DetectByteExtractTest32", DetectByteExtractTest32); + UtRegisterTest("DetectByteExtractTest33", DetectByteExtractTest33); + UtRegisterTest("DetectByteExtractTest34", DetectByteExtractTest34); + UtRegisterTest("DetectByteExtractTest35", DetectByteExtractTest35); + UtRegisterTest("DetectByteExtractTest36", DetectByteExtractTest36); + UtRegisterTest("DetectByteExtractTest37", DetectByteExtractTest37); + UtRegisterTest("DetectByteExtractTest38", DetectByteExtractTest38); + UtRegisterTest("DetectByteExtractTest39", DetectByteExtractTest39); + UtRegisterTest("DetectByteExtractTest40", DetectByteExtractTest40); + UtRegisterTest("DetectByteExtractTest41", DetectByteExtractTest41); + UtRegisterTest("DetectByteExtractTest42", DetectByteExtractTest42); + + UtRegisterTest("DetectByteExtractTest43", DetectByteExtractTest43); + UtRegisterTest("DetectByteExtractTest44", DetectByteExtractTest44); + + UtRegisterTest("DetectByteExtractTest45", DetectByteExtractTest45); + UtRegisterTest("DetectByteExtractTest46", DetectByteExtractTest46); + + UtRegisterTest("DetectByteExtractTest47", DetectByteExtractTest47); + UtRegisterTest("DetectByteExtractTest48", DetectByteExtractTest48); + + UtRegisterTest("DetectByteExtractTest49", DetectByteExtractTest49); + UtRegisterTest("DetectByteExtractTest50", DetectByteExtractTest50); + + UtRegisterTest("DetectByteExtractTest51", DetectByteExtractTest51); + UtRegisterTest("DetectByteExtractTest52", DetectByteExtractTest52); + + UtRegisterTest("DetectByteExtractTest53", DetectByteExtractTest53); + UtRegisterTest("DetectByteExtractTest54", DetectByteExtractTest54); + + UtRegisterTest("DetectByteExtractTest55", DetectByteExtractTest55); + UtRegisterTest("DetectByteExtractTest56", DetectByteExtractTest56); + UtRegisterTest("DetectByteExtractTest57", DetectByteExtractTest57); + + UtRegisterTest("DetectByteExtractTest58", DetectByteExtractTest58); + UtRegisterTest("DetectByteExtractTest59", DetectByteExtractTest59); + UtRegisterTest("DetectByteExtractTest60", DetectByteExtractTest60); + UtRegisterTest("DetectByteExtractTest61", DetectByteExtractTest61); + UtRegisterTest("DetectByteExtractTest62", DetectByteExtractTest62); + UtRegisterTest("DetectByteExtractTest63", DetectByteExtractTest63); + + UtRegisterTest("DetectByteExtractTestParseNoBase", + DetectByteExtractTestParseNoBase); #endif /* UNITTESTS */ return; diff --git a/src/detect-byte-extract.h b/src/detect-byte-extract.h index 020494da0e5e..be3641bf270a 100644 --- a/src/detect-byte-extract.h +++ b/src/detect-byte-extract.h @@ -60,12 +60,9 @@ typedef struct DetectByteExtractData_ { } DetectByteExtractData; void DetectByteExtractRegister(void); -int DetectByteExtractSetup(DetectEngineCtx *, Signature *, char *); -void DetectByteExtractFree(void *); -int DetectByteExtractMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); -SigMatch *DetectByteExtractRetrieveSMVar(const char *, Signature *); -int DetectByteExtractDoMatch(DetectEngineThreadCtx *, SigMatch *, Signature *, + +SigMatch *DetectByteExtractRetrieveSMVar(const char *, const Signature *); +int DetectByteExtractDoMatch(DetectEngineThreadCtx *, const SigMatchData *, const Signature *, uint8_t *, uint16_t, uint64_t *, uint8_t); #endif /* __DETECT_BYTEEXTRACT_H__ */ diff --git a/src/detect-bytejump.c b/src/detect-bytejump.c index 0542af6675ad..272b23ebddd4 100644 --- a/src/detect-bytejump.c +++ b/src/detect-bytejump.c @@ -60,41 +60,22 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -void DetectBytejumpRegisterTests(void); +static int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx); +static DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); +static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr); +static void DetectBytejumpFree(void *ptr); +static void DetectBytejumpRegisterTests(void); void DetectBytejumpRegister (void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_BYTEJUMP].name = "byte_jump"; sigmatch_table[DETECT_BYTEJUMP].Match = DetectBytejumpMatch; sigmatch_table[DETECT_BYTEJUMP].Setup = DetectBytejumpSetup; sigmatch_table[DETECT_BYTEJUMP].Free = DetectBytejumpFree; sigmatch_table[DETECT_BYTEJUMP].RegisterTests = DetectBytejumpRegisterTests; - sigmatch_table[DETECT_BYTEJUMP].flags |= SIGMATCH_PAYLOAD; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed " - "at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** \brief Byte jump match function @@ -106,13 +87,13 @@ void DetectBytejumpRegister (void) * \retval 1 match * \retval 0 no match */ -int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, - SigMatch *m, uint8_t *payload, uint32_t payload_len, +int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s, + const SigMatchCtx *ctx, uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset) { SCEnter(); - DetectBytejumpData *data = (DetectBytejumpData *)m->ctx; + const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; uint8_t *ptr = NULL; uint8_t *jumpptr = NULL; int32_t len = 0; @@ -156,18 +137,18 @@ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, extbytes = ByteExtractStringUint64(&val, data->base, data->nbytes, (const char *)ptr); if(extbytes <= 0) { - SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " - "of string data: %d", data->nbytes, extbytes); - SCReturnInt(-1); + SCLogDebug("error extracting %d bytes of string data: %d", + data->nbytes, extbytes); + SCReturnInt(0); } } else { int endianness = (flags & DETECT_BYTEJUMP_LITTLE) ? BYTE_LITTLE_ENDIAN : BYTE_BIG_ENDIAN; extbytes = ByteExtractUint64(&val, endianness, data->nbytes, ptr); if (extbytes != data->nbytes) { - SCLogError(SC_ERR_BYTE_EXTRACT_FAILED,"Error extracting %d bytes " - "of numeric data: %d", data->nbytes, extbytes); - SCReturnInt(-1); + SCLogDebug("error extracting %d bytes of numeric data: %d", + data->nbytes, extbytes); + SCReturnInt(0); } } @@ -218,10 +199,10 @@ int DetectBytejumpDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SCReturnInt(1); } -int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectBytejumpData *data = (DetectBytejumpData *)m->ctx; + const DetectBytejumpData *data = (const DetectBytejumpData *)ctx; uint8_t *ptr = NULL; uint8_t *jumpptr = NULL; uint16_t len = 0; @@ -328,7 +309,7 @@ int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, return 1; } -DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) +static DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) { DetectBytejumpData *data = NULL; char args[10][64]; @@ -522,7 +503,7 @@ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset) return NULL; } -int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) +static int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; @@ -535,32 +516,18 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) goto error; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { - if (data->flags & DETECT_BYTEJUMP_DCE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytejump specified " - "with file_data option set."); - goto error; - } - AppLayerHtpEnableResponseBodyCallback(); - } - sm_list = s->list; - s->flags |= SIG_FLAG_APPLAYER; - if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->init_data->list; + if (data->flags & DETECT_BYTEJUMP_RELATIVE) { + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->flags & DETECT_BYTEJUMP_DCE) { if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -572,100 +539,14 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) sm_list = DETECT_SM_LIST_PMATCH; } - s->alproto = ALPROTO_DCERPC; - s->flags |= SIG_FLAG_APPLAYER; + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + goto error; } else if (data->flags & DETECT_BYTEJUMP_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -679,11 +560,6 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) } if (data->flags & DETECT_BYTEJUMP_DCE) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " - "bytejump with dce enabled"); - goto error; - } if ((data->flags & DETECT_BYTEJUMP_STRING) || (data->flags & DETECT_BYTEJUMP_LITTLE) || (data->flags & DETECT_BYTEJUMP_BIG) || @@ -713,7 +589,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (sm == NULL) goto error; sm->type = DETECT_BYTEJUMP; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; SigMatchAppendSMToList(s, sm, sm_list); if (!(data->flags & DETECT_BYTEJUMP_RELATIVE)) @@ -743,7 +619,7 @@ int DetectBytejumpSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) * * \param data pointer to DetectBytejumpData */ -void DetectBytejumpFree(void *ptr) +static void DetectBytejumpFree(void *ptr) { if (ptr == NULL) return; @@ -756,11 +632,14 @@ void DetectBytejumpFree(void *ptr) /* UNITTESTS */ #ifdef UNITTESTS #include "util-unittest-helper.h" +static int g_file_data_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; + /** * \test DetectBytejumpTestParse01 is a test to make sure that we return * "something" when given valid bytejump opt */ -int DetectBytejumpTestParse01(void) +static int DetectBytejumpTestParse01(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -776,7 +655,7 @@ int DetectBytejumpTestParse01(void) /** * \test DetectBytejumpTestParse02 is a test for setting the required opts */ -int DetectBytejumpTestParse02(void) +static int DetectBytejumpTestParse02(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -800,7 +679,7 @@ int DetectBytejumpTestParse02(void) /** * \test DetectBytejumpTestParse03 is a test for setting the optional flags */ -int DetectBytejumpTestParse03(void) +static int DetectBytejumpTestParse03(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -832,7 +711,7 @@ int DetectBytejumpTestParse03(void) * * \todo This fails becuase we can only have 9 captures and there are 10. */ -int DetectBytejumpTestParse04(void) +static int DetectBytejumpTestParse04(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -862,7 +741,7 @@ int DetectBytejumpTestParse04(void) /** * \test DetectBytejumpTestParse05 is a test for setting base without string */ -int DetectBytejumpTestParse05(void) +static int DetectBytejumpTestParse05(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -878,7 +757,7 @@ int DetectBytejumpTestParse05(void) /** * \test DetectBytejumpTestParse06 is a test for too many bytes to extract */ -int DetectBytejumpTestParse06(void) +static int DetectBytejumpTestParse06(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -893,7 +772,7 @@ int DetectBytejumpTestParse06(void) /** * \test DetectBytejumpTestParse07 is a test for too many string bytes to extract */ -int DetectBytejumpTestParse07(void) +static int DetectBytejumpTestParse07(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -908,7 +787,7 @@ int DetectBytejumpTestParse07(void) /** * \test DetectBytejumpTestParse08 is a test for offset too big */ -int DetectBytejumpTestParse08(void) +static int DetectBytejumpTestParse08(void) { int result = 0; DetectBytejumpData *data = NULL; @@ -923,7 +802,7 @@ int DetectBytejumpTestParse08(void) /** * \test Test dce option. */ -int DetectBytejumpTestParse09(void) +static int DetectBytejumpTestParse09(void) { Signature *s = SigAlloc(); if (s == NULL) @@ -947,7 +826,7 @@ int DetectBytejumpTestParse09(void) result &= (DetectBytejumpSetup(NULL, s, "4,0, string, oct, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, string, hex, dce") == -1); result &= (DetectBytejumpSetup(NULL, s, "4,0, from_beginning, dce") == -1); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); return result; @@ -956,7 +835,7 @@ int DetectBytejumpTestParse09(void) /** * \test Test dce option. */ -int DetectBytejumpTestParse10(void) +static int DetectBytejumpTestParse10(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -980,12 +859,12 @@ int DetectBytejumpTestParse10(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTEJUMP); + bd = (DetectBytejumpData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -1007,12 +886,12 @@ int DetectBytejumpTestParse10(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTEJUMP); + bd = (DetectBytejumpData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -1034,12 +913,12 @@ int DetectBytejumpTestParse10(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTEJUMP); - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTEJUMP); + bd = (DetectBytejumpData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && !(bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -1060,7 +939,7 @@ int DetectBytejumpTestParse10(void) /** * \test Test dce option. */ -int DetectBytejumpTestParse11(void) +static int DetectBytejumpTestParse11(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1179,15 +1058,15 @@ static int DetectBytejumpTestParse12(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[g_file_data_buffer_id] == NULL) { goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_BYTEJUMP) { + if (s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_BYTEJUMP) { goto end; } - bd = (DetectBytejumpData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + bd = (DetectBytejumpData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; if ((bd->flags & DETECT_BYTEJUMP_DCE) && (bd->flags & DETECT_BYTEJUMP_RELATIVE) && (bd->flags & DETECT_BYTEJUMP_STRING) && @@ -1211,7 +1090,7 @@ static int DetectBytejumpTestParse12(void) * byte_jump and byte_jump relative works if the previous keyword is pcre * (bug 142) */ -int DetectByteJumpTestPacket01 (void) +static int DetectByteJumpTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1243,7 +1122,7 @@ int DetectByteJumpTestPacket01 (void) * byte_jump and byte_jump relative works if the previous keyword is byte_jump * (bug 165) */ -int DetectByteJumpTestPacket02 (void) +static int DetectByteJumpTestPacket02 (void) { int result = 0; uint8_t buf[] = { 0x00, 0x00, 0x00, 0x77, 0xff, 0x53, @@ -1271,7 +1150,7 @@ int DetectByteJumpTestPacket02 (void) return result; } -int DetectByteJumpTestPacket03(void) +static int DetectByteJumpTestPacket03(void) { int result = 0; uint8_t *buf = NULL; @@ -1306,7 +1185,7 @@ int DetectByteJumpTestPacket03(void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket04 (void) +static int DetectByteJumpTestPacket04 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; @@ -1329,7 +1208,7 @@ int DetectByteJumpTestPacket04 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket05 (void) +static int DetectByteJumpTestPacket05 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XYZ04abcdABCD"; @@ -1352,7 +1231,7 @@ int DetectByteJumpTestPacket05 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket06 (void) +static int DetectByteJumpTestPacket06 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XX04abcdABCD"; @@ -1375,7 +1254,7 @@ int DetectByteJumpTestPacket06 (void) /** * \test check matches of with from_beginning (bug 626/627) */ -int DetectByteJumpTestPacket07 (void) +static int DetectByteJumpTestPacket07 (void) { int result = 0; uint8_t *buf = (uint8_t *)"XX04abcdABCD"; @@ -1401,29 +1280,32 @@ int DetectByteJumpTestPacket07 (void) /** * \brief this function registers unit tests for DetectBytejump */ -void DetectBytejumpRegisterTests(void) +static void DetectBytejumpRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01, 1); - UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02, 1); - UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03, 1); - UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04, 1); - UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05, 1); - UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06, 1); - UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07, 1); - UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08, 1); - UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09, 1); - UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10, 1); - UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11, 1); - UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12, 1); - - UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01, 1); - UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02, 1); - UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03, 1); - UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04, 1); - UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05, 1); - UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06, 1); - UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); + + UtRegisterTest("DetectBytejumpTestParse01", DetectBytejumpTestParse01); + UtRegisterTest("DetectBytejumpTestParse02", DetectBytejumpTestParse02); + UtRegisterTest("DetectBytejumpTestParse03", DetectBytejumpTestParse03); + UtRegisterTest("DetectBytejumpTestParse04", DetectBytejumpTestParse04); + UtRegisterTest("DetectBytejumpTestParse05", DetectBytejumpTestParse05); + UtRegisterTest("DetectBytejumpTestParse06", DetectBytejumpTestParse06); + UtRegisterTest("DetectBytejumpTestParse07", DetectBytejumpTestParse07); + UtRegisterTest("DetectBytejumpTestParse08", DetectBytejumpTestParse08); + UtRegisterTest("DetectBytejumpTestParse09", DetectBytejumpTestParse09); + UtRegisterTest("DetectBytejumpTestParse10", DetectBytejumpTestParse10); + UtRegisterTest("DetectBytejumpTestParse11", DetectBytejumpTestParse11); + UtRegisterTest("DetectBytejumpTestParse12", DetectBytejumpTestParse12); + + UtRegisterTest("DetectByteJumpTestPacket01", DetectByteJumpTestPacket01); + UtRegisterTest("DetectByteJumpTestPacket02", DetectByteJumpTestPacket02); + UtRegisterTest("DetectByteJumpTestPacket03", DetectByteJumpTestPacket03); + UtRegisterTest("DetectByteJumpTestPacket04", DetectByteJumpTestPacket04); + UtRegisterTest("DetectByteJumpTestPacket05", DetectByteJumpTestPacket05); + UtRegisterTest("DetectByteJumpTestPacket06", DetectByteJumpTestPacket06); + UtRegisterTest("DetectByteJumpTestPacket07", DetectByteJumpTestPacket07); #endif /* UNITTESTS */ } diff --git a/src/detect-bytejump.h b/src/detect-bytejump.h index e7a8eabb657c..42bda26299b7 100644 --- a/src/detect-bytejump.h +++ b/src/detect-bytejump.h @@ -58,43 +58,6 @@ typedef struct DetectBytejumpData_ { */ void DetectBytejumpRegister (void); -/** - * This function is used to add the parsed byte_jump data - * into the current signature. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param optstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -int DetectBytejumpSetup(DetectEngineCtx *, Signature *, char *); - -/** - * \brief this function will free memory associated with DetectBytejumpData - * - * \param data pointer to DetectBytejumpData - */ -void DetectBytejumpFree(void *ptr); - -/** - * This function is used to parse byte_jump options passed via - * - * byte_jump: bytes, offset [,flags [, ...]] - * - * flags: "big", "little", "relative", "string", "oct", "dec", "hex" - * "align", "from beginning", "multiplier N", "post_offset N" - * - * \param optstr Pointer to the user provided byte_jump options - * \param offset Used to pass the offset back, if byte_jump uses a byte_extract - * var. - * - * \retval data pointer to DetectBytejumpData on success - * \retval NULL on failure - */ -DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); - /** * This function is used to match byte_jump * @@ -112,9 +75,7 @@ DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset); * does: if (DetectBytejumpMatch(...)) { match }, then they catch an * error as a match. */ -int DetectBytejumpMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m); -int DetectBytejumpDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, +int DetectBytejumpDoMatch(DetectEngineThreadCtx *, const Signature *, const SigMatchCtx *, uint8_t *, uint32_t, uint8_t, int32_t); #endif /* __DETECT_BYTEJUMP_H__ */ diff --git a/src/detect-bytetest.c b/src/detect-bytetest.c index 47ede78f9cf8..4ad7f53e8378 100644 --- a/src/detect-bytetest.c +++ b/src/detect-bytetest.c @@ -62,41 +62,21 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -void DetectBytetestRegisterTests(void); +static int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx); +static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr); +static void DetectBytetestFree(void *ptr); +static void DetectBytetestRegisterTests(void); void DetectBytetestRegister (void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_BYTETEST].name = "byte_test"; sigmatch_table[DETECT_BYTETEST].Match = DetectBytetestMatch; sigmatch_table[DETECT_BYTETEST].Setup = DetectBytetestSetup; sigmatch_table[DETECT_BYTETEST].Free = DetectBytetestFree; sigmatch_table[DETECT_BYTETEST].RegisterTests = DetectBytetestRegisterTests; - sigmatch_table[DETECT_BYTETEST].flags |= SIGMATCH_PAYLOAD; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** \brief Bytetest detection code @@ -111,12 +91,14 @@ void DetectBytetestRegister (void) * \retval 1 match * \retval 0 no match */ -int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *m, uint8_t *payload, uint32_t payload_len, +int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchCtx *ctx, + uint8_t *payload, uint32_t payload_len, uint8_t flags, int32_t offset, uint64_t value) { SCEnter(); - DetectBytetestData *data = (DetectBytetestData *)m->ctx; + const DetectBytetestData *data = (const DetectBytetestData *)ctx; uint8_t *ptr = NULL; int32_t len = 0; uint64_t val = 0; @@ -252,14 +234,14 @@ int DetectBytetestDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch } -int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - return DetectBytetestDoMatch(det_ctx, s, m, p->payload, p->payload_len, - ((DetectBytetestData *)m->ctx)->flags, 0, 0); + return DetectBytetestDoMatch(det_ctx, s, ctx, p->payload, p->payload_len, + ((DetectBytetestData *)ctx)->flags, 0, 0); } -DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset) +static DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offset) { DetectBytetestData *data = NULL; char *args[9] = { @@ -447,7 +429,7 @@ DetectBytetestData *DetectBytetestParse(char *optstr, char **value, char **offse return NULL; } -int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) +static int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) { SigMatch *sm = NULL; SigMatch *prev_pm = NULL; @@ -461,32 +443,19 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) goto error; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { - if (data->flags & DETECT_BYTETEST_DCE) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "dce bytetest specified " - "with file_data option set."); - goto error; - } - AppLayerHtpEnableResponseBodyCallback(); - } - sm_list = s->list; - s->flags |= SIG_FLAG_APPLAYER; + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->init_data->list; + if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (data->flags & DETECT_BYTETEST_DCE) { if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 12, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -498,100 +467,14 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) sm_list = DETECT_SM_LIST_PMATCH; } - s->alproto = ALPROTO_DCERPC; - s->flags |= SIG_FLAG_APPLAYER; + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + goto error; } else if (data->flags & DETECT_BYTETEST_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) { sm_list = DETECT_SM_LIST_PMATCH; } else { @@ -605,11 +488,6 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) } if (data->flags & DETECT_BYTETEST_DCE) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Non dce alproto sig has " - "bytetest with dce enabled"); - goto error; - } if ((data->flags & DETECT_BYTETEST_STRING) || (data->flags & DETECT_BYTETEST_LITTLE) || (data->flags & DETECT_BYTETEST_BIG) || @@ -650,7 +528,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (sm == NULL) goto error; sm->type = DETECT_BYTETEST; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; SigMatchAppendSMToList(s, sm, sm_list); if (!(data->flags & DETECT_BYTETEST_RELATIVE)) @@ -679,7 +557,7 @@ int DetectBytetestSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) * * \param data pointer to DetectBytetestData */ -void DetectBytetestFree(void *ptr) +static void DetectBytetestFree(void *ptr) { if (ptr == NULL) return; @@ -692,11 +570,14 @@ void DetectBytetestFree(void *ptr) /* UNITTESTS */ #ifdef UNITTESTS #include "util-unittest-helper.h" +static int g_file_data_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; + /** * \test DetectBytetestTestParse01 is a test to make sure that we return "something" * when given valid bytetest opt */ -int DetectBytetestTestParse01(void) +static int DetectBytetestTestParse01(void) { int result = 0; DetectBytetestData *data = NULL; @@ -712,7 +593,7 @@ int DetectBytetestTestParse01(void) /** * \test DetectBytetestTestParse02 is a test for setting the required opts */ -int DetectBytetestTestParse02(void) +static int DetectBytetestTestParse02(void) { int result = 0; DetectBytetestData *data = NULL; @@ -736,7 +617,7 @@ int DetectBytetestTestParse02(void) /** * \test DetectBytetestTestParse03 is a test for setting the relative flag */ -int DetectBytetestTestParse03(void) +static int DetectBytetestTestParse03(void) { int result = 0; DetectBytetestData *data = NULL; @@ -761,7 +642,7 @@ int DetectBytetestTestParse03(void) /** * \test DetectBytetestTestParse04 is a test for setting the string/oct flags */ -int DetectBytetestTestParse04(void) +static int DetectBytetestTestParse04(void) { int result = 0; DetectBytetestData *data = NULL; @@ -786,7 +667,7 @@ int DetectBytetestTestParse04(void) /** * \test DetectBytetestTestParse05 is a test for setting the string/dec flags */ -int DetectBytetestTestParse05(void) +static int DetectBytetestTestParse05(void) { int result = 0; DetectBytetestData *data = NULL; @@ -810,7 +691,7 @@ int DetectBytetestTestParse05(void) /** * \test DetectBytetestTestParse06 is a test for setting the string/hex flags */ -int DetectBytetestTestParse06(void) +static int DetectBytetestTestParse06(void) { int result = 0; DetectBytetestData *data = NULL; @@ -834,7 +715,7 @@ int DetectBytetestTestParse06(void) /** * \test DetectBytetestTestParse07 is a test for setting the big flag */ -int DetectBytetestTestParse07(void) +static int DetectBytetestTestParse07(void) { int result = 0; DetectBytetestData *data = NULL; @@ -858,7 +739,7 @@ int DetectBytetestTestParse07(void) /** * \test DetectBytetestTestParse08 is a test for setting the little flag */ -int DetectBytetestTestParse08(void) +static int DetectBytetestTestParse08(void) { int result = 0; DetectBytetestData *data = NULL; @@ -882,7 +763,7 @@ int DetectBytetestTestParse08(void) /** * \test DetectBytetestTestParse09 is a test for neg operator only */ -int DetectBytetestTestParse09(void) +static int DetectBytetestTestParse09(void) { int result = 0; DetectBytetestData *data = NULL; @@ -906,7 +787,7 @@ int DetectBytetestTestParse09(void) /** * \test DetectBytetestTestParse10 is a test for whitespace */ -int DetectBytetestTestParse10(void) +static int DetectBytetestTestParse10(void) { int result = 0; DetectBytetestData *data = NULL; @@ -930,7 +811,7 @@ int DetectBytetestTestParse10(void) /** * \test DetectBytetestTestParse11 is a test for whitespace */ -int DetectBytetestTestParse11(void) +static int DetectBytetestTestParse11(void) { int result = 0; DetectBytetestData *data = NULL; @@ -957,7 +838,7 @@ int DetectBytetestTestParse11(void) /** * \test DetectBytetestTestParse12 is a test for hex w/o string */ -int DetectBytetestTestParse12(void) +static int DetectBytetestTestParse12(void) { int result = 0; DetectBytetestData *data = NULL; @@ -972,7 +853,7 @@ int DetectBytetestTestParse12(void) /** * \test DetectBytetestTestParse13 is a test for too many bytes to extract */ -int DetectBytetestTestParse13(void) +static int DetectBytetestTestParse13(void) { int result = 0; DetectBytetestData *data = NULL; @@ -987,7 +868,7 @@ int DetectBytetestTestParse13(void) /** * \test DetectBytetestTestParse14 is a test for large string extraction */ -int DetectBytetestTestParse14(void) +static int DetectBytetestTestParse14(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1011,7 +892,7 @@ int DetectBytetestTestParse14(void) /** * \test DetectBytetestTestParse15 is a test for too many bytes to extract (string) */ -int DetectBytetestTestParse15(void) +static int DetectBytetestTestParse15(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1026,7 +907,7 @@ int DetectBytetestTestParse15(void) /** * \test DetectBytetestTestParse16 is a test for offset too big */ -int DetectBytetestTestParse16(void) +static int DetectBytetestTestParse16(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1041,7 +922,7 @@ int DetectBytetestTestParse16(void) /** * \test Test dce option. */ -int DetectBytetestTestParse17(void) +static int DetectBytetestTestParse17(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1063,7 +944,7 @@ int DetectBytetestTestParse17(void) /** * \test Test dce option. */ -int DetectBytetestTestParse18(void) +static int DetectBytetestTestParse18(void) { int result = 0; DetectBytetestData *data = NULL; @@ -1085,7 +966,7 @@ int DetectBytetestTestParse18(void) /** * \test Test dce option. */ -int DetectBytetestTestParse19(void) +static int DetectBytetestTestParse19(void) { Signature *s = SigAlloc(); if (s == NULL) @@ -1110,7 +991,7 @@ int DetectBytetestTestParse19(void) /** * \test Test dce option. */ -int DetectBytetestTestParse20(void) +static int DetectBytetestTestParse20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1133,12 +1014,12 @@ int DetectBytetestTestParse20(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTETEST); + bd = (DetectBytetestData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1160,12 +1041,12 @@ int DetectBytetestTestParse20(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTETEST); + bd = (DetectBytetestData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (!(bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1187,12 +1068,12 @@ int DetectBytetestTestParse20(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_BYTETEST); - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_BYTETEST); + bd = (DetectBytetestData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ((bd->flags & DETECT_BYTETEST_DCE) && !(bd->flags & DETECT_BYTETEST_RELATIVE) && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1214,7 +1095,7 @@ int DetectBytetestTestParse20(void) /** * \test Test dce option. */ -int DetectBytetestTestParse21(void) +static int DetectBytetestTestParse21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1355,17 +1236,17 @@ static int DetectBytetestTestParse22(void) } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { + if (s->sm_lists_tail[g_file_data_buffer_id] == NULL) { printf("empty server body list: "); goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_BYTETEST) { + if (s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_BYTETEST) { printf("bytetest not last sm in server body list: "); goto end; } - bd = (DetectBytetestData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + bd = (DetectBytetestData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; if (bd->flags & DETECT_BYTETEST_DCE && bd->flags & DETECT_BYTETEST_RELATIVE && (bd->flags & DETECT_BYTETEST_STRING) && @@ -1390,7 +1271,7 @@ static int DetectBytetestTestParse22(void) * byte_test and byte_test relative works if the previous keyword is pcre * (bug 142) */ -int DetectByteTestTestPacket01 (void) +static int DetectByteTestTestPacket01 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1422,7 +1303,7 @@ int DetectByteTestTestPacket01 (void) * byte_test and byte_test relative works if the previous keyword is byte_jump * (bug 158) */ -int DetectByteTestTestPacket02 (void) +static int DetectByteTestTestPacket02 (void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1449,7 +1330,7 @@ int DetectByteTestTestPacket02 (void) return result; } -int DetectByteTestTestPacket03(void) +static int DetectByteTestTestPacket03(void) { int result = 0; uint8_t *buf = NULL; @@ -1480,7 +1361,7 @@ int DetectByteTestTestPacket03(void) } /** \test Test the byte_test signature matching with operator <= */ -int DetectByteTestTestPacket04(void) +static int DetectByteTestTestPacket04(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1510,7 +1391,7 @@ int DetectByteTestTestPacket04(void) } /** \test Test the byte_test signature matching with operator >= */ -int DetectByteTestTestPacket05(void) +static int DetectByteTestTestPacket05(void) { int result = 0; uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" @@ -1545,36 +1426,40 @@ int DetectByteTestTestPacket05(void) /** * \brief this function registers unit tests for DetectBytetest */ -void DetectBytetestRegisterTests(void) +static void DetectBytetestRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01, 1); - UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02, 1); - UtRegisterTest("DetectBytetestTestParse03", DetectBytetestTestParse03, 1); - UtRegisterTest("DetectBytetestTestParse04", DetectBytetestTestParse04, 1); - UtRegisterTest("DetectBytetestTestParse05", DetectBytetestTestParse05, 1); - UtRegisterTest("DetectBytetestTestParse06", DetectBytetestTestParse06, 1); - UtRegisterTest("DetectBytetestTestParse07", DetectBytetestTestParse07, 1); - UtRegisterTest("DetectBytetestTestParse08", DetectBytetestTestParse08, 1); - UtRegisterTest("DetectBytetestTestParse09", DetectBytetestTestParse09, 1); - UtRegisterTest("DetectBytetestTestParse10", DetectBytetestTestParse10, 1); - UtRegisterTest("DetectBytetestTestParse11", DetectBytetestTestParse11, 1); - UtRegisterTest("DetectBytetestTestParse12", DetectBytetestTestParse12, 1); - UtRegisterTest("DetectBytetestTestParse13", DetectBytetestTestParse13, 1); - UtRegisterTest("DetectBytetestTestParse14", DetectBytetestTestParse14, 1); - UtRegisterTest("DetectBytetestTestParse15", DetectBytetestTestParse15, 1); - UtRegisterTest("DetectBytetestTestParse17", DetectBytetestTestParse17, 1); - UtRegisterTest("DetectBytetestTestParse18", DetectBytetestTestParse18, 1); - UtRegisterTest("DetectBytetestTestParse19", DetectBytetestTestParse19, 1); - UtRegisterTest("DetectBytetestTestParse20", DetectBytetestTestParse20, 1); - UtRegisterTest("DetectBytetestTestParse21", DetectBytetestTestParse21, 1); - UtRegisterTest("DetectBytetestTestParse22", DetectBytetestTestParse22, 1); - - UtRegisterTest("DetectByteTestTestPacket01", DetectByteTestTestPacket01, 1); - UtRegisterTest("DetectByteTestTestPacket02", DetectByteTestTestPacket02, 1); - UtRegisterTest("DetectByteTestTestPacket03", DetectByteTestTestPacket03, 1); - UtRegisterTest("DetectByteTestTestPacket04", DetectByteTestTestPacket04, 1); - UtRegisterTest("DetectByteTestTestPacket05", DetectByteTestTestPacket05, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); + + UtRegisterTest("DetectBytetestTestParse01", DetectBytetestTestParse01); + UtRegisterTest("DetectBytetestTestParse02", DetectBytetestTestParse02); + UtRegisterTest("DetectBytetestTestParse03", DetectBytetestTestParse03); + UtRegisterTest("DetectBytetestTestParse04", DetectBytetestTestParse04); + UtRegisterTest("DetectBytetestTestParse05", DetectBytetestTestParse05); + UtRegisterTest("DetectBytetestTestParse06", DetectBytetestTestParse06); + UtRegisterTest("DetectBytetestTestParse07", DetectBytetestTestParse07); + UtRegisterTest("DetectBytetestTestParse08", DetectBytetestTestParse08); + UtRegisterTest("DetectBytetestTestParse09", DetectBytetestTestParse09); + UtRegisterTest("DetectBytetestTestParse10", DetectBytetestTestParse10); + UtRegisterTest("DetectBytetestTestParse11", DetectBytetestTestParse11); + UtRegisterTest("DetectBytetestTestParse12", DetectBytetestTestParse12); + UtRegisterTest("DetectBytetestTestParse13", DetectBytetestTestParse13); + UtRegisterTest("DetectBytetestTestParse14", DetectBytetestTestParse14); + UtRegisterTest("DetectBytetestTestParse15", DetectBytetestTestParse15); + UtRegisterTest("DetectBytetestTestParse16", DetectBytetestTestParse16); + UtRegisterTest("DetectBytetestTestParse17", DetectBytetestTestParse17); + UtRegisterTest("DetectBytetestTestParse18", DetectBytetestTestParse18); + UtRegisterTest("DetectBytetestTestParse19", DetectBytetestTestParse19); + UtRegisterTest("DetectBytetestTestParse20", DetectBytetestTestParse20); + UtRegisterTest("DetectBytetestTestParse21", DetectBytetestTestParse21); + UtRegisterTest("DetectBytetestTestParse22", DetectBytetestTestParse22); + + UtRegisterTest("DetectByteTestTestPacket01", DetectByteTestTestPacket01); + UtRegisterTest("DetectByteTestTestPacket02", DetectByteTestTestPacket02); + UtRegisterTest("DetectByteTestTestPacket03", DetectByteTestTestPacket03); + UtRegisterTest("DetectByteTestTestPacket04", DetectByteTestTestPacket04); + UtRegisterTest("DetectByteTestTestPacket05", DetectByteTestTestPacket05); #endif /* UNITTESTS */ } diff --git a/src/detect-bytetest.h b/src/detect-bytetest.h index 55cc3961c8d2..d55a47f304a5 100644 --- a/src/detect-bytetest.h +++ b/src/detect-bytetest.h @@ -67,62 +67,8 @@ typedef struct DetectBytetestData_ { */ void DetectBytetestRegister (void); -/** - * This function is used to add the parsed byte_test data - * into the current signature. - * - * \param de_ctx pointer to the Detection Engine Context - * \param s pointer to the Current Signature - * \param optstr pointer to the user provided options - * - * \retval 0 on Success - * \retval -1 on Failure - */ -int DetectBytetestSetup(DetectEngineCtx *, Signature *, char *); - -/** - * \brief this function will free memory associated with DetectBytetestData - * - * \param data pointer to DetectBytetestData - */ -void DetectBytetestFree(void *ptr); - -/** - * This function is used to parse byte_test options passed via - * - * byte_test: bytes, [!]op, value, offset [,flags [, ...]] - * - * flags: "big", "little", "relative", "string", "oct", "dec", "hex" - * - * \param optstr Pointer to the user provided byte_test options - * \param value Used to pass the value back, if byte_test uses a byte_extract - * var. - * \param offset Used to pass the offset back, if byte_test uses a byte_extract - * var. - * - * \retval data pointer to DetectBytetestData on success - * \retval NULL on failure - */ -DetectBytetestData *DetectBytetestParse(char *optstr, char **value, - char **offset); - -/** - * This function is used to match byte_test - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectBytetestData - * - * \retval -1 error - * \retval 0 no match - * \retval 1 match - * - * \todo The return seems backwards. We should return a non-zero error code. One of the error codes is "no match". As-is if someone accidentally does: if (DetectBytetestMatch(...)) { match }, then they catch an error as a match. - */ -int DetectBytetestMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m); -int DetectBytetestDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, uint8_t *, uint32_t, +int DetectBytetestDoMatch(DetectEngineThreadCtx *, const Signature *, + const SigMatchCtx *ctx, uint8_t *, uint32_t, uint8_t, int32_t, uint64_t); #endif /* __DETECT_BYTETEST_H__ */ diff --git a/src/detect-cipservice.c b/src/detect-cipservice.c new file mode 100644 index 000000000000..de9aa04c4028 --- /dev/null +++ b/src/detect-cipservice.c @@ -0,0 +1,462 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + * + * Set up ENIP Commnad and CIP Service rule parsing and entry point for matching + */ + +#include "suricata-common.h" +#include "util-unittest.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "util-byte.h" + +#include "detect-cipservice.h" +#include "detect-engine-enip.h" + +/* + * CIP SERVICE CODE + */ + +/** + * \brief CIP Service Detect Prototypes + */ +static int DetectCipServiceSetup(DetectEngineCtx *, Signature *, char *); +static void DetectCipServiceFree(void *); +static void DetectCipServiceRegisterTests(void); +static int g_cip_buffer_id = 0; + +/** + * \brief Registration function for cip_service: keyword + */ +void DetectCipServiceRegister(void) +{ + SCEnter(); + sigmatch_table[DETECT_CIPSERVICE].name = "cip_service"; //rule keyword + sigmatch_table[DETECT_CIPSERVICE].desc = "Rules for detecting CIP Service "; + sigmatch_table[DETECT_CIPSERVICE].Match = NULL; + sigmatch_table[DETECT_CIPSERVICE].Setup = DetectCipServiceSetup; + sigmatch_table[DETECT_CIPSERVICE].Free = DetectCipServiceFree; + sigmatch_table[DETECT_CIPSERVICE].RegisterTests + = DetectCipServiceRegisterTests; + + DetectAppLayerInspectEngineRegister("cip", + ALPROTO_ENIP, SIG_FLAG_TOSERVER, + DetectEngineInspectCIP); + DetectAppLayerInspectEngineRegister("cip", + ALPROTO_ENIP, SIG_FLAG_TOCLIENT, + DetectEngineInspectCIP); + + g_cip_buffer_id = DetectBufferTypeGetByName("cip"); + + SCReturn; +} + +/** + * \brief This function is used to parse cip_service options passed via cip_service: keyword + * + * \param rulestr Pointer to the user provided rulestr options + * Takes comma seperated string with numeric tokens. Only first 3 are used + * + * \retval cipserviced pointer to DetectCipServiceData on success + * \retval NULL on failure + */ +static DetectCipServiceData *DetectCipServiceParse(const char *rulestrc) +{ + const char delims[] = ","; + DetectCipServiceData *cipserviced = NULL; + + //SCLogDebug("DetectCipServiceParse - rule string %s", rulestr); + + /* strtok_r modifies the string so work with a copy */ + char *rulestr = SCStrdup(rulestrc); + if (unlikely(rulestr == NULL)) + goto error; + + cipserviced = SCMalloc(sizeof(DetectCipServiceData)); + if (unlikely(cipserviced == NULL)) + goto error; + + cipserviced->cipservice = 0; + cipserviced->cipclass = 0; + cipserviced->matchattribute = 1; + cipserviced->cipattribute = 0; + + char* token; + char *save; + int var; + int input[3] = { 0, 0, 0 }; + int i = 0; + + token = strtok_r(rulestr, delims, &save); + while (token != NULL) + { + if (i > 2) //for now only need 3 parameters + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "too many parameters"); + goto error; + } + + if (i < 2) //if on service or class + { + if (!isdigit((int) *token)) + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "parameter error %s", token); + goto error; + } + } else //if on attribute + { + + if (token[0] == '!') + { + cipserviced->matchattribute = 0; + token++; + } + + if (!isdigit((int) *token)) + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "attribute error %s", token); + goto error; + } + + } + + unsigned long num = atol(token); + if ((num > MAX_CIP_SERVICE) && (i == 0))//if service greater than 7 bit + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid CIP service %lu", num); + goto error; + } else if ((num > MAX_CIP_CLASS) && (i == 1))//if service greater than 16 bit + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid CIP class %lu", num); + goto error; + } else if ((num > MAX_CIP_ATTRIBUTE) && (i == 2))//if service greater than 16 bit + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid CIP attribute %lu", num); + goto error; + } + + sscanf(token, "%d", &var); + input[i++] = var; + + token = strtok_r(NULL, delims, &save); + } + + if (i == 0) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "no tokens found"); + goto error; + } + + cipserviced->cipservice = input[0]; + cipserviced->cipclass = input[1]; + cipserviced->cipattribute = input[2]; + cipserviced->tokens = i; + + SCLogDebug("DetectCipServiceParse - tokens %d", cipserviced->tokens); + SCLogDebug("DetectCipServiceParse - service %d", cipserviced->cipservice); + SCLogDebug("DetectCipServiceParse - class %d", cipserviced->cipclass); + SCLogDebug("DetectCipServiceParse - match attribute %d", + cipserviced->matchattribute); + SCLogDebug("DetectCipServiceParse - attribute %d", + cipserviced->cipattribute); + + SCFree(rulestr); + SCReturnPtr(cipserviced, "DetectENIPFunction"); + +error: + if (cipserviced) + SCFree(cipserviced); + if (rulestr) + SCFree(rulestr); + SCReturnPtr(NULL, "DetectENIP"); +} + +/** + * \brief this function is used to a cipserviced the parsed cip_service data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rulestr pointer to the user provided cip_service options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectCipServiceSetup(DetectEngineCtx *de_ctx, Signature *s, + char *rulestr) +{ + SCEnter(); + + DetectCipServiceData *cipserviced = NULL; + SigMatch *sm = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_ENIP) != 0) + return -1; + + cipserviced = DetectCipServiceParse(rulestr); + if (cipserviced == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_CIPSERVICE; + sm->ctx = (void *) cipserviced; + + SigMatchAppendSMToList(s, sm, g_cip_buffer_id); + SCReturnInt(0); + +error: + if (cipserviced != NULL) + DetectCipServiceFree(cipserviced); + if (sm != NULL) + SCFree(sm); + SCReturnInt(-1); +} + +/** + * \brief this function will free memory associated with DetectCipServiceData + * + * \param ptr pointer to DetectCipServiceData + */ +static void DetectCipServiceFree(void *ptr) +{ + DetectCipServiceData *cipserviced = (DetectCipServiceData *) ptr; + SCFree(cipserviced); +} + +#ifdef UNITTESTS + +/** + * \test Test CIP Command parameter parsing + */ +static int DetectCipServiceParseTest01 (void) +{ + DetectCipServiceData *cipserviced = NULL; + cipserviced = DetectCipServiceParse("7"); + FAIL_IF_NULL(cipserviced); + FAIL_IF(cipserviced->cipservice != 7); + DetectCipServiceFree(cipserviced); + PASS; +} + +/** + * \test Test CIP Service signature + */ +static int DetectCipServiceSignatureTest01 (void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (cip_service:1; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectCipService + */ +static void DetectCipServiceRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectCipServiceParseTest01", + DetectCipServiceParseTest01); + UtRegisterTest("DetectCipServiceSignatureTest01", + DetectCipServiceSignatureTest01); +#endif /* UNITTESTS */ +} + +/* + * ENIP COMMAND CODE + */ + +/** + * \brief ENIP Commond Detect Prototypes + */ +static int DetectEnipCommandSetup(DetectEngineCtx *, Signature *, char *); +static void DetectEnipCommandFree(void *); +static void DetectEnipCommandRegisterTests(void); +static int g_enip_buffer_id = 0; + +/** + * \brief Registration function for enip_command: keyword + */ +void DetectEnipCommandRegister(void) +{ + sigmatch_table[DETECT_ENIPCOMMAND].name = "enip_command"; //rule keyword + sigmatch_table[DETECT_ENIPCOMMAND].desc + = "Rules for detecting EtherNet/IP command"; + sigmatch_table[DETECT_ENIPCOMMAND].Match = NULL; + sigmatch_table[DETECT_ENIPCOMMAND].Setup = DetectEnipCommandSetup; + sigmatch_table[DETECT_ENIPCOMMAND].Free = DetectEnipCommandFree; + sigmatch_table[DETECT_ENIPCOMMAND].RegisterTests + = DetectEnipCommandRegisterTests; + + DetectAppLayerInspectEngineRegister("enip", + ALPROTO_ENIP, SIG_FLAG_TOSERVER, + DetectEngineInspectENIP); + DetectAppLayerInspectEngineRegister("enip", + ALPROTO_ENIP, SIG_FLAG_TOCLIENT, + DetectEngineInspectENIP); + + g_enip_buffer_id = DetectBufferTypeGetByName("enip"); +} + +/** + * \brief This function is used to parse cip_service options passed via enip_command: keyword + * + * \param rulestr Pointer to the user provided rulestr options + * Takes single single numeric value + * + * \retval enipcmdd pointer to DetectCipServiceData on success + * \retval NULL on failure + */ +static DetectEnipCommandData *DetectEnipCommandParse(const char *rulestr) +{ + DetectEnipCommandData *enipcmdd = NULL; + + enipcmdd = SCMalloc(sizeof(DetectEnipCommandData)); + if (unlikely(enipcmdd == NULL)) + goto error; + + if (!(isdigit((int) *rulestr))) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ENIP command %s", rulestr); + goto error; + } + + unsigned long cmd = atol(rulestr); + if (cmd > MAX_ENIP_CMD) //if command greater than 16 bit + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid ENIP command %lu", cmd); + goto error; + } + + enipcmdd->enipcommand = (uint16_t) atoi(rulestr); + + return enipcmdd; + +error: + if (enipcmdd) + SCFree(enipcmdd); + return NULL; +} + +/** + * \brief this function is used by enipcmdd to parse enip_command data into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param rulestr pointer to the user provided enip command options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectEnipCommandSetup(DetectEngineCtx *de_ctx, Signature *s, + char *rulestr) +{ + DetectEnipCommandData *enipcmdd = NULL; + SigMatch *sm = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_ENIP) != 0) + return -1; + + enipcmdd = DetectEnipCommandParse(rulestr); + if (enipcmdd == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_ENIPCOMMAND; + sm->ctx = (void *) enipcmdd; + + SigMatchAppendSMToList(s, sm, g_enip_buffer_id); + SCReturnInt(0); + +error: + if (enipcmdd != NULL) + DetectEnipCommandFree(enipcmdd); + if (sm != NULL) + SCFree(sm); + SCReturnInt(-1); +} + +/** + * \brief this function will free memory associated with DetectEnipCommandData + * + * \param ptr pointer to DetectEnipCommandData + */ +static void DetectEnipCommandFree(void *ptr) +{ + DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) ptr; + SCFree(enipcmdd); +} + +#ifdef UNITTESTS + +/** + * \test ENIP parameter test + */ + +static int DetectEnipCommandParseTest01 (void) +{ + DetectEnipCommandData *enipcmdd = NULL; + + enipcmdd = DetectEnipCommandParse("1"); + FAIL_IF_NULL(enipcmdd); + FAIL_IF_NOT(enipcmdd->enipcommand == 1); + + DetectEnipCommandFree(enipcmdd); + PASS; +} + +/** + * \test ENIP Command signature test + */ +static int DetectEnipCommandSignatureTest01 (void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (enip_command:1; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectEnipCommand + */ +static void DetectEnipCommandRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectEnipCommandParseTest01", + DetectEnipCommandParseTest01); + UtRegisterTest("DetectEnipCommandSignatureTest01", + DetectEnipCommandSignatureTest01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-cipservice.h b/src/detect-cipservice.h new file mode 100644 index 000000000000..fc6c5aaf7004 --- /dev/null +++ b/src/detect-cipservice.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Kevin Wong + */ + +#ifndef _DETECT_CIPSERVICE_H +#define _DETECT_CIPSERVICE_H + +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "flow.h" +#include "queue.h" +#include "app-layer-enip-common.h" + +#define ENIP_PORT 44818 //standard EtherNet/IP port + +/** + * CIP Service rule data structure + */ +typedef struct DetectCipServiceData_ +{ + uint8_t cipservice; /* cip service type */ + uint16_t cipclass; + uint16_t cipattribute; + uint8_t matchattribute; /* whether to match on attribute*/ + uint8_t tokens; /* number of parameters*/ +} DetectCipServiceData; + +/** + * ENIP Command rule data structure + */ +typedef struct DetectEnipCommandData_ +{ + uint16_t enipcommand; /* enip command */ +} DetectEnipCommandData; + +void DetectCipServiceRegister(void); +void DetectEnipCommandRegister(void); + +/** + * link list node for storing CIP service data + */ +typedef struct CIPServiceData_ +{ + uint8_t service; //cip service + union + { + struct + { + uint8_t path_size; //cip path size + uint16_t path_offset; //offset to cip path + } request; + struct + { + uint8_t status; + } response; + }; + struct CIPServiceData* next; +} CIPServiceData; + +/** + * ENIP data structure + */ +typedef struct ENIPData_ +{ + int direction; + ENIPEncapHdr header; //encapsulation header + ENIPEncapDataHdr encap_data_header; //encapsulation data header + ENIPEncapAddresItem encap_addr_item; //encapsulated address item + ENIPEncapDataItem encap_data_item; //encapsulated data item + + CIPServiceData* service_head; //head of cip service data list + CIPServiceData* service_tail; //tail of cip service data list + +} ENIPData; + +#endif /* _DETECT_CIPSERVICE_H */ diff --git a/src/detect-classtype.c b/src/detect-classtype.c index fd0aebeb88f1..edf555516351 100644 --- a/src/detect-classtype.c +++ b/src/detect-classtype.c @@ -37,48 +37,28 @@ #include "util-debug.h" #include "util-unittest.h" -#define DETECT_CLASSTYPE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$" +#define PARSE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; static int DetectClasstypeSetup(DetectEngineCtx *, Signature *, char *); -void DetectClasstypeRegisterTests(void); +static void DetectClasstypeRegisterTests(void); /** * \brief Registers the handler functions for the "Classtype" keyword. */ void DetectClasstypeRegister(void) { - const char *eb = NULL; - int eo; - int opts = 0; - - SCLogDebug("Registering the Classtype keyword handler"); - sigmatch_table[DETECT_CLASSTYPE].name = "classtype"; sigmatch_table[DETECT_CLASSTYPE].desc = "information about the classification of rules and alerts"; - sigmatch_table[DETECT_CLASSTYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Classtype"; + sigmatch_table[DETECT_CLASSTYPE].url = DOC_URL DOC_VERSION "/rules/meta.html#classtype"; sigmatch_table[DETECT_CLASSTYPE].Match = NULL; sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup; sigmatch_table[DETECT_CLASSTYPE].Free = NULL; sigmatch_table[DETECT_CLASSTYPE].RegisterTests = DetectClasstypeRegisterTests; - regex = pcre_compile(DETECT_CLASSTYPE_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_CLASSTYPE_REGEX, eo, eb); - goto end; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto end; - } - - end: - return; + DetectSetupParseRegexes(PARSE_REGEX, ®ex, ®ex_study); } /** @@ -173,7 +153,7 @@ static int DetectClasstypeSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw * \test Check that supplying an invalid classtype in the rule, results in the * rule being invalidated. */ -int DetectClasstypeTest01() +static int DetectClasstypeTest01() { int result = 0; @@ -182,9 +162,8 @@ int DetectClasstypeTest01() goto end; } - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; " @@ -203,7 +182,7 @@ int DetectClasstypeTest01() * properly, with rules containing invalid classtypes being rejected * and the ones containing valid classtypes parsed and returned. */ -int DetectClasstypeTest02() +static int DetectClasstypeTest02() { int result = 0; Signature *last = NULL; @@ -214,9 +193,8 @@ int DetectClasstypeTest02() goto end; } - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:bad-unknown; sid:1;)"); @@ -270,7 +248,7 @@ int DetectClasstypeTest02() * \test Check that the signatures are assigned priority based on classtype they * are given. */ -int DetectClasstypeTest03() +static int DetectClasstypeTest03() { int result = 0; Signature *last = NULL; @@ -281,9 +259,8 @@ int DetectClasstypeTest03() goto end; } - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)"); @@ -331,14 +308,14 @@ int DetectClasstypeTest03() /** * \brief This function registers unit tests for Classification Config API. */ -void DetectClasstypeRegisterTests(void) +static void DetectClasstypeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01, 1); - UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02, 1); - UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03, 1); + UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01); + UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02); + UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03); #endif /* UNITTESTS */ diff --git a/src/detect-content.c b/src/detect-content.c index 64500e391b05..64904b0168f3 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -41,34 +41,24 @@ #include "util-unittest.h" #include "util-print.h" #include "util-debug.h" -#include "util-spm-bm.h" +#include "util-spm.h" #include "threads.h" #include "util-unittest-helper.h" #include "pkt-var.h" #include "host.h" #include "util-profiling.h" -int DetectContentMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -int DetectContentSetup(DetectEngineCtx *, Signature *, char *); -void DetectContentRegisterTests(void); +static void DetectContentRegisterTests(void); void DetectContentRegister (void) { sigmatch_table[DETECT_CONTENT].name = "content"; sigmatch_table[DETECT_CONTENT].desc = "match on payload content"; - sigmatch_table[DETECT_CONTENT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Content"; + sigmatch_table[DETECT_CONTENT].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#content"; sigmatch_table[DETECT_CONTENT].Match = NULL; sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup; sigmatch_table[DETECT_CONTENT].Free = DetectContentFree; sigmatch_table[DETECT_CONTENT].RegisterTests = DetectContentRegisterTests; - - sigmatch_table[DETECT_CONTENT].flags |= SIGMATCH_PAYLOAD; -} - -/* pass on the content_max_id */ -uint32_t DetectContentMaxId(DetectEngineCtx *de_ctx) -{ - return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store); } /** @@ -192,6 +182,9 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, } escape = 0; converted = 1; + } else if (str[i] == '"') { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid unescaped double quote within content section"); + goto error; } else { str[x] = str[i]; x++; @@ -223,7 +216,8 @@ int DetectContentDataParse(const char *keyword, const char *contentstr, * \brief DetectContentParse * \initonly */ -DetectContentData *DetectContentParse (char *contentstr) +DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr) { DetectContentData *cd = NULL; uint8_t *content = NULL; @@ -235,13 +229,6 @@ DetectContentData *DetectContentParse (char *contentstr) if (ret == -1) { return NULL; } - if (len > 255) { - SCLogError(SC_ERR_NOT_SUPPORTED, "Currently we don't support content " - "length greater than 255. Please split the pattern, if " - "length > 255. The length of the content after " - "normalization is \"%"PRIu16"\".", len); - return NULL; - } cd = SCMalloc(sizeof(DetectContentData) + len); if (unlikely(cd == NULL)) { @@ -258,8 +245,15 @@ DetectContentData *DetectContentParse (char *contentstr) memcpy(cd->content, content, len); cd->content_len = len; - /* Prepare Boyer Moore context for searching faster */ - cd->bm_ctx = BoyerMooreCtxInit(cd->content, cd->content_len); + /* Prepare SPM search context. */ + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 0, + spm_global_thread_ctx); + if (cd->spm_ctx == NULL) { + SCFree(content); + SCFree(cd); + return NULL; + } + cd->depth = 0; cd->offset = 0; cd->within = 0; @@ -270,7 +264,8 @@ DetectContentData *DetectContentParse (char *contentstr) } -DetectContentData *DetectContentParseEncloseQuotes(char *contentstr) +DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr) { char str[strlen(contentstr) + 3]; // 2 for quotes, 1 for \0 @@ -279,7 +274,7 @@ DetectContentData *DetectContentParseEncloseQuotes(char *contentstr) str[strlen(contentstr) + 1] = '\"'; str[strlen(contentstr) + 2] = '\0'; - return DetectContentParse(str); + return DetectContentParse(spm_global_thread_ctx, str); } /** @@ -292,8 +287,7 @@ void DetectContentPrint(DetectContentData *cd) SCLogDebug("DetectContentData \"cd\" is NULL"); return; } - char *tmpstr=SCMalloc(sizeof(char) * cd->content_len + 1); - + char *tmpstr = SCMalloc(sizeof(char) * cd->content_len + 1); if (tmpstr != NULL) { for (i = 0; i < cd->content_len; i++) { if (isprint(cd->content[i])) @@ -319,19 +313,20 @@ void DetectContentPrint(DetectContentData *cd) SCLogDebug("flags: %u ", cd->flags); SCLogDebug("negated: %s ", cd->flags & DETECT_CONTENT_NEGATED ? "true" : "false"); SCLogDebug("relative match next: %s ", cd->flags & DETECT_CONTENT_RELATIVE_NEXT ? "true" : "false"); + if (cd->replace && cd->replace_len) { - char *tmpstr=SCMalloc(sizeof(char) * cd->replace_len + 1); + char *tmprstr = SCMalloc(sizeof(char) * cd->replace_len + 1); - if (tmpstr != NULL) { + if (tmprstr != NULL) { for (i = 0; i < cd->replace_len; i++) { if (isprint(cd->replace[i])) - tmpstr[i] = cd->replace[i]; + tmprstr[i] = cd->replace[i]; else - tmpstr[i] = '.'; + tmprstr[i] = '.'; } - tmpstr[i] = '\0'; - SCLogDebug("Replace: \"%s\"", tmpstr); - SCFree(tmpstr); + tmprstr[i] = '\0'; + SCLogDebug("Replace: \"%s\"", tmprstr); + SCFree(tmprstr); } else { SCLogDebug("Replace: "); for (i = 0; i < cd->replace_len; i++) @@ -361,7 +356,7 @@ void DetectContentPrintAll(SigMatch *sm) for (; first_sm != NULL; first_sm = first_sm->next) { if (first_sm->type == DETECT_CONTENT) { SCLogDebug("Printing SigMatch DETECT_CONTENT %d", ++i); - DetectContentPrint(first_sm->ctx); + DetectContentPrint((DetectContentData*)first_sm->ctx); } } } @@ -383,21 +378,13 @@ int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr) DetectContentData *cd = NULL; SigMatch *sm = NULL; - cd = DetectContentParse(contentstr); + cd = DetectContentParse(de_ctx->spm_global_thread_ctx, contentstr); if (cd == NULL) goto error; DetectContentPrint(cd); - int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { - AppLayerHtpEnableResponseBodyCallback(); - s->alproto = ALPROTO_HTTP; - } - - s->flags |= SIG_FLAG_APPLAYER; - sm_list = s->list; - } else { + int sm_list = s->init_data->list; + if (sm_list == DETECT_SM_LIST_NOTSET) { sm_list = DETECT_SM_LIST_PMATCH; } @@ -428,25 +415,31 @@ void DetectContentFree(void *ptr) if (cd == NULL) SCReturn; - BoyerMooreCtxDeInit(cd->bm_ctx); + SpmDestroyCtx(cd->spm_ctx); SCFree(cd); SCReturn; } #ifdef UNITTESTS /* UNITTESTS */ +static int g_file_data_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectCotentParseTest01 this is a test to make sure we can deal with escaped colons */ -int DetectContentParseTest01 (void) +static int DetectContentParseTest01 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\:def\""; char *teststringparsed = "abc:def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); @@ -459,20 +452,25 @@ int DetectContentParseTest01 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest02 this is a test to make sure we can deal with escaped semi-colons */ -int DetectContentParseTest02 (void) +static int DetectContentParseTest02 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\;def\""; char *teststringparsed = "abc;def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); @@ -485,20 +483,25 @@ int DetectContentParseTest02 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest03 this is a test to make sure we can deal with escaped double-quotes */ -int DetectContentParseTest03 (void) +static int DetectContentParseTest03 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\\"def\""; char *teststringparsed = "abc\"def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (memcmp(cd->content, teststringparsed, strlen(teststringparsed)) != 0) { SCLogDebug("expected %s got ", teststringparsed); @@ -511,20 +514,25 @@ int DetectContentParseTest03 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest04 this is a test to make sure we can deal with escaped backslashes */ -int DetectContentParseTest04 (void) +static int DetectContentParseTest04 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\\\def\""; char *teststringparsed = "abc\\def"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { @@ -538,19 +546,24 @@ int DetectContentParseTest04 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest05 test illegal escape */ -int DetectContentParseTest05 (void) +static int DetectContentParseTest05 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"abc\\def\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got "); PrintRawUriFp(stdout,cd->content,cd->content_len); @@ -558,20 +571,25 @@ int DetectContentParseTest05 (void) result = 0; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest06 test a binary content */ -int DetectContentParseTest06 (void) +static int DetectContentParseTest06 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"a|42|c|44|e|46|\""; char *teststringparsed = "abcdef"; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { uint16_t len = (cd->content_len > strlen(teststringparsed)); if (memcmp(cd->content, teststringparsed, len) != 0) { @@ -585,42 +603,53 @@ int DetectContentParseTest06 (void) SCLogDebug("expected %s got NULL: ", teststringparsed); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest07 test an empty content */ -int DetectContentParseTest07 (void) +static int DetectContentParseTest07 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } /** * \test DetectCotentParseTest08 test an empty content */ -int DetectContentParseTest08 (void) +static int DetectContentParseTest08 (void) { int result = 1; DetectContentData *cd = NULL; char *teststring = "\"\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { SCLogDebug("expected NULL got %p: ", cd); result = 0; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -633,7 +662,7 @@ int DetectContentParseTest08 (void) * \retval return 1 if match * \retval return 0 if not */ -int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, +static int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, uint32_t sid) { int result = 0; @@ -705,7 +734,7 @@ int DetectContentLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, ch /** * \brief Wrapper for DetectContentLongPatternMatchTest */ -int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) +static int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) { /** Real packet with the following tcp data: * "Hi, this is a big test to check content matches of splitted" @@ -740,7 +769,7 @@ int DetectContentLongPatternMatchTestWrp(char *sig, uint32_t sid) /** * \test Check if we match a normal pattern (not splitted) */ -int DetectContentLongPatternMatchTest01() +static int DetectContentLongPatternMatchTest01() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test\"; sid:1;)"; @@ -750,7 +779,7 @@ int DetectContentLongPatternMatchTest01() /** * \test Check if we match a splitted pattern */ -int DetectContentLongPatternMatchTest02() +static int DetectContentLongPatternMatchTest02() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"Hi, this is a big test to check content matches of" @@ -762,7 +791,7 @@ int DetectContentLongPatternMatchTest02() * \test Check that we don't match the signature if one of the splitted * chunks doesn't match the packet */ -int DetectContentLongPatternMatchTest03() +static int DetectContentLongPatternMatchTest03() { /** The last chunk of the content should not match */ char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" @@ -774,7 +803,7 @@ int DetectContentLongPatternMatchTest03() /** * \test Check if we match multiple content (not splitted) */ -int DetectContentLongPatternMatchTest04() +static int DetectContentLongPatternMatchTest04() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is\"; depth:15 ;content:\"a big test\"; " @@ -790,7 +819,7 @@ int DetectContentLongPatternMatchTest04() * Here we should specify only contents that fit in 32 bytes * Each of them with their modifier values */ -int DetectContentLongPatternMatchTest05() +static int DetectContentLongPatternMatchTest05() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big\"; depth:17; " @@ -810,7 +839,7 @@ int DetectContentLongPatternMatchTest05() * Here we should specify contents that fit and contents that must be splitted * Each of them with their modifier values */ -int DetectContentLongPatternMatchTest06() +static int DetectContentLongPatternMatchTest06() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big test to check cont\"; depth:36;" @@ -826,7 +855,7 @@ int DetectContentLongPatternMatchTest06() * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ -int DetectContentLongPatternMatchTest07() +static int DetectContentLongPatternMatchTest07() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"chunks!\"; " @@ -841,7 +870,7 @@ int DetectContentLongPatternMatchTest07() * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ -int DetectContentLongPatternMatchTest08() +static int DetectContentLongPatternMatchTest08() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"ent matches\"; " @@ -857,7 +886,7 @@ int DetectContentLongPatternMatchTest08() * \test Check if we match contents that are in the payload * but not in the same order as specified in the signature */ -int DetectContentLongPatternMatchTest09() +static int DetectContentLongPatternMatchTest09() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"ent matches\"; " @@ -873,7 +902,7 @@ int DetectContentLongPatternMatchTest09() /** * \test Check if we match two consecutive simple contents */ -int DetectContentLongPatternMatchTest10() +static int DetectContentLongPatternMatchTest10() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"Hi, this is a big test to check \"; " @@ -885,7 +914,7 @@ int DetectContentLongPatternMatchTest10() /** * \test Check if we match two contents of length 1 */ -int DetectContentLongPatternMatchTest11() +static int DetectContentLongPatternMatchTest11() { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\"; " " content:\"H\"; " @@ -894,130 +923,169 @@ int DetectContentLongPatternMatchTest11() return DetectContentLongPatternMatchTestWrp(sig, 1); } -int DetectContentParseTest09(void) +static int DetectContentParseTest09(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "!\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } - + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseTest10(void) +static int DetectContentParseTest10(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "!\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseNegTest11(void) +static int DetectContentParseNegTest11(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseNegTest12(void) +static int DetectContentParseNegTest12(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseNegTest13(void) +static int DetectContentParseNegTest13(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = "!\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseNegTest14(void) +static int DetectContentParseNegTest14(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = " \"!boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (!(cd->flags & DETECT_CONTENT_NEGATED)) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseNegTest15(void) +static int DetectContentParseNegTest15(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = " !\"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { if (cd->flags & DETECT_CONTENT_NEGATED) result = 1; DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } -int DetectContentParseNegTest16(void) +static int DetectContentParseNegTest16(void) { int result = 0; DetectContentData *cd = NULL; char *teststring = " \"boo\""; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd != NULL) { result = (cd->content_len == 3 && memcmp(cd->content,"boo",3) == 0); DetectContentFree(cd); } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); return result; } @@ -1025,7 +1093,7 @@ int DetectContentParseNegTest16(void) * \test Test cases where if within specified is < content lenggth we invalidate * the sig. */ -int DetectContentParseTest17(void) +static int DetectContentParseTest17(void) { int result = 0; char *sigstr = "alert tcp any any -> any any (msg:\"Dummy\"; " @@ -1051,7 +1119,7 @@ int DetectContentParseTest17(void) /** * \test Test content for dce sig. */ -int DetectContentParseTest18(void) +static int DetectContentParseTest18(void) { Signature *s = SigAlloc(); int result = 1; @@ -1064,7 +1132,7 @@ int DetectContentParseTest18(void) s->alproto = ALPROTO_DCERPC; result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); @@ -1073,7 +1141,7 @@ int DetectContentParseTest18(void) return 0; result &= (DetectContentSetup(de_ctx, s, "\"one\"") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); end: SigFree(s); @@ -1086,7 +1154,7 @@ int DetectContentParseTest18(void) * \test Test content for dce sig. */ -int DetectContentParseTest19(void) +static int DetectContentParseTest19(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1109,13 +1177,13 @@ int DetectContentParseTest19(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1138,13 +1206,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || @@ -1169,13 +1237,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1187,7 +1255,7 @@ int DetectContentParseTest19(void) goto end; } result &= (data->offset == 5 && data->depth == 9); - data = (DetectContentData *)s->sm_lists[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || @@ -1210,13 +1278,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1240,13 +1308,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || !(data->flags & DETECT_CONTENT_WITHIN) || @@ -1270,13 +1338,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1300,13 +1368,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1330,13 +1398,13 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_CONTENT); + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_CONTENT); result &= (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL); - data = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + data = (DetectContentData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || data->flags & DETECT_CONTENT_WITHIN || @@ -1358,7 +1426,7 @@ int DetectContentParseTest19(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -1375,7 +1443,7 @@ int DetectContentParseTest19(void) /** * \test Test content for dce sig. */ -int DetectContentParseTest20(void) +static int DetectContentParseTest20(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1404,7 +1472,7 @@ int DetectContentParseTest20(void) /** * \test Parsing test */ -int DetectContentParseTest21(void) +static int DetectContentParseTest21(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1433,7 +1501,7 @@ int DetectContentParseTest21(void) /** * \test Parsing test */ -int DetectContentParseTest22(void) +static int DetectContentParseTest22(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1462,7 +1530,7 @@ int DetectContentParseTest22(void) /** * \test Parsing test */ -int DetectContentParseTest23(void) +static int DetectContentParseTest23(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1491,7 +1559,7 @@ int DetectContentParseTest23(void) /** * \test Parsing test */ -int DetectContentParseTest24(void) +static int DetectContentParseTest24(void) { DetectEngineCtx *de_ctx = NULL; DetectContentData *cd = 0; @@ -1532,7 +1600,7 @@ int DetectContentParseTest24(void) /** * \test Parsing test */ -int DetectContentParseTest25(void) +static int DetectContentParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1561,7 +1629,7 @@ int DetectContentParseTest25(void) /** * \test Parsing test */ -int DetectContentParseTest26(void) +static int DetectContentParseTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1590,7 +1658,7 @@ int DetectContentParseTest26(void) /** * \test Parsing test */ -int DetectContentParseTest27(void) +static int DetectContentParseTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1619,7 +1687,7 @@ int DetectContentParseTest27(void) /** * \test Parsing test */ -int DetectContentParseTest28(void) +static int DetectContentParseTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1648,7 +1716,7 @@ int DetectContentParseTest28(void) /** * \test Parsing test */ -int DetectContentParseTest29(void) +static int DetectContentParseTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1677,7 +1745,7 @@ int DetectContentParseTest29(void) /** * \test Parsing test */ -int DetectContentParseTest30(void) +static int DetectContentParseTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1706,7 +1774,7 @@ int DetectContentParseTest30(void) /** * \test Parsing test */ -int DetectContentParseTest31(void) +static int DetectContentParseTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1735,7 +1803,7 @@ int DetectContentParseTest31(void) /** * \test Parsing test */ -int DetectContentParseTest32(void) +static int DetectContentParseTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1764,7 +1832,7 @@ int DetectContentParseTest32(void) /** * \test Parsing test */ -int DetectContentParseTest33(void) +static int DetectContentParseTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1793,7 +1861,7 @@ int DetectContentParseTest33(void) /** * \test Parsing test */ -int DetectContentParseTest34(void) +static int DetectContentParseTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1822,7 +1890,7 @@ int DetectContentParseTest34(void) /** * \test Parsing test */ -int DetectContentParseTest35(void) +static int DetectContentParseTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -1874,8 +1942,8 @@ static int DetectContentParseTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -1914,8 +1982,8 @@ static int DetectContentParseTest37(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -1954,8 +2022,8 @@ static int DetectContentParseTest38(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -2038,8 +2106,8 @@ static int DetectContentParseTest39(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -2078,8 +2146,8 @@ static int DetectContentParseTest40(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("content not in HSBDMATCH list: "); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); goto end; } @@ -2092,7 +2160,7 @@ static int DetectContentParseTest40(void) return result; } -int DetectContentParseTest41(void) +static int DetectContentParseTest41(void) { int result = 1; DetectContentData *cd = NULL; @@ -2108,18 +2176,26 @@ int DetectContentParseTest41(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; } -int DetectContentParseTest42(void) +/** + * Tests that content lengths > 255 are supported. + */ +static int DetectContentParseTest42(void) { int result = 1; DetectContentData *cd = NULL; @@ -2135,18 +2211,23 @@ int DetectContentParseTest42(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); - if (cd != NULL) { - SCLogDebug("expected NULL got %p: ", cd); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); + if (cd == NULL) { + SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; } -int DetectContentParseTest43(void) +static int DetectContentParseTest43(void) { int result = 1; DetectContentData *cd = NULL; @@ -2166,18 +2247,26 @@ int DetectContentParseTest43(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); if (cd == NULL) { SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; } -int DetectContentParseTest44(void) +/** + * Tests that content lengths > 255 are supported. + */ +static int DetectContentParseTest44(void) { int result = 1; DetectContentData *cd = NULL; @@ -2197,17 +2286,43 @@ int DetectContentParseTest44(void) teststring[idx++] = '\"'; teststring[idx++] = '\0'; - cd = DetectContentParse(teststring); - if (cd != NULL) { - SCLogDebug("expected NULL got %p: ", cd); + uint16_t spm_matcher = SinglePatternMatchDefaultMatcher(); + SpmGlobalThreadCtx *spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher); + FAIL_IF(spm_global_thread_ctx == NULL); + + cd = DetectContentParse(spm_global_thread_ctx, teststring); + if (cd == NULL) { + SCLogDebug("expected not NULL"); result = 0; } + SpmDestroyGlobalThreadCtx(spm_global_thread_ctx); SCFree(teststring); DetectContentFree(cd); return result; } +/** + * \test Parsing test to check for unescaped quote within content section + */ +static int DetectContentParseTest45(void) +{ + DetectEngineCtx *de_ctx = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"test\"; content:\"|ff|\" content:\"TEST\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + + PASS; +} + static int SigTestNegativeTestContent(char *rule, uint8_t *buf) { uint16_t buflen = strlen((char *)buf); @@ -2261,6 +2376,18 @@ static int SigTest41TestNegatedContent(void) return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!\"GES\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); } +/** + * \test crash condition: as packet has no direction, it defaults to toclient + * in stream ctx inspection of packet. There a null ptr deref happens + * We don't care about the match/nomatch here. + */ +static int SigTest41aTestNegatedContent(void) +{ + (void)SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; flow:to_server; content:\"GET\"; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n"); + return 1; +} + + /** * \test A positive test that checks that the content string doesn't contain * the negated content within the specified depth @@ -2546,7 +2673,7 @@ static int SigTest76TestBug134(void) char sig[] = "alert tcp any any -> any 515 " "(msg:\"detect IFS\"; flow:to_server,established; content:\"${IFS}\";" " depth:50; offset:0; sid:900091; rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } @@ -2573,7 +2700,7 @@ static int SigTest77TestBug139(void) char sig[] = "alert udp any any -> any 53 (msg:\"dns testing\";" " content:\"|00 00|\"; depth:5; offset:13; sid:9436601;" " rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { result = 0; goto end; } @@ -2584,111 +2711,259 @@ static int SigTest77TestBug139(void) UTHFreePacket(p); return result; } + +static int DetectLongContentTestCommon(char *sig, uint32_t sid) +{ + /* Packet with 512 A's in it for testing long content. */ + static uint8_t pkt[739] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, + 0x02, 0xd5, 0x4a, 0x18, 0x40, 0x00, 0x40, 0x06, + 0xd7, 0xd6, 0x0a, 0x10, 0x01, 0x0b, 0x0a, 0x10, + 0x01, 0x0a, 0xdb, 0x36, 0x00, 0x50, 0xca, 0xc5, + 0xcc, 0xd1, 0x95, 0x77, 0x0f, 0x7d, 0x80, 0x18, + 0x00, 0xe5, 0x77, 0x9d, 0x00, 0x00, 0x01, 0x01, + 0x08, 0x0a, 0x1d, 0xe0, 0x86, 0xc6, 0xfc, 0x73, + 0x49, 0xf3, 0x50, 0x4f, 0x53, 0x54, 0x20, 0x2f, + 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, + 0x31, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x63, + 0x75, 0x72, 0x6c, 0x2f, 0x37, 0x2e, 0x33, 0x37, + 0x2e, 0x30, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, + 0x3a, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x36, 0x2e, + 0x31, 0x2e, 0x31, 0x30, 0x0d, 0x0a, 0x41, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x2a, 0x2f, + 0x2a, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x3a, 0x20, 0x35, 0x32, 0x38, 0x0d, 0x0a, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x78, 0x2d, 0x77, 0x77, 0x77, 0x2d, + 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x75, 0x72, 0x6c, + 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x0d, + 0x0a, 0x0d, 0x0a, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58 + }; + + return DetectContentLongPatternMatchTest(pkt, (uint16_t)sizeof(pkt), sig, + sid); +} + +static int DetectLongContentTest1(void) +{ + /* Signature with 256 A's. */ + char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + + return DetectLongContentTestCommon(sig, 1); +} + +static int DetectLongContentTest2(void) +{ + /* Signature with 512 A's. */ + char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + + return DetectLongContentTestCommon(sig, 1); +} + +static int DetectLongContentTest3(void) +{ + /* Signature with 513 A's. */ + char *sig = "alert tcp any any -> any any (msg:\"Test Rule\"; content:\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"; sid:1;)"; + + return !DetectLongContentTestCommon(sig, 1); +} + #endif /* UNITTESTS */ /** * \brief this function registers unit tests for DetectContent */ -void DetectContentRegisterTests(void) +static void DetectContentRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01, 1); - UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02, 1); - UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03, 1); - UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04, 1); - UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05, 1); - UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06, 1); - UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07, 1); - UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08, 1); - UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09, 1); - UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10, 1); - UtRegisterTest("DetectContentParseNegTest11", DetectContentParseNegTest11, 1); - UtRegisterTest("DetectContentParseNegTest12", DetectContentParseNegTest12, 1); - UtRegisterTest("DetectContentParseNegTest13", DetectContentParseNegTest13, 1); - UtRegisterTest("DetectContentParseNegTest14", DetectContentParseNegTest14, 1); - UtRegisterTest("DetectContentParseNegTest15", DetectContentParseNegTest15, 1); - UtRegisterTest("DetectContentParseNegTest16", DetectContentParseNegTest16, 1); - UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17, 1); - UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18, 1); - UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19, 1); - UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20, 1); - UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21, 1); - UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22, 1); - UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23, 1); - UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24, 1); - UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25, 1); - UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26, 1); - UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27, 1); - UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28, 1); - UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29, 1); - UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30, 1); - UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31, 1); - UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32, 1); - UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33, 1); - UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34, 1); - UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35, 1); - UtRegisterTest("DetectContentParseTest36", DetectContentParseTest36, 1); - UtRegisterTest("DetectContentParseTest37", DetectContentParseTest37, 1); - UtRegisterTest("DetectContentParseTest38", DetectContentParseTest38, 1); - UtRegisterTest("DetectContentParseTest39", DetectContentParseTest39, 1); - UtRegisterTest("DetectContentParseTest40", DetectContentParseTest40, 1); - UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41, 1); - UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42, 1); - UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43, 1); - UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); + + UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01); + UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02); + UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03); + UtRegisterTest("DetectContentParseTest04", DetectContentParseTest04); + UtRegisterTest("DetectContentParseTest05", DetectContentParseTest05); + UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06); + UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07); + UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08); + UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09); + UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10); + UtRegisterTest("DetectContentParseNegTest11", DetectContentParseNegTest11); + UtRegisterTest("DetectContentParseNegTest12", DetectContentParseNegTest12); + UtRegisterTest("DetectContentParseNegTest13", DetectContentParseNegTest13); + UtRegisterTest("DetectContentParseNegTest14", DetectContentParseNegTest14); + UtRegisterTest("DetectContentParseNegTest15", DetectContentParseNegTest15); + UtRegisterTest("DetectContentParseNegTest16", DetectContentParseNegTest16); + UtRegisterTest("DetectContentParseTest17", DetectContentParseTest17); + UtRegisterTest("DetectContentParseTest18", DetectContentParseTest18); + UtRegisterTest("DetectContentParseTest19", DetectContentParseTest19); + UtRegisterTest("DetectContentParseTest20", DetectContentParseTest20); + UtRegisterTest("DetectContentParseTest21", DetectContentParseTest21); + UtRegisterTest("DetectContentParseTest22", DetectContentParseTest22); + UtRegisterTest("DetectContentParseTest23", DetectContentParseTest23); + UtRegisterTest("DetectContentParseTest24", DetectContentParseTest24); + UtRegisterTest("DetectContentParseTest25", DetectContentParseTest25); + UtRegisterTest("DetectContentParseTest26", DetectContentParseTest26); + UtRegisterTest("DetectContentParseTest27", DetectContentParseTest27); + UtRegisterTest("DetectContentParseTest28", DetectContentParseTest28); + UtRegisterTest("DetectContentParseTest29", DetectContentParseTest29); + UtRegisterTest("DetectContentParseTest30", DetectContentParseTest30); + UtRegisterTest("DetectContentParseTest31", DetectContentParseTest31); + UtRegisterTest("DetectContentParseTest32", DetectContentParseTest32); + UtRegisterTest("DetectContentParseTest33", DetectContentParseTest33); + UtRegisterTest("DetectContentParseTest34", DetectContentParseTest34); + UtRegisterTest("DetectContentParseTest35", DetectContentParseTest35); + UtRegisterTest("DetectContentParseTest36", DetectContentParseTest36); + UtRegisterTest("DetectContentParseTest37", DetectContentParseTest37); + UtRegisterTest("DetectContentParseTest38", DetectContentParseTest38); + UtRegisterTest("DetectContentParseTest39", DetectContentParseTest39); + UtRegisterTest("DetectContentParseTest40", DetectContentParseTest40); + UtRegisterTest("DetectContentParseTest41", DetectContentParseTest41); + UtRegisterTest("DetectContentParseTest42", DetectContentParseTest42); + UtRegisterTest("DetectContentParseTest43", DetectContentParseTest43); + UtRegisterTest("DetectContentParseTest44", DetectContentParseTest44); + UtRegisterTest("DetectContentParseTest45", DetectContentParseTest45); /* The reals */ - UtRegisterTest("DetectContentLongPatternMatchTest01", DetectContentLongPatternMatchTest01, 1); - UtRegisterTest("DetectContentLongPatternMatchTest02", DetectContentLongPatternMatchTest02, 1); - UtRegisterTest("DetectContentLongPatternMatchTest03", DetectContentLongPatternMatchTest03, 1); - UtRegisterTest("DetectContentLongPatternMatchTest04", DetectContentLongPatternMatchTest04, 1); - UtRegisterTest("DetectContentLongPatternMatchTest05", DetectContentLongPatternMatchTest05, 1); - UtRegisterTest("DetectContentLongPatternMatchTest06", DetectContentLongPatternMatchTest06, 1); - UtRegisterTest("DetectContentLongPatternMatchTest07", DetectContentLongPatternMatchTest07, 1); - UtRegisterTest("DetectContentLongPatternMatchTest08", DetectContentLongPatternMatchTest08, 1); - UtRegisterTest("DetectContentLongPatternMatchTest09", DetectContentLongPatternMatchTest09, 1); - UtRegisterTest("DetectContentLongPatternMatchTest10", DetectContentLongPatternMatchTest10, 1); - UtRegisterTest("DetectContentLongPatternMatchTest11", DetectContentLongPatternMatchTest11, 1); + UtRegisterTest("DetectContentLongPatternMatchTest01", + DetectContentLongPatternMatchTest01); + UtRegisterTest("DetectContentLongPatternMatchTest02", + DetectContentLongPatternMatchTest02); + UtRegisterTest("DetectContentLongPatternMatchTest03", + DetectContentLongPatternMatchTest03); + UtRegisterTest("DetectContentLongPatternMatchTest04", + DetectContentLongPatternMatchTest04); + UtRegisterTest("DetectContentLongPatternMatchTest05", + DetectContentLongPatternMatchTest05); + UtRegisterTest("DetectContentLongPatternMatchTest06", + DetectContentLongPatternMatchTest06); + UtRegisterTest("DetectContentLongPatternMatchTest07", + DetectContentLongPatternMatchTest07); + UtRegisterTest("DetectContentLongPatternMatchTest08", + DetectContentLongPatternMatchTest08); + UtRegisterTest("DetectContentLongPatternMatchTest09", + DetectContentLongPatternMatchTest09); + UtRegisterTest("DetectContentLongPatternMatchTest10", + DetectContentLongPatternMatchTest10); + UtRegisterTest("DetectContentLongPatternMatchTest11", + DetectContentLongPatternMatchTest11); /* Negated content tests */ - UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent, 1); - UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent, 1); - UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent, 1); - UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent, 1); - UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent, 1); - UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent, 1); - UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent, 1); - UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent, 1); - UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent, 1); - UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent, 1); - UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent, 1); - UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent, 1); - UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent, 1); - UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent, 1); - UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent, 1); - UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent, 1); - UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent, 1); - UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent, 1); - UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent, 1); - UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent, 1); - UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent, 1); - UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent, 1); - UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent, 1); - UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent, 1); - UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent, 1); - UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent, 1); - UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent, 1); - UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent, 1); - UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent, 1); - UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent, 1); - UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent, 1); - UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent, 1); - UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent, 1); - UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent, 1); - UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent, 1); - - UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134, 1); - UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139, 1); - + UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent); + UtRegisterTest("SigTest41aTestNegatedContent", + SigTest41aTestNegatedContent); + UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent); + UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent); + UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent); + UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent); + UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent); + UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent); + UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent); + UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent); + UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent); + UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent); + UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent); + UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent); + UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent); + UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent); + UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent); + UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent); + UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent); + UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent); + UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent); + UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent); + UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent); + UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent); + UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent); + UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent); + UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent); + UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent); + UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent); + UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent); + UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent); + UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent); + UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent); + UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent); + UtRegisterTest("SigTest74TestNegatedContent", SigTest74TestNegatedContent); + UtRegisterTest("SigTest75TestNegatedContent", SigTest75TestNegatedContent); + + UtRegisterTest("SigTest76TestBug134", SigTest76TestBug134); + UtRegisterTest("SigTest77TestBug139", SigTest77TestBug139); + + UtRegisterTest("DetectLongContentTest1", DetectLongContentTest1); + UtRegisterTest("DetectLongContentTest2", DetectLongContentTest2); + UtRegisterTest("DetectLongContentTest3", DetectLongContentTest3); #endif /* UNITTESTS */ } diff --git a/src/detect-content.h b/src/detect-content.h index c5c47263d6e3..5976adb86855 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -61,14 +61,28 @@ ((c)->flags & DETECT_CONTENT_DEPTH) || \ ((c)->flags & DETECT_CONTENT_OFFSET) )) -#include "util-spm-bm.h" +/* if a pattern has no depth/offset limits, no relative specifiers and isn't + * chopped for the mpm, we can take the mpm and consider this pattern a match + * w/o futher inspection. Warning: this may still mean other patterns depend + * on this pattern that force match validation anyway. */ +#define DETECT_CONTENT_MPM_IS_CONCLUSIVE(c) \ + !( ((c)->flags & DETECT_CONTENT_DISTANCE) || \ + ((c)->flags & DETECT_CONTENT_WITHIN) || \ + ((c)->flags & DETECT_CONTENT_DEPTH) || \ + ((c)->flags & DETECT_CONTENT_OFFSET) || \ + ((c)->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)) + + +#include "util-spm.h" typedef struct DetectContentData_ { uint8_t *content; - uint8_t content_len; - uint8_t replace_len; + uint16_t content_len; + uint16_t replace_len; /* for chopped fast pattern, the length */ uint16_t fp_chop_len; + /* for chopped fast pattern, the offset */ + uint16_t fp_chop_offset; /* would want to move PatIntId here and flags down to remove the padding * gap, but I think the first four members was used as a template for * casting. \todo check this and fix it if posssible */ @@ -76,12 +90,10 @@ typedef struct DetectContentData_ { PatIntId id; uint16_t depth; uint16_t offset; - /* for chopped fast pattern, the offset */ - uint16_t fp_chop_offset; int32_t distance; int32_t within; - /* Boyer Moore context (for spm search) */ - BmCtx *bm_ctx; + /* SPM search context. */ + SpmCtx *spm_ctx; /* pointer to replacement data */ uint8_t *replace; } DetectContentData; @@ -89,10 +101,12 @@ typedef struct DetectContentData_ { /* prototypes */ void DetectContentRegister (void); uint32_t DetectContentMaxId(DetectEngineCtx *); -DetectContentData *DetectContentParse (char *contentstr); +DetectContentData *DetectContentParse(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr); int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen, uint32_t *flags); -DetectContentData *DetectContentParseEncloseQuotes(char *); +DetectContentData *DetectContentParseEncloseQuotes(SpmGlobalThreadCtx *spm_global_thread_ctx, + char *contentstr); int DetectContentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentstr); void DetectContentPrint(DetectContentData *); diff --git a/src/detect-csum.c b/src/detect-csum.c index b6dc16c2a127..7f9c307a79c4 100644 --- a/src/detect-csum.c +++ b/src/detect-csum.c @@ -40,48 +40,48 @@ #include "util-profiling.h" /* prototypes for the "ipv4-csum" rule keyword */ -int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectIPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectIPV4CsumFree(void *); +static void DetectIPV4CsumFree(void *); /* prototypes for the "tcpv4-csum" rule keyword */ -int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectTCPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectTCPV4CsumFree(void *); +static void DetectTCPV4CsumFree(void *); /* prototypes for the "tcpv6-csum" rule keyword */ -int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectTCPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectTCPV6CsumFree(void *); +static void DetectTCPV6CsumFree(void *); /* prototypes for the "udpv4-csum" rule keyword */ -int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectUDPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectUDPV4CsumFree(void *); +static void DetectUDPV4CsumFree(void *); /* prototypes for the "udpv6-csum" rule keyword */ -int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectUDPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectUDPV6CsumFree(void *); +static void DetectUDPV6CsumFree(void *); /* prototypes for the "icmpv4-csum" rule keyword */ -int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectICMPV4CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectICMPV4CsumFree(void *); +static void DetectICMPV4CsumFree(void *); /* prototypes for the "icmpv6-csum" rule keyword */ -int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectICMPV6CsumMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, char *); -void DetectICMPV6CsumFree(void *); +static void DetectICMPV6CsumFree(void *); -void DetectCsumRegisterTests(void); +static void DetectCsumRegisterTests(void); /** * \brief Registers handlers for all the checksum keywords. The checksum @@ -99,7 +99,7 @@ void DetectCsumRegisterTests(void); * DetectEngineCtx * (de_ctx) - A pointer to the detection engine context * Signature *(s) - Pointer to signature for the current Signature being * parsed from the rules - * SigMatch * (m) - Pointer to the head of the SigMatchs added to the + * SigMatchCtx * (m) - Pointer to the head of the SigMatchs added to the * current Signature being parsed * char * (csum_str) - Pointer to a string holding the keyword value * @@ -114,7 +114,7 @@ void DetectCsumRegisterTests(void); * Packet * (p) - Pointer to the Packet currently being handled * Signature * (s) - Pointer to the Signature, the packet is being * currently matched with - * SigMatch * (m) - Pointer to the keyword structure from the above + * SigMatchCtx * (m) - Pointer to the keyword structure from the above * Signature, the Packet is being currently matched * with * @@ -229,10 +229,10 @@ static int DetectCsumParseArg(const char *key, DetectCsumData *cd) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || PKT_IS_PSEUDOPKT(p)) return 0; @@ -242,12 +242,13 @@ int DetectIPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level3_comp_csum == -1) - p->level3_comp_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, - IPV4_GET_HLEN(p)); + p->level3_comp_csum = IPV4Checksum((uint16_t *)p->ip4h, + IPV4_GET_HLEN(p), + p->ip4h->ip_csum); - if (p->level3_comp_csum == p->ip4h->ip_csum && cd->valid == 1) + if (p->level3_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level3_comp_csum != p->ip4h->ip_csum && cd->valid == 0) + else if (p->level3_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -285,7 +286,7 @@ static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -298,7 +299,7 @@ static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csum return -1; } -void DetectIPV4CsumFree(void *ptr) +static void DetectIPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -323,10 +324,10 @@ void DetectIPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->tcph == NULL || p->proto != IPPROTO_TCP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -336,13 +337,15 @@ int DetectTCPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, - (p->payload_len + TCP_GET_HLEN(p))); + p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); - if (p->level4_comp_csum == p->tcph->th_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->tcph->th_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -380,7 +383,7 @@ static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -393,7 +396,7 @@ static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectTCPV4CsumFree(void *ptr) +static void DetectTCPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -418,10 +421,10 @@ void DetectTCPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->tcph == NULL || p->proto != IPPROTO_TCP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -431,13 +434,15 @@ int DetectTCPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, - (p->payload_len + TCP_GET_HLEN(p))); + p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); - if (p->level4_comp_csum == p->tcph->th_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->tcph->th_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -475,7 +480,7 @@ static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -488,7 +493,7 @@ static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectTCPV6CsumFree(void *ptr) +static void DetectTCPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -513,10 +518,10 @@ void DetectTCPV6CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p) || p->udph->uh_sum == 0) return 0; @@ -526,14 +531,15 @@ int DetectUDPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->udph, - (p->payload_len + - UDP_HEADER_LEN) ); + p->level4_comp_csum = UDPV4Checksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->udph, + (p->payload_len + + UDP_HEADER_LEN), + p->udph->uh_sum); - if (p->level4_comp_csum == p->udph->uh_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->udph->uh_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -571,7 +577,7 @@ static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -584,7 +590,7 @@ static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectUDPV4CsumFree(void *ptr) +static void DetectUDPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -609,10 +615,10 @@ void DetectUDPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->udph == NULL || p->proto != IPPROTO_UDP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -622,14 +628,15 @@ int DetectUDPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, } if (p->level4_comp_csum == -1) - p->level4_comp_csum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->udph, - (p->payload_len + - UDP_HEADER_LEN) ); + p->level4_comp_csum = UDPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->udph, + (p->payload_len + + UDP_HEADER_LEN), + p->udph->uh_sum); - if (p->level4_comp_csum == p->udph->uh_sum && cd->valid == 1) + if (p->level4_comp_csum == 0 && cd->valid == 1) return 1; - else if (p->level4_comp_csum != p->udph->uh_sum && cd->valid == 0) + else if (p->level4_comp_csum != 0 && cd->valid == 0) return 1; else return 0; @@ -680,7 +687,7 @@ static int DetectUDPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *csu return -1; } -void DetectUDPV6CsumFree(void *ptr) +static void DetectUDPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -705,10 +712,10 @@ void DetectUDPV6CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->icmpv4h == NULL || p->proto != IPPROTO_ICMP || PKT_IS_PSEUDOPKT(p)) return 0; @@ -762,7 +769,7 @@ static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -775,7 +782,7 @@ static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs return -1; } -void DetectICMPV4CsumFree(void *ptr) +static void DetectICMPV4CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -800,10 +807,10 @@ void DetectICMPV4CsumFree(void *ptr) * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ -int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) +static int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectCsumData *cd = (DetectCsumData *)m->ctx; + const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->icmpv6h == NULL || p->proto != IPPROTO_ICMPV6 || PKT_IS_PSEUDOPKT(p) || (GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))) <= 0) { @@ -814,10 +821,13 @@ int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, return cd->valid; } - if (p->level4_comp_csum == -1) + if (p->level4_comp_csum == -1) { + uint16_t len = IPV6_GET_RAW_PLEN(p->ip6h) - + ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); p->level4_comp_csum = ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->icmpv6h, - GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))); + len); + } if (p->level4_comp_csum == p->icmpv6h->csum && cd->valid == 1) return 1; @@ -857,7 +867,7 @@ static int DetectICMPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs if (DetectCsumParseArg(csum_str, cd) == 0) goto error; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -870,7 +880,7 @@ static int DetectICMPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, char *cs return -1; } -void DetectICMPV6CsumFree(void *ptr) +static void DetectICMPV6CsumFree(void *ptr) { DetectCsumData *cd = (DetectCsumData *)ptr; @@ -883,622 +893,107 @@ void DetectICMPV6CsumFree(void *ptr) /* ---------------------------------- Unit Tests --------------------------- */ #ifdef UNITTESTS +#include "detect-engine.h" -int DetectCsumIPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectIPV4CsumSetup(NULL, &s, "\"valid\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"invalid\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"vaLid\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"VALID\"") == 0); - result &= (DetectIPV4CsumSetup(NULL, &s, "\"iNvaLid\"") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumIPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectIPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectIPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumIPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectIPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectIPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectIPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumICMPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV4CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectICMPV4CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumICMPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectICMPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumICMPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectICMPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectICMPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumTCPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV4CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectTCPV4CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumTCPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectTCPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumTCPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectTCPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectTCPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumUDPV4ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV4CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectUDPV4CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumUDPV4InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV4CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectUDPV4CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; +#define mystr(s) #s +#define TEST1(kwstr) {\ + DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ + FAIL_IF_NULL(de_ctx);\ + de_ctx->flags = DE_QUIET;\ + \ + Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:invalid; sid:2;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaLid; sid:3;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:VALID; sid:4;)");\ + FAIL_IF_NULL(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:iNvaLid; sid:5;)");\ + FAIL_IF_NULL(s);\ + DetectEngineCtxFree(de_ctx);\ } -int DetectCsumUDPV4ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV4CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectUDPV4CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectUDPV4CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} -int DetectCsumTCPV6ValidArgsTestParse01(void) +static int DetectCsumValidArgsTestParse01(void) { - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV6CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectTCPV6CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; + TEST1(ipv4); + TEST1(tcpv4); + TEST1(tcpv6); + TEST1(udpv4); + TEST1(udpv6); + TEST1(icmpv4); + TEST1(icmpv6); + PASS; } - -int DetectCsumTCPV6InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV6CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectTCPV6CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; +#undef TEST1 + +#define TEST2(kwstr) { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ + FAIL_IF_NULL(de_ctx);\ + Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaid; sid:1;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:invaalid; sid:2;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaLiid; sid:3;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:VALieD; sid:4;)");\ + FAIL_IF(s);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:iNvamid; sid:5;)");\ + FAIL_IF(s);\ + DetectEngineCtxFree(de_ctx);\ } -int DetectCsumTCPV6ValidArgsTestParse03(void) +int DetectCsumInvalidArgsTestParse02(void) { - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectTCPV6CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectTCPV6CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectTCPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; + TEST2(ipv4); + TEST2(tcpv4); + TEST2(tcpv6); + TEST2(udpv4); + TEST2(udpv6); + TEST2(icmpv4); + TEST2(icmpv6); + PASS; } - -int DetectCsumUDPV6ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV6CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectUDPV6CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; +#undef TEST2 + +#define TEST3(kwstr, kwtype) { \ + DetectEngineCtx *de_ctx = DetectEngineCtxInit();\ + FAIL_IF_NULL(de_ctx);\ + Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\ + FAIL_IF_NULL(s);\ + SigMatch *sm = DetectGetLastSMFromLists(s, (kwtype), -1);\ + FAIL_IF_NULL(sm);\ + FAIL_IF_NULL(sm->ctx);\ + FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 1);\ + s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:INVALID; sid:2;)");\ + FAIL_IF_NULL(s);\ + sm = DetectGetLastSMFromLists(s, (kwtype), -1);\ + FAIL_IF_NULL(sm);\ + FAIL_IF_NULL(sm->ctx);\ + FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 0);\ + DetectEngineCtxFree(de_ctx);\ } -int DetectCsumUDPV6InValidArgsTestParse02(void) +int DetectCsumValidArgsTestParse03(void) { - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV6CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectUDPV6CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumUDPV6ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectUDPV6CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectUDPV6CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectUDPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumICMPV6ValidArgsTestParse01(void) -{ - Signature s; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV6CsumSetup(NULL, &s, "valid") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "invalid") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "vaLid") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "VALID") == 0); - result &= (DetectICMPV6CsumSetup(NULL, &s, "iNvaLid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumICMPV6InValidArgsTestParse02(void) -{ - Signature s; - int result = -1; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV6CsumSetup(NULL, &s, "vaid") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "invaalid") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "vaLiid") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "VALieD") == -1); - result &= (DetectICMPV6CsumSetup(NULL, &s, "iNvamid") == -1); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; -} - -int DetectCsumICMPV6ValidArgsTestParse03(void) -{ - Signature s; - DetectCsumData *cd = NULL; - int result = 0; - SigMatch *temp = NULL; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectICMPV6CsumSetup(NULL, &s, "valid") == 0); - - while (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 1); - } - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - s.sm_lists[DETECT_SM_LIST_MATCH] = NULL; - - result &= (DetectICMPV6CsumSetup(NULL, &s, "INVALID") == 0); - - if (s.sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - if (s.sm_lists[DETECT_SM_LIST_MATCH]->ctx != NULL) { - cd = (DetectCsumData *)s.sm_lists[DETECT_SM_LIST_MATCH]->ctx; - result &= (cd->valid == 0); - } - DetectICMPV6CsumFree(s.sm_lists[DETECT_SM_LIST_MATCH]->ctx); - temp = s.sm_lists[DETECT_SM_LIST_MATCH]; - s.sm_lists[DETECT_SM_LIST_MATCH] = s.sm_lists[DETECT_SM_LIST_MATCH]->next; - SCFree(temp); - } - - return result; + TEST3(ipv4, DETECT_IPV4_CSUM); + TEST3(tcpv4, DETECT_TCPV4_CSUM); + TEST3(tcpv6, DETECT_TCPV6_CSUM); + TEST3(udpv4, DETECT_UDPV4_CSUM); + TEST3(udpv6, DETECT_UDPV6_CSUM); + TEST3(icmpv4, DETECT_ICMPV4_CSUM); + TEST3(icmpv6, DETECT_ICMPV6_CSUM); + PASS; } +#undef TEST3 +#undef mystr #include "detect-engine.h" #include "stream-tcp.h" -int DetectCsumICMPV6Test01(void) +static int DetectCsumICMPV6Test01(void) { - int result = 0; DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; ThreadVars tv; @@ -1506,10 +1001,7 @@ int DetectCsumICMPV6Test01(void) DecodeThreadVars dtv; Packet *p = PacketGetFromAlloc(); - if (p == NULL) { - printf("failure PacketGetFromAlloc\n"); - goto end; - } + FAIL_IF_NULL(p); uint8_t pkt[] = { 0x00, 0x30, 0x18, 0xa8, 0x7c, 0x23, 0x2c, 0x41, @@ -1537,19 +1029,13 @@ int DetectCsumICMPV6Test01(void) FlowInitConfig(FLOW_QUIET); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("DetectEngineCtxInit failure\n"); - goto end; - } - de_ctx->mpm_matcher = DEFAULT_MPM; + FAIL_IF_NULL(de_ctx); + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any " "(icmpv6-csum:valid; sid:1;)"); - if (s == NULL) { - printf("SigInit failed\n"); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DecodeEthernet(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL); @@ -1558,90 +1044,33 @@ int DetectCsumICMPV6Test01(void) SigMatchSignatures(&tv, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 didn't alert on p, but it should: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; - - end: - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - } + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); PACKET_RECYCLE(p); FlowShutdown(); - SCFree(p); - - return result; + PASS; } #endif /* UNITTESTS */ -void DetectCsumRegisterTests(void) +static void DetectCsumRegisterTests(void) { - #ifdef UNITTESTS - UtRegisterTest("DetectCsumIPV4ValidArgsTestParse01", - DetectCsumIPV4ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumIPV4InValidArgsTestParse02", - DetectCsumIPV4InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumIPV4ValidArgsTestParse03", - DetectCsumIPV4ValidArgsTestParse03, 1); - - UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse01", - DetectCsumICMPV4ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumICMPV4InValidArgsTestParse02", - DetectCsumICMPV4InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumICMPV4ValidArgsTestParse03", - DetectCsumICMPV4ValidArgsTestParse03, 1); - - UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse01", - DetectCsumTCPV4ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumTCPV4InValidArgsTestParse02", - DetectCsumTCPV4InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumTCPV4ValidArgsTestParse03", - DetectCsumTCPV4ValidArgsTestParse03, 1); - - UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse01", - DetectCsumUDPV4ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumUDPV4InValidArgsTestParse02", - DetectCsumUDPV4InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumUDPV4ValidArgsTestParse03", - DetectCsumUDPV4ValidArgsTestParse03, 1); - - UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse01", - DetectCsumUDPV6ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumUDPV6InValidArgsTestParse02", - DetectCsumUDPV6InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumUDPV6ValidArgsTestParse03", - DetectCsumUDPV6ValidArgsTestParse03, 1); - - UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse01", - DetectCsumTCPV6ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumTCPV6InValidArgsTestParse02", - DetectCsumTCPV6InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumTCPV6ValidArgsTestParse03", - DetectCsumTCPV6ValidArgsTestParse03, 1); - - UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse01", - DetectCsumICMPV6ValidArgsTestParse01, 1); - UtRegisterTest("DetectCsumICMPV6InValidArgsTestParse02", - DetectCsumICMPV6InValidArgsTestParse02, 1); - UtRegisterTest("DetectCsumICMPV6ValidArgsTestParse03", - DetectCsumICMPV6ValidArgsTestParse03, 1); + UtRegisterTest("DetectCsumValidArgsTestParse01", + DetectCsumValidArgsTestParse01); + UtRegisterTest("DetectCsumInvalidArgsTestParse02", + DetectCsumInvalidArgsTestParse02); + UtRegisterTest("DetectCsumValidArgsTestParse03", + DetectCsumValidArgsTestParse03); UtRegisterTest("DetectCsumICMPV6Test01", - DetectCsumICMPV6Test01, 1); - + DetectCsumICMPV6Test01); #endif /* UNITTESTS */ - } diff --git a/src/detect-dce-iface.c b/src/detect-dce-iface.c index aba6c2869c4b..e1bf69d4dfc5 100644 --- a/src/detect-dce-iface.c +++ b/src/detect-dce-iface.c @@ -47,56 +47,63 @@ #include "util-unittest-helper.h" #include "stream-tcp.h" -#define DETECT_DCE_IFACE_PCRE_PARSE_ARGS "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*,(<|>|=|!)([0-9]{1,5}))?(?:\\s*,(any_frag))?\\s*$" +#define PARSE_REGEX "^\\s*([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12})(?:\\s*,(<|>|=|!)([0-9]{1,5}))?(?:\\s*,(any_frag))?\\s*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, Signature *, SigMatch *); +static int DetectDceIfaceMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectDceIfaceSetup(DetectEngineCtx *, Signature *, char *); -void DetectDceIfaceFree(void *); +static void DetectDceIfaceFree(void *); +static void DetectDceIfaceRegisterTests(void); +static int g_dce_generic_list_id = 0; + +static int InspectDceGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registers the keyword handlers for the "dce_iface" keyword. */ void DetectDceIfaceRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_DCE_IFACE].name = "dce_iface"; - sigmatch_table[DETECT_DCE_IFACE].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_IFACE].Match = NULL; - sigmatch_table[DETECT_DCE_IFACE].AppLayerMatch = DetectDceIfaceMatch; + sigmatch_table[DETECT_DCE_IFACE].AppLayerTxMatch = DetectDceIfaceMatch; sigmatch_table[DETECT_DCE_IFACE].Setup = DetectDceIfaceSetup; sigmatch_table[DETECT_DCE_IFACE].Free = DetectDceIfaceFree; sigmatch_table[DETECT_DCE_IFACE].RegisterTests = DetectDceIfaceRegisterTests; - sigmatch_table[DETECT_DCE_IFACE].flags |= SIGMATCH_PAYLOAD; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - parse_regex = pcre_compile(DETECT_DCE_IFACE_PCRE_PARSE_ARGS, opts, &eb, - &eo, NULL); - if (parse_regex == NULL) { - SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_DCE_IFACE_PCRE_PARSE_ARGS, eo, eb); - goto error; - } + g_dce_generic_list_id = DetectBufferTypeRegister("dce_generic"); - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_DCERPC, SIG_FLAG_TOSERVER, InspectDceGeneric); + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_SMB, SIG_FLAG_TOSERVER, InspectDceGeneric); - return; + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_DCERPC, SIG_FLAG_TOCLIENT, InspectDceGeneric); + DetectAppLayerInspectEngineRegister("dce_generic", + ALPROTO_SMB, SIG_FLAG_TOCLIENT, InspectDceGeneric); +} - error: - /* we need to handle error?! */ - return; +static int InspectDceGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } + /** * \internal * \brief Parses the argument sent along with the "dce_iface" keyword. @@ -106,17 +113,17 @@ void DetectDceIfaceRegister(void) * \retval did Pointer to a DetectDceIfaceData instance that holds the data * from the parsed arg. */ -static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) +static DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) { DetectDceIfaceData *did = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; uint8_t hex_value; - const char *pcre_sub_str = NULL; + char copy_str[128] = ""; int i = 0, j = 0; int len = 0; - char temp_str[3]; + char temp_str[3] = ""; int version; ret = pcre_exec(parse_regex, parse_regex_study, arg, strlen(arg), 0, 0, ov, @@ -131,24 +138,24 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) memset(did, 0, sizeof(DetectDceIfaceData)); /* retrieve the iface uuid string. iface uuid is a compulsion in the keyword */ - res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 1, &pcre_sub_str); + res = pcre_copy_substring(arg, ov, MAX_SUBSTRINGS, 1, copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } /* parse the iface uuid string */ - len = strlen(pcre_sub_str); + len = strlen(copy_str); j = 0; temp_str[2] = '\0'; for (i = 0; i < len; ) { - if (pcre_sub_str[i] == '-') { + if (copy_str[i] == '-') { i++; continue; } - temp_str[0] = pcre_sub_str[i]; - temp_str[1] = pcre_sub_str[i + 1]; + temp_str[0] = copy_str[i]; + temp_str[1] = copy_str[i + 1]; hex_value = strtol(temp_str, NULL, 16); did->uuid[j] = hex_value; @@ -164,13 +171,13 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) if (ret == 4 || ret == 5) { /* first handle the version number, so that we can do some additional * validations of the version number, wrt. the operator */ - res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 3, &pcre_sub_str); + res = pcre_copy_substring(arg, ov, MAX_SUBSTRINGS, 3, copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - version = atoi(pcre_sub_str); + version = atoi(copy_str); if (version > UINT16_MAX) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface version " "invalid: %d\n", version); @@ -178,17 +185,14 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) } did->version = version; - /* free the substring */ - pcre_free_substring(pcre_sub_str); - /* now let us handle the operator supplied with the version number */ - res = pcre_get_substring(arg, ov, MAX_SUBSTRINGS, 2, &pcre_sub_str); + res = pcre_copy_substring(arg, ov, MAX_SUBSTRINGS, 2, copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - switch (pcre_sub_str[0]) { + switch (copy_str[0]) { case '<': if (version == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "DCE_IFACE interface " @@ -217,9 +221,6 @@ static inline DetectDceIfaceData *DetectDceIfaceArgParse(const char *arg) did->op = DETECT_DCE_IFACE_OP_NE; break; } - - /* free the substring */ - pcre_free_substring(pcre_sub_str); } return did; @@ -257,6 +258,24 @@ static inline int DetectDceIfaceMatchIfaceVersion(uint16_t version, } } +#include "app-layer-smb.h" +DCERPCState *DetectDceGetState(AppProto alproto, void *alstate) +{ + switch(alproto) { + case ALPROTO_DCERPC: + return alstate; + case ALPROTO_SMB: { + SMBState *smb_state = (SMBState *)alstate; + return &smb_state->ds; + } + case ALPROTO_SMB2: + // not implemented + return NULL; + } + + return NULL; +} + /** * \brief App layer match function for the "dce_iface" keyword. * @@ -271,16 +290,17 @@ static inline int DetectDceIfaceMatchIfaceVersion(uint16_t version, * \retval 1 On Match. * \retval 0 On no match. */ -int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectDceIfaceMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; DCERPCUuidEntry *item = NULL; int i = 0; - DetectDceIfaceData *dce_data = (DetectDceIfaceData *)m->ctx; - DCERPCState *dcerpc_state = (DCERPCState *)state; + DetectDceIfaceData *dce_data = (DetectDceIfaceData *)m; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); @@ -350,11 +370,14 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) DetectDceIfaceData *did = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + return -1; + did = DetectDceIfaceArgParse(arg); if (did == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dec_iface option in " "signature"); - goto error; + return -1; } sm = SigMatchAlloc(); @@ -364,16 +387,7 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_DCE_IFACE; sm->ctx = (void *)did; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - s->alproto = ALPROTO_DCERPC; - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; + SigMatchAppendSMToList(s, sm, g_dce_generic_list_id); return 0; error: @@ -383,7 +397,7 @@ static int DetectDceIfaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return -1; } -void DetectDceIfaceFree(void *ptr) +static void DetectDceIfaceFree(void *ptr) { SCFree(ptr); @@ -411,12 +425,12 @@ static int DetectDceIfaceTestParse01(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -454,12 +468,12 @@ static int DetectDceIfaceTestParse02(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -497,12 +511,12 @@ static int DetectDceIfaceTestParse03(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<10") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; result &= 1; for (i = 0; i < 16; i++) { if (did->uuid[i] != test_uuid[i]) { @@ -536,12 +550,12 @@ static int DetectDceIfaceTestParse04(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,!10") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -576,12 +590,12 @@ static int DetectDceIfaceTestParse05(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=10") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -619,12 +633,12 @@ static int DetectDceIfaceTestParse06(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -662,12 +676,12 @@ static int DetectDceIfaceTestParse07(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,>1,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -703,12 +717,12 @@ static int DetectDceIfaceTestParse08(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,<1,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -746,8 +760,8 @@ static int DetectDceIfaceTestParse09(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,=1,any_frag") == 0); - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -785,12 +799,12 @@ static int DetectDceIfaceTestParse10(void) result = (DetectDceIfaceSetup(NULL, s, "12345678-1234-1234-1234-123456789ABC,!1,any_frag") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { + if (s->sm_lists[g_dce_generic_list_id] == NULL) { SCReturnInt(0); } - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - did = temp->ctx; + temp = s->sm_lists[g_dce_generic_list_id]; + did = (DetectDceIfaceData *)temp->ctx; if (did == NULL) { SCReturnInt(0); } @@ -840,7 +854,6 @@ static int DetectDceIfaceTestParse11(void) */ static int DetectDceIfaceTestParse12(void) { - int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; @@ -906,100 +919,60 @@ static int DetectDceIfaceTestParse12(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any " "(msg:\"DCERPC\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5,=0,any_frag; " "sid:1;)"); - if (s == NULL) - goto end; + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SCLogDebug("handling to_server chunk"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); + FAIL_IF(r != 0); dcerpc_state = f.alstate; - if (dcerpc_state == NULL) { - SCLogDebug("no dcerpc state: "); - goto end; - } + FAIL_IF(dcerpc_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 didn't match (1): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); SCLogDebug("handling to_client chunk"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(r != 0); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(PacketAlertCheck(p, 1)); - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched, but shouldn't have: "); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(r != 0); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sid 1 matched, but shouldn't have: "); - goto end; - } - - result = 1; - -end: + FAIL_IF(!PacketAlertCheck(p, 1)); if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /* Disabled because of bug_753. Would be enabled, once we rewrite @@ -1429,15 +1402,16 @@ static int DetectDceIfaceTestParse14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1451,15 +1425,16 @@ static int DetectDceIfaceTestParse14(void) if (PacketAlertCheck(p, 1)) goto end; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1469,15 +1444,16 @@ static int DetectDceIfaceTestParse14(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_request, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_request, dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1639,15 +1615,16 @@ static int DetectDceIfaceTestParse15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1663,15 +1640,16 @@ static int DetectDceIfaceTestParse15(void) if (PacketAlertCheck(p, 2)) goto end; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1685,15 +1663,16 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_alter_context, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_alter_context, dcerpc_alter_context_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1707,15 +1686,16 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_alter_context_resp, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_alter_context_resp, dcerpc_alter_context_resp_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1729,15 +1709,16 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1751,15 +1732,16 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1773,15 +1755,16 @@ static int DetectDceIfaceTestParse15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1814,30 +1797,27 @@ static int DetectDceIfaceTestParse15(void) #endif -void DetectDceIfaceRegisterTests(void) +static void DetectDceIfaceRegisterTests(void) { - #ifdef UNITTESTS - UtRegisterTest("DetectDceIfaceTestParse01", DetectDceIfaceTestParse01, 1); - UtRegisterTest("DetectDceIfaceTestParse02", DetectDceIfaceTestParse02, 1); - UtRegisterTest("DetectDceIfaceTestParse03", DetectDceIfaceTestParse03, 1); - UtRegisterTest("DetectDceIfaceTestParse04", DetectDceIfaceTestParse04, 1); - UtRegisterTest("DetectDceIfaceTestParse05", DetectDceIfaceTestParse05, 1); - UtRegisterTest("DetectDceIfaceTestParse06", DetectDceIfaceTestParse06, 1); - UtRegisterTest("DetectDceIfaceTestParse07", DetectDceIfaceTestParse07, 1); - UtRegisterTest("DetectDceIfaceTestParse08", DetectDceIfaceTestParse08, 1); - UtRegisterTest("DetectDceIfaceTestParse09", DetectDceIfaceTestParse09, 1); - UtRegisterTest("DetectDceIfaceTestParse10", DetectDceIfaceTestParse10, 1); - UtRegisterTest("DetectDceIfaceTestParse11", DetectDceIfaceTestParse11, 1); - UtRegisterTest("DetectDceIfaceTestParse12", DetectDceIfaceTestParse12, 1); + UtRegisterTest("DetectDceIfaceTestParse01", DetectDceIfaceTestParse01); + UtRegisterTest("DetectDceIfaceTestParse02", DetectDceIfaceTestParse02); + UtRegisterTest("DetectDceIfaceTestParse03", DetectDceIfaceTestParse03); + UtRegisterTest("DetectDceIfaceTestParse04", DetectDceIfaceTestParse04); + UtRegisterTest("DetectDceIfaceTestParse05", DetectDceIfaceTestParse05); + UtRegisterTest("DetectDceIfaceTestParse06", DetectDceIfaceTestParse06); + UtRegisterTest("DetectDceIfaceTestParse07", DetectDceIfaceTestParse07); + UtRegisterTest("DetectDceIfaceTestParse08", DetectDceIfaceTestParse08); + UtRegisterTest("DetectDceIfaceTestParse09", DetectDceIfaceTestParse09); + UtRegisterTest("DetectDceIfaceTestParse10", DetectDceIfaceTestParse10); + UtRegisterTest("DetectDceIfaceTestParse11", DetectDceIfaceTestParse11); + UtRegisterTest("DetectDceIfaceTestParse12", DetectDceIfaceTestParse12); /* Disabled because of bug_753. Would be enabled, once we rewrite * dce parser */ #if 0 UtRegisterTest("DetectDceIfaceTestParse13", DetectDceIfaceTestParse13, 1); #endif - UtRegisterTest("DetectDceIfaceTestParse14", DetectDceIfaceTestParse14, 1); - UtRegisterTest("DetectDceIfaceTestParse15", DetectDceIfaceTestParse15, 1); + UtRegisterTest("DetectDceIfaceTestParse14", DetectDceIfaceTestParse14); + UtRegisterTest("DetectDceIfaceTestParse15", DetectDceIfaceTestParse15); #endif - - return; } diff --git a/src/detect-dce-iface.h b/src/detect-dce-iface.h index 6a051b0d433d..3eb18b1c726b 100644 --- a/src/detect-dce-iface.h +++ b/src/detect-dce-iface.h @@ -24,6 +24,8 @@ #ifndef __DETECT_DCE_IFACE_H__ #define __DETECT_DCE_IFACE_H__ +#include "app-layer-dcerpc.h" + typedef enum DetectDceIfaceOperators_ { DETECT_DCE_IFACE_OP_NONE = 0, DETECT_DCE_IFACE_OP_LT, @@ -40,6 +42,7 @@ typedef struct DetectDceIfaceData_ { } DetectDceIfaceData; void DetectDceIfaceRegister(void); -void DetectDceIfaceRegisterTests(void); + +DCERPCState *DetectDceGetState(AppProto alproto, void *alstate); #endif /* __DETECT_DCE_IFACE_H__ */ diff --git a/src/detect-dce-opnum.c b/src/detect-dce-opnum.c index 559550797ede..9098a47150e5 100644 --- a/src/detect-dce-opnum.c +++ b/src/detect-dce-opnum.c @@ -41,60 +41,41 @@ #include "queue.h" #include "stream-tcp-reassemble.h" #include "detect-dce-opnum.h" +#include "detect-dce-iface.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #include "stream-tcp.h" -#define DETECT_DCE_OPNUM_PCRE_PARSE_ARGS "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" +#define PARSE_REGEX "^\\s*([0-9]{1,5}(\\s*-\\s*[0-9]{1,5}\\s*)?)(,\\s*[0-9]{1,5}(\\s*-\\s*[0-9]{1,5})?\\s*)*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; -int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, Signature *, SigMatch *); +static int DetectDceOpnumMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectDceOpnumSetup(DetectEngineCtx *, Signature *, char *); -void DetectDceOpnumFree(void *); +static void DetectDceOpnumFree(void *); +static void DetectDceOpnumRegisterTests(void); +static int g_dce_generic_list_id = 0; /** * \brief Registers the keyword handlers for the "dce_opnum" keyword. */ void DetectDceOpnumRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_DCE_OPNUM].name = "dce_opnum"; - sigmatch_table[DETECT_DCE_OPNUM].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_OPNUM].Match = NULL; - sigmatch_table[DETECT_DCE_OPNUM].AppLayerMatch = DetectDceOpnumMatch; + sigmatch_table[DETECT_DCE_OPNUM].AppLayerTxMatch = DetectDceOpnumMatch; sigmatch_table[DETECT_DCE_OPNUM].Setup = DetectDceOpnumSetup; sigmatch_table[DETECT_DCE_OPNUM].Free = DetectDceOpnumFree; sigmatch_table[DETECT_DCE_OPNUM].RegisterTests = DetectDceOpnumRegisterTests; - sigmatch_table[DETECT_DCE_OPNUM].flags |= SIGMATCH_PAYLOAD; - - parse_regex = pcre_compile(DETECT_DCE_OPNUM_PCRE_PARSE_ARGS, opts, &eb, - &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_DCE_OPNUM_PCRE_PARSE_ARGS, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - error: - /* we need to handle error?! */ - return; + g_dce_generic_list_id = DetectBufferTypeRegister("dce_generic"); } /** @@ -103,7 +84,7 @@ void DetectDceOpnumRegister(void) * * \retval dor Pointer to the new instance DetectDceOpnumRange. */ -static inline DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) +static DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) { DetectDceOpnumRange *dor = NULL; @@ -124,7 +105,7 @@ static inline DetectDceOpnumRange *DetectDceOpnumAllocDetectDceOpnumRange(void) * \retval did Pointer to a DetectDceIfaceData instance that holds the data * from the parsed arg. */ -static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) +static DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) { DetectDceOpnumData *dod = NULL; @@ -182,6 +163,13 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) dor = DetectDceOpnumAllocDetectDceOpnumRange(); if (dor == NULL) goto error; + if (prev_dor == NULL) { + prev_dor = dor; + dod->range = dor; + } else { + prev_dor->next = dor; + prev_dor = dor; + } if ((hyphen_token = index(dup_str_temp, '-')) != NULL) { hyphen_token[0] = '\0'; @@ -199,20 +187,17 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; - if (prev_dor == NULL) { - prev_dor = dor; - dod->range = dor; - } else { - prev_dor->next = dor; - prev_dor = dor; - } - dup_str_temp = dup_str; } dor = DetectDceOpnumAllocDetectDceOpnumRange(); if (dor == NULL) goto error; + if (prev_dor == NULL) { + dod->range = dor; + } else { + prev_dor->next = dor; + } if ( (hyphen_token = index(dup_str, '-')) != NULL) { hyphen_token[0] = '\0'; @@ -230,12 +215,6 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) if (dor->range1 > DCE_OPNUM_RANGE_MAX) goto error; - if (prev_dor == NULL) { - dod->range = dor; - } else { - prev_dor->next = dor; - } - if (dup_str_head != NULL) SCFree(dup_str_head); @@ -262,15 +241,16 @@ static inline DetectDceOpnumData *DetectDceOpnumArgParse(const char *arg) * \retval 1 On Match. * \retval 0 On no match. */ -int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectDceOpnumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectDceOpnumData *dce_data = (DetectDceOpnumData *)m->ctx; + DetectDceOpnumData *dce_data = (DetectDceOpnumData *)m; DetectDceOpnumRange *dor = dce_data->range; - DCERPCState *dcerpc_state = (DCERPCState *)state; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); if (dcerpc_state == NULL) { SCLogDebug("No DCERPCState for the flow"); SCReturnInt(0); @@ -313,14 +293,17 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) if (arg == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dce_opnum option in " "signature, option needs a value"); - goto error; + return -1; } + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + return -1; + dod = DetectDceOpnumArgParse(arg); if (dod == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Error parsing dce_opnum option in " "signature"); - goto error; + return -1; } sm = SigMatchAlloc(); @@ -330,16 +313,7 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->type = DETECT_DCE_OPNUM; sm->ctx = (void *)dod; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - s->alproto = ALPROTO_DCERPC; - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; + SigMatchAppendSMToList(s, sm, g_dce_generic_list_id); return 0; error: @@ -349,7 +323,7 @@ static int DetectDceOpnumSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) return -1; } -void DetectDceOpnumFree(void *ptr) +static void DetectDceOpnumFree(void *ptr) { DetectDceOpnumData *dod = ptr; DetectDceOpnumRange *dor = NULL; @@ -377,8 +351,6 @@ static int DetectDceOpnumTestParse01(void) Signature *s = SigAlloc(); int result = 0; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,24") == 0); result &= (DetectDceOpnumSetup(NULL, s, "12,12-24") == 0); @@ -387,7 +359,7 @@ static int DetectDceOpnumTestParse01(void) result &= (DetectDceOpnumSetup(NULL, s, "12,26,62,61,6513--") == -1); result &= (DetectDceOpnumSetup(NULL, s, "12-14,12,121,62-8") == -1); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { + if (s->sm_lists[g_dce_generic_list_id] != NULL) { SigFree(s); result &= 1; } @@ -403,13 +375,11 @@ static int DetectDceOpnumTestParse02(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -432,13 +402,11 @@ static int DetectDceOpnumTestParse03(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12-24") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -461,13 +429,11 @@ static int DetectDceOpnumTestParse04(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "12-24,24,62-72,623-635,62,25,213-235") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -527,13 +493,11 @@ static int DetectDceOpnumTestParse05(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "1,2,3,4,5,6,7") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -593,13 +557,11 @@ static int DetectDceOpnumTestParse06(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -641,13 +603,11 @@ static int DetectDceOpnumTestParse07(void) DetectDceOpnumRange *dor = NULL; SigMatch *temp = NULL; - memset(s, 0, sizeof(Signature)); - result = (DetectDceOpnumSetup(NULL, s, "1-2,3-4,5-6,7-8,9") == 0); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - temp = s->sm_lists[DETECT_SM_LIST_AMATCH]; - dod = temp->ctx; + if (s->sm_lists[g_dce_generic_list_id] != NULL) { + temp = s->sm_lists[g_dce_generic_list_id]; + dod = (DetectDceOpnumData *)temp->ctx; if (dod == NULL) goto end; dor = dod->range; @@ -1185,15 +1145,16 @@ static int DetectDceOpnumTestParse08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1201,25 +1162,27 @@ static int DetectDceOpnumTestParse08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - dcerpc_bindack, dcerpc_bindack_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, + dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, - dcerpc_request, dcerpc_request_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_EOF, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1724,15 +1687,16 @@ static int DetectDceOpnumTestParse09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_request, dcerpc_request_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -2922,22 +2886,20 @@ static int DetectDceOpnumTestParse13(void) return result; } #endif +#endif /* UNITTESTS */ - -#endif -void DetectDceOpnumRegisterTests(void) +static void DetectDceOpnumRegisterTests(void) { - #ifdef UNITTESTS - UtRegisterTest("DetectDceOpnumTestParse01", DetectDceOpnumTestParse01, 1); - UtRegisterTest("DetectDceOpnumTestParse02", DetectDceOpnumTestParse02, 1); - UtRegisterTest("DetectDceOpnumTestParse03", DetectDceOpnumTestParse03, 1); - UtRegisterTest("DetectDceOpnumTestParse04", DetectDceOpnumTestParse04, 1); - UtRegisterTest("DetectDceOpnumTestParse05", DetectDceOpnumTestParse05, 1); - UtRegisterTest("DetectDceOpnumTestParse06", DetectDceOpnumTestParse06, 1); - UtRegisterTest("DetectDceOpnumTestParse07", DetectDceOpnumTestParse07, 1); - UtRegisterTest("DetectDceOpnumTestParse08", DetectDceOpnumTestParse08, 1); - UtRegisterTest("DetectDceOpnumTestParse09", DetectDceOpnumTestParse09, 1); + UtRegisterTest("DetectDceOpnumTestParse01", DetectDceOpnumTestParse01); + UtRegisterTest("DetectDceOpnumTestParse02", DetectDceOpnumTestParse02); + UtRegisterTest("DetectDceOpnumTestParse03", DetectDceOpnumTestParse03); + UtRegisterTest("DetectDceOpnumTestParse04", DetectDceOpnumTestParse04); + UtRegisterTest("DetectDceOpnumTestParse05", DetectDceOpnumTestParse05); + UtRegisterTest("DetectDceOpnumTestParse06", DetectDceOpnumTestParse06); + UtRegisterTest("DetectDceOpnumTestParse07", DetectDceOpnumTestParse07); + UtRegisterTest("DetectDceOpnumTestParse08", DetectDceOpnumTestParse08); + UtRegisterTest("DetectDceOpnumTestParse09", DetectDceOpnumTestParse09); /* Disabled because of bug_753. Would be enabled, once we rewrite * dce parser */ #if 0 @@ -2947,6 +2909,4 @@ void DetectDceOpnumRegisterTests(void) UtRegisterTest("DetectDceOpnumTestParse13", DetectDceOpnumTestParse13, 1); #endif #endif - - return; } diff --git a/src/detect-dce-opnum.h b/src/detect-dce-opnum.h index a4c1a9b76d8c..7316ab75f548 100644 --- a/src/detect-dce-opnum.h +++ b/src/detect-dce-opnum.h @@ -38,6 +38,5 @@ typedef struct DetectDceOpnumData_ { } DetectDceOpnumData; void DetectDceOpnumRegister(void); -void DetectDceOpnumRegisterTests(void); #endif /* __DETECT_DCE_OPNUM_H__ */ diff --git a/src/detect-dce-stub-data.c b/src/detect-dce-stub-data.c index d5e660ebd442..ee7275dede6e 100644 --- a/src/detect-dce-stub-data.c +++ b/src/detect-dce-stub-data.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -19,6 +19,7 @@ * \file * * \author Anoop Saldanha + * \author Anoop Saldanha * * Implements dce_stub_data keyword */ @@ -31,6 +32,8 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" #include "flow.h" #include "flow-var.h" @@ -40,7 +43,9 @@ #include "app-layer-dcerpc.h" #include "queue.h" #include "stream-tcp-reassemble.h" + #include "detect-dce-stub-data.h" +#include "detect-dce-iface.h" #include "util-debug.h" @@ -49,27 +54,173 @@ #include "stream-tcp.h" -int DetectDceStubDataMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, - void *, Signature *, SigMatch *); +#define BUFFER_NAME "dce_stub_data" +#define KEYWORD_NAME "dce_stub_data" + static int DetectDceStubDataSetup(DetectEngineCtx *, Signature *, char *); +static void DetectDceStubDataRegisterTests(void); +static int g_dce_stub_data_buffer_id = 0; + +/** \brief DCERPC Stub Data Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxDceStubDataRequest(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); + if (dcerpc_state == NULL) + return; + + uint32_t buffer_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; + const uint8_t *buffer = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxDceStubDataRequestRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataRequest, + ALPROTO_DCERPC, 0, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + if (r == 0) { + r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataRequest, + ALPROTO_SMB, 0, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + } + return r; +} + +/** \brief DCERPC Stub Data Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxDceStubDataResponse(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); + if (dcerpc_state == NULL) + return; + + uint32_t buffer_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; + const uint8_t *buffer = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxDceStubDataResponseRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataResponse, + ALPROTO_DCERPC, 0, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + if (r == 0) { + r = PrefilterAppendTxEngine(sgh, PrefilterTxDceStubDataResponse, + ALPROTO_SMB, 0, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + } + return r; +} + +static int InspectEngineDceStubData(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + uint32_t buffer_len = 0; + uint8_t *buffer = NULL; + + DCERPCState *dcerpc_state = DetectDceGetState(f->alproto, f->alstate); + if (dcerpc_state == NULL) + goto end; + + if (flags & STREAM_TOSERVER) { + buffer_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; + buffer = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; + } else if (flags & STREAM_TOCLIENT) { + buffer_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; + buffer = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; + } + + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, + dcerpc_state); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + +end: + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} /** * \brief Registers the keyword handlers for the "dce_stub_data" keyword. */ void DetectDceStubDataRegister(void) { sigmatch_table[DETECT_DCE_STUB_DATA].name = "dce_stub_data"; - sigmatch_table[DETECT_DCE_STUB_DATA].alproto = ALPROTO_DCERPC; sigmatch_table[DETECT_DCE_STUB_DATA].Match = NULL; - sigmatch_table[DETECT_DCE_STUB_DATA].AppLayerMatch = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].Setup = DetectDceStubDataSetup; sigmatch_table[DETECT_DCE_STUB_DATA].Free = NULL; sigmatch_table[DETECT_DCE_STUB_DATA].RegisterTests = DetectDceStubDataRegisterTests; sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_DCE_STUB_DATA].flags |= SIGMATCH_PAYLOAD; - return; + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxDceStubDataRequestRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxDceStubDataResponseRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_DCERPC, SIG_FLAG_TOSERVER, + InspectEngineDceStubData); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_DCERPC, SIG_FLAG_TOCLIENT, + InspectEngineDceStubData); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SMB, SIG_FLAG_TOSERVER, + InspectEngineDceStubData); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SMB, SIG_FLAG_TOCLIENT, + InspectEngineDceStubData); + + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); } /** @@ -86,19 +237,11 @@ void DetectDceStubDataRegister(void) static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "rule contains conflicting keywords."); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_DCERPC) != 0) + return -1; - s->list = DETECT_SM_LIST_DMATCH; - s->alproto = ALPROTO_DCERPC; - s->flags |= SIG_FLAG_APPLAYER; + s->init_data->list = g_dce_stub_data_buffer_id; return 0; - - error: - return -1; } /************************************Unittests*********************************/ @@ -107,20 +250,15 @@ static int DetectDceStubDataSetup(DetectEngineCtx *de_ctx, Signature *s, char *a static int DetectDceStubDataTestParse01(void) { - Signature s; - int result = 0; - - memset(&s, 0, sizeof(Signature)); - - result = (DetectDceStubDataSetup(NULL, &s, NULL) == 0); - - if (s.sm_lists[DETECT_SM_LIST_AMATCH] == NULL) { - result = 1; - } else { - result = 0; - } - - return result; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags = DE_QUIET; + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (dce_stub_data; content:\"1\"; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF_NULL(s->sm_lists[g_dce_stub_data_buffer_id]); + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -621,15 +759,16 @@ static int DetectDceStubDataTestParse02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -647,15 +786,16 @@ static int DetectDceStubDataTestParse02(void) goto end; /* do detect */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -666,15 +806,16 @@ static int DetectDceStubDataTestParse02(void) if (PacketAlertCheck(p, 1)) goto end; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_EOF, - dcerpc_request, dcerpc_request_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_EOF, dcerpc_request, + dcerpc_request_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -708,7 +849,6 @@ static int DetectDceStubDataTestParse02(void) */ static int DetectDceStubDataTestParse03(void) { - int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; @@ -1160,8 +1300,7 @@ static int DetectDceStubDataTestParse03(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; @@ -1170,52 +1309,34 @@ static int DetectDceStubDataTestParse03(void) "(msg:\"DCERPC\"; " "dce_stub_data; content:\"|42 42 42 42|\";" "sid:1;)"); - if (s == NULL) - goto end; + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_request, dcerpc_request_len); - if (r != 0) { - SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_request, + dcerpc_request_len); + FAIL_IF(r != 0); dcerpc_state = f.alstate; - if (dcerpc_state == NULL) { - SCLogDebug("no dcerpc state: "); - goto end; - } + FAIL_IF (dcerpc_state == NULL); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); - if (!PacketAlertCheck(p, 1)) - goto end; - - result = 1; - - end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } static int DetectDceStubDataTestParse04(void) @@ -1382,15 +1503,16 @@ static int DetectDceStubDataTestParse04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_bind, dcerpc_bind_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_bind, + dcerpc_bind_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1401,29 +1523,31 @@ static int DetectDceStubDataTestParse04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_bindack, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_bindack, dcerpc_bindack_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* request1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request1, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request1, dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1434,15 +1558,16 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response1, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response1, dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1453,15 +1578,16 @@ static int DetectDceStubDataTestParse04(void) goto end; /* request2 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request2, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request2, dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1472,15 +1598,16 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response2 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, dcerpc_response2, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response2, dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1491,15 +1618,16 @@ static int DetectDceStubDataTestParse04(void) goto end; /* request3 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, dcerpc_request3, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request3, dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1510,15 +1638,16 @@ static int DetectDceStubDataTestParse04(void) goto end; /* response3 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, - dcerpc_response3, dcerpc_response3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, + dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1693,15 +1822,16 @@ static int DetectDceStubDataTestParse05(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER | STREAM_START, - dcerpc_request1, dcerpc_request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER | STREAM_START, dcerpc_request1, + dcerpc_request1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dcerpc_state = f.alstate; if (dcerpc_state == NULL) { @@ -1718,15 +1848,16 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - dcerpc_response1, dcerpc_response1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response1, + dcerpc_response1_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1737,15 +1868,16 @@ static int DetectDceStubDataTestParse05(void) goto end; /* request2 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - dcerpc_request2, dcerpc_request2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request2, + dcerpc_request2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1756,15 +1888,16 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response2 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, - dcerpc_response2, dcerpc_response2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT, dcerpc_response2, + dcerpc_response2_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1775,15 +1908,16 @@ static int DetectDceStubDataTestParse05(void) goto end; /* request3 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, - dcerpc_request3, dcerpc_request3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, dcerpc_request3, + dcerpc_request3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; @@ -1794,15 +1928,16 @@ static int DetectDceStubDataTestParse05(void) goto end; /* response3 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT | STREAM_EOF, - dcerpc_response3, dcerpc_response3_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOCLIENT | STREAM_EOF, dcerpc_response3, + dcerpc_response3_len); if (r != 0) { SCLogDebug("AppLayerParse for dcerpc failed. Returned %" PRId32, r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); p->flowflags &=~ FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; @@ -1834,14 +1969,19 @@ static int DetectDceStubDataTestParse05(void) #endif -void DetectDceStubDataRegisterTests(void) +static void DetectDceStubDataRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDceStubDataTestParse01", DetectDceStubDataTestParse01, 1); - UtRegisterTest("DetectDceStubDataTestParse02", DetectDceStubDataTestParse02, 1); - UtRegisterTest("DetectDceStubDataTestParse03", DetectDceStubDataTestParse03, 1); - UtRegisterTest("DetectDceStubDataTestParse04", DetectDceStubDataTestParse04, 1); - UtRegisterTest("DetectDceStubDataTestParse05", DetectDceStubDataTestParse05, 1); + UtRegisterTest("DetectDceStubDataTestParse01", + DetectDceStubDataTestParse01); + UtRegisterTest("DetectDceStubDataTestParse02", + DetectDceStubDataTestParse02); + UtRegisterTest("DetectDceStubDataTestParse03", + DetectDceStubDataTestParse03); + UtRegisterTest("DetectDceStubDataTestParse04", + DetectDceStubDataTestParse04); + UtRegisterTest("DetectDceStubDataTestParse05", + DetectDceStubDataTestParse05); #endif return; diff --git a/src/detect-dce-stub-data.h b/src/detect-dce-stub-data.h index adc45388a7ce..80c82145c0e8 100644 --- a/src/detect-dce-stub-data.h +++ b/src/detect-dce-stub-data.h @@ -25,6 +25,5 @@ #define __DETECT_DCE_STUB_DATA_H__ void DetectDceStubDataRegister(void); -void DetectDceStubDataRegisterTests(void); #endif /* __DETECT_DCE_STUB_DATA_H__ */ diff --git a/src/detect-depth.c b/src/detect-depth.c index 4aa33dee12c0..18453178f9e8 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -33,11 +33,11 @@ #include "detect-content.h" #include "detect-uricontent.h" #include "detect-byte-extract.h" -#include "detect-parse.h" #include "flow-var.h" #include "app-layer.h" +#include "util-byte.h" #include "util-debug.h" static int DetectDepthSetup (DetectEngineCtx *, Signature *, char *); @@ -46,13 +46,11 @@ void DetectDepthRegister (void) { sigmatch_table[DETECT_DEPTH].name = "depth"; sigmatch_table[DETECT_DEPTH].desc = "designate how many bytes from the beginning of the payload will be checked"; - sigmatch_table[DETECT_DEPTH].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Depth"; + sigmatch_table[DETECT_DEPTH].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#depth"; sigmatch_table[DETECT_DEPTH].Match = NULL; sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup; sigmatch_table[DETECT_DEPTH].Free = NULL; sigmatch_table[DETECT_DEPTH].RegisterTests = NULL; - - sigmatch_table[DETECT_DEPTH].flags |= SIGMATCH_PAYLOAD; } static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depthstr) @@ -62,35 +60,19 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (depthstr[0] == '\"' && depthstr[strlen(depthstr) - 1] == '\"') { + /* Strip leading and trailing "s. */ + if (depthstr[0] == '\"') { str = SCStrdup(depthstr + 1); if (unlikely(str == NULL)) goto end; - str[strlen(depthstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs " "preceding content, uricontent option, http_client_body, " @@ -136,11 +118,10 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths cd->depth = ((DetectByteExtractData *)bed_sm->ctx)->local_id; cd->flags |= DETECT_CONTENT_DEPTH_BE; } else { - cd->depth = (uint32_t)atoi(str); - if (cd->depth < cd->content_len) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "depth - %"PRIu16 - " smaller than content length - %"PRIu32, - cd->depth, cd->content_len); + if (ByteExtractStringUint16(&cd->depth, 0, 0, str) != (int)strlen(str)) + { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "invalid value for depth: %s", str); goto end; } /* Now update the real limit, as depth is relative to the offset */ diff --git a/src/detect-detection-filter.c b/src/detect-detection-filter.c index 40cf0b278172..f209f6991ef7 100644 --- a/src/detect-detection-filter.c +++ b/src/detect-detection-filter.c @@ -51,10 +51,11 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectDetectionFilterMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectDetectionFilterSetup(DetectEngineCtx *, Signature *, char *); -void DetectDetectionFilterRegisterTests(void); -void DetectDetectionFilterFree(void *); +static void DetectDetectionFilterRegisterTests(void); +static void DetectDetectionFilterFree(void *); /** * \brief Registration function for detection_filter: keyword @@ -63,7 +64,7 @@ void DetectDetectionFilterRegister (void) { sigmatch_table[DETECT_DETECTION_FILTER].name = "detection_filter"; sigmatch_table[DETECT_DETECTION_FILTER].desc = "alert on every match after a threshold has been reached"; - sigmatch_table[DETECT_DETECTION_FILTER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule-Thresholding#detection_filter"; + sigmatch_table[DETECT_DETECTION_FILTER].url = DOC_URL DOC_VERSION "/rules/thresholding.html#detection-filter"; sigmatch_table[DETECT_DETECTION_FILTER].Match = DetectDetectionFilterMatch; sigmatch_table[DETECT_DETECTION_FILTER].Setup = DetectDetectionFilterSetup; sigmatch_table[DETECT_DETECTION_FILTER].Free = DetectDetectionFilterFree; @@ -71,30 +72,11 @@ void DetectDetectionFilterRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_DETECTION_FILTER].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) +static int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { return 1; } @@ -108,7 +90,7 @@ int DetectDetectionFilterMatch (ThreadVars *thv, DetectEngineThreadCtx *det_ctx, * \retval df pointer to DetectThresholdData on success * \retval NULL on failure */ -DetectThresholdData *DetectDetectionFilterParse (char *rawstr) +static DetectThresholdData *DetectDetectionFilterParse (char *rawstr) { DetectThresholdData *df = NULL; #define MAX_SUBSTRINGS 30 @@ -121,14 +103,17 @@ DetectThresholdData *DetectDetectionFilterParse (char *rawstr) int seconds_pos = 0, count_pos = 0; uint16_t pos = 0; int i = 0; + char *saveptr = NULL; copy_str = SCStrdup(rawstr); if (unlikely(copy_str == NULL)) { goto error; } - for(pos = 0, df_opt = strtok(copy_str,","); pos < strlen(copy_str) && df_opt != NULL; pos++, df_opt = strtok(NULL,",")) { - + for (pos = 0, df_opt = strtok_r(copy_str,",", &saveptr); + pos < strlen(copy_str) && df_opt != NULL; + pos++, df_opt = strtok_r(NULL,",", &saveptr)) + { if(strstr(df_opt,"count")) count_found++; if(strstr(df_opt,"second")) @@ -222,7 +207,7 @@ DetectThresholdData *DetectDetectionFilterParse (char *rawstr) * \retval 0 on Success * \retval -1 on Failure */ -int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +static int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { SCEnter(); DetectThresholdData *df = NULL; @@ -230,15 +215,13 @@ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw SigMatch *tmpm = NULL; /* checks if there's a previous instance of threshold */ - tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists_tail[DETECT_SM_LIST_MATCH]); + tmpm = DetectGetLastSMFromLists(s, DETECT_THRESHOLD, -1); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } /* checks there's no previous instance of detection_filter */ - tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists_tail[DETECT_SM_LIST_MATCH]); + tmpm = DetectGetLastSMFromLists(s, DETECT_DETECTION_FILTER, -1); if (tmpm != NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "At most one \"detection_filter\" is allowed per rule"); SCReturnInt(-1); @@ -253,15 +236,17 @@ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw goto error; sm->type = DETECT_DETECTION_FILTER; - sm->ctx = (void *)df; + sm->ctx = (SigMatchCtx *)df; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); return 0; error: - if (df) SCFree(df); - if (sm) SCFree(sm); + if (df) + SCFree(df); + if (sm) + SCFree(sm); return -1; } @@ -271,18 +256,17 @@ int DetectDetectionFilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw * * \param df_ptr pointer to DetectDetectionFilterData */ -void DetectDetectionFilterFree(void *df_ptr) +static void DetectDetectionFilterFree(void *df_ptr) { DetectThresholdData *df = (DetectThresholdData *)df_ptr; - if (df) SCFree(df); + if (df) + SCFree(df); } /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-threshold.h" @@ -295,7 +279,7 @@ void DetectDetectionFilterFree(void *df_ptr) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse01 (void) +static int DetectDetectionFilterTestParse01 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track by_dst,count 10,seconds 60"); @@ -313,16 +297,16 @@ int DetectDetectionFilterTestParse01 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse02 (void) +static int DetectDetectionFilterTestParse02 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track both,count 10,seconds 60"); if (df && (df->track == TRACK_DST || df->track == TRACK_SRC) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); - return 1; + return 0; } - return 0; + return 1; } /** @@ -331,7 +315,7 @@ int DetectDetectionFilterTestParse02 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse03 (void) +static int DetectDetectionFilterTestParse03 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("track by_dst, seconds 60, count 10"); @@ -350,16 +334,16 @@ int DetectDetectionFilterTestParse03 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse04 (void) +static int DetectDetectionFilterTestParse04 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60, count 10"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 60)) { DetectDetectionFilterFree(df); - return 1; + return 0; } - return 0; + return 1; } /** @@ -368,7 +352,7 @@ int DetectDetectionFilterTestParse04 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse05 (void) +static int DetectDetectionFilterTestParse05 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 60"); @@ -386,16 +370,16 @@ int DetectDetectionFilterTestParse05 (void) * \retval 1 on succces * \retval 0 on failure */ -int DetectDetectionFilterTestParse06 (void) +static int DetectDetectionFilterTestParse06 (void) { DetectThresholdData *df = NULL; df = DetectDetectionFilterParse("count 10, track by_dst, seconds 0"); if (df && (df->track == TRACK_DST) && (df->count == 10) && (df->seconds == 0)) { DetectDetectionFilterFree(df); - return 1; + return 0; } - return 0; + return 1; } /** @@ -645,18 +629,27 @@ static int DetectDetectionFilterTestSig3(void) } #endif /* UNITTESTS */ -void DetectDetectionFilterRegisterTests(void) +static void DetectDetectionFilterRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDetectionFilterTestParse01", DetectDetectionFilterTestParse01, 1); - UtRegisterTest("DetectDetectionFilterTestParse02", DetectDetectionFilterTestParse02, 0); - UtRegisterTest("DetectDetectionFilterTestParse03", DetectDetectionFilterTestParse03, 1); - UtRegisterTest("DetectDetectionFilterTestParse04", DetectDetectionFilterTestParse04, 0); - UtRegisterTest("DetectDetectionFilterTestParse05", DetectDetectionFilterTestParse05, 1); - UtRegisterTest("DetectDetectionFilterTestParse06", DetectDetectionFilterTestParse06, 0); - UtRegisterTest("DetectDetectionFilterTestSig1", DetectDetectionFilterTestSig1, 1); - UtRegisterTest("DetectDetectionFilterTestSig2", DetectDetectionFilterTestSig2, 1); - UtRegisterTest("DetectDetectionFilterTestSig3", DetectDetectionFilterTestSig3, 1); + UtRegisterTest("DetectDetectionFilterTestParse01", + DetectDetectionFilterTestParse01); + UtRegisterTest("DetectDetectionFilterTestParse02", + DetectDetectionFilterTestParse02); + UtRegisterTest("DetectDetectionFilterTestParse03", + DetectDetectionFilterTestParse03); + UtRegisterTest("DetectDetectionFilterTestParse04", + DetectDetectionFilterTestParse04); + UtRegisterTest("DetectDetectionFilterTestParse05", + DetectDetectionFilterTestParse05); + UtRegisterTest("DetectDetectionFilterTestParse06", + DetectDetectionFilterTestParse06); + UtRegisterTest("DetectDetectionFilterTestSig1", + DetectDetectionFilterTestSig1); + UtRegisterTest("DetectDetectionFilterTestSig2", + DetectDetectionFilterTestSig2); + UtRegisterTest("DetectDetectionFilterTestSig3", + DetectDetectionFilterTestSig3); #endif /* UNITTESTS */ } diff --git a/src/detect-detection-filter.h b/src/detect-detection-filter.h index 2c74d4f40f87..f136d3aca5f9 100644 --- a/src/detect-detection-filter.h +++ b/src/detect-detection-filter.h @@ -24,21 +24,11 @@ #ifndef __DETECT_DETECTION_FILTER_H__ #define __DETECT_DETECTION_FILTER_H__ -#include "decode-events.h" -#include "decode-ipv4.h" -#include "decode-tcp.h" - /** * Registration function for detection_filter: keyword */ void DetectDetectionFilterRegister (void); -/** - * This function registers unit tests for detection_filter - */ - -void DetectDetectionFilterRegisterTests(void); - #endif /*__DETECT_DETECTION_FILTER_H__ */ diff --git a/src/detect-distance.c b/src/detect-distance.c index 14af5c27ee0d..10f65284779f 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -32,7 +32,6 @@ #include "detect-parse.h" #include "detect-engine.h" #include "app-layer.h" -#include "detect-parse.h" #include "detect-content.h" #include "detect-uricontent.h" @@ -47,19 +46,17 @@ #include "util-unittest-helper.h" static int DetectDistanceSetup(DetectEngineCtx *, Signature *, char *); -void DetectDistanceRegisterTests(void); +static void DetectDistanceRegisterTests(void); void DetectDistanceRegister(void) { sigmatch_table[DETECT_DISTANCE].name = "distance"; sigmatch_table[DETECT_DISTANCE].desc = "indicates a relation between this content keyword and the content preceding it"; - sigmatch_table[DETECT_DISTANCE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Distance"; + sigmatch_table[DETECT_DISTANCE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#distance"; sigmatch_table[DETECT_DISTANCE].Match = NULL; sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup; sigmatch_table[DETECT_DISTANCE].Free = NULL; sigmatch_table[DETECT_DISTANCE].RegisterTests = DetectDistanceRegisterTests; - - sigmatch_table[DETECT_DISTANCE].flags |= SIGMATCH_PAYLOAD; } static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, @@ -70,35 +67,19 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (distancestr[0] == '\"' && distancestr[strlen(distancestr) - 1] == '\"') { + /* Strip leading and trailing "s. */ + if (distancestr[0] == '\"') { str = SCStrdup(distancestr + 1); if (unlikely(str == NULL)) goto end; - str[strlen(distancestr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } - /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrieve the sm to apply the distance against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "distance needs " "preceding content, uricontent option, http_client_body, " @@ -146,23 +127,22 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } cd->flags |= DETECT_CONTENT_DISTANCE; - SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, pm->prev, - DETECT_PCRE, pm->prev); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (prev_pm == NULL) { ret = 0; goto end; } if (prev_pm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)prev_pm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + DetectContentData *prev_cd = (DetectContentData *)prev_pm->ctx; + if (prev_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't " "have relative keywords around a fast_pattern " "only content"); goto end; } - cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + prev_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } else if (prev_pm->type == DETECT_PCRE) { DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx; pd->flags |= DETECT_PCRE_RELATIVE_NEXT; @@ -187,7 +167,6 @@ static int DetectDistanceTest01(void) goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (content:\"|AA BB|\"; content:\"|CC DD EE FF 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE|\"; distance: 4; within: 19; sid:1; rev:1;)"); @@ -236,7 +215,7 @@ static int DetectDistanceTest01(void) * distance works, if the previous keyword is byte_jump and content * (bug 163) */ -int DetectDistanceTestPacket01 (void) +static int DetectDistanceTestPacket01 (void) { int result = 0; uint8_t buf[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -260,11 +239,12 @@ int DetectDistanceTestPacket01 (void) } #endif /* UNITTESTS */ -void DetectDistanceRegisterTests(void) +static void DetectDistanceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDistanceTest01 -- distance / within mix", DetectDistanceTest01, 1); - UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01, 1); + UtRegisterTest("DetectDistanceTest01 -- distance / within mix", + DetectDistanceTest01); + UtRegisterTest("DetectDistanceTestPacket01", DetectDistanceTestPacket01); #endif /* UNITTESTS */ } diff --git a/src/detect-dnp3.c b/src/detect-dnp3.c new file mode 100644 index 000000000000..153e151f8e23 --- /dev/null +++ b/src/detect-dnp3.c @@ -0,0 +1,1036 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" + +#include "stream.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-dnp3.h" +#include "detect-engine.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer-dnp3.h" + +static int g_dnp3_match_buffer_id = 0; +static int g_dnp3_data_buffer_id = 0; + +/** + * The detection struct. + */ +typedef struct DetectDNP3_ { + union { + struct { + /* Function code for function code detection. */ + uint8_t function_code; + }; + struct { + /* Internal indicator flags for IIN detection. */ + uint16_t ind_flags; + }; + struct { + /* Object info for object detection. */ + uint8_t obj_group; + uint8_t obj_variation; + }; + }; +} DetectDNP3; + +/** + * Indicator names to value mappings (Snort compatible). + */ +DNP3Mapping DNP3IndicatorsMap[] = { + {"device_restart", 0x8000}, + {"device_trouble", 0x4000}, + {"local_control", 0x2000}, + {"need_time", 0x1000}, + {"class_3_events", 0x0800}, + {"class_2_events", 0x0400}, + {"class_1_events", 0x0200}, + {"all_stations", 0x0100}, + + {"reserved_1", 0x0080}, + {"reserved_2", 0x0040}, + {"config_corrupt", 0x0020}, + {"already_executing", 0x0010}, + {"event_buffer_overflow", 0x0008}, + {"parameter_error", 0x0004}, + {"object_unknown", 0x0002}, + {"no_func_code_support", 0x0001}, + + {NULL, 0}, +}; + +/** + * Application function code name to code mappings (Snort compatible). + */ +DNP3Mapping DNP3FunctionNameMap[] = { + {"confirm", 0}, + {"read", 1}, + {"write", 2}, + {"select", 3}, + {"operate", 4}, + {"direct_operate", 5}, + {"direct_operate_nr", 6}, + {"immed_freeze", 7}, + {"immed_freeze_nr", 8}, + {"freeze_clear", 9}, + {"freeze_clear_nr", 10}, + {"freeze_at_time", 11}, + {"freeze_at_time_nr", 12}, + {"cold_restart", 13}, + {"warm_restart", 14}, + {"initialize_data", 15}, + {"initialize_appl", 16}, + {"start_appl", 17}, + {"stop_appl", 18}, + {"save_config", 19}, + {"enable_unsolicited", 20}, + {"disable_unsolicited", 21}, + {"assign_class", 22}, + {"delay_measure", 23}, + {"record_current_time", 24}, + {"open_file", 25}, + {"close_file", 26}, + {"delete_file", 27}, + {"get_file_info", 28}, + {"authenticate_file", 29}, + {"abort_file", 30}, + {"activate_config", 31}, + {"authenticate_req", 32}, + {"authenticate_err", 33}, + {"response", 129}, + {"unsolicited_response", 130}, + {"authenticate_resp", 131} +}; + +static void DetectDNP3FuncRegisterTests(void); +static void DetectDNP3IndRegisterTests(void); +static void DetectDNP3ObjRegisterTests(void); +static void DetectDNP3DataRegisterTests(void); + +/** + * \brief Utility function to trim leading and trailing whitespace + * from a string. + */ +static char *TrimString(char *str) +{ + char *end = str + strlen(str) - 1; + while (isspace(*str)) { + str++; + } + while (end > str && isspace(*end)) { + end--; + } + *(end + 1) = '\0'; + return str; +} + +static int DetectEngineInspectDNP3Data(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + DNP3Transaction *tx = (DNP3Transaction *)txv; + + int r = 0; + + /* Content match - should probably be put into its own file. */ + if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { + r = DetectEngineContentInspection(de_ctx, det_ctx, s, + smd, f, tx->request_buffer, + tx->request_buffer_len, 0, 0, NULL); + } + else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { + r = DetectEngineContentInspection(de_ctx, det_ctx, s, + smd, f, tx->response_buffer, + tx->response_buffer_len, 0, 0, NULL); + } + + SCReturnInt(r); +} + +static int DetectEngineInspectDNP3(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} + +/** + * \brief Parse the provided function name or code to its integer + * value. + * + * If the value passed is a number, it will be checked that it falls + * within the range of valid function codes. If function name is + * passed it will be resolved to its function code. + * + * \retval The function code as an integer if successul, -1 on + * failure. + */ +static int DetectDNP3FuncParseFunctionCode(char *str, uint8_t *fc) +{ + if (ByteExtractStringUint8(fc, 10, strlen(str), str) >= 0) { + return 1; + } + + /* Lookup by name. */ + for (size_t i = 0; + i < sizeof(DNP3FunctionNameMap) / sizeof(DNP3Mapping); i++) { + if (strcasecmp(str, DNP3FunctionNameMap[i].name) == 0) { + *fc = DNP3FunctionNameMap[i].value; + return 1; + } + } + + return 0; +} + +static int DetectDNP3FuncSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + DetectDNP3 *dnp3 = NULL; + SigMatch *sm = NULL; + uint8_t function_code; + + if (!DetectDNP3FuncParseFunctionCode(str, &function_code)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "Invalid argument \"%s\" supplied to dnp3_func keyword.", str); + return -1; + } + + dnp3 = SCCalloc(1, sizeof(DetectDNP3)); + if (unlikely(dnp3 == NULL)) { + goto error; + } + dnp3->function_code = function_code; + + sm = SigMatchAlloc(); + if (sm == NULL) { + goto error; + } + sm->type = DETECT_AL_DNP3FUNC; + sm->ctx = (void *)dnp3; + s->alproto = ALPROTO_DNP3; + s->flags |= SIG_FLAG_STATE_MATCH; + + SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id); + + SCReturnInt(0); +error: + if (dnp3 != NULL) { + SCFree(dnp3); + } + if (sm != NULL) { + SCFree(sm); + } + SCReturnInt(-1); +} + +static int DetectDNP3IndParseByName(char *str, uint16_t *flags) +{ + char tmp[strlen(str) + 1]; + char *p, *last = NULL; + + strlcpy(tmp, str, sizeof(tmp)); + + for ((p = strtok_r(tmp, ",", &last)); p; (p = strtok_r(NULL, ",", &last))) { + p = TrimString(p); + int found = 0; + int i = 0; + while (DNP3IndicatorsMap[i].name != NULL) { + if (strcasecmp(p, DNP3IndicatorsMap[i].name) == 0) { + *flags |= DNP3IndicatorsMap[i].value; + found = 1; + break; + } + i++; + } + + if (!found) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "Bad argument \"%s\" supplied to dnp3.ind keyword.", p); + return 0; + } + } + + return 1; +} + +static int DetectDNP3IndParse(char *str, uint16_t *flags) +{ + *flags = 0; + + if (ByteExtractStringUint16(flags, 0, strlen(str), str) > 0) { + return 1; + } + + /* Parse by name - will log a more specific error message on error. */ + if (DetectDNP3IndParseByName(str, flags)) { + return 1; + } + + return 0; +} + +static int DetectDNP3IndSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + DetectDNP3 *detect = NULL; + SigMatch *sm = NULL; + uint16_t flags; + + if (!DetectDNP3IndParse(str, &flags)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "Invalid argument \"%s\" supplied to dnp3.ind keyword.", str); + return -1; + } + + detect = SCCalloc(1, sizeof(DetectDNP3)); + if (unlikely(detect == NULL)) { + goto error; + } + detect->ind_flags = flags; + + sm = SigMatchAlloc(); + if (sm == NULL) { + goto error; + } + sm->type = DETECT_AL_DNP3IND; + sm->ctx = (void *)detect; + s->alproto = ALPROTO_DNP3; + s->flags |= SIG_FLAG_STATE_MATCH; + + SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id); + + SCReturnInt(0); +error: + if (detect != NULL) { + SCFree(detect); + } + if (sm != NULL) { + SCFree(sm); + } + SCReturnInt(-1); +} + +/** + * \brief Parse the value of string of the dnp3_obj keyword. + * + * \param str the input string + * \param gout pointer to variable to store the parsed group integer + * \param vout pointer to variable to store the parsed variation integer + * + * \retval 1 if parsing successful otherwise 0. + */ +static int DetectDNP3ObjParse(const char *str, uint8_t *group, uint8_t *var) +{ + size_t size = strlen(str) + 1; + char groupstr[size], *varstr, *sep; + strlcpy(groupstr, str, size); + + sep = strchr(groupstr, ','); + if (sep == NULL) { + return 0; + } + *sep = '\0'; + varstr = sep + 1; + + if (ByteExtractStringUint8(group, 0, strlen(groupstr), groupstr) < 0) { + return 0; + } + + if (ByteExtractStringUint8(var, 0, strlen(varstr), varstr) < 0) { + return 0; + } + + return 1; +} + +static int DetectDNP3ObjSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + uint8_t group; + uint8_t variation; + DetectDNP3 *detect = NULL; + SigMatch *sm = NULL; + + if (!DetectDNP3ObjParse(str, &group, &variation)) { + goto fail; + } + + detect = SCCalloc(1, sizeof(*detect)); + if (unlikely(detect == NULL)) { + goto fail; + } + detect->obj_group = group; + detect->obj_variation = variation; + + sm = SigMatchAlloc(); + if (unlikely(sm == NULL)) { + goto fail; + } + sm->type = DETECT_AL_DNP3OBJ; + sm->ctx = (void *)detect; + s->alproto = ALPROTO_DNP3; + s->flags |= SIG_FLAG_STATE_MATCH; + SigMatchAppendSMToList(s, sm, g_dnp3_match_buffer_id); + + SCReturnInt(1); +fail: + if (detect != NULL) { + SCFree(detect); + } + if (sm != NULL) { + SCFree(sm); + } + SCReturnInt(0); +} + +static void DetectDNP3Free(void *ptr) +{ + SCEnter(); + if (ptr != NULL) { + SCFree(ptr); + } + SCReturn; +} + +static int DetectDNP3FuncMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + int match = 0; + + if (flags & STREAM_TOSERVER) { + match = detect->function_code == tx->request_ah.function_code; + } + else if (flags & STREAM_TOCLIENT) { + match = detect->function_code == tx->response_ah.function_code; + } + + return match; +} + +static int DetectDNP3ObjMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + DNP3ObjectList *objects = NULL; + + if (flags & STREAM_TOSERVER) { + objects = &tx->request_objects; + } + else if (flags & STREAM_TOCLIENT) { + objects = &tx->response_objects; + } + + if (objects != NULL) { + DNP3Object *object; + TAILQ_FOREACH(object, objects, next) { + if (object->group == detect->obj_group && + object->variation == detect->obj_variation) { + return 1; + } + } + } + + return 0; +} + +static int DetectDNP3IndMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + DNP3Transaction *tx = (DNP3Transaction *)txv; + DetectDNP3 *detect = (DetectDNP3 *)ctx; + + if (flags & STREAM_TOCLIENT) { + if ((tx->response_iin.iin1 & (detect->ind_flags >> 8)) || + (tx->response_iin.iin2 & (detect->ind_flags & 0xf))) { + return 1; + } + } + + return 0; +} + +static void DetectDNP3FuncRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3FUNC].name = "dnp3_func"; + sigmatch_table[DETECT_AL_DNP3FUNC].alias = "dnp3.func"; + sigmatch_table[DETECT_AL_DNP3FUNC].Match = NULL; + sigmatch_table[DETECT_AL_DNP3FUNC].AppLayerTxMatch = DetectDNP3FuncMatch; + sigmatch_table[DETECT_AL_DNP3FUNC].Setup = DetectDNP3FuncSetup; + sigmatch_table[DETECT_AL_DNP3FUNC].Free = DetectDNP3Free; + sigmatch_table[DETECT_AL_DNP3FUNC].RegisterTests = + DetectDNP3FuncRegisterTests; + + SCReturn; +} + +static void DetectDNP3IndRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3IND].name = "dnp3_ind"; + sigmatch_table[DETECT_AL_DNP3IND].alias = "dnp3.ind"; + sigmatch_table[DETECT_AL_DNP3IND].Match = NULL; + sigmatch_table[DETECT_AL_DNP3IND].AppLayerTxMatch = DetectDNP3IndMatch; + sigmatch_table[DETECT_AL_DNP3IND].Setup = DetectDNP3IndSetup; + sigmatch_table[DETECT_AL_DNP3IND].Free = DetectDNP3Free; + sigmatch_table[DETECT_AL_DNP3IND].RegisterTests = + DetectDNP3IndRegisterTests; + + SCReturn; +} + +static void DetectDNP3ObjRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3OBJ].name = "dnp3_obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].alias = "dnp3.obj"; + sigmatch_table[DETECT_AL_DNP3OBJ].Match = NULL; + sigmatch_table[DETECT_AL_DNP3OBJ].AppLayerTxMatch = DetectDNP3ObjMatch; + sigmatch_table[DETECT_AL_DNP3OBJ].Setup = DetectDNP3ObjSetup; + sigmatch_table[DETECT_AL_DNP3OBJ].Free = DetectDNP3Free; + sigmatch_table[DETECT_AL_DNP3OBJ].RegisterTests = + DetectDNP3ObjRegisterTests; + + SCReturn; +} + +static int DetectDNP3DataSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + s->init_data->list = g_dnp3_data_buffer_id; + s->alproto = ALPROTO_DNP3; + SCReturnInt(0); +} + +static void DetectDNP3DataRegister(void) +{ + SCEnter(); + + sigmatch_table[DETECT_AL_DNP3DATA].name = "dnp3_data"; + sigmatch_table[DETECT_AL_DNP3DATA].Match = NULL; + sigmatch_table[DETECT_AL_DNP3DATA].Setup = DetectDNP3DataSetup; + sigmatch_table[DETECT_AL_DNP3DATA].Free = NULL; + sigmatch_table[DETECT_AL_DNP3DATA].RegisterTests = + DetectDNP3DataRegisterTests; + + sigmatch_table[DETECT_AL_DNP3DATA].flags |= SIGMATCH_NOOPT; + + DetectAppLayerInspectEngineRegister("dnp3_data", + ALPROTO_DNP3, SIG_FLAG_TOSERVER, + DetectEngineInspectDNP3Data); + DetectAppLayerInspectEngineRegister("dnp3_data", + ALPROTO_DNP3, SIG_FLAG_TOCLIENT, + DetectEngineInspectDNP3Data); + + g_dnp3_data_buffer_id = DetectBufferTypeGetByName("dnp3_data"); + SCReturn; +} + +void DetectDNP3Register(void) +{ + DetectDNP3DataRegister(); + + DetectDNP3FuncRegister(); + DetectDNP3IndRegister(); + DetectDNP3ObjRegister(); + + /* Register the list of func, ind and obj. */ + DetectAppLayerInspectEngineRegister("dnp3", + ALPROTO_DNP3, SIG_FLAG_TOSERVER, + DetectEngineInspectDNP3); + DetectAppLayerInspectEngineRegister("dnp3", + ALPROTO_DNP3, SIG_FLAG_TOCLIENT, + DetectEngineInspectDNP3); + + g_dnp3_match_buffer_id = DetectBufferTypeRegister("dnp3"); + +} + +#ifdef UNITTESTS + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "detect-engine.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectDNP3FuncParseFunctionCodeTest(void) +{ + uint8_t fc; + + /* Valid. */ + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("0", &fc)); + FAIL_IF(fc != 0); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("1", &fc)); + FAIL_IF(fc != 1); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("254", &fc)); + FAIL_IF(fc != 254); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("255", &fc)); + FAIL_IF(fc != 255); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("confirm", &fc)); + FAIL_IF(fc != 0); + + FAIL_IF_NOT(DetectDNP3FuncParseFunctionCode("CONFIRM", &fc)); + FAIL_IF(fc != 0); + + /* Invalid. */ + FAIL_IF(DetectDNP3FuncParseFunctionCode("", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("-1", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("-2", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("256", &fc)); + FAIL_IF(DetectDNP3FuncParseFunctionCode("unknown_function_code", &fc)); + + PASS; +} + +static int DetectDNP3FuncTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectDNP3 *dnp3func = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->sig_list = SigInit(de_ctx, + "alert dnp3 any any -> any any " + "(msg:\"SURICATA DNP3 Write request\"; " + "dnp3_func:2; sid:5000009; rev:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]); + FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx); + + dnp3func = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx; + FAIL_IF(dnp3func->function_code != 2); + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + PASS; +} + +static int DetectDNP3IndTestParseAsInteger(void) +{ + uint16_t flags = 0; + + FAIL_IF(!DetectDNP3IndParse("0", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("1", &flags)); + FAIL_IF(flags != 0x0001); + + FAIL_IF(!DetectDNP3IndParse("0x0", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("0x0000", &flags)); + FAIL_IF(flags != 0); + FAIL_IF(!DetectDNP3IndParse("0x0001", &flags)); + FAIL_IF(flags != 0x0001); + + FAIL_IF(!DetectDNP3IndParse("0x8421", &flags)); + FAIL_IF(flags != 0x8421); + + FAIL_IF(DetectDNP3IndParse("a", &flags)); + + PASS; +} + +static int DetectDNP3IndTestParseByName(void) +{ + uint16_t flags = 0; + + FAIL_IF(!DetectDNP3IndParse("all_stations", &flags)); + FAIL_IF(!(flags & 0x0100)); + FAIL_IF(!DetectDNP3IndParse("class_1_events , class_2_events", &flags)); + FAIL_IF(!(flags & 0x0200)); + FAIL_IF(!(flags & 0x0400)); + FAIL_IF((flags & 0xf9ff)); + + FAIL_IF(DetectDNP3IndParse("something", &flags)); + + PASS; +} + +static int DetectDNP3ObjSetupTest(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectDNP3 *detect = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + de_ctx->sig_list = SigInit(de_ctx, + "alert dnp3 any any -> any any " + "(msg:\"SURICATA DNP3 Object Test\"; " + "dnp3_obj:99,99; sid:1; rev:1;)"); + FAIL_IF(de_ctx->sig_list == NULL); + + FAIL_IF(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id] == NULL); + FAIL_IF(de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx == NULL); + + detect = (DetectDNP3 *)de_ctx->sig_list->sm_lists_tail[g_dnp3_match_buffer_id]->ctx; + FAIL_IF(detect->obj_group != 99); + FAIL_IF(detect->obj_variation != 99); + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + PASS; +} + +static int DetectDNP3ObjParseTest(void) +{ + uint8_t group, var; + + FAIL_IF(!DetectDNP3ObjParse("0,0", &group, &var)); + FAIL_IF(group != 0 || var != 0); + + FAIL_IF(!DetectDNP3ObjParse("255,255", &group, &var)); + FAIL_IF(group != 255 || var != 255); + + FAIL_IF(DetectDNP3ObjParse("-1,-1", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("256,256", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("a,1", &group, &var)); + FAIL_IF(DetectDNP3ObjParse("1,a", &group, &var)); + + PASS; +} + +/** + * Test request (to server) content match. + */ +static int DetectDNP3DataTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + + uint8_t request[] = { + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + 0xa5, 0xe9, + + 0xff, 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + + /* CRC. */ + 0x72, 0xef, + + 0x00, 0x00, 0x00, 0x00, 0x00, + + /* CRC. */ + 0xff, 0xff, + }; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_DNP3; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + /* Either direction - should match. */ + Signature *s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00 00 00 00|\"; " + "sid:1; rev:1;)"); + FAIL_IF(s == NULL); + + /* To server - should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_server; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00 00 00 00|\"; " + "sid:2; rev:1;)"); + FAIL_IF(s == NULL); + + /* To client - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_client; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00 00 00 00|\"; " + "sid:3; rev:1;)"); + FAIL_IF(s == NULL); + + /* The content of a CRC - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|72 ef|\"; " + "sid:4; rev:1;)"); + FAIL_IF(s == NULL); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request)); + SCMutexUnlock(&f.m); + FAIL_IF(r); + + FAIL_IF(f.alstate == NULL); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(!PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +/** + * Test response (to client) content match. + */ +static int DetectDNP3DataTest02(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + + uint8_t request[] = { + /* Link header. */ + 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00, + + /* CRC. */ + 0xa5, 0xe9, + + /* Transport header. */ + 0xff, + + /* Application layer. */ + 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + + /* CRC. */ + 0x72, 0xef, + + /* Application layer. */ + 0x00, 0x00, 0x00, 0x00, 0x00, + + /* CRC. */ + 0xff, 0xff, + }; + + uint8_t response[] = { + /* Link header. */ + 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00, + + /* CRC. */ + 0xe2, 0x59, + + /* Transport header. */ + 0xc3, + + /* Application layyer. */ + 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, + + /* CRC. */ + 0x7a, 0x65, + + /* Application layer. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* CRC. */ + 0xff, 0xff + }; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(response, sizeof(response), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_DNP3; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOCLIENT | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + /* Either direction - should match. */ + Signature *s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00|\"; " + "sid:1; rev:1;)"); + FAIL_IF(s == NULL); + + /* To server - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_server; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00|\"; " + "sid:2; rev:1;)"); + FAIL_IF(s == NULL); + + /* To client - should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "flow:established,to_client; " + "dnp3_data; " + "content:\"|01 01 01 00 00 00 00|\"; " + "sid:3; rev:1;)"); + FAIL_IF(s == NULL); + + /* The content of a CRC - should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert dnp3 any any -> any any (" + "msg:\"DetectDNP3DataTest01\"; " + "dnp3_data; " + "content:\"|7a 65|\"; " + "sid:4; rev:1;)"); + FAIL_IF(s == NULL); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + /* Send through the request, then response. */ + SCMutexLock(&f.m); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, + STREAM_TOSERVER, request, sizeof(request)); + SCMutexUnlock(&f.m); + FAIL_IF(r); + FAIL_IF(f.alstate == NULL); + + SCMutexLock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNP3, STREAM_TOCLIENT, + response, sizeof(response)); + SCMutexUnlock(&f.m); + FAIL_IF(r); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(!PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + PASS; +} + +#endif + +static void DetectDNP3FuncRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3FuncParseFunctionCodeTest", + DetectDNP3FuncParseFunctionCodeTest); + UtRegisterTest("DetectDNP3FuncTest01", DetectDNP3FuncTest01); +#endif +} + +static void DetectDNP3IndRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3IndTestParseAsInteger", + DetectDNP3IndTestParseAsInteger); + UtRegisterTest("DetectDNP3IndTestParseByName", + DetectDNP3IndTestParseByName); +#endif +} + +static void DetectDNP3ObjRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3ObjParseTest", DetectDNP3ObjParseTest); + UtRegisterTest("DetectDNP3ObjSetupTest", DetectDNP3ObjSetupTest); +#endif +} + +void DetectDNP3DataRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectDNP3DataTest01", DetectDNP3DataTest01); + UtRegisterTest("DetectDNP3DataTest02", DetectDNP3DataTest02); +#endif +} diff --git a/src/detect-dnp3.h b/src/detect-dnp3.h new file mode 100644 index 000000000000..b8230db7c96c --- /dev/null +++ b/src/detect-dnp3.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_DNP3_H__ +#define __DETECT_DNP3_H__ + +/** + * Struct for mapping symbolic names to values. + */ +typedef struct DNP3Mapping_ { + char *name; + uint16_t value; +} DNP3Mapping; + +/* Map of internal indicators to value for external use. */ +extern DNP3Mapping DNP3IndicatorsMap[]; + +void DetectDNP3Register(void); + +#endif /* __DETECT_DNP3_H__ */ diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index 84333cb4df5b..7269df5fcc37 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -54,29 +54,52 @@ #include "app-layer.h" #include "app-layer-dns-common.h" #include "detect-dns-query.h" +#include "detect-engine-dns.h" -#include "util-unittest.h" #include "util-unittest-helper.h" static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, char *); static void DetectDnsQueryRegisterTests(void); +static int g_dns_query_buffer_id = 0; /** - * \brief Registration function for keyword: http_uri + * \brief Registration function for keyword: dns_query */ void DetectDnsQueryRegister (void) { sigmatch_table[DETECT_AL_DNS_QUERY].name = "dns_query"; sigmatch_table[DETECT_AL_DNS_QUERY].desc = "content modifier to match specifically and only on the DNS query-buffer"; sigmatch_table[DETECT_AL_DNS_QUERY].Match = NULL; - sigmatch_table[DETECT_AL_DNS_QUERY].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_DNS_QUERY].alproto = ALPROTO_DNS; sigmatch_table[DETECT_AL_DNS_QUERY].Setup = DetectDnsQuerySetup; sigmatch_table[DETECT_AL_DNS_QUERY].Free = NULL; sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerMpmRegister("dns_query", SIG_FLAG_TOSERVER, 2, + PrefilterTxDnsQueryRegister); + + DetectAppLayerInspectEngineRegister("dns_query", + ALPROTO_DNS, SIG_FLAG_TOSERVER, + DetectEngineInspectDnsQueryName); + + DetectBufferTypeSetDescriptionByName("dns_query", + "dns request query"); + + g_dns_query_buffer_id = DetectBufferTypeGetByName("dns_query"); + + /* register these generic engines from here for now */ + DetectAppLayerInspectEngineRegister("dns_request", + ALPROTO_DNS, SIG_FLAG_TOSERVER, + DetectEngineInspectDnsRequest); + DetectAppLayerInspectEngineRegister("dns_response", + ALPROTO_DNS, SIG_FLAG_TOCLIENT, + DetectEngineInspectDnsResponse); + + DetectBufferTypeSetDescriptionByName("dns_request", + "dns requests"); + DetectBufferTypeSetDescriptionByName("dns_response", + "dns responses"); } @@ -93,47 +116,14 @@ void DetectDnsQueryRegister (void) static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { - s->list = DETECT_SM_LIST_DNSQUERY_MATCH; + s->init_data->list = g_dns_query_buffer_id; s->alproto = ALPROTO_DNS; return 0; } -/** - * \brief Run the pattern matcher against the queries - * - * \param f locked flow - * \param dns_state initialized dns state - * - * \warning Make sure the flow/state is locked - * \todo what should we return? Just the fact that we matched? - */ -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - DNSState *dns_state, uint8_t flags, void *txv, - uint64_t tx_id) -{ - SCEnter(); - - DNSTransaction *tx = (DNSTransaction *)txv; - DNSQueryEntry *query = NULL; - uint8_t *buffer; - uint16_t buffer_len; - uint32_t cnt = 0; - - TAILQ_FOREACH(query, &tx->query_list, next) { - SCLogDebug("tx %p query %p", tx, query); - - buffer = (uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); - buffer_len = query->len; - - cnt += DnsQueryPatternSearch(det_ctx, - buffer, buffer_len, - flags); - } - - SCReturnUInt(cnt); -} - #ifdef UNITTESTS +#include "detect-isdataat.h" + /** \test simple google.com query matching */ static int DetectDnsQueryTest01(void) { @@ -173,7 +163,7 @@ static int DetectDnsQueryTest01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -186,14 +176,15 @@ static int DetectDnsQueryTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -305,7 +296,7 @@ static int DetectDnsQueryTest02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -324,14 +315,15 @@ static int DetectDnsQueryTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -351,14 +343,15 @@ static int DetectDnsQueryTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, + buf2, sizeof(buf2)); if (r != 0) { printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -372,14 +365,15 @@ static int DetectDnsQueryTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf3, sizeof(buf3)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p3); @@ -457,7 +451,7 @@ static int DetectDnsQueryTest03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -470,14 +464,15 @@ static int DetectDnsQueryTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -563,7 +558,7 @@ static int DetectDnsQueryTest04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -576,14 +571,15 @@ static int DetectDnsQueryTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -599,14 +595,15 @@ static int DetectDnsQueryTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf2, sizeof(buf2)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf2, sizeof(buf2)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -727,7 +724,7 @@ static int DetectDnsQueryTest05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -746,14 +743,15 @@ static int DetectDnsQueryTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -773,14 +771,15 @@ static int DetectDnsQueryTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf2, sizeof(buf2)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf2, sizeof(buf2)); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -794,14 +793,15 @@ static int DetectDnsQueryTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf3, sizeof(buf3)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, + buf3, sizeof(buf3)); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p3); @@ -815,14 +815,15 @@ static int DetectDnsQueryTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf4, sizeof(buf4)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf4, sizeof(buf4)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p4); @@ -896,7 +897,7 @@ static int DetectDnsQueryTest06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -918,14 +919,15 @@ static int DetectDnsQueryTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf, sizeof(buf)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf, sizeof(buf)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -1042,7 +1044,7 @@ static int DetectDnsQueryTest07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " @@ -1067,14 +1069,15 @@ static int DetectDnsQueryTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf1, sizeof(buf1)); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, + STREAM_TOSERVER, buf1, sizeof(buf1)); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); dns_state = f.alstate; if (dns_state == NULL) { @@ -1094,14 +1097,15 @@ static int DetectDnsQueryTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, buf2, sizeof(buf2)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, + buf2, sizeof(buf2)); if (r != -1) { printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -1119,14 +1123,15 @@ static int DetectDnsQueryTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, buf3, sizeof(buf3)); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, + buf3, sizeof(buf3)); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p3); @@ -1164,17 +1169,48 @@ static int DetectDnsQueryTest07(void) return result; } +static int DetectDnsQueryIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert dns any any -> any any (" + "dns_query; content:\"one\"; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_dns_query_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif static void DetectDnsQueryRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01, 1); - UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02, 1); - UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03, 1); - UtRegisterTest("DetectDnsQueryTest04 -- tcp splicing", DetectDnsQueryTest04, 1); - UtRegisterTest("DetectDnsQueryTest05 -- tcp splicing/multi tx", DetectDnsQueryTest05, 1); - UtRegisterTest("DetectDnsQueryTest06 -- pcre", DetectDnsQueryTest06, 1); - UtRegisterTest("DetectDnsQueryTest07 -- app layer event", DetectDnsQueryTest07, 1); + UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01); + UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02); + UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03); + UtRegisterTest("DetectDnsQueryTest04 -- tcp splicing", + DetectDnsQueryTest04); + UtRegisterTest("DetectDnsQueryTest05 -- tcp splicing/multi tx", + DetectDnsQueryTest05); + UtRegisterTest("DetectDnsQueryTest06 -- pcre", DetectDnsQueryTest06); + UtRegisterTest("DetectDnsQueryTest07 -- app layer event", + DetectDnsQueryTest07); + + UtRegisterTest("DetectDnsQueryIsdataatParseTest", + DetectDnsQueryIsdataatParseTest); #endif } diff --git a/src/detect-dns-query.h b/src/detect-dns-query.h index 75605231288f..ef6dac2c913f 100644 --- a/src/detect-dns-query.h +++ b/src/detect-dns-query.h @@ -27,7 +27,5 @@ #include "app-layer-dns-common.h" void DetectDnsQueryRegister (void); -uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - DNSState *dns_state, uint8_t flags, void *txv, uint64_t tx_id); #endif /* __DETECT_DNS_QUERY_H__ */ diff --git a/src/detect-dsize.c b/src/detect-dsize.c index 3e971f519011..5f7b7575b524 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -28,6 +28,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "flow-var.h" @@ -48,11 +49,15 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectDsizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, char *str); -void DsizeRegisterTests(void); +static void DsizeRegisterTests(void); static void DetectDsizeFree(void *); +static int PrefilterSetupDsize(SigGroupHead *sgh); +static _Bool PrefilterDsizeIsPrefilterable(const Signature *s); + /** * \brief Registration function for dsize: keyword */ @@ -60,34 +65,32 @@ void DetectDsizeRegister (void) { sigmatch_table[DETECT_DSIZE].name = "dsize"; sigmatch_table[DETECT_DSIZE].desc = "match on the size of the packet payload"; - sigmatch_table[DETECT_DSIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Dsize"; + sigmatch_table[DETECT_DSIZE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#dsize"; sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch; sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup; sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_DSIZE].SupportsPrefilter = PrefilterDsizeIsPrefilterable; + sigmatch_table[DETECT_DSIZE].SetupPrefilter = PrefilterSetupDsize; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; +static inline int +DsizeMatch(const uint16_t psize, const uint8_t mode, + const uint16_t dsize, const uint16_t dsize2) +{ + if (mode == DETECTDSIZE_EQ && dsize == psize) + return 1; + else if (mode == DETECTDSIZE_LT && psize < dsize) + return 1; + else if (mode == DETECTDSIZE_GT && psize > dsize) + return 1; + else if (mode == DETECTDSIZE_RA && psize > dsize && psize < dsize2) + return 1; -error: - /* XXX */ - return; + return 0; } /** @@ -103,7 +106,8 @@ void DetectDsizeRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; @@ -112,18 +116,11 @@ int DetectDsizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, SCReturnInt(0); } - DetectDsizeData *dd = (DetectDsizeData *)m->ctx; + const DetectDsizeData *dd = (const DetectDsizeData *)ctx; SCLogDebug("p->payload_len %"PRIu16"", p->payload_len); - if (dd->mode == DETECTDSIZE_EQ && dd->dsize == p->payload_len) - ret = 1; - else if (dd->mode == DETECTDSIZE_LT && p->payload_len < dd->dsize) - ret = 1; - else if (dd->mode == DETECTDSIZE_GT && p->payload_len > dd->dsize) - ret = 1; - else if (dd->mode == DETECTDSIZE_RA && p->payload_len > dd->dsize && p->payload_len < dd->dsize2) - ret = 1; + ret = DsizeMatch(p->payload_len, dd->mode, dd->dsize, dd->dsize2); SCReturnInt(ret); } @@ -259,9 +256,7 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr DetectDsizeData *dd = NULL; SigMatch *sm = NULL; - if (SigMatchGetLastSMFromLists(s, 2, - DETECT_DSIZE, - s->sm_lists_tail[DETECT_SM_LIST_MATCH]) != NULL) { + if (DetectGetLastSMFromLists(s, DETECT_DSIZE, -1)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use 2 or more dsizes in " "the same sig. Invalidating signature."); goto error; @@ -285,7 +280,7 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr } sm->type = DETECT_DSIZE; - sm->ctx = (void *)dd; + sm->ctx = (SigMatchCtx *)dd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -295,8 +290,8 @@ static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr s->flags |= SIG_FLAG_REQUIRE_PACKET; s->flags |= SIG_FLAG_DSIZE; - if (s->dsize_sm == NULL) { - s->dsize_sm = sm; + if (s->init_data->dsize_sm == NULL) { + s->init_data->dsize_sm = sm; } return 0; @@ -317,13 +312,74 @@ void DetectDsizeFree(void *de_ptr) if(dd) SCFree(dd); } +/* prefilter code */ + +static void +PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + const uint16_t dsize = p->payload_len; + if (DsizeMatch(dsize, ctx->v1.u8[0], ctx->v1.u16[1], ctx->v1.u16[2])) + { + SCLogDebug("packet matches dsize %u", dsize); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketDsizeSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectDsizeData *a = smctx; + v->u8[0] = a->mode; + v->u16[1] = a->dsize; + v->u16[2] = a->dsize2; +} + +static _Bool +PrefilterPacketDsizeCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectDsizeData *a = smctx; + if (v.u8[0] == a->mode && + v.u16[1] == a->dsize && + v.u16[2] == a->dsize2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupDsize(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_DSIZE, + PrefilterPacketDsizeSet, + PrefilterPacketDsizeCompare, + PrefilterPacketDsizeMatch); +} + +static _Bool PrefilterDsizeIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_DSIZE: + return TRUE; + } + } + return FALSE; +} + /* * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS -#include "detect.h" #include "detect-engine.h" + /** * \test this is a test for a valid dsize value 1 * @@ -808,31 +864,31 @@ int DetectDsizeIcmpv6Test01 (void) /** * \brief this function registers unit tests for dsize */ -void DsizeRegisterTests(void) +static void DsizeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DsizeTestParse01", DsizeTestParse01, 1); - UtRegisterTest("DsizeTestParse02", DsizeTestParse02, 1); - UtRegisterTest("DsizeTestParse03", DsizeTestParse03, 1); - UtRegisterTest("DsizeTestParse04", DsizeTestParse04, 1); - UtRegisterTest("DsizeTestParse05", DsizeTestParse05, 1); - UtRegisterTest("DsizeTestParse06", DsizeTestParse06, 1); - UtRegisterTest("DsizeTestParse07", DsizeTestParse07, 1); - UtRegisterTest("DsizeTestParse08", DsizeTestParse08, 1); - UtRegisterTest("DsizeTestParse09", DsizeTestParse09, 1); - UtRegisterTest("DsizeTestParse10", DsizeTestParse10, 1); - UtRegisterTest("DsizeTestParse11", DsizeTestParse11, 1); - UtRegisterTest("DsizeTestParse12", DsizeTestParse12, 1); - UtRegisterTest("DsizeTestParse13", DsizeTestParse13, 1); - UtRegisterTest("DsizeTestParse14", DsizeTestParse14, 1); - UtRegisterTest("DsizeTestParse15", DsizeTestParse15, 1); - UtRegisterTest("DsizeTestParse16", DsizeTestParse16, 1); - UtRegisterTest("DsizeTestParse17", DsizeTestParse17, 1); - UtRegisterTest("DsizeTestParse18", DsizeTestParse18, 1); - UtRegisterTest("DsizeTestParse19", DsizeTestParse19, 1); - UtRegisterTest("DsizeTestParse20", DsizeTestParse20, 1); - - UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01, 1); + UtRegisterTest("DsizeTestParse01", DsizeTestParse01); + UtRegisterTest("DsizeTestParse02", DsizeTestParse02); + UtRegisterTest("DsizeTestParse03", DsizeTestParse03); + UtRegisterTest("DsizeTestParse04", DsizeTestParse04); + UtRegisterTest("DsizeTestParse05", DsizeTestParse05); + UtRegisterTest("DsizeTestParse06", DsizeTestParse06); + UtRegisterTest("DsizeTestParse07", DsizeTestParse07); + UtRegisterTest("DsizeTestParse08", DsizeTestParse08); + UtRegisterTest("DsizeTestParse09", DsizeTestParse09); + UtRegisterTest("DsizeTestParse10", DsizeTestParse10); + UtRegisterTest("DsizeTestParse11", DsizeTestParse11); + UtRegisterTest("DsizeTestParse12", DsizeTestParse12); + UtRegisterTest("DsizeTestParse13", DsizeTestParse13); + UtRegisterTest("DsizeTestParse14", DsizeTestParse14); + UtRegisterTest("DsizeTestParse15", DsizeTestParse15); + UtRegisterTest("DsizeTestParse16", DsizeTestParse16); + UtRegisterTest("DsizeTestParse17", DsizeTestParse17); + UtRegisterTest("DsizeTestParse18", DsizeTestParse18); + UtRegisterTest("DsizeTestParse19", DsizeTestParse19); + UtRegisterTest("DsizeTestParse20", DsizeTestParse20); + + UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-address-ipv4.c b/src/detect-engine-address-ipv4.c index 20e9e57e5df2..7de2af6a899a 100644 --- a/src/detect-engine-address-ipv4.c +++ b/src/detect-engine-address-ipv4.c @@ -38,7 +38,6 @@ #include "util-error.h" #include "util-debug.h" -#include "util-unittest.h" /** * \brief Compares 2 addresses(address ranges) and returns the relationship @@ -117,7 +116,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, uint32_t a_ip2 = ntohl(a->ip2.addr_data32[0]); uint32_t b_ip1 = ntohl(b->ip.addr_data32[0]); uint32_t b_ip2 = ntohl(b->ip2.addr_data32[0]); - DetectPort *port = NULL; DetectAddress *tmp = NULL; DetectAddress *tmp_c = NULL; int r = 0; @@ -159,19 +157,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; - if (de_ctx != NULL) { - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp_c->cnt += b->cnt; - b->cnt += a->cnt; - } - /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 @@ -195,40 +180,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; - if (de_ctx != NULL) { - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'a' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += tmp->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - } - /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] @@ -257,14 +208,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(a_ip2 + 1); b->ip2.addr_data32[0] = htonl(b_ip2); - if (de_ctx != NULL) { - /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - a->cnt += b->cnt; - } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); @@ -274,26 +217,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); - if (de_ctx != NULL) { - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadClearSigs(a->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, a->port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - } } else { SCLogDebug("3"); @@ -311,40 +234,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; - - if (de_ctx != NULL) { - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'b' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += b->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - } } /* we have 2 or three parts: * @@ -373,28 +262,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(b_ip2 + 1); b->ip2.addr_data32[0] = htonl(a_ip2); - - if (de_ctx != NULL) { - /* 'b' overlaps 'a' so a needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadClearSigs(b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp->port, b->port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &a->port, port); - - tmp->cnt += b->cnt; - b->cnt = 0; - b->cnt += a->cnt; - a->cnt += tmp->cnt; - tmp->cnt = 0; - } } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); @@ -403,16 +270,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); - - if (de_ctx != NULL) { - /* 'a' overlaps 'b' so a needs the 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - b->cnt += a->cnt; - } } else { SCLogDebug("DetectAddressCutIPv4: 3"); @@ -430,22 +287,6 @@ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; - - if (de_ctx != NULL) { - /* 'a' stays the same wrt sigs - * 'b' keeps it's own sigs and gets a's sigs prepended - * 'c' gets 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - - b->cnt += a->cnt; - tmp_c->cnt += a->cnt; - } } } @@ -1597,18 +1438,18 @@ void DetectAddressIPv4Tests(void) { #ifdef UNITTESTS UtRegisterTest("DetectAddressIPv4TestAddressCmp01", - DetectAddressIPv4TestAddressCmp01, 1); + DetectAddressIPv4TestAddressCmp01); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace02", - DetectAddressIPv4IsCompleteIPSpace02, 1); + DetectAddressIPv4IsCompleteIPSpace02); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace03", - DetectAddressIPv4IsCompleteIPSpace03, 1); + DetectAddressIPv4IsCompleteIPSpace03); UtRegisterTest("DetectAddressIPv4IsCompleteIPSpace04", - DetectAddressIPv4IsCompleteIPSpace04, 1); - UtRegisterTest("DetectAddressIPv4CutNot05", DetectAddressIPv4CutNot05, 1); - UtRegisterTest("DetectAddressIPv4CutNot06", DetectAddressIPv4CutNot06, 1); - UtRegisterTest("DetectAddressIPv4CutNot07", DetectAddressIPv4CutNot07, 1); - UtRegisterTest("DetectAddressIPv4CutNot08", DetectAddressIPv4CutNot08, 1); - UtRegisterTest("DetectAddressIPv4CutNot09", DetectAddressIPv4CutNot09, 1); - UtRegisterTest("DetectAddressIPv4Join10", DetectAddressIPv4Join10, 1); + DetectAddressIPv4IsCompleteIPSpace04); + UtRegisterTest("DetectAddressIPv4CutNot05", DetectAddressIPv4CutNot05); + UtRegisterTest("DetectAddressIPv4CutNot06", DetectAddressIPv4CutNot06); + UtRegisterTest("DetectAddressIPv4CutNot07", DetectAddressIPv4CutNot07); + UtRegisterTest("DetectAddressIPv4CutNot08", DetectAddressIPv4CutNot08); + UtRegisterTest("DetectAddressIPv4CutNot09", DetectAddressIPv4CutNot09); + UtRegisterTest("DetectAddressIPv4Join10", DetectAddressIPv4Join10); #endif } diff --git a/src/detect-engine-address-ipv6.c b/src/detect-engine-address-ipv6.c index 84a04d593360..2195ae10df0e 100644 --- a/src/detect-engine-address-ipv6.c +++ b/src/detect-engine-address-ipv6.c @@ -367,7 +367,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, uint32_t b_ip2[4] = { ntohl(b->ip2.addr_data32[0]), ntohl(b->ip2.addr_data32[1]), ntohl(b->ip2.addr_data32[2]), ntohl(b->ip2.addr_data32[3]) }; - DetectPort *port = NULL; DetectAddress *tmp = NULL; /* default to NULL */ @@ -407,19 +406,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, *c = tmp_c; - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &tmp_c->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &b->port, port); - - tmp_c->cnt += b->cnt; - b->cnt += a->cnt; - /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 @@ -442,40 +428,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'a' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp_c->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += tmp->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] @@ -498,14 +450,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(a_ip2, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); - /* 'b' overlaps 'a' so 'a' needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - a->cnt += b->cnt; - } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -513,24 +457,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6Copy(a_ip1, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadClearSigs(a->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, a->port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } else { AddressCutIPv6Copy(b_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(a_ip1, a->ip2.addr_data32); @@ -548,39 +474,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6Copy(b_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - /* 'a' gets clean and then 'b' sigs - * 'b' gets clean, then 'a' then 'b' sigs - * 'c' gets 'b' sigs */ - /* store old a list */ - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp->sh); - /* clean a list */ - SigGroupHeadClearSigs(a->sh); - /* copy old b to c */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp_c->sh); - /* copy old b to a */ - SigGroupHeadCopySigs(de_ctx, b->sh, &a->sh); - /* prepend old a before b */ - SigGroupHeadCopySigs(de_ctx, tmp->sh, &b->sh); - - /* clean tmp list */ - SigGroupHeadClearSigs(tmp->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp_c->port, port); - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += b->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } /* we have 2 or three parts: * @@ -603,40 +496,12 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(b_ip2, b->ip.addr_data32); AddressCutIPv6Copy(a_ip2, b->ip2.addr_data32); - - /* 'b' overlaps 'a' so a needs the 'b' sigs */ - SigGroupHeadCopySigs(de_ctx, b->sh, &tmp->sh); - SigGroupHeadClearSigs(b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, tmp->sh, &a->sh); - SigGroupHeadClearSigs(tmp->sh); - - for (port = b->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp->port, b->port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - for (port = tmp->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&a->port, port); - - tmp->cnt += b->cnt; - b->cnt = 0; - b->cnt += a->cnt; - a->cnt += tmp->cnt; - tmp->cnt = 0; } else if (AddressIPv6EqU32(a_ip2, b_ip2) == 1) { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); AddressCutIPv6Copy(b_ip1, b->ip.addr_data32); AddressCutIPv6Copy(b_ip2, b->ip2.addr_data32); - - /* 'a' overlaps 'b' so a needs the 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - - b->cnt += a->cnt; } else { AddressCutIPv6Copy(a_ip1, a->ip.addr_data32); AddressCutIPv6CopySubOne(b_ip1, a->ip2.addr_data32); @@ -653,20 +518,6 @@ int DetectAddressCutIPv6(DetectEngineCtx *de_ctx, DetectAddress *a, AddressCutIPv6CopyAddOne(b_ip2, tmp_c->ip.addr_data32); AddressCutIPv6Copy(a_ip2, tmp_c->ip2.addr_data32); *c = tmp_c; - - /* 'a' stays the same wrt sigs - * 'b' keeps it's own sigs and gets a's sigs prepended - * 'c' gets 'a' sigs */ - SigGroupHeadCopySigs(de_ctx, a->sh, &b->sh); - SigGroupHeadCopySigs(de_ctx, a->sh, &tmp_c->sh); - - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&b->port, port); - for (port = a->port; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx,&tmp_c->port, port); - - b->cnt += a->cnt; - tmp_c->cnt += a->cnt; } } @@ -2230,49 +2081,48 @@ void DetectAddressIPv6Tests(void) { #ifdef UNITTESTS - UtRegisterTest("AddressTestIPv6Gt01", AddressTestIPv6Gt01, 1); - UtRegisterTest("AddressTestIPv6Gt02", AddressTestIPv6Gt02, 1); - UtRegisterTest("AddressTestIPv6Gt03", AddressTestIPv6Gt03, 1); - UtRegisterTest("AddressTestIPv6Gt04", AddressTestIPv6Gt04, 1); - - UtRegisterTest("AddressTestIPv6Lt01", AddressTestIPv6Lt01, 1); - UtRegisterTest("AddressTestIPv6Lt02", AddressTestIPv6Lt02, 1); - UtRegisterTest("AddressTestIPv6Lt03", AddressTestIPv6Lt03, 1); - UtRegisterTest("AddressTestIPv6Lt04", AddressTestIPv6Lt04, 1); - - UtRegisterTest("AddressTestIPv6Eq01", AddressTestIPv6Eq01, 1); - UtRegisterTest("AddressTestIPv6Eq02", AddressTestIPv6Eq02, 1); - UtRegisterTest("AddressTestIPv6Eq03", AddressTestIPv6Eq03, 1); - UtRegisterTest("AddressTestIPv6Eq04", AddressTestIPv6Eq04, 1); - - UtRegisterTest("AddressTestIPv6Le01", AddressTestIPv6Le01, 1); - UtRegisterTest("AddressTestIPv6Le02", AddressTestIPv6Le02, 1); - UtRegisterTest("AddressTestIPv6Le03", AddressTestIPv6Le03, 1); - UtRegisterTest("AddressTestIPv6Le04", AddressTestIPv6Le04, 1); - UtRegisterTest("AddressTestIPv6Le05", AddressTestIPv6Le05, 1); - - UtRegisterTest("AddressTestIPv6Ge01", AddressTestIPv6Ge01, 1); - UtRegisterTest("AddressTestIPv6Ge02", AddressTestIPv6Ge02, 1); - UtRegisterTest("AddressTestIPv6Ge03", AddressTestIPv6Ge03, 1); - UtRegisterTest("AddressTestIPv6Ge04", AddressTestIPv6Ge04, 1); - UtRegisterTest("AddressTestIPv6Ge05", AddressTestIPv6Ge05, 1); - - UtRegisterTest("AddressTestIPv6SubOne01", AddressTestIPv6SubOne01, 1); - UtRegisterTest("AddressTestIPv6SubOne02", AddressTestIPv6SubOne02, 1); - - UtRegisterTest("AddressTestIPv6AddOne01", AddressTestIPv6AddOne01, 1); - UtRegisterTest("AddressTestIPv6AddOne02", AddressTestIPv6AddOne02, 1); - - UtRegisterTest("AddressTestIPv6AddressCmp01", - AddressTestIPv6AddressCmp01, 1); - - UtRegisterTest("AddressTestIPv6CutNot01", AddressTestIPv6CutNot01, 1); - UtRegisterTest("AddressTestIPv6CutNot02", AddressTestIPv6CutNot02, 1); - UtRegisterTest("AddressTestIPv6CutNot03", AddressTestIPv6CutNot03, 1); - UtRegisterTest("AddressTestIPv6CutNot04", AddressTestIPv6CutNot04, 1); - UtRegisterTest("AddressTestIPv6CutNot05", AddressTestIPv6CutNot05, 1); - - UtRegisterTest("AddressTestIPv6Join01", AddressTestIPv6Join01, 1); + UtRegisterTest("AddressTestIPv6Gt01", AddressTestIPv6Gt01); + UtRegisterTest("AddressTestIPv6Gt02", AddressTestIPv6Gt02); + UtRegisterTest("AddressTestIPv6Gt03", AddressTestIPv6Gt03); + UtRegisterTest("AddressTestIPv6Gt04", AddressTestIPv6Gt04); + + UtRegisterTest("AddressTestIPv6Lt01", AddressTestIPv6Lt01); + UtRegisterTest("AddressTestIPv6Lt02", AddressTestIPv6Lt02); + UtRegisterTest("AddressTestIPv6Lt03", AddressTestIPv6Lt03); + UtRegisterTest("AddressTestIPv6Lt04", AddressTestIPv6Lt04); + + UtRegisterTest("AddressTestIPv6Eq01", AddressTestIPv6Eq01); + UtRegisterTest("AddressTestIPv6Eq02", AddressTestIPv6Eq02); + UtRegisterTest("AddressTestIPv6Eq03", AddressTestIPv6Eq03); + UtRegisterTest("AddressTestIPv6Eq04", AddressTestIPv6Eq04); + + UtRegisterTest("AddressTestIPv6Le01", AddressTestIPv6Le01); + UtRegisterTest("AddressTestIPv6Le02", AddressTestIPv6Le02); + UtRegisterTest("AddressTestIPv6Le03", AddressTestIPv6Le03); + UtRegisterTest("AddressTestIPv6Le04", AddressTestIPv6Le04); + UtRegisterTest("AddressTestIPv6Le05", AddressTestIPv6Le05); + + UtRegisterTest("AddressTestIPv6Ge01", AddressTestIPv6Ge01); + UtRegisterTest("AddressTestIPv6Ge02", AddressTestIPv6Ge02); + UtRegisterTest("AddressTestIPv6Ge03", AddressTestIPv6Ge03); + UtRegisterTest("AddressTestIPv6Ge04", AddressTestIPv6Ge04); + UtRegisterTest("AddressTestIPv6Ge05", AddressTestIPv6Ge05); + + UtRegisterTest("AddressTestIPv6SubOne01", AddressTestIPv6SubOne01); + UtRegisterTest("AddressTestIPv6SubOne02", AddressTestIPv6SubOne02); + + UtRegisterTest("AddressTestIPv6AddOne01", AddressTestIPv6AddOne01); + UtRegisterTest("AddressTestIPv6AddOne02", AddressTestIPv6AddOne02); + + UtRegisterTest("AddressTestIPv6AddressCmp01", AddressTestIPv6AddressCmp01); + + UtRegisterTest("AddressTestIPv6CutNot01", AddressTestIPv6CutNot01); + UtRegisterTest("AddressTestIPv6CutNot02", AddressTestIPv6CutNot02); + UtRegisterTest("AddressTestIPv6CutNot03", AddressTestIPv6CutNot03); + UtRegisterTest("AddressTestIPv6CutNot04", AddressTestIPv6CutNot04); + UtRegisterTest("AddressTestIPv6CutNot05", AddressTestIPv6CutNot05); + + UtRegisterTest("AddressTestIPv6Join01", AddressTestIPv6Join01); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-address.c b/src/detect-engine-address.c index 51385bba5aca..079ec36dc005 100644 --- a/src/detect-engine-address.c +++ b/src/detect-engine-address.c @@ -45,6 +45,7 @@ #include "util-debug.h" #include "util-print.h" +#include "util-var.h" /* prototypes */ void DetectAddressPrint(DetectAddress *); @@ -53,18 +54,6 @@ static int DetectAddressCut(DetectEngineCtx *, DetectAddress *, DetectAddress *, DetectAddress **); int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn); -/** memory usage counters - * \todo not MT safe */ -#ifdef DEBUG -static uint32_t detect_address_group_memory = 0; -static uint32_t detect_address_group_init_cnt = 0; -static uint32_t detect_address_group_free_cnt = 0; - -static uint32_t detect_address_group_head_memory = 0; -static uint32_t detect_address_group_head_init_cnt = 0; -static uint32_t detect_address_group_head_free_cnt = 0; -#endif - /** * \brief Creates and returns a new instance of a DetectAddress. * @@ -78,11 +67,6 @@ DetectAddress *DetectAddressInit(void) return NULL; memset(ag, 0, sizeof(DetectAddress)); -#ifdef DEBUG - detect_address_group_memory += sizeof(DetectAddress); - detect_address_group_init_cnt++; -#endif - return ag; } @@ -96,36 +80,6 @@ void DetectAddressFree(DetectAddress *ag) if (ag == NULL) return; - SCLogDebug("ag %p, sh %p", ag, ag->sh); - - /* only free the head if we have the original */ - if (ag->sh != NULL && !(ag->flags & ADDRESS_SIGGROUPHEAD_COPY)) { - SCLogDebug("- ag %p, sh %p not a copy, so call SigGroupHeadFree", ag, - ag->sh); - SigGroupHeadFree(ag->sh); - } - ag->sh = NULL; - - if (!(ag->flags & ADDRESS_HAVEPORT)) { - SCLogDebug("- ag %p dst_gh %p", ag, ag->dst_gh); - - if (ag->dst_gh != NULL) - DetectAddressHeadFree(ag->dst_gh); - ag->dst_gh = NULL; - } else { - SCLogDebug("- ag %p port %p", ag, ag->port); - - if (ag->port != NULL && !(ag->flags & ADDRESS_PORTS_COPY)) { - SCLogDebug("- ag %p port %p, not a copy so call DetectPortCleanupList", - ag, ag->port); - DetectPortCleanupList(ag->port); - } - ag->port = NULL; - } -#ifdef DEBUG - detect_address_group_memory -= sizeof(DetectAddress); - detect_address_group_free_cnt++; -#endif SCFree(ag); return; @@ -152,47 +106,9 @@ DetectAddress *DetectAddressCopy(DetectAddress *orig) COPY_ADDRESS(&orig->ip, &ag->ip); COPY_ADDRESS(&orig->ip2, &ag->ip2); - ag->cnt = 1; - return ag; } -/** - * \brief Prints the memory statistics for the detection-engine-address section. - */ -void DetectAddressPrintMemory(void) -{ -#ifdef DEBUG - SCLogDebug(" * Address group memory stats (DetectAddress %" PRIuMAX "):", - (uintmax_t)sizeof(DetectAddress)); - SCLogDebug(" - detect_address_group_memory %" PRIu32, - detect_address_group_memory); - SCLogDebug(" - detect_address_group_init_cnt %" PRIu32, - detect_address_group_init_cnt); - SCLogDebug(" - detect_address_group_free_cnt %" PRIu32, - detect_address_group_free_cnt); - SCLogDebug(" - outstanding groups %" PRIu32, - detect_address_group_init_cnt - detect_address_group_free_cnt); - SCLogDebug(" * Address group memory stats done"); - SCLogDebug(" * Address group head memory stats (DetectAddressHead %" PRIuMAX "):", - (uintmax_t)sizeof(DetectAddressHead)); - SCLogDebug(" - detect_address_group_head_memory %" PRIu32, - detect_address_group_head_memory); - SCLogDebug(" - detect_address_group_head_init_cnt %" PRIu32, - detect_address_group_head_init_cnt); - SCLogDebug(" - detect_address_group_head_free_cnt %" PRIu32, - detect_address_group_head_free_cnt); - SCLogDebug(" - outstanding groups %" PRIu32, - (detect_address_group_head_init_cnt - - detect_address_group_head_free_cnt)); - SCLogDebug(" * Address group head memory stats done"); - SCLogDebug(" X Total %" PRIu32 "\n", (detect_address_group_memory + - detect_address_group_head_memory)); -#endif - - return; -} - /** * \brief Used to check if a DetectAddress list contains an instance with * a similar DetectAddress. The comparison done is not the one that @@ -233,7 +149,6 @@ void DetectAddressPrintList(DetectAddress *head) SCLogInfo("list:"); if (head != NULL) { for (cur = head; cur != NULL; cur = cur->next) { - SCLogInfo("SIGS %6u ", cur->sh ? cur->sh->sig_cnt : 0); DetectAddressPrint(cur); } } @@ -406,13 +321,7 @@ int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, if (r == ADDRESS_EQ) { /* exact overlap/match */ if (cur != new) { - DetectPort *port = new->port; - for ( ; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &cur->port, port); - SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); - cur->cnt += new->cnt; DetectAddressFree(new); - return 0; } @@ -522,21 +431,12 @@ int DetectAddressInsert(DetectEngineCtx *de_ctx, DetectAddressHead *gh, int DetectAddressJoin(DetectEngineCtx *de_ctx, DetectAddress *target, DetectAddress *source) { - DetectPort *port = NULL; - if (target == NULL || source == NULL) return -1; if (target->ip.family != source->ip.family) return -1; - target->cnt += source->cnt; - SigGroupHeadCopySigs(de_ctx, source->sh, &target->sh); - - port = source->port; - for ( ; port != NULL; port = port->next) - DetectPortInsertCopy(de_ctx, &target->port, port); - if (target->ip.family == AF_INET) return DetectAddressJoinIPv4(de_ctx, target, source); else if (target->ip.family == AF_INET6) @@ -709,12 +609,16 @@ int DetectAddressParseString(DetectAddress *dd, char *str) ip[mask - ip] = '\0'; mask++; + int cidr = atoi(mask); + if (cidr < 0 || cidr > 128) + goto error; + r = inet_pton(AF_INET6, ip, &in6); if (r <= 0) goto error; memcpy(&ip6addr, &in6.s6_addr, sizeof(ip6addr)); - DetectAddressParseIPv6CIDR(atoi(mask), &mask6); + DetectAddressParseIPv6CIDR(cidr, &mask6); memcpy(&netmask, &mask6.s6_addr, sizeof(netmask)); dd->ip2.addr_data32[0] = dd->ip.addr_data32[0] = ip6addr[0] & netmask[0]; @@ -903,14 +807,15 @@ int DetectAddressSetup(DetectAddressHead *gh, char *s) * that are negated. * \param s Pointer to the character string holding the address to be * parsed. - * \param negate Flag that indicates if the receieved address string is negated + * \param negate Flag that indicates if the received address string is negated * or not. 0 if it is not, 1 it it is. * * \retval 0 On successfully parsing. * \retval -1 On failure. */ -int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, - int negate) +static int DetectAddressParse2(const DetectEngineCtx *de_ctx, + DetectAddressHead *gh, DetectAddressHead *ghn, + const char *s, int negate, ResolvedVariablesList *var_list) { size_t x = 0; size_t u = 0; @@ -951,7 +856,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, /* normal block */ SCLogDebug("normal block"); - if (DetectAddressParse2(gh, ghn, address, (negate + n_set) % 2) < 0) + if (DetectAddressParse2(de_ctx, gh, ghn, address, (negate + n_set) % 2, var_list) < 0) goto error; } else { /* negated block @@ -964,7 +869,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, DetectAddressHead tmp_gh = { NULL, NULL, NULL }; DetectAddressHead tmp_ghn = { NULL, NULL, NULL }; - if (DetectAddressParse2(&tmp_gh, &tmp_ghn, address, 0) < 0) + if (DetectAddressParse2(de_ctx, &tmp_gh, &tmp_ghn, address, 0, var_list) < 0) goto error; DetectAddress *tmp_ad; @@ -1028,10 +933,11 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, } else if (d_set == 1) { address[x - 1] = '\0'; - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; + if (strlen(rule_var_address) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " @@ -1039,6 +945,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, "\"!$HOME_NET\" instead of !$HOME_NET. See issue #295.", s); goto error; } + SCLogDebug("rule_var_address %s", rule_var_address); temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { @@ -1048,8 +955,15 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - DetectAddressParse2(gh, ghn, temp_rule_var_address, - (negate + n_set) % 2); + + + if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, + (negate + n_set) % 2, var_list) < 0) + { + if (temp_rule_var_address != rule_var_address) + SCFree(temp_rule_var_address); + goto error; + } d_set = 0; n_set = 0; if (temp_rule_var_address != rule_var_address) @@ -1079,11 +993,18 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, } x = 0; + if (AddVariableToResolveList(var_list, address) == -1) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a address " + "groups declaration. This is likely a misconfiguration."); + goto error; + } + if (d_set == 1) { - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; + if (strlen(rule_var_address) == 0) { SCLogError(SC_ERR_INVALID_SIGNATURE, "variable %s resolved " "to nothing. This is likely a misconfiguration. " @@ -1091,6 +1012,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, "\"!$HOME_NET\" instead of !$HOME_NET. See issue #295.", s); goto error; } + SCLogDebug("rule_var_address %s", rule_var_address); temp_rule_var_address = rule_var_address; if ((negate + n_set) % 2) { @@ -1100,9 +1022,12 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - if (DetectAddressParse2(gh, ghn, temp_rule_var_address, - (negate + n_set) % 2) < 0) { + + if (DetectAddressParse2(de_ctx, gh, ghn, temp_rule_var_address, + (negate + n_set) % 2, var_list) < 0) { SCLogDebug("DetectAddressParse2 hates us"); + if (temp_rule_var_address != rule_var_address) + SCFree(temp_rule_var_address); goto error; } d_set = 0; @@ -1141,6 +1066,7 @@ int DetectAddressParse2(DetectAddressHead *gh, DetectAddressHead *ghn, char *s, return 0; error: + return -1; } @@ -1325,7 +1251,6 @@ int DetectAddressMergeNot(DetectAddressHead *gh, DetectAddressHead *ghn) #endif if (ghn->ipv4_head != NULL || ghn->ipv6_head != NULL) { int cnt = 0; - DetectAddress *ad; for (ad = ghn->ipv4_head; ad; ad = ad->next) cnt++; @@ -1363,6 +1288,8 @@ int DetectAddressTestConfVars(void) { SCLogDebug("Testing address conf vars for any misconfigured values"); + ResolvedVariablesList var_list = TAILQ_HEAD_INITIALIZER(var_list); + ConfNode *address_vars_node = ConfGetNode("vars.address-groups"); if (address_vars_node == NULL) { return 0; @@ -1389,7 +1316,10 @@ int DetectAddressTestConfVars(void) goto error; } - int r = DetectAddressParse2(gh, ghn, seq_node->val, /* start with negate no */0); + int r = DetectAddressParse2(NULL, gh, ghn, seq_node->val, /* start with negate no */0, &var_list); + + CleanVariableResolveList(&var_list); + if (r < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "failed to parse address var \"%s\" with value \"%s\". " @@ -1417,6 +1347,98 @@ int DetectAddressTestConfVars(void) return -1; } +#include "util-hash-lookup3.h" + +typedef struct DetectAddressMap_ { + char *string; + DetectAddressHead *address; +} DetectAddressMap; + +static uint32_t DetectAddressMapHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + const DetectAddressMap *map = (DetectAddressMap *)data; + uint32_t hash = 0; + + hash = hashlittle_safe(map->string, strlen(map->string), 0); + hash %= ht->array_size; + + return hash; +} + +static char DetectAddressMapCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + DetectAddressMap *map1 = (DetectAddressMap *)data1; + DetectAddressMap *map2 = (DetectAddressMap *)data2; + + + int r = (strcmp(map1->string, map2->string) == 0); + return r; +} + +static void DetectAddressMapFreeFunc(void *data) +{ + DetectAddressMap *map = (DetectAddressMap *)data; + if (map != NULL) { + DetectAddressHeadFree(map->address); + SCFree(map->string); + } + SCFree(map); +} + +int DetectAddressMapInit(DetectEngineCtx *de_ctx) +{ + de_ctx->address_table = HashListTableInit(4096, DetectAddressMapHashFunc, + DetectAddressMapCompareFunc, + DetectAddressMapFreeFunc); + if (de_ctx->address_table == NULL) + return -1; + + return 0; +} + +void DetectAddressMapFree(DetectEngineCtx *de_ctx) +{ + if (de_ctx->address_table == NULL) + return; + + HashListTableFree(de_ctx->address_table); + de_ctx->address_table = NULL; + return; +} + +int DetectAddressMapAdd(DetectEngineCtx *de_ctx, const char *string, + DetectAddressHead *address) +{ + DetectAddressMap *map = SCCalloc(1, sizeof(*map)); + if (map == NULL) + return -1; + + map->string = SCStrdup(string); + if (map->string == NULL) { + SCFree(map); + return -1; + } + map->address = address; + + BUG_ON(HashListTableAdd(de_ctx->address_table, (void *)map, 0) != 0); + return 0; +} + +const DetectAddressHead *DetectAddressMapLookup(DetectEngineCtx *de_ctx, + const char *string) +{ + DetectAddressMap map = { (char *)string, NULL }; + + const DetectAddressMap *res = HashListTableLookup(de_ctx->address_table, + &map, 0); + if (res == NULL) + return NULL; + else { + return (const DetectAddressHead *)res->address; + } +} + /** * \brief Parses an address group sent as a character string and updates the * DetectAddressHead sent as the argument with the relevant address @@ -1429,7 +1451,8 @@ int DetectAddressTestConfVars(void) * \retval 0 On success. * \retval -1 On failure. */ -int DetectAddressParse(DetectAddressHead *gh, char *str) +int DetectAddressParse(const DetectEngineCtx *de_ctx, + DetectAddressHead *gh, const char *str) { int r; DetectAddressHead *ghn = NULL; @@ -1447,7 +1470,7 @@ int DetectAddressParse(DetectAddressHead *gh, char *str) goto error; } - r = DetectAddressParse2(gh, ghn, str, /* start with negate no */0); + r = DetectAddressParse2(de_ctx, gh, ghn, str, /* start with negate no */0, NULL); if (r < 0) { SCLogDebug("DetectAddressParse2 returned %d", r); goto error; @@ -1472,6 +1495,31 @@ int DetectAddressParse(DetectAddressHead *gh, char *str) return -1; } +const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, + const char *string) +{ + const DetectAddressHead *h = DetectAddressMapLookup(de_ctx, string); + if (h != NULL) { + SCLogDebug("found: %s :: %p", string, h); + return h; + } + + SCLogDebug("%s not found", string); + + DetectAddressHead *head = DetectAddressHeadInit(); + if (head == NULL) + return NULL; + + if (DetectAddressParse(de_ctx, head, string) == -1) + { + DetectAddressHeadFree(head); + return NULL; + } + + DetectAddressMapAdd((DetectEngineCtx *)de_ctx, string, head); + return head; +} + /** * \brief Returns a new instance of DetectAddressHead. * @@ -1484,11 +1532,6 @@ DetectAddressHead *DetectAddressHeadInit(void) return NULL; memset(gh, 0, sizeof(DetectAddressHead)); -#ifdef DEBUG - detect_address_group_head_init_cnt++; - detect_address_group_head_memory += sizeof(DetectAddressHead); -#endif - return gh; } @@ -1530,10 +1573,6 @@ void DetectAddressHeadFree(DetectAddressHead *gh) if (gh != NULL) { DetectAddressHeadCleanup(gh); SCFree(gh); -#ifdef DEBUG - detect_address_group_head_free_cnt++; - detect_address_group_head_memory -= sizeof(DetectAddressHead); -#endif } return; @@ -1858,7 +1897,7 @@ void DetectAddressPrint(DetectAddress *gr) * \retval g On success pointer to an DetectAddress if we find a match * for the Address "a", in the DetectAddressHead "gh". */ -DetectAddress *DetectAddressLookupInHead(DetectAddressHead *gh, Address *a) +DetectAddress *DetectAddressLookupInHead(const DetectAddressHead *gh, Address *a) { SCEnter(); @@ -3164,7 +3203,7 @@ int AddressTestAddressGroupSetup01(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0) result = 1; @@ -3179,7 +3218,7 @@ int AddressTestAddressGroupSetup02(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) result = 1; @@ -3194,11 +3233,11 @@ int AddressTestAddressGroupSetup03(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.3"); + r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { result = 1; @@ -3216,18 +3255,18 @@ int AddressTestAddressGroupSetup04(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "1.2.3.4"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.3"); + r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head != prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { - DetectAddress *prev_head = gh->ipv4_head; + DetectAddress *ph = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.2"); - if (r == 0 && gh->ipv4_head != prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next == prev_head) { + r = DetectAddressParse(NULL, gh, "1.2.3.2"); + if (r == 0 && gh->ipv4_head != ph && + gh->ipv4_head != NULL && gh->ipv4_head->next == ph) { result = 1; } } @@ -3244,18 +3283,18 @@ int AddressTestAddressGroupSetup05(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.2"); + int r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.3"); + r = DetectAddressParse(NULL, gh, "1.2.3.3"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { - DetectAddress *prev_head = gh->ipv4_head; + DetectAddress *ph = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.4"); - if (r == 0 && gh->ipv4_head == prev_head && - gh->ipv4_head != NULL && gh->ipv4_head->next != prev_head) { + r = DetectAddressParse(NULL, gh, "1.2.3.4"); + if (r == 0 && gh->ipv4_head == ph && + gh->ipv4_head != NULL && gh->ipv4_head->next != ph) { result = 1; } } @@ -3272,11 +3311,11 @@ int AddressTestAddressGroupSetup06(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "1.2.3.2"); + int r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head != NULL) { DetectAddress *prev_head = gh->ipv4_head; - r = DetectAddressParse(gh, "1.2.3.2"); + r = DetectAddressParse(NULL, gh, "1.2.3.2"); if (r == 0 && gh->ipv4_head == prev_head && gh->ipv4_head != NULL && gh->ipv4_head->next == NULL) { result = 1; @@ -3294,9 +3333,9 @@ int AddressTestAddressGroupSetup07(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.0.0.0/8"); + int r = DetectAddressParse(NULL, gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.10.10.10"); + r = DetectAddressParse(NULL, gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3315,9 +3354,9 @@ int AddressTestAddressGroupSetup08(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.0.0.0/8"); + r = DetectAddressParse(NULL, gh, "10.0.0.0/8"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3336,9 +3375,9 @@ int AddressTestAddressGroupSetup09(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.0/24"); + int r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3357,9 +3396,9 @@ int AddressTestAddressGroupSetup10(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0 && gh->ipv4_head != NULL) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0 && gh->ipv4_head != NULL && gh->ipv4_head->next != NULL && gh->ipv4_head->next->next != NULL) { @@ -3378,11 +3417,11 @@ int AddressTestAddressGroupSetup11(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { - r = DetectAddressParse(gh, "0.0.0.0/0"); + r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, @@ -3417,11 +3456,11 @@ int AddressTestAddressGroupSetup12 (void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + int r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0) { - r = DetectAddressParse(gh, "0.0.0.0/0"); + r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, @@ -3456,11 +3495,11 @@ int AddressTestAddressGroupSetup13(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "0.0.0.0/0"); + int r = DetectAddressParse(NULL, gh, "0.0.0.0/0"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.10-10.10.11.1"); + r = DetectAddressParse(NULL, gh, "10.10.10.10-10.10.11.1"); if (r == 0) { - r = DetectAddressParse(gh, "10.10.10.0/24"); + r = DetectAddressParse(NULL, gh, "10.10.10.0/24"); if (r == 0) { DetectAddress *one = gh->ipv4_head, *two = one->next, *three = two->next, *four = three->next, @@ -3495,7 +3534,7 @@ int AddressTestAddressGroupSetupIPv414(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "!1.2.3.4"); + int r = DetectAddressParse(NULL, gh, "!1.2.3.4"); if (r == 0) { DetectAddress *one = gh->ipv4_head; DetectAddress *two = one ? one->next : NULL; @@ -3529,7 +3568,7 @@ int AddressTestAddressGroupSetupIPv415(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "!0.0.0.0"); + int r = DetectAddressParse(NULL, gh, "!0.0.0.0"); if (r == 0) { DetectAddress *one = gh->ipv4_head; @@ -3553,7 +3592,7 @@ int AddressTestAddressGroupSetupIPv416(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "!255.255.255.255"); + int r = DetectAddressParse(NULL, gh, "!255.255.255.255"); if (r == 0) { DetectAddress *one = gh->ipv4_head; @@ -3577,7 +3616,7 @@ int AddressTestAddressGroupSetup14(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::1"); + int r = DetectAddressParse(NULL, gh, "2001::1"); if (r == 0) result = 1; @@ -3592,7 +3631,7 @@ int AddressTestAddressGroupSetup15(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::1"); + int r = DetectAddressParse(NULL, gh, "2001::1"); if (r == 0 && gh->ipv6_head != NULL) result = 1; @@ -3607,11 +3646,11 @@ int AddressTestAddressGroupSetup16(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4"); + int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::3"); + r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { result = 1; @@ -3629,18 +3668,18 @@ int AddressTestAddressGroupSetup17(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4"); + int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::3"); + r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head != prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { - DetectAddress *prev_head = gh->ipv6_head; + DetectAddress *ph = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::2"); - if (r == 0 && gh->ipv6_head != prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next == prev_head) { + r = DetectAddressParse(NULL, gh, "2001::2"); + if (r == 0 && gh->ipv6_head != ph && + gh->ipv6_head != NULL && gh->ipv6_head->next == ph) { result = 1; } } @@ -3657,18 +3696,18 @@ int AddressTestAddressGroupSetup18(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::2"); + int r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::3"); + r = DetectAddressParse(NULL, gh, "2001::3"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { - DetectAddress *prev_head = gh->ipv6_head; + DetectAddress *ph = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::4"); - if (r == 0 && gh->ipv6_head == prev_head && - gh->ipv6_head != NULL && gh->ipv6_head->next != prev_head) { + r = DetectAddressParse(NULL, gh, "2001::4"); + if (r == 0 && gh->ipv6_head == ph && + gh->ipv6_head != NULL && gh->ipv6_head->next != ph) { result = 1; } } @@ -3685,11 +3724,11 @@ int AddressTestAddressGroupSetup19(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::2"); + int r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head != NULL) { DetectAddress *prev_head = gh->ipv6_head; - r = DetectAddressParse(gh, "2001::2"); + r = DetectAddressParse(NULL, gh, "2001::2"); if (r == 0 && gh->ipv6_head == prev_head && gh->ipv6_head != NULL && gh->ipv6_head->next == NULL) { result = 1; @@ -3707,9 +3746,9 @@ int AddressTestAddressGroupSetup20(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2000::/3"); + int r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2001::4"); + r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3728,9 +3767,9 @@ int AddressTestAddressGroupSetup21(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4"); + int r = DetectAddressParse(NULL, gh, "2001::4"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2000::/3"); + r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3749,9 +3788,9 @@ int AddressTestAddressGroupSetup22(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2000::/3"); + int r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2001::4-2001::6"); + r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3770,9 +3809,9 @@ int AddressTestAddressGroupSetup23(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4-2001::6"); + int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0 && gh->ipv6_head != NULL) { - r = DetectAddressParse(gh, "2000::/3"); + r = DetectAddressParse(NULL, gh, "2000::/3"); if (r == 0 && gh->ipv6_head != NULL && gh->ipv6_head->next != NULL && gh->ipv6_head->next->next != NULL) { @@ -3791,11 +3830,11 @@ int AddressTestAddressGroupSetup24(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4-2001::6"); + int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0) { - r = DetectAddressParse(gh, "2001::/3"); + r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { - r = DetectAddressParse(gh, "::/0"); + r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, @@ -3861,11 +3900,11 @@ int AddressTestAddressGroupSetup25(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "2001::4-2001::6"); + int r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0) { - r = DetectAddressParse(gh, "::/0"); + r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { - r = DetectAddressParse(gh, "2001::/3"); + r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, @@ -3931,11 +3970,11 @@ int AddressTestAddressGroupSetup26(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "::/0"); + int r = DetectAddressParse(NULL, gh, "::/0"); if (r == 0) { - r = DetectAddressParse(gh, "2001::4-2001::6"); + r = DetectAddressParse(NULL, gh, "2001::4-2001::6"); if (r == 0) { - r = DetectAddressParse(gh, "2001::/3"); + r = DetectAddressParse(NULL, gh, "2001::/3"); if (r == 0) { DetectAddress *one = gh->ipv6_head, *two = one->next, *three = two->next, *four = three->next, @@ -4001,7 +4040,7 @@ int AddressTestAddressGroupSetup27(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.2.3.4]"); + int r = DetectAddressParse(NULL, gh, "[1.2.3.4]"); if (r == 0) result = 1; @@ -4016,7 +4055,7 @@ int AddressTestAddressGroupSetup28(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.2.3.4,4.3.2.1]"); + int r = DetectAddressParse(NULL, gh, "[1.2.3.4,4.3.2.1]"); if (r == 0) result = 1; @@ -4031,7 +4070,7 @@ int AddressTestAddressGroupSetup29(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.2.3.4,4.3.2.1,10.10.10.10]"); + int r = DetectAddressParse(NULL, gh, "[1.2.3.4,4.3.2.1,10.10.10.10]"); if (r == 0) result = 1; @@ -4046,7 +4085,7 @@ int AddressTestAddressGroupSetup30(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); + int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,2.3.4.5],4.3.2.1,[10.10.10.10,11.11.11.11]]"); if (r == 0) result = 1; @@ -4061,7 +4100,7 @@ int AddressTestAddressGroupSetup31(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); + int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,[2.3.4.5,3.4.5.6]],4.3.2.1,[10.10.10.10,[11.11.11.11,12.12.12.12]]]"); if (r == 0) result = 1; @@ -4076,7 +4115,7 @@ int AddressTestAddressGroupSetup32(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12.12.12,13.13.13.13]]]]"); + int r = DetectAddressParse(NULL, gh, "[[1.2.3.4,[2.3.4.5,[3.4.5.6,4.5.6.7]]],4.3.2.1,[10.10.10.10,[11.11.11.11,[12.12.12.12,13.13.13.13]]]]"); if (r == 0) result = 1; @@ -4091,7 +4130,7 @@ int AddressTestAddressGroupSetup33(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "![1.1.1.1,[2.2.2.2,[3.3.3.3,4.4.4.4]]]"); + int r = DetectAddressParse(NULL, gh, "![1.1.1.1,[2.2.2.2,[3.3.3.3,4.4.4.4]]]"); if (r == 0) result = 1; @@ -4106,7 +4145,7 @@ int AddressTestAddressGroupSetup34(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.0.0.0/8,![1.1.1.1,[1.2.1.1,1.3.1.1]]]"); + int r = DetectAddressParse(NULL, gh, "[1.0.0.0/8,![1.1.1.1,[1.2.1.1,1.3.1.1]]]"); if (r == 0) result = 1; @@ -4121,7 +4160,7 @@ int AddressTestAddressGroupSetup35(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.0.0.0/8,[2.0.0.0/8,![1.1.1.1,2.2.2.2]]]"); + int r = DetectAddressParse(NULL, gh, "[1.0.0.0/8,[2.0.0.0/8,![1.1.1.1,2.2.2.2]]]"); if (r == 0) result = 1; @@ -4136,7 +4175,7 @@ int AddressTestAddressGroupSetup36 (void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[1.0.0.0/8,[2.0.0.0/8,[3.0.0.0/8,!1.1.1.1]]]"); + int r = DetectAddressParse(NULL, gh, "[1.0.0.0/8,[2.0.0.0/8,[3.0.0.0/8,!1.1.1.1]]]"); if (r == 0) result = 1; @@ -4151,7 +4190,7 @@ int AddressTestAddressGroupSetup37(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[0.0.0.0/0,::/0]"); + int r = DetectAddressParse(NULL, gh, "[0.0.0.0/0,::/0]"); if (r == 0) result = 1; @@ -4170,7 +4209,7 @@ static int AddressTestAddressGroupSetup38(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "![192.168.0.0/16,!192.168.14.0/24]"); + int r = DetectAddressParse(NULL, gh, "![192.168.0.0/16,!192.168.14.0/24]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4191,7 +4230,7 @@ static int AddressTestAddressGroupSetup39(void) DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,!192.168.14.0/24]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,!192.168.14.0/24]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4211,7 +4250,7 @@ static int AddressTestAddressGroupSetup40(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,[!192.168.14.0/24]]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,[!192.168.14.0/24]]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4231,7 +4270,7 @@ static int AddressTestAddressGroupSetup41(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,![192.168.14.0/24]]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.14.0/24]]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 3, expectations) == TRUE) result = 1; @@ -4249,7 +4288,7 @@ static int AddressTestAddressGroupSetup42(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[2001::/3]"); + int r = DetectAddressParse(NULL, gh, "[2001::/3]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 1, expectations) == TRUE) result = 1; @@ -4268,7 +4307,7 @@ static int AddressTestAddressGroupSetup43(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[2001::/3,!3000::/5]"); + int r = DetectAddressParse(NULL, gh, "[2001::/3,!3000::/5]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 2, expectations) == TRUE) result = 1; @@ -4286,7 +4325,7 @@ static int AddressTestAddressGroupSetup44(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "3ffe:ffff:7654:feda:1245:ba98:3210:4562/96"); + int r = DetectAddressParse(NULL, gh, "3ffe:ffff:7654:feda:1245:ba98:3210:4562/96"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 1, expectations) == TRUE) result = 1; @@ -4302,7 +4341,7 @@ static int AddressTestAddressGroupSetup45(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[192.168.1.3,!192.168.0.0/16]"); + int r = DetectAddressParse(NULL, gh, "[192.168.1.3,!192.168.0.0/16]"); if (r != 0) { result = 1; } @@ -4322,7 +4361,7 @@ static int AddressTestAddressGroupSetup46(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24]]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24]]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 4, expectations) == TRUE) result = 1; @@ -4345,7 +4384,7 @@ static int AddressTestAddressGroupSetup47(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]]"); + int r = DetectAddressParse(NULL, gh, "[![192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 5, expectations) == TRUE) result = 1; @@ -4367,7 +4406,7 @@ static int AddressTestAddressGroupSetup48(void) int result = 0; DetectAddressHead *gh = DetectAddressHeadInit(); if (gh != NULL) { - int r = DetectAddressParse(gh, "[192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]"); + int r = DetectAddressParse(NULL, gh, "[192.168.0.0/16,![192.168.1.0/24,192.168.3.0/24],!192.168.5.0/24]"); if (r == 0) { if (UTHValidateDetectAddressHead(gh, 4, expectations) == TRUE) result = 1; @@ -4888,320 +4927,6 @@ int AddressConfVarsTest05(void) return result; } -#include "detect-engine.h" - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions01(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("255.0.0.0/8"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("0.0.0.0/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a1); - DetectAddressInsert(de_ctx, h, a2); - - if (h == NULL) - goto end; - - DetectAddress *x = h->ipv4_head; - for ( ; x != NULL; x = x->next) { - SCLogDebug("x %p next %p", x, x->next); - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv4_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions02(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("255.0.0.0/8"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("0.0.0.0/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a2); - DetectAddressInsert(de_ctx, h, a1); - - BUG_ON(h == NULL); - - SCLogDebug("dp3"); - - DetectAddress *x = h->ipv4_head; - for ( ; x != NULL; x = x->next) { - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv4_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions03(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("ffff::/16"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("::/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a1); - DetectAddressInsert(de_ctx, h, a2); - - if (h == NULL) - goto end; - - DetectAddress *x = h->ipv6_head; - for ( ; x != NULL; x = x->next) { - SCLogDebug("x %p next %p", x, x->next); - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv6_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - -/** - * \test Test sig distribution over address groups - */ -static int AddressTestFunctions04(void) -{ - DetectAddress *a1 = NULL; - DetectAddress *a2 = NULL; - DetectAddressHead *h = NULL; - int result = 0; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature s[2]; - memset(s,0x00,sizeof(s)); - - s[0].num = 0; - s[1].num = 1; - - a1 = DetectAddressParseSingle("ffff::/16"); - if (a1 == NULL) { - printf("a1 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a1->sh, &s[0]); - - a2 = DetectAddressParseSingle("::/0"); - if (a2 == NULL) { - printf("a2 == NULL: "); - goto end; - } - SigGroupHeadAppendSig(de_ctx, &a2->sh, &s[1]); - - SCLogDebug("a1"); - DetectAddressPrint(a1); - SCLogDebug("a2"); - DetectAddressPrint(a2); - - h = DetectAddressHeadInit(); - if (h == NULL) - goto end; - DetectAddressInsert(de_ctx, h, a2); - DetectAddressInsert(de_ctx, h, a1); - - BUG_ON(h == NULL); - - SCLogDebug("dp3"); - - DetectAddress *x = h->ipv6_head; - for ( ; x != NULL; x = x->next) { - DetectAddressPrint(x); - //SigGroupHeadPrintSigs(de_ctx, x->sh); - } - - DetectAddress *one = h->ipv6_head; - DetectAddress *two = one->next; - - int sig = 0; - if ((one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(one->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'one', but it shouldn't: ", sig); - goto end; - } - sig = 1; - if (!(two->sh->init->sig_array[sig / 8] & (1 << (sig % 8)))) { - printf("sig %d part of 'two', but it shouldn't: ", sig); - goto end; - } - - result = 1; -end: - if (h != NULL) - DetectAddressHeadFree(h); - return result; -} - #endif /* UNITTESTS */ void DetectAddressTests(void) @@ -5210,204 +4935,199 @@ void DetectAddressTests(void) DetectAddressIPv4Tests(); DetectAddressIPv6Tests(); - UtRegisterTest("AddressTestParse01", AddressTestParse01, 1); - UtRegisterTest("AddressTestParse02", AddressTestParse02, 1); - UtRegisterTest("AddressTestParse03", AddressTestParse03, 1); - UtRegisterTest("AddressTestParse04", AddressTestParse04, 1); - UtRegisterTest("AddressTestParse05", AddressTestParse05, 1); - UtRegisterTest("AddressTestParse06", AddressTestParse06, 1); - UtRegisterTest("AddressTestParse07", AddressTestParse07, 1); - UtRegisterTest("AddressTestParse08", AddressTestParse08, 1); - UtRegisterTest("AddressTestParse09", AddressTestParse09, 1); - UtRegisterTest("AddressTestParse10", AddressTestParse10, 1); - UtRegisterTest("AddressTestParse11", AddressTestParse11, 1); - UtRegisterTest("AddressTestParse12", AddressTestParse12, 1); - UtRegisterTest("AddressTestParse13", AddressTestParse13, 1); - UtRegisterTest("AddressTestParse14", AddressTestParse14, 1); - UtRegisterTest("AddressTestParse15", AddressTestParse15, 1); - UtRegisterTest("AddressTestParse16", AddressTestParse16, 1); - UtRegisterTest("AddressTestParse17", AddressTestParse17, 1); - UtRegisterTest("AddressTestParse18", AddressTestParse18, 1); - UtRegisterTest("AddressTestParse19", AddressTestParse19, 1); - UtRegisterTest("AddressTestParse20", AddressTestParse20, 1); - UtRegisterTest("AddressTestParse21", AddressTestParse21, 1); - UtRegisterTest("AddressTestParse22", AddressTestParse22, 1); - UtRegisterTest("AddressTestParse23", AddressTestParse23, 1); - UtRegisterTest("AddressTestParse24", AddressTestParse24, 1); - UtRegisterTest("AddressTestParse25", AddressTestParse25, 1); - UtRegisterTest("AddressTestParse26", AddressTestParse26, 1); - UtRegisterTest("AddressTestParse27", AddressTestParse27, 1); - UtRegisterTest("AddressTestParse28", AddressTestParse28, 1); - UtRegisterTest("AddressTestParse29", AddressTestParse29, 1); - UtRegisterTest("AddressTestParse30", AddressTestParse30, 1); - UtRegisterTest("AddressTestParse31", AddressTestParse31, 1); - UtRegisterTest("AddressTestParse32", AddressTestParse32, 1); - UtRegisterTest("AddressTestParse33", AddressTestParse33, 1); - UtRegisterTest("AddressTestParse34", AddressTestParse34, 1); - UtRegisterTest("AddressTestParse35", AddressTestParse35, 1); - UtRegisterTest("AddressTestParse36", AddressTestParse36, 1); - UtRegisterTest("AddressTestParse37", AddressTestParse37, 1); - - UtRegisterTest("AddressTestMatch01", AddressTestMatch01, 1); - UtRegisterTest("AddressTestMatch02", AddressTestMatch02, 1); - UtRegisterTest("AddressTestMatch03", AddressTestMatch03, 1); - UtRegisterTest("AddressTestMatch04", AddressTestMatch04, 1); - UtRegisterTest("AddressTestMatch05", AddressTestMatch05, 1); - UtRegisterTest("AddressTestMatch06", AddressTestMatch06, 1); - UtRegisterTest("AddressTestMatch07", AddressTestMatch07, 1); - UtRegisterTest("AddressTestMatch08", AddressTestMatch08, 1); - UtRegisterTest("AddressTestMatch09", AddressTestMatch09, 1); - UtRegisterTest("AddressTestMatch10", AddressTestMatch10, 1); - UtRegisterTest("AddressTestMatch11", AddressTestMatch11, 1); - - UtRegisterTest("AddressTestCmp01", AddressTestCmp01, 1); - UtRegisterTest("AddressTestCmp02", AddressTestCmp02, 1); - UtRegisterTest("AddressTestCmp03", AddressTestCmp03, 1); - UtRegisterTest("AddressTestCmp04", AddressTestCmp04, 1); - UtRegisterTest("AddressTestCmp05", AddressTestCmp05, 1); - UtRegisterTest("AddressTestCmp06", AddressTestCmp06, 1); - UtRegisterTest("AddressTestCmpIPv407", AddressTestCmpIPv407, 1); - UtRegisterTest("AddressTestCmpIPv408", AddressTestCmpIPv408, 1); - - UtRegisterTest("AddressTestCmp07", AddressTestCmp07, 1); - UtRegisterTest("AddressTestCmp08", AddressTestCmp08, 1); - UtRegisterTest("AddressTestCmp09", AddressTestCmp09, 1); - UtRegisterTest("AddressTestCmp10", AddressTestCmp10, 1); - UtRegisterTest("AddressTestCmp11", AddressTestCmp11, 1); - UtRegisterTest("AddressTestCmp12", AddressTestCmp12, 1); + UtRegisterTest("AddressTestParse01", AddressTestParse01); + UtRegisterTest("AddressTestParse02", AddressTestParse02); + UtRegisterTest("AddressTestParse03", AddressTestParse03); + UtRegisterTest("AddressTestParse04", AddressTestParse04); + UtRegisterTest("AddressTestParse05", AddressTestParse05); + UtRegisterTest("AddressTestParse06", AddressTestParse06); + UtRegisterTest("AddressTestParse07", AddressTestParse07); + UtRegisterTest("AddressTestParse08", AddressTestParse08); + UtRegisterTest("AddressTestParse09", AddressTestParse09); + UtRegisterTest("AddressTestParse10", AddressTestParse10); + UtRegisterTest("AddressTestParse11", AddressTestParse11); + UtRegisterTest("AddressTestParse12", AddressTestParse12); + UtRegisterTest("AddressTestParse13", AddressTestParse13); + UtRegisterTest("AddressTestParse14", AddressTestParse14); + UtRegisterTest("AddressTestParse15", AddressTestParse15); + UtRegisterTest("AddressTestParse16", AddressTestParse16); + UtRegisterTest("AddressTestParse17", AddressTestParse17); + UtRegisterTest("AddressTestParse18", AddressTestParse18); + UtRegisterTest("AddressTestParse19", AddressTestParse19); + UtRegisterTest("AddressTestParse20", AddressTestParse20); + UtRegisterTest("AddressTestParse21", AddressTestParse21); + UtRegisterTest("AddressTestParse22", AddressTestParse22); + UtRegisterTest("AddressTestParse23", AddressTestParse23); + UtRegisterTest("AddressTestParse24", AddressTestParse24); + UtRegisterTest("AddressTestParse25", AddressTestParse25); + UtRegisterTest("AddressTestParse26", AddressTestParse26); + UtRegisterTest("AddressTestParse27", AddressTestParse27); + UtRegisterTest("AddressTestParse28", AddressTestParse28); + UtRegisterTest("AddressTestParse29", AddressTestParse29); + UtRegisterTest("AddressTestParse30", AddressTestParse30); + UtRegisterTest("AddressTestParse31", AddressTestParse31); + UtRegisterTest("AddressTestParse32", AddressTestParse32); + UtRegisterTest("AddressTestParse33", AddressTestParse33); + UtRegisterTest("AddressTestParse34", AddressTestParse34); + UtRegisterTest("AddressTestParse35", AddressTestParse35); + UtRegisterTest("AddressTestParse36", AddressTestParse36); + UtRegisterTest("AddressTestParse37", AddressTestParse37); + + UtRegisterTest("AddressTestMatch01", AddressTestMatch01); + UtRegisterTest("AddressTestMatch02", AddressTestMatch02); + UtRegisterTest("AddressTestMatch03", AddressTestMatch03); + UtRegisterTest("AddressTestMatch04", AddressTestMatch04); + UtRegisterTest("AddressTestMatch05", AddressTestMatch05); + UtRegisterTest("AddressTestMatch06", AddressTestMatch06); + UtRegisterTest("AddressTestMatch07", AddressTestMatch07); + UtRegisterTest("AddressTestMatch08", AddressTestMatch08); + UtRegisterTest("AddressTestMatch09", AddressTestMatch09); + UtRegisterTest("AddressTestMatch10", AddressTestMatch10); + UtRegisterTest("AddressTestMatch11", AddressTestMatch11); + + UtRegisterTest("AddressTestCmp01", AddressTestCmp01); + UtRegisterTest("AddressTestCmp02", AddressTestCmp02); + UtRegisterTest("AddressTestCmp03", AddressTestCmp03); + UtRegisterTest("AddressTestCmp04", AddressTestCmp04); + UtRegisterTest("AddressTestCmp05", AddressTestCmp05); + UtRegisterTest("AddressTestCmp06", AddressTestCmp06); + UtRegisterTest("AddressTestCmpIPv407", AddressTestCmpIPv407); + UtRegisterTest("AddressTestCmpIPv408", AddressTestCmpIPv408); + + UtRegisterTest("AddressTestCmp07", AddressTestCmp07); + UtRegisterTest("AddressTestCmp08", AddressTestCmp08); + UtRegisterTest("AddressTestCmp09", AddressTestCmp09); + UtRegisterTest("AddressTestCmp10", AddressTestCmp10); + UtRegisterTest("AddressTestCmp11", AddressTestCmp11); + UtRegisterTest("AddressTestCmp12", AddressTestCmp12); UtRegisterTest("AddressTestAddressGroupSetup01", - AddressTestAddressGroupSetup01, 1); + AddressTestAddressGroupSetup01); UtRegisterTest("AddressTestAddressGroupSetup02", - AddressTestAddressGroupSetup02, 1); + AddressTestAddressGroupSetup02); UtRegisterTest("AddressTestAddressGroupSetup03", - AddressTestAddressGroupSetup03, 1); + AddressTestAddressGroupSetup03); UtRegisterTest("AddressTestAddressGroupSetup04", - AddressTestAddressGroupSetup04, 1); + AddressTestAddressGroupSetup04); UtRegisterTest("AddressTestAddressGroupSetup05", - AddressTestAddressGroupSetup05, 1); + AddressTestAddressGroupSetup05); UtRegisterTest("AddressTestAddressGroupSetup06", - AddressTestAddressGroupSetup06, 1); + AddressTestAddressGroupSetup06); UtRegisterTest("AddressTestAddressGroupSetup07", - AddressTestAddressGroupSetup07, 1); + AddressTestAddressGroupSetup07); UtRegisterTest("AddressTestAddressGroupSetup08", - AddressTestAddressGroupSetup08, 1); + AddressTestAddressGroupSetup08); UtRegisterTest("AddressTestAddressGroupSetup09", - AddressTestAddressGroupSetup09, 1); + AddressTestAddressGroupSetup09); UtRegisterTest("AddressTestAddressGroupSetup10", - AddressTestAddressGroupSetup10, 1); + AddressTestAddressGroupSetup10); UtRegisterTest("AddressTestAddressGroupSetup11", - AddressTestAddressGroupSetup11, 1); + AddressTestAddressGroupSetup11); UtRegisterTest("AddressTestAddressGroupSetup12", - AddressTestAddressGroupSetup12, 1); + AddressTestAddressGroupSetup12); UtRegisterTest("AddressTestAddressGroupSetup13", - AddressTestAddressGroupSetup13, 1); + AddressTestAddressGroupSetup13); UtRegisterTest("AddressTestAddressGroupSetupIPv414", - AddressTestAddressGroupSetupIPv414, 1); + AddressTestAddressGroupSetupIPv414); UtRegisterTest("AddressTestAddressGroupSetupIPv415", - AddressTestAddressGroupSetupIPv415, 1); + AddressTestAddressGroupSetupIPv415); UtRegisterTest("AddressTestAddressGroupSetupIPv416", - AddressTestAddressGroupSetupIPv416, 1); + AddressTestAddressGroupSetupIPv416); UtRegisterTest("AddressTestAddressGroupSetup14", - AddressTestAddressGroupSetup14, 1); + AddressTestAddressGroupSetup14); UtRegisterTest("AddressTestAddressGroupSetup15", - AddressTestAddressGroupSetup15, 1); + AddressTestAddressGroupSetup15); UtRegisterTest("AddressTestAddressGroupSetup16", - AddressTestAddressGroupSetup16, 1); + AddressTestAddressGroupSetup16); UtRegisterTest("AddressTestAddressGroupSetup17", - AddressTestAddressGroupSetup17, 1); + AddressTestAddressGroupSetup17); UtRegisterTest("AddressTestAddressGroupSetup18", - AddressTestAddressGroupSetup18, 1); + AddressTestAddressGroupSetup18); UtRegisterTest("AddressTestAddressGroupSetup19", - AddressTestAddressGroupSetup19, 1); + AddressTestAddressGroupSetup19); UtRegisterTest("AddressTestAddressGroupSetup20", - AddressTestAddressGroupSetup20, 1); + AddressTestAddressGroupSetup20); UtRegisterTest("AddressTestAddressGroupSetup21", - AddressTestAddressGroupSetup21, 1); + AddressTestAddressGroupSetup21); UtRegisterTest("AddressTestAddressGroupSetup22", - AddressTestAddressGroupSetup22, 1); + AddressTestAddressGroupSetup22); UtRegisterTest("AddressTestAddressGroupSetup23", - AddressTestAddressGroupSetup23, 1); + AddressTestAddressGroupSetup23); UtRegisterTest("AddressTestAddressGroupSetup24", - AddressTestAddressGroupSetup24, 1); + AddressTestAddressGroupSetup24); UtRegisterTest("AddressTestAddressGroupSetup25", - AddressTestAddressGroupSetup25, 1); + AddressTestAddressGroupSetup25); UtRegisterTest("AddressTestAddressGroupSetup26", - AddressTestAddressGroupSetup26, 1); + AddressTestAddressGroupSetup26); UtRegisterTest("AddressTestAddressGroupSetup27", - AddressTestAddressGroupSetup27, 1); + AddressTestAddressGroupSetup27); UtRegisterTest("AddressTestAddressGroupSetup28", - AddressTestAddressGroupSetup28, 1); + AddressTestAddressGroupSetup28); UtRegisterTest("AddressTestAddressGroupSetup29", - AddressTestAddressGroupSetup29, 1); + AddressTestAddressGroupSetup29); UtRegisterTest("AddressTestAddressGroupSetup30", - AddressTestAddressGroupSetup30, 1); + AddressTestAddressGroupSetup30); UtRegisterTest("AddressTestAddressGroupSetup31", - AddressTestAddressGroupSetup31, 1); + AddressTestAddressGroupSetup31); UtRegisterTest("AddressTestAddressGroupSetup32", - AddressTestAddressGroupSetup32, 1); + AddressTestAddressGroupSetup32); UtRegisterTest("AddressTestAddressGroupSetup33", - AddressTestAddressGroupSetup33, 1); + AddressTestAddressGroupSetup33); UtRegisterTest("AddressTestAddressGroupSetup34", - AddressTestAddressGroupSetup34, 1); + AddressTestAddressGroupSetup34); UtRegisterTest("AddressTestAddressGroupSetup35", - AddressTestAddressGroupSetup35, 1); + AddressTestAddressGroupSetup35); UtRegisterTest("AddressTestAddressGroupSetup36", - AddressTestAddressGroupSetup36, 1); + AddressTestAddressGroupSetup36); UtRegisterTest("AddressTestAddressGroupSetup37", - AddressTestAddressGroupSetup37, 1); + AddressTestAddressGroupSetup37); UtRegisterTest("AddressTestAddressGroupSetup38", - AddressTestAddressGroupSetup38, 1); + AddressTestAddressGroupSetup38); UtRegisterTest("AddressTestAddressGroupSetup39", - AddressTestAddressGroupSetup39, 1); + AddressTestAddressGroupSetup39); UtRegisterTest("AddressTestAddressGroupSetup40", - AddressTestAddressGroupSetup40, 1); + AddressTestAddressGroupSetup40); UtRegisterTest("AddressTestAddressGroupSetup41", - AddressTestAddressGroupSetup41, 1); + AddressTestAddressGroupSetup41); UtRegisterTest("AddressTestAddressGroupSetup42", - AddressTestAddressGroupSetup42, 1); + AddressTestAddressGroupSetup42); UtRegisterTest("AddressTestAddressGroupSetup43", - AddressTestAddressGroupSetup43, 1); + AddressTestAddressGroupSetup43); UtRegisterTest("AddressTestAddressGroupSetup44", - AddressTestAddressGroupSetup44, 1); + AddressTestAddressGroupSetup44); UtRegisterTest("AddressTestAddressGroupSetup45", - AddressTestAddressGroupSetup45, 1); + AddressTestAddressGroupSetup45); UtRegisterTest("AddressTestAddressGroupSetup46", - AddressTestAddressGroupSetup46, 1); + AddressTestAddressGroupSetup46); UtRegisterTest("AddressTestAddressGroupSetup47", - AddressTestAddressGroupSetup47, 1); + AddressTestAddressGroupSetup47); UtRegisterTest("AddressTestAddressGroupSetup48", - AddressTestAddressGroupSetup48, 1); - - UtRegisterTest("AddressTestCutIPv401", AddressTestCutIPv401, 1); - UtRegisterTest("AddressTestCutIPv402", AddressTestCutIPv402, 1); - UtRegisterTest("AddressTestCutIPv403", AddressTestCutIPv403, 1); - UtRegisterTest("AddressTestCutIPv404", AddressTestCutIPv404, 1); - UtRegisterTest("AddressTestCutIPv405", AddressTestCutIPv405, 1); - UtRegisterTest("AddressTestCutIPv406", AddressTestCutIPv406, 1); - UtRegisterTest("AddressTestCutIPv407", AddressTestCutIPv407, 1); - UtRegisterTest("AddressTestCutIPv408", AddressTestCutIPv408, 1); - UtRegisterTest("AddressTestCutIPv409", AddressTestCutIPv409, 1); - UtRegisterTest("AddressTestCutIPv410", AddressTestCutIPv410, 1); + AddressTestAddressGroupSetup48); + + UtRegisterTest("AddressTestCutIPv401", AddressTestCutIPv401); + UtRegisterTest("AddressTestCutIPv402", AddressTestCutIPv402); + UtRegisterTest("AddressTestCutIPv403", AddressTestCutIPv403); + UtRegisterTest("AddressTestCutIPv404", AddressTestCutIPv404); + UtRegisterTest("AddressTestCutIPv405", AddressTestCutIPv405); + UtRegisterTest("AddressTestCutIPv406", AddressTestCutIPv406); + UtRegisterTest("AddressTestCutIPv407", AddressTestCutIPv407); + UtRegisterTest("AddressTestCutIPv408", AddressTestCutIPv408); + UtRegisterTest("AddressTestCutIPv409", AddressTestCutIPv409); + UtRegisterTest("AddressTestCutIPv410", AddressTestCutIPv410); UtRegisterTest("AddressTestParseInvalidMask01", - AddressTestParseInvalidMask01, 1); + AddressTestParseInvalidMask01); UtRegisterTest("AddressTestParseInvalidMask02", - AddressTestParseInvalidMask02, 1); + AddressTestParseInvalidMask02); UtRegisterTest("AddressTestParseInvalidMask03", - AddressTestParseInvalidMask03, 1); - - UtRegisterTest("AddressConfVarsTest01 ", AddressConfVarsTest01, 1); - UtRegisterTest("AddressConfVarsTest02 ", AddressConfVarsTest02, 1); - UtRegisterTest("AddressConfVarsTest03 ", AddressConfVarsTest03, 1); - UtRegisterTest("AddressConfVarsTest04 ", AddressConfVarsTest04, 1); - UtRegisterTest("AddressConfVarsTest05 ", AddressConfVarsTest05, 1); - - UtRegisterTest("AddressTestFunctions01", AddressTestFunctions01, 1); - UtRegisterTest("AddressTestFunctions02", AddressTestFunctions02, 1); - UtRegisterTest("AddressTestFunctions03", AddressTestFunctions03, 1); - UtRegisterTest("AddressTestFunctions04", AddressTestFunctions04, 1); + AddressTestParseInvalidMask03); + + UtRegisterTest("AddressConfVarsTest01 ", AddressConfVarsTest01); + UtRegisterTest("AddressConfVarsTest02 ", AddressConfVarsTest02); + UtRegisterTest("AddressConfVarsTest03 ", AddressConfVarsTest03); + UtRegisterTest("AddressConfVarsTest04 ", AddressConfVarsTest04); + UtRegisterTest("AddressConfVarsTest05 ", AddressConfVarsTest05); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-address.h b/src/detect-engine-address.h index f185b7abde8f..8c5d1256f07f 100644 --- a/src/detect-engine-address.h +++ b/src/detect-engine-address.h @@ -26,14 +26,13 @@ /* prototypes */ void DetectAddressRegister (void); -void DetectAddressPrintMemory(void); DetectAddressHead *DetectAddressHeadInit(void); void DetectAddressHeadFree(DetectAddressHead *); void DetectAddressHeadCleanup(DetectAddressHead *); int DetectAddressParseString(DetectAddress *, char *); -int DetectAddressParse(DetectAddressHead *, char *); +int DetectAddressParse(const DetectEngineCtx *, DetectAddressHead *, const char *); DetectAddress *DetectAddressInit(void); void DetectAddressFree(DetectAddress *); @@ -45,7 +44,7 @@ void DetectAddressPrintList(DetectAddress *); int DetectAddressInsert(DetectEngineCtx *, DetectAddressHead *, DetectAddress *); int DetectAddressJoin(DetectEngineCtx *, DetectAddress *, DetectAddress *); -DetectAddress *DetectAddressLookupInHead(DetectAddressHead *, Address *); +DetectAddress *DetectAddressLookupInHead(const DetectAddressHead *, Address *); DetectAddress *DetectAddressLookupInList(DetectAddress *, DetectAddress *); int DetectAddressMatch(DetectAddress *, Address *); @@ -60,4 +59,9 @@ int DetectAddressTestConfVars(void); void DetectAddressTests(void); +int DetectAddressMapInit(DetectEngineCtx *de_ctx); +void DetectAddressMapFree(DetectEngineCtx *de_ctx); +const DetectAddressHead *DetectParseAddress(DetectEngineCtx *de_ctx, + const char *string); + #endif /* __DETECT_ADDRESS_H__ */ diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index f59c030562e4..5187bf9f3cbc 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -46,7 +46,6 @@ void PacketAlertTagInit(void) memset(&g_tag_pa, 0x00, sizeof(g_tag_pa)); - g_tag_pa.order_id = 1000; g_tag_pa.action = ACTION_ALERT; g_tag_pa.s = &g_tag_signature; } @@ -68,30 +67,30 @@ PacketAlert *PacketAlertGetTag(void) * \retval 0 alert is suppressed */ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p, uint16_t pos) + const Signature *s, Packet *p, PacketAlert *pa) { SCEnter(); int ret = 1; - DetectThresholdData *td = NULL; - SigMatch *sm; + const DetectThresholdData *td = NULL; + const SigMatchData *smd; if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { SCReturnInt(1); } /* handle suppressions first */ - if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_SUPPRESS] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_SUPPRESS); - sm = NULL; + smd = NULL; do { - td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_SUPPRESS); + td = SigGetThresholdTypeIter(s, p, &smd, DETECT_SM_LIST_SUPPRESS); if (td != NULL) { SCLogDebug("td %p", td); /* PacketAlertThreshold returns 2 if the alert is suppressed but * we do need to apply rule actions to the packet. */ KEYWORD_PROFILING_START; - ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); + ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); if (ret == 0 || ret == 2) { KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 0); /* It doesn't match threshold, remove it */ @@ -99,22 +98,22 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det } KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1); } - } while (sm != NULL); + } while (smd != NULL); } /* if we're still here, consider thresholding */ - if (s->sm_lists[DETECT_SM_LIST_THRESHOLD] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_THRESHOLD] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_THRESHOLD); - sm = NULL; + smd = NULL; do { - td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_THRESHOLD); + td = SigGetThresholdTypeIter(s, p, &smd, DETECT_SM_LIST_THRESHOLD); if (td != NULL) { SCLogDebug("td %p", td); /* PacketAlertThreshold returns 2 if the alert is suppressed but * we do need to apply rule actions to the packet. */ KEYWORD_PROFILING_START; - ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); + ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s, pa); if (ret == 0 || ret == 2) { KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD ,0); /* It doesn't match threshold, remove it */ @@ -122,7 +121,7 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det } KEYWORD_PROFILING_END(det_ctx, DETECT_THRESHOLD, 1); } - } while (sm != NULL); + } while (smd != NULL); } SCReturnInt(1); } @@ -187,7 +186,8 @@ int PacketAlertRemove(Packet *p, uint16_t pos) * \param flags alert flags * \param alert_msg ptr to StreamMsg object that the signature matched on */ -int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint64_t tx_id, uint8_t flags) +int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, + Packet *p, uint64_t tx_id, uint8_t flags) { int i = 0; @@ -240,25 +240,27 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx { SCEnter(); int i = 0; - Signature *s = NULL; - SigMatch *sm = NULL; while (i < p->alerts.cnt) { SCLogDebug("Sig->num: %"PRIu16, p->alerts.alerts[i].num); - s = de_ctx->sig_array[p->alerts.alerts[i].num]; + const Signature *s = de_ctx->sig_array[p->alerts.alerts[i].num]; - int res = PacketAlertHandle(de_ctx, det_ctx, s, p, i); + int res = PacketAlertHandle(de_ctx, det_ctx, s, p, &p->alerts.alerts[i]); if (res > 0) { /* Now, if we have an alert, we have to check if we want * to tag this session or src/dst host */ - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH); - sm = s->sm_lists[DETECT_SM_LIST_TMATCH]; - while (sm) { - /* tags are set only for alerts */ - KEYWORD_PROFILING_START; - sigmatch_table[sm->type].Match(NULL, det_ctx, p, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - sm = sm->next; + if (s->sm_arrays[DETECT_SM_LIST_TMATCH] != NULL) { + KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_TMATCH); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_TMATCH]; + while (1) { + /* tags are set only for alerts */ + KEYWORD_PROFILING_START; + sigmatch_table[smd->type].Match(NULL, det_ctx, p, (Signature *)s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + } } if (s->flags & SIG_FLAG_IPONLY) { @@ -268,8 +270,7 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx if (p->flow != NULL) { /* Update flow flags for iponly */ - FLOWLOCK_WRLOCK(p->flow); - FlowSetIPOnlyFlagNoLock(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0); + FlowSetIPOnlyFlag(p->flow, (p->flowflags & FLOW_PKT_TOSERVER) ? 1 : 0); if (s->action & ACTION_DROP) p->flow->flags |= FLOW_ACTION_DROP; @@ -282,19 +283,27 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx if (s->action & ACTION_PASS) { FlowSetNoPacketInspectionFlag(p->flow); } - FLOWLOCK_UNLOCK(p->flow); } } } - /* set verdict on packet */ - PACKET_UPDATE_ACTION(p, p->alerts.alerts[i].action); + /* set actions on packet */ + DetectSignatureApplyActions(p, p->alerts.alerts[i].s); if (PACKET_TEST_ACTION(p, ACTION_PASS)) { /* Ok, reset the alert cnt to end in the previous of pass * so we ignore the rest with less prio */ p->alerts.cnt = i; + + /* if an stream/app-layer match we enforce the pass for the flow */ + if ((p->flow != NULL) && + (p->alerts.alerts[i].flags & + (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH))) + { + FlowSetNoPacketInspectionFlag(p->flow); + } break; + /* if the signature wants to drop, check if the * PACKET_ALERT_FLAG_DROP_FLOW flag is set. */ } else if ((PACKET_TEST_ACTION(p, ACTION_DROP)) && @@ -302,10 +311,8 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx (s->flags & SIG_FLAG_APPLAYER)) && p->flow != NULL) { - FLOWLOCK_WRLOCK(p->flow); /* This will apply only on IPS mode (check StreamTcpPacket) */ - p->flow->flags |= FLOW_ACTION_DROP; - FLOWLOCK_UNLOCK(p->flow); + p->flow->flags |= FLOW_ACTION_DROP; // XXX API? } } @@ -324,6 +331,12 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx * keyword context for sessions and hosts */ if (!(p->flags & PKT_PSEUDO_STREAM_END)) TagHandlePacket(de_ctx, det_ctx, p); + + /* Set flag on flow to indicate that it has alerts */ + if (p->flow != NULL && p->alerts.cnt > 0) { + FlowSetHasAlertsFlag(p->flow); + } + } diff --git a/src/detect-engine-alert.h b/src/detect-engine-alert.h index 6f200b268d4e..dc6687885cc0 100644 --- a/src/detect-engine-alert.h +++ b/src/detect-engine-alert.h @@ -29,7 +29,8 @@ #include "detect.h" void PacketAlertFinalize(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *); -int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *, uint64_t tx_id, uint8_t); +int PacketAlertAppend(DetectEngineThreadCtx *, const Signature *, + Packet *, uint64_t tx_id, uint8_t); int PacketAlertCheck(Packet *, uint32_t); int PacketAlertRemove(Packet *, uint16_t); void PacketAlertTagInit(void); diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 3ac8d0802b38..51ac3930aaed 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -27,6 +27,7 @@ #include "suricata.h" #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-engine-analyzer.h" #include "detect-engine-mpm.h" #include "conf.h" @@ -42,13 +43,41 @@ static pcre *percent_re = NULL; static pcre_extra *percent_re_study = NULL; static char log_path[PATH_MAX]; +typedef struct FpPatternStats_ { + uint16_t min; + uint16_t max; + uint32_t cnt; + uint64_t tot; +} FpPatternStats; + +static FpPatternStats fp_pattern_stats[DETECT_SM_LIST_MAX]; + +static void FpPatternStatsAdd(int list, uint16_t patlen) +{ + if (list < 0 || list >= DETECT_SM_LIST_MAX) + return; + + FpPatternStats *f = &fp_pattern_stats[list]; + + if (f->min == 0) + f->min = patlen; + else if (patlen < f->min) + f->min = patlen; + + if (patlen > f->max) + f->max = patlen; + + f->cnt++; + f->tot += patlen; +} + void EngineAnalysisFP(Signature *s, char *line) { int fast_pattern_set = 0; int fast_pattern_only_set = 0; int fast_pattern_chop_set = 0; DetectContentData *fp_cd = NULL; - SigMatch *mpm_sm = s->mpm_sm; + SigMatch *mpm_sm = s->init_data->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; @@ -66,6 +95,13 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, "%s\n", line); fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n"); + if (s->init_data->prefilter_sm != NULL) { + fprintf(fp_engine_analysis_FD, " Prefilter on: %s\n", + sigmatch_table[s->init_data->prefilter_sm->type].name); + fprintf(fp_engine_analysis_FD, "\n"); + return; + } + if (fp_cd == NULL) { fprintf(fp_engine_analysis_FD, " No content present\n"); fprintf(fp_engine_analysis_FD, "\n"); @@ -76,28 +112,13 @@ void EngineAnalysisFP(Signature *s, char *line) int list_type = SigMatchListSMBelongsTo(s, mpm_sm); if (list_type == DETECT_SM_LIST_PMATCH) fprintf(fp_engine_analysis_FD, "content\n"); - else if (list_type == DETECT_SM_LIST_UMATCH) - fprintf(fp_engine_analysis_FD, "http uri content\n"); - else if (list_type == DETECT_SM_LIST_HRUDMATCH) - fprintf(fp_engine_analysis_FD, "http raw uri content\n"); - else if (list_type == DETECT_SM_LIST_HHDMATCH) - fprintf(fp_engine_analysis_FD, "http header content\n"); - else if (list_type == DETECT_SM_LIST_HRHDMATCH) - fprintf(fp_engine_analysis_FD, "http raw header content\n"); - else if (list_type == DETECT_SM_LIST_HMDMATCH) - fprintf(fp_engine_analysis_FD, "http method content\n"); - else if (list_type == DETECT_SM_LIST_HCDMATCH) - fprintf(fp_engine_analysis_FD, "http cookie content\n"); - else if (list_type == DETECT_SM_LIST_HCBDMATCH) - fprintf(fp_engine_analysis_FD, "http client body content\n"); - else if (list_type == DETECT_SM_LIST_HSBDMATCH) - fprintf(fp_engine_analysis_FD, "http server body content\n"); - else if (list_type == DETECT_SM_LIST_HSCDMATCH) - fprintf(fp_engine_analysis_FD, "http stat code content\n"); - else if (list_type == DETECT_SM_LIST_HSMDMATCH) - fprintf(fp_engine_analysis_FD, "http stat msg content\n"); - else if (list_type == DETECT_SM_LIST_HUADMATCH) - fprintf(fp_engine_analysis_FD, "http user agent content\n"); + else { + const char *desc = DetectBufferTypeGetDescriptionById(list_type); + const char *name = DetectBufferTypeGetNameById(list_type); + if (desc && name) { + fprintf(fp_engine_analysis_FD, "%s (%s)\n", desc, name); + } + } int flags_set = 0; fprintf(fp_engine_analysis_FD, " Flags:"); @@ -162,10 +183,14 @@ void EngineAnalysisFP(Signature *s, char *line) fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); + + FpPatternStatsAdd(list_type, patlen); } else { fprintf(fp_engine_analysis_FD, " Final content: "); PrintRawUriFp(fp_engine_analysis_FD, pat, patlen); fprintf(fp_engine_analysis_FD, "\n"); + + FpPatternStatsAdd(list_type, patlen); } SCFree(pat); @@ -220,6 +245,7 @@ int SetupFPAnalyzer(void) fprintf(fp_engine_analysis_FD, "----------------------------------------------" "---------------------\n"); + memset(&fp_pattern_stats, 0, sizeof(fp_pattern_stats)); return 1; } @@ -286,6 +312,19 @@ int SetupRuleAnalyzer(void) void CleanupFPAnalyzer(void) { + fprintf(fp_engine_analysis_FD, "============\n" + "Summary:\n============\n"); + int i; + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + FpPatternStats *f = &fp_pattern_stats[i]; + if (f->cnt == 0) + continue; + + fprintf(fp_engine_analysis_FD, + "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns %u, avg pattern len %.2f byte(s)\n", + DetectSigmatchListEnumToString(i), f->min, f->max, f->cnt, (float)((double)f->tot/(float)f->cnt)); + } + if (fp_engine_analysis_FD != NULL) { fclose(fp_engine_analysis_FD); fp_engine_analysis_FD = NULL; @@ -355,10 +394,10 @@ int PerCentEncodingMatch (uint8_t *content, uint8_t content_len) return ret; } -static void EngineAnalysisRulesPrintFP(Signature *s) +static void EngineAnalysisRulesPrintFP(const Signature *s) { DetectContentData *fp_cd = NULL; - SigMatch *mpm_sm = s->mpm_sm; + SigMatch *mpm_sm = s->init_data->mpm_sm; if (mpm_sm != NULL) { fp_cd = (DetectContentData *)mpm_sm->ctx; @@ -407,30 +446,13 @@ static void EngineAnalysisRulesPrintFP(Signature *s) fprintf(rule_engine_analysis_FD, "%s", payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream"); } - else if (list_type == DETECT_SM_LIST_UMATCH) - fprintf(rule_engine_analysis_FD, "http uri content"); - else if (list_type == DETECT_SM_LIST_HRUDMATCH) - fprintf(rule_engine_analysis_FD, "http raw uri content"); - else if (list_type == DETECT_SM_LIST_HHDMATCH) - fprintf(rule_engine_analysis_FD, "http header content"); - else if (list_type == DETECT_SM_LIST_HRHDMATCH) - fprintf(rule_engine_analysis_FD, "http raw header content"); - else if (list_type == DETECT_SM_LIST_HMDMATCH) - fprintf(rule_engine_analysis_FD, "http method content"); - else if (list_type == DETECT_SM_LIST_HCDMATCH) - fprintf(rule_engine_analysis_FD, "http cookie content"); - else if (list_type == DETECT_SM_LIST_HCBDMATCH) - fprintf(rule_engine_analysis_FD, "http client body content"); - else if (list_type == DETECT_SM_LIST_HSBDMATCH) - fprintf(rule_engine_analysis_FD, "http server body content"); - else if (list_type == DETECT_SM_LIST_HSCDMATCH) - fprintf(rule_engine_analysis_FD, "http stat code content"); - else if (list_type == DETECT_SM_LIST_HSMDMATCH) - fprintf(rule_engine_analysis_FD, "http stat msg content"); - else if (list_type == DETECT_SM_LIST_HUADMATCH) - fprintf(rule_engine_analysis_FD, "http user agent content"); - else if (list_type == DETECT_SM_LIST_DNSQUERY_MATCH) - fprintf(rule_engine_analysis_FD, "dns query name content"); + else { + const char *desc = DetectBufferTypeGetDescriptionById(list_type); + const char *name = DetectBufferTypeGetNameById(list_type); + if (desc && name) { + fprintf(rule_engine_analysis_FD, "%s (%s)", desc, name); + } + } fprintf(rule_engine_analysis_FD, "\" buffer.\n"); @@ -459,7 +481,7 @@ void EngineAnalysisRulesFailure(char *line, char *file, int lineno) * * \param s Pointer to the signature. */ -void EngineAnalysisRules(Signature *s, char *line) +void EngineAnalysisRules(const Signature *s, const char *line) { uint32_t rule_bidirectional = 0; uint32_t rule_pcre = 0; @@ -477,7 +499,7 @@ void EngineAnalysisRules(Signature *s, char *line) //uint32_t rule_flowvar = 0; uint32_t rule_content_http = 0; uint32_t rule_content_offset_depth = 0; - uint32_t list_id = 0; + int32_t list_id = 0; uint32_t rule_warning = 0; uint32_t raw_http_buf = 0; uint32_t norm_http_buf = 0; @@ -509,8 +531,23 @@ void EngineAnalysisRules(Signature *s, char *line) uint32_t warn_offset_depth_pkt_stream = 0; uint32_t warn_offset_depth_alproto = 0; uint32_t warn_non_alproto_fp_for_alproto_sig = 0; - - if (s->init_flags & SIG_FLAG_INIT_BIDIREC) { + uint32_t warn_no_direction = 0; + uint32_t warn_both_direction = 0; + + const int nlists = DetectBufferTypeMaxId(); + const int filedata_id = DetectBufferTypeGetByName("file_data"); + const int httpmethod_id = DetectBufferTypeGetByName("http_method"); + const int httpuri_id = DetectBufferTypeGetByName("http_uri"); + const int httpuseragent_id = DetectBufferTypeGetByName("http_user_agent"); + const int httpcookie_id = DetectBufferTypeGetByName("http_cookie"); + const int httpstatcode_id = DetectBufferTypeGetByName("http_stat_code"); + const int httpstatmsg_id = DetectBufferTypeGetByName("http_stat_msg"); + const int httpheader_id = DetectBufferTypeGetByName("http_header"); + const int httprawheader_id = DetectBufferTypeGetByName("http_raw_header"); + const int httpclientbody_id = DetectBufferTypeGetByName("http_client_body"); + const int httprawuri_id = DetectBufferTypeGetByName("http_raw_uri"); + + if (s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { rule_bidirectional = 1; } @@ -528,62 +565,61 @@ void EngineAnalysisRules(Signature *s, char *line) rule_ipv6_only += 1; } - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - + for (list_id = 0; list_id < nlists; list_id++) { SigMatch *sm = NULL; - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_PCRE) { - if (list_id == DETECT_SM_LIST_HCBDMATCH) { + if (list_id == httpclientbody_id) { rule_pcre_http += 1; http_client_body_buf += 1; raw_http_buf += 1; } - else if (list_id == DETECT_SM_LIST_UMATCH) { + else if (list_id == httpuri_id) { rule_pcre_http += 1; norm_http_buf += 1; http_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HHDMATCH) { + else if (list_id == httpheader_id) { rule_pcre_http += 1; norm_http_buf += 1; http_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HCDMATCH) { + else if (list_id == httpcookie_id) { rule_pcre_http += 1; norm_http_buf += 1; http_cookie_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSBDMATCH) { + else if (list_id == filedata_id) { rule_pcre_http += 1; http_server_body_buf += 1; raw_http_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRHDMATCH) { + else if (list_id == httprawheader_id) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HMDMATCH) { + else if (list_id == httpmethod_id) { rule_pcre_http += 1; raw_http_buf += 1; http_method_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRUDMATCH) { + else if (list_id == httprawuri_id) { rule_pcre_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSMDMATCH) { + else if (list_id == httpstatmsg_id) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSCDMATCH) { + else if (list_id == httpstatcode_id) { rule_pcre_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; } - else if (list_id == DETECT_SM_LIST_HUADMATCH) { + else if (list_id == httpuseragent_id) { rule_pcre_http += 1; norm_http_buf += 1; http_ua_buf += 1; @@ -594,9 +630,9 @@ void EngineAnalysisRules(Signature *s, char *line) } else if (sm->type == DETECT_CONTENT) { - if (list_id == DETECT_SM_LIST_UMATCH - || list_id == DETECT_SM_LIST_HHDMATCH - || list_id == DETECT_SM_LIST_HCDMATCH) { + if (list_id == httpuri_id + || list_id == httpheader_id + || list_id == httpcookie_id) { rule_content_http += 1; norm_http_buf += 1; DetectContentData *cd = (DetectContentData *)sm->ctx; @@ -604,47 +640,47 @@ void EngineAnalysisRules(Signature *s, char *line) warn_encoding_norm_http_buf += 1; rule_warning += 1; } - if (list_id == DETECT_SM_LIST_UMATCH) { + if (list_id == httpuri_id) { http_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HHDMATCH) { + else if (list_id == httpheader_id) { http_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HCDMATCH) { + else if (list_id == httpcookie_id) { http_cookie_buf += 1; } } - else if (list_id == DETECT_SM_LIST_HCBDMATCH) { + else if (list_id == httpclientbody_id) { rule_content_http += 1; raw_http_buf += 1; http_client_body_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSBDMATCH) { + else if (list_id == filedata_id) { rule_content_http += 1; raw_http_buf += 1; http_server_body_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRHDMATCH) { + else if (list_id == httprawheader_id) { rule_content_http += 1; raw_http_buf += 1; http_raw_header_buf += 1; } - else if (list_id == DETECT_SM_LIST_HRUDMATCH) { + else if (list_id == httprawuri_id) { rule_content_http += 1; raw_http_buf += 1; http_raw_uri_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSMDMATCH) { + else if (list_id == httpstatmsg_id) { rule_content_http += 1; raw_http_buf += 1; http_stat_msg_buf += 1; } - else if (list_id == DETECT_SM_LIST_HSCDMATCH) { + else if (list_id == httpstatcode_id) { rule_content_http += 1; raw_http_buf += 1; http_stat_code_buf += 1; } - else if (list_id == DETECT_SM_LIST_HMDMATCH) { + else if (list_id == httpmethod_id) { rule_content_http += 1; raw_http_buf += 1; http_method_buf += 1; @@ -668,7 +704,8 @@ void EngineAnalysisRules(Signature *s, char *line) } DetectFlowData *fd = (DetectFlowData *)sm->ctx; if (fd != NULL) { - if (fd->flags & FLOW_PKT_NOSTREAM) rule_flow_nostream = 1; + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) + rule_flow_nostream = 1; } } else if (sm->type == DETECT_FLOWBITS) { @@ -757,17 +794,27 @@ void EngineAnalysisRules(Signature *s, char *line) rule_warning += 1; warn_offset_depth_alproto = 1; } - if (s->mpm_sm != NULL && s->alproto == ALPROTO_HTTP && - SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH) { + if (s->init_data->mpm_sm != NULL && s->alproto == ALPROTO_HTTP && + SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == DETECT_SM_LIST_PMATCH) { rule_warning += 1; warn_non_alproto_fp_for_alproto_sig = 1; } + if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) { + warn_no_direction += 1; + rule_warning += 1; + } + if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) { + warn_both_direction += 1; + rule_warning += 1; + } + if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) { fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id); fprintf(rule_engine_analysis_FD, "%s\n", line); if (s->flags & SIG_FLAG_IPONLY) fprintf(rule_engine_analysis_FD, " Rule is ip only.\n"); + if (s->flags & SIG_FLAG_PDONLY) fprintf(rule_engine_analysis_FD, " Rule is PD only.\n"); if (rule_ipv6_only) fprintf(rule_engine_analysis_FD, " Rule is IPv6 only.\n"); if (rule_ipv4_only) fprintf(rule_engine_analysis_FD, " Rule is IPv4 only.\n"); if (packet_buf) fprintf(rule_engine_analysis_FD, " Rule matches on packets.\n"); @@ -793,7 +840,12 @@ void EngineAnalysisRules(Signature *s, char *line) } /* print fast pattern info */ - EngineAnalysisRulesPrintFP(s); + if (s->init_data->prefilter_sm) { + fprintf(rule_engine_analysis_FD, " Prefilter on: %s.\n", + sigmatch_table[s->init_data->prefilter_sm->type].name); + } else { + EngineAnalysisRulesPrintFP(s); + } /* this is where the warnings start */ if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) { @@ -869,6 +921,12 @@ void EngineAnalysisRules(Signature *s, char *line) "stream. Consider adding fast_pattern over a http " "buffer for increased performance."); } + if (warn_no_direction) { + fprintf(rule_engine_analysis_FD, " Warning: Rule has no direction indicator.\n"); + } + if (warn_both_direction) { + fprintf(rule_engine_analysis_FD, " Warning: Rule is inspecting both directions.\n"); + } if (rule_warning == 0) { fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n"); } diff --git a/src/detect-engine-analyzer.h b/src/detect-engine-analyzer.h index d92b20604c53..d9a808159594 100644 --- a/src/detect-engine-analyzer.h +++ b/src/detect-engine-analyzer.h @@ -36,7 +36,7 @@ int PerCentEncodingSetup (); int PerCentEncodingMatch (uint8_t *content, uint8_t content_len); void EngineAnalysisFP(Signature *s, char *line); -void EngineAnalysisRules(Signature *s, char *line); +void EngineAnalysisRules(const Signature *s, const char *line); void EngineAnalysisRulesFailure(char *line, char *file, int lineno); #endif /* __DETECT_ENGINE_ANALYZER_H__ */ diff --git a/src/detect-engine-apt-event.c b/src/detect-engine-apt-event.c deleted file mode 100644 index 5ca416892dc6..000000000000 --- a/src/detect-engine-apt-event.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Anoop Saldanha - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "app-layer-parser.h" -#include "detect-app-layer-event.h" -#include "detect-engine-state.h" -#include "stream.h" -#include "detect-engine-apt-event.h" -#include "util-profiling.h" -#include "util-unittest.h" - -int DetectEngineAptEventInspect(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - AppLayerDecoderEvents *decoder_events = NULL; - int r = 0; - AppProto alproto; - SigMatch *sm; - DetectAppLayerEventData *aled = NULL; - - alproto = f->alproto; - decoder_events = AppLayerParserGetEventsByTx(f->proto, alproto, alstate, tx_id); - if (decoder_events == NULL) - goto end; - - for (sm = s->sm_lists[DETECT_SM_LIST_APP_EVENT]; sm != NULL; sm = sm->next) { - aled = (DetectAppLayerEventData *)sm->ctx; - KEYWORD_PROFILING_START; - if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - continue; - } - - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - goto end; - } - - r = 1; - - end: - if (r == 1) { - return DETECT_ENGINE_INSPECT_SIG_MATCH; - } else { - if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) == - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) - { - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; - } - } -} - diff --git a/src/detect-engine-content-inspection.c b/src/detect-engine-content-inspection.c index 0b7c23af9875..e7f83da7c175 100644 --- a/src/detect-engine-content-inspection.c +++ b/src/detect-engine-content-inspection.c @@ -42,11 +42,12 @@ #include "detect-uricontent.h" #include "detect-urilen.h" #include "detect-lua.h" +#include "detect-base64-decode.h" +#include "detect-base64-data.h" #include "app-layer-dcerpc.h" #include "util-spm.h" -#include "util-spm-bm.h" #include "util-debug.h" #include "util-print.h" @@ -98,7 +99,7 @@ * \retval 1 match */ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, @@ -111,19 +112,19 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx if (det_ctx->inspection_recursion_counter == de_ctx->inspection_recursion_limit) { det_ctx->discontinue_matching = 1; - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); } - if (sm == NULL || buffer_len == 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + if (smd == NULL || buffer_len == 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); } /* \todo unify this which is phase 2 of payload inspection unification */ - if (sm->type == DETECT_CONTENT) { + if (smd->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; + DetectContentData *cd = (DetectContentData *)smd->ctx; SCLogDebug("inspecting content %"PRIu32" buffer_len %"PRIu32, cd->id, buffer_len); /* we might have already have this content matched by the mpm. @@ -277,10 +278,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx * greater than sbuffer_len found is anyways NULL */ /* do the actual search */ - if (cd->flags & DETECT_CONTENT_NOCASE) - found = BoyerMooreNocase(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx); - else - found = BoyerMoore(cd->content, cd->content_len, sbuffer, sbuffer_len, cd->bm_ctx); + found = SpmScan(cd->spm_ctx, det_ctx->spm_thread_ctx, sbuffer, + sbuffer_len); /* next we evaluate the result in combination with the * negation flag. */ @@ -319,17 +318,18 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* bail out if we have no next match. Technically this is an * error, as the current cd has the DETECT_CONTENT_RELATIVE_NEXT * flag set. */ - if (sm->next == NULL) { + if (smd->is_last) { goto no_match; } SCLogDebug("content %"PRIu32, cd->id); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); /* see if the next buffer keywords match. If not, we will * search for another occurence of this content and see * if the others match then until we run out of matches */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } @@ -344,10 +344,10 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } while(1); - } else if (sm->type == DETECT_ISDATAAT) { + } else if (smd->type == DETECT_ISDATAAT) { SCLogDebug("inspecting isdataat"); - DetectIsdataatData *id = (DetectIsdataatData *)sm->ctx; + DetectIsdataatData *id = (DetectIsdataatData *)smd->ctx; if (id->flags & ISDATAAT_RELATIVE) { if (det_ctx->buffer_offset + id->dataat > buffer_len) { SCLogDebug("det_ctx->buffer_offset + id->dataat %"PRIu32" > %"PRIu32, det_ctx->buffer_offset + id->dataat, buffer_len); @@ -374,9 +374,9 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx } } - } else if (sm->type == DETECT_PCRE) { + } else if (smd->type == DETECT_PCRE) { SCLogDebug("inspecting pcre"); - DetectPcreData *pe = (DetectPcreData *)sm->ctx; + DetectPcreData *pe = (DetectPcreData *)smd->ctx; uint32_t prev_buffer_offset = det_ctx->buffer_offset; uint32_t prev_offset = 0; int r = 0; @@ -386,7 +386,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx Packet *p = NULL; if (inspection_mode == DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD) p = (Packet *)data; - r = DetectPcrePayloadMatch(det_ctx, s, sm, p, f, + r = DetectPcrePayloadMatch(det_ctx, s, smd, p, f, buffer, buffer_len); if (r == 0) { goto no_match; @@ -396,7 +396,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCLogDebug("no relative match coming up, so this is a match"); goto match; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); /* save it, in case we need to do a pcre match once again */ prev_offset = det_ctx->pcre_match_start_offset; @@ -404,8 +404,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* see if the next payload keywords match. If not, we will * search for another occurence of this pcre and see * if the others match, until we run out of matches */ - r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, - f, buffer, buffer_len, stream_start_offset, inspection_mode, data); + r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); if (r == 1) { SCReturnInt(1); } @@ -417,8 +417,8 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx det_ctx->pcre_match_start_offset = prev_offset; } while (1); - } else if (sm->type == DETECT_BYTETEST) { - DetectBytetestData *btd = (DetectBytetestData *)sm->ctx; + } else if (smd->type == DETECT_BYTETEST) { + DetectBytetestData *btd = (DetectBytetestData *)smd->ctx; uint8_t flags = btd->flags; int32_t offset = btd->offset; uint64_t value = btd->value; @@ -431,7 +431,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* if we have dce enabled we will have to use the endianness * specified by the dce header */ - if (flags & DETECT_BYTETEST_DCE) { + if (flags & DETECT_BYTETEST_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ @@ -439,15 +439,15 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTETEST_LITTLE: 0); } - if (DetectBytetestDoMatch(det_ctx, s, sm, buffer, buffer_len, flags, + if (DetectBytetestDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, flags, offset, value) != 1) { goto no_match; } goto match; - } else if (sm->type == DETECT_BYTEJUMP) { - DetectBytejumpData *bjd = (DetectBytejumpData *)sm->ctx; + } else if (smd->type == DETECT_BYTEJUMP) { + DetectBytejumpData *bjd = (DetectBytejumpData *)smd->ctx; uint8_t flags = bjd->flags; int32_t offset = bjd->offset; @@ -457,7 +457,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx /* if we have dce enabled we will have to use the endianness * specified by the dce header */ - if (flags & DETECT_BYTEJUMP_DCE) { + if (flags & DETECT_BYTEJUMP_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done * processing we reset the flags to the original value*/ @@ -465,22 +465,22 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTEJUMP_LITTLE: 0); } - if (DetectBytejumpDoMatch(det_ctx, s, sm, buffer, buffer_len, + if (DetectBytejumpDoMatch(det_ctx, s, smd->ctx, buffer, buffer_len, flags, offset) != 1) { goto no_match; } goto match; - } else if (sm->type == DETECT_BYTE_EXTRACT) { + } else if (smd->type == DETECT_BYTE_EXTRACT) { - DetectByteExtractData *bed = (DetectByteExtractData *)sm->ctx; + DetectByteExtractData *bed = (DetectByteExtractData *)smd->ctx; uint8_t endian = bed->endian; /* if we have dce enabled we will have to use the endianness * specified by the dce header */ if ((bed->flags & DETECT_BYTE_EXTRACT_FLAG_ENDIAN) && - endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE) { + endian == DETECT_BYTE_EXTRACT_ENDIAN_DCE && data != NULL) { DCERPCState *dcerpc_state = (DCERPCState *)data; /* enable the endianness flag temporarily. once we are done @@ -489,7 +489,7 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx DETECT_BYTE_EXTRACT_ENDIAN_LITTLE : DETECT_BYTE_EXTRACT_ENDIAN_BIG); } - if (DetectByteExtractDoMatch(det_ctx, sm, s, buffer, + if (DetectByteExtractDoMatch(det_ctx, smd, s, buffer, buffer_len, &det_ctx->bj_values[bed->local_id], endian) != 1) { @@ -499,11 +499,11 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx goto match; /* we should never get here, but bail out just in case */ - } else if (sm->type == DETECT_AL_URILEN) { + } else if (smd->type == DETECT_AL_URILEN) { SCLogDebug("inspecting uri len"); int r = 0; - DetectUrilenData *urilend = (DetectUrilenData *) sm->ctx; + DetectUrilenData *urilend = (DetectUrilenData *) smd->ctx; switch (urilend->mode) { case DETECT_URILEN_EQ: @@ -535,15 +535,11 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx goto no_match; #ifdef HAVE_LUA } - else if (sm->type == DETECT_LUA) { + else if (smd->type == DETECT_LUA) { SCLogDebug("lua starting"); - /* for flowvar gets and sets we need to know the flow's lock status */ - int flow_lock = LUA_FLOW_LOCKED_BY_PARENT; - if (inspection_mode <= DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM) - flow_lock = LUA_FLOW_NOT_LOCKED_BY_PARENT; - if (DetectLuaMatchBuffer(det_ctx, s, sm, buffer, buffer_len, - det_ctx->buffer_offset, f, flow_lock) != 1) + if (DetectLuaMatchBuffer(det_ctx, s, smd, buffer, buffer_len, + det_ctx->buffer_offset, f) != 1) { SCLogDebug("lua no_match"); goto no_match; @@ -551,26 +547,37 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx SCLogDebug("lua match"); goto match; #endif /* HAVE_LUA */ + } else if (smd->type == DETECT_BASE64_DECODE) { + if (DetectBase64DecodeDoMatch(det_ctx, s, smd, buffer, buffer_len)) { + if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) { + /* Base64 is a terminal list. */ + goto final_match; + } + } + } } else { - SCLogDebug("sm->type %u", sm->type); + SCLogDebug("sm->type %u", smd->type); #ifdef DEBUG BUG_ON(1); #endif } no_match: - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); SCReturnInt(0); match: /* this sigmatch matched, inspect the next one. If it was the last, * the buffer portion of the signature matched. */ - if (sm->next != NULL) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data); + if (!smd->is_last) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd+1, + f, buffer, buffer_len, stream_start_offset, inspection_mode, data); SCReturnInt(r); - } else { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - SCReturnInt(1); } +final_match: + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + SCReturnInt(1); } diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 090e39495dca..b3436f736617 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -24,34 +24,17 @@ #ifndef __DETECT_ENGINE_CONTENT_INSPECTION_H__ #define __DETECT_ENGINE_CONTENT_INSPECTION_H__ -/** \warning make sure to add new entries to the proper position - * wrt flow lock status +/** indication to content engine what type of data + * we're inspecting */ enum { - /* called with flow unlocked */ DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD = 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, - - /* called with flow locked */ - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, SigMatch *sm, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, diff --git a/src/detect-engine-dcepayload.c b/src/detect-engine-dcepayload.c index c2f7610eb54a..a680b1e74d62 100644 --- a/src/detect-engine-dcepayload.c +++ b/src/detect-engine-dcepayload.c @@ -47,6424 +47,19 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -/** - * \brief Do the content inspection & validation for a signature against dce stub. - * - * \param de_ctx Detection engine context. - * \param det_ctx Detection engine thread context. - * \param s Signature to inspect. - * \param sm SigMatch to inspect. - * \param f Flow. - * \param flags App layer flags. - * \param state App layer state. - * - * \retval 0 No match. - * \retval 1 Match. - */ -int DetectEngineInspectDcePayload(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, - Flow *f, uint8_t flags, void *alstate) -{ - SCEnter(); - DCERPCState *dcerpc_state = (DCERPCState *)alstate; - uint8_t *dce_stub_data = NULL; - uint16_t dce_stub_data_len; - int r = 0; - - if (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL || dcerpc_state == NULL) { - SCReturnInt(0); - } - - if (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && - dcerpc_state->dcerpc.dcerpcrequest.stub_data_fresh != 0) { - /* the request stub and stub_len */ - dce_stub_data = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer; - dce_stub_data_len = dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len; - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], - f, - dce_stub_data, - dce_stub_data_len, - 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, - //dce_stub_data, dce_stub_data_len, dcerpc_state); - if (r == 1) { - SCReturnInt(1); - } - } - - if (dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer != NULL && - dcerpc_state->dcerpc.dcerpcresponse.stub_data_fresh == 0) { - /* the response stub and stub_len */ - dce_stub_data = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer; - dce_stub_data_len = dcerpc_state->dcerpc.dcerpcresponse.stub_data_buffer_len; - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], - f, - dce_stub_data, - dce_stub_data_len, - 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DCE, dcerpc_state); - //r = DoInspectDcePayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_DMATCH], f, - //dce_stub_data, dce_stub_data_len, dcerpc_state); - if (r == 1) { - SCReturnInt(1); - } - } - - SCReturnInt(0); -} - -/**************************************Unittests*******************************/ - -#ifdef UNITTESTS - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest01(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - uint8_t request3[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x26, 0x65, 0x3c, 0x6e, 0x6d, 0x64, 0x24, 0x39, - 0x56, 0x43, 0x3e, 0x61, 0x5c, 0x54, 0x42, 0x23, - 0x75, 0x6b, 0x71, 0x27, 0x66, 0x2e, 0x6e, 0x3d, - 0x58, 0x23, 0x54, 0x77, 0x3b, 0x52, 0x6b, 0x50, - 0x3b, 0x74, 0x2c, 0x54, 0x25, 0x5c, 0x51, 0x7c, - 0x29, 0x7c, 0x5f, 0x4a, 0x35, 0x5c, 0x3d, 0x3f, - 0x33, 0x55, 0x3b, 0x5a, 0x57, 0x31, 0x59, 0x4f, - 0x6d, 0x6d, 0x7b, 0x3e, 0x38, 0x4d, 0x68, 0x75, - 0x64, 0x21, 0x50, 0x63, 0x47, 0x42, 0x56, 0x39, - 0x6c, 0x6f, 0x61, 0x53, 0x32, 0x56, 0x43, 0x52, - 0x43, 0x67, 0x26, 0x45, 0x28, 0x6b, 0x77, 0x28, - 0x7c, 0x64, 0x61, 0x24, 0x38, 0x6b, 0x59, 0x2a, - 0x4f, 0x6e, 0x5b, 0x57, 0x24, 0x54, 0x33, 0x37, - 0x47, 0x58, 0x4b, 0x58, 0x3d, 0x21, 0x38, 0x7c, - 0x2c, 0x24, 0x5f, 0x67, 0x3a, 0x41, 0x3e, 0x2a, - 0x72, 0x66, 0x2d, 0x6b, 0x66, 0x7b, 0x2b, 0x75, - 0x78, 0x2f, 0x4d, 0x4c, 0x51, 0x70, 0x5d, 0x55, - 0x54, 0x3c, 0x63, 0x46, 0x6b, 0x64, 0x4d, 0x25, - 0x45, 0x21, 0x34, 0x65, 0x48, 0x32, 0x58, 0x4c, - 0x70, 0x4c, 0x4c, 0x75, 0x5c, 0x77, 0x68, 0x78, - 0x34, 0x5c, 0x2d, 0x39, 0x58, 0x3b, 0x40, 0x71, - 0x77, 0x47, 0x32, 0x2e, 0x3c, 0x61, 0x6f, 0x6d, - 0x5f, 0x43, 0x74, 0x36, 0x4f, 0x21, 0x44, 0x66, - 0x36, 0x62, 0x30, 0x29, 0x5a, 0x34, 0x66, 0x4e, - 0x51, 0x23, 0x4e, 0x38, 0x51, 0x78, 0x74, 0x58, - 0x2e, 0x6d, 0x51, 0x49, 0x55, 0x73, 0x2a, 0x71, - 0x3c, 0x74, 0x38, 0x6f, 0x5d, 0x4b, 0x74, 0x68, - 0x65, 0x4a, 0x58, 0x41, 0x55, 0x29, 0x42, 0x69, - 0x55, 0x3b, 0x2b, 0x47, 0x64, 0x3b, 0x77, 0x72, - 0x74, 0x38, 0x53, 0x5c, 0x69, 0x49, 0x49, 0x5b, - 0x31, 0x41, 0x6a, 0x4e, 0x2c, 0x6a, 0x63, 0x3f, - 0x58, 0x4e, 0x25, 0x3e, 0x57, 0x41, 0x61, 0x26, - 0x5e, 0x24, 0x69, 0x7a, 0x38, 0x60, 0x73, 0x70, - 0x7d, 0x63, 0x34, 0x78, 0x4d, 0x50, 0x35, 0x69, - 0x49, 0x22, 0x45, 0x44, 0x3f, 0x6e, 0x75, 0x64, - 0x57, 0x3a, 0x61, 0x60, 0x34, 0x21, 0x61, 0x21, - 0x2a, 0x78, 0x7b, 0x52, 0x43, 0x50, 0x5b, 0x76, - 0x5f, 0x4b, 0x6a, 0x5d, 0x23, 0x5b, 0x57, 0x40, - 0x53, 0x51, 0x33, 0x21, 0x35, 0x7d, 0x31, 0x46, - 0x65, 0x52, 0x28, 0x25, 0x30, 0x5a, 0x37, 0x7c, - 0x2c, 0x3d, 0x2a, 0x48, 0x24, 0x5a, 0x2f, 0x47, - 0x64, 0x73, 0x64, 0x3d, 0x7a, 0x5b, 0x34, 0x5e, - 0x42, 0x22, 0x32, 0x47, 0x6e, 0x58, 0x3b, 0x3e, - 0x25, 0x2f, 0x58, 0x78, 0x42, 0x66, 0x71, 0x56, - 0x2a, 0x66, 0x66, 0x5b, 0x55, 0x35, 0x7a, 0x41, - 0x7c, 0x7c, 0x6a, 0x2d, 0x59, 0x25, 0x22, 0x34, - 0x5a, 0x61, 0x37, 0x48, 0x39, 0x31, 0x4a, 0x55, - 0x6a, 0x68, 0x40, 0x2f, 0x45, 0x69, 0x46, 0x25, - 0x51, 0x7d, 0x4f, 0x71, 0x21, 0x33, 0x55, 0x50, - 0x56, 0x5f, 0x75, 0x27, 0x64, 0x36, 0x7a, 0x39, - 0x40, 0x6a, 0x77, 0x38, 0x5d, 0x39, 0x30, 0x5e, - 0x74, 0x54, 0x24, 0x3f, 0x3d, 0x79, 0x3b, 0x27, - 0x7d, 0x68, 0x7d, 0x40, 0x71, 0x7a, 0x65, 0x54, - 0x50, 0x66, 0x33, 0x3c, 0x42, 0x69, 0x6e, 0x3c, - 0x63, 0x63, 0x69, 0x7a, 0x5e, 0x7b, 0x76, 0x26, - 0x71, 0x6f, 0x4a, 0x6d, 0x70, 0x73, 0x66, 0x3b, - 0x26, 0x70, 0x43, 0x5b, 0x52, 0x4c, 0x6d, 0x51, - 0x2a, 0x66, 0x6c, 0x3e, 0x68, 0x6a, 0x31, 0x41, - 0x79, 0x72, 0x37, 0x47, 0x7d, 0x2b, 0x3c, 0x40, - 0x6b, 0x75, 0x56, 0x70, 0x7b, 0x2d, 0x5f, 0x33, - 0x30, 0x30, 0x21, 0x35, 0x7a, 0x7a, 0x67, 0x48, - 0x5e, 0x3b, 0x73, 0x50, 0x54, 0x47, 0x23, 0x2b, - 0x4c, 0x4e, 0x2f, 0x24, 0x44, 0x34, 0x23, 0x5d, - 0x76, 0x51, 0x5a, 0x73, 0x72, 0x3e, 0x47, 0x77, - 0x40, 0x28, 0x65, 0x2e, 0x2a, 0x75, 0x3c, 0x2a, - 0x27, 0x4a, 0x3f, 0x3c, 0x66, 0x2d, 0x21, 0x79, - 0x2d, 0x2b, 0x78, 0x7c, 0x5a, 0x73, 0x46, 0x6b, - 0x39, 0x65, 0x5e, 0x3d, 0x38, 0x40, 0x32, 0x3e, - 0x21, 0x62, 0x34, 0x41, 0x58, 0x53, 0x67, 0x34, - 0x58, 0x56, 0x61, 0x5b, 0x3e, 0x4e, 0x2c, 0x5b, - 0x73, 0x35, 0x34, 0x35, 0x21, 0x3a, 0x61, 0x5f, - 0x6e, 0x45, 0x78, 0x44, 0x28, 0x23, 0x48, 0x65, - 0x53, 0x47, 0x6e, 0x2c, 0x38, 0x5e, 0x2c, 0x57, - 0x58, 0x30, 0x7a, 0x3b, 0x4b, 0x4a, 0x74, 0x7d, - 0x3e, 0x4d, 0x30, 0x24, 0x76, 0x66, 0x6d, 0x2e, - 0x74, 0x75, 0x28, 0x48, 0x5c, 0x23, 0x6c, 0x46, - 0x27, 0x46, 0x6e, 0x34, 0x63, 0x21, 0x58, 0x54, - 0x50, 0x2f, 0x40, 0x47, 0x40, 0x32, 0x36, 0x48, - 0x5f, 0x7d, 0x4a, 0x41, 0x6e, 0x60, 0x2c, 0x4a, - 0x6a, 0x67, 0x6c, 0x41, 0x27, 0x23, 0x30, 0x48, - 0x6a, 0x49, 0x73, 0x26, 0x77, 0x75, 0x4d, 0x65, - 0x5b, 0x34, 0x79, 0x67, 0x61, 0x5b, 0x5c, 0x2b, - 0x71, 0x3f, 0x62, 0x51, 0x3a, 0x53, 0x42, 0x26, - 0x6f, 0x36, 0x57, 0x3f, 0x2b, 0x34, 0x24, 0x30, - 0x60, 0x55, 0x70, 0x65, 0x70, 0x57, 0x5d, 0x68, - 0x36, 0x52, 0x5d, 0x3f, 0x6a, 0x3a, 0x33, 0x31, - 0x6c, 0x4e, 0x57, 0x79, 0x49, 0x79, 0x69, 0x71, - 0x6f, 0x70, 0x6a, 0x76, 0x4b, 0x2f, 0x33, 0x51, - 0x68, 0x30, 0x2e, 0x77, 0x78, 0x55, 0x2f, 0x53, - 0x52, 0x5e, 0x57, 0x60, 0x3b, 0x6f, 0x69, 0x61, - 0x6c, 0x60, 0x5a, 0x34, 0x5a, 0x35, 0x4b, 0x28, - 0x54, 0x32, 0x6a, 0x35, 0x36, 0x6d, 0x68, 0x47, - 0x5c, 0x74, 0x2e, 0x5f, 0x6c, 0x6d, 0x55, 0x42, - 0x77, 0x64, 0x7d, 0x53, 0x4d, 0x39, 0x2c, 0x41, - 0x42, 0x23, 0x3a, 0x73, 0x40, 0x60, 0x5d, 0x38, - 0x6d, 0x36, 0x56, 0x57, 0x2a, 0x28, 0x3d, 0x3b, - 0x5c, 0x75, 0x35, 0x2d, 0x69, 0x2d, 0x44, 0x51, - 0x27, 0x63, 0x66, 0x33, 0x46, 0x42, 0x2e, 0x36, - 0x6b, 0x7b, 0x2c, 0x23, 0x3b, 0x5a, 0x50, 0x2a, - 0x65, 0x28, 0x3b, 0x3c, 0x51, 0x3f, 0x4d, 0x63, - 0x38, 0x25, 0x74, 0x2e, 0x51, 0x22, 0x31, 0x74, - 0x35, 0x33, 0x23, 0x2d, 0x3f, 0x77, 0x26, 0x2c, - 0x55, 0x6d, 0x27, 0x39, 0x79, 0x76, 0x63, 0x4b, - 0x43, 0x4a, 0x3a, 0x6b, 0x59, 0x55, 0x65, 0x26, - 0x2f, 0x3f, 0x56, 0x67, 0x5a, 0x77, 0x71, 0x22, - 0x51, 0x2b, 0x6d, 0x4c, 0x2c, 0x57, 0x66, 0x76, - 0x37, 0x70, 0x5f, 0x52, 0x29, 0x44, 0x52, 0x22, - 0x57, 0x37, 0x27, 0x79, 0x29, 0x5c, 0x57, 0x3b, - 0x54, 0x3c, 0x3f, 0x53, 0x35, 0x27, 0x5e, 0x7c, - 0x49, 0x77, 0x57, 0x5a, 0x22, 0x76, 0x7c, 0x5b, - 0x2f, 0x53, 0x5e, 0x55, 0x6d, 0x64, 0x67, 0x34, - 0x41, 0x23, 0x76, 0x67, 0x23, 0x78, 0x6a, 0x63, - 0x27, 0x68, 0x43, 0x7d, 0x58, 0x49, 0x2d, 0x79, - 0x2e, 0x75, 0x60, 0x6b, 0x34, 0x48, 0x6f, 0x4a, - 0x6c, 0x48, 0x40, 0x68, 0x5f, 0x35, 0x25, 0x6c, - 0x38, 0x5c, 0x30, 0x32, 0x4c, 0x36, 0x31, 0x29, - 0x74, 0x4a, 0x55, 0x56, 0x6d, 0x4e, 0x23, 0x54, - 0x2e, 0x69, 0x78, 0x61, 0x76, 0x66, 0x22, 0x44, - 0x73, 0x25, 0x44, 0x29, 0x2a, 0x28, 0x3b, 0x67, - 0x48, 0x58, 0x37, 0x4a, 0x76, 0x76, 0x51, 0x4a, - 0x61, 0x70, 0x51, 0x74, 0x40, 0x23, 0x29, 0x63, - 0x69, 0x4a, 0x29, 0x23, 0x34, 0x6a, 0x3b, 0x25, - 0x28, 0x54, 0x45, 0x33, 0x28, 0x44, 0x30, 0x61, - 0x5b, 0x60, 0x51, 0x3f, 0x68, 0x50, 0x70, 0x3d, - 0x58, 0x2e, 0x6e, 0x59, 0x5a, 0x62, 0x66, 0x4d, - 0x7a, 0x2e, 0x37, 0x37, 0x3d, 0x7b, 0x74, 0x79, - 0x48, 0x45, 0x77, 0x56, 0x33, 0x76, 0x71, 0x60, - 0x74, 0x3f, 0x61, 0x22, 0x52, 0x51, 0x71, 0x69 - }; - uint32_t request3_len = sizeof(request3); - - uint8_t request4[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x75, 0x3e, 0x76, 0x3e, 0x66, 0x6b, 0x6b, 0x3e, - 0x6d, 0x59, 0x38, 0x2b, 0x63, 0x4d, 0x2c, 0x73, - 0x54, 0x57, 0x34, 0x25, 0x5b, 0x42, 0x7d, 0x5d, - 0x37, 0x34, 0x2c, 0x79, 0x24, 0x4b, 0x74, 0x73, - 0x25, 0x36, 0x73, 0x3a, 0x2c, 0x55, 0x69, 0x3c, - 0x58, 0x67, 0x33, 0x53, 0x67, 0x5c, 0x61, 0x7b, - 0x44, 0x2e, 0x42, 0x2d, 0x6b, 0x50, 0x55, 0x24, - 0x70, 0x58, 0x60, 0x38, 0x42, 0x45, 0x70, 0x6d, - 0x2f, 0x27, 0x27, 0x2c, 0x21, 0x6d, 0x57, 0x6e, - 0x43, 0x3c, 0x5b, 0x27, 0x7a, 0x34, 0x49, 0x5a, - 0x69, 0x30, 0x3f, 0x6f, 0x77, 0x70, 0x39, 0x2d, - 0x51, 0x74, 0x4b, 0x25, 0x70, 0x51, 0x64, 0x4d, - 0x75, 0x52, 0x5e, 0x3e, 0x37, 0x30, 0x5d, 0x3b, - 0x2c, 0x72, 0x25, 0x6c, 0x6f, 0x79, 0x69, 0x3c, - 0x5b, 0x73, 0x3d, 0x41, 0x28, 0x28, 0x64, 0x60, - 0x4b, 0x7a, 0x2c, 0x4a, 0x6b, 0x3d, 0x2e, 0x6c, - 0x7a, 0x54, 0x70, 0x61, 0x6f, 0x4b, 0x40, 0x28, - 0x59, 0x31, 0x25, 0x21, 0x57, 0x79, 0x4b, 0x31, - 0x6f, 0x4e, 0x71, 0x2b, 0x3c, 0x24, 0x30, 0x28, - 0x3c, 0x61, 0x28, 0x4b, 0x35, 0x61, 0x4d, 0x55, - 0x5e, 0x66, 0x34, 0x5f, 0x61, 0x70, 0x7b, 0x67, - 0x51, 0x55, 0x68, 0x78, 0x26, 0x3a, 0x27, 0x4e, - 0x71, 0x79, 0x4f, 0x67, 0x2c, 0x5a, 0x79, 0x75, - 0x59, 0x3a, 0x33, 0x4a, 0x36, 0x71, 0x72, 0x6d, - 0x49, 0x3e, 0x53, 0x59, 0x2b, 0x2b, 0x27, 0x4e, - 0x50, 0x5d, 0x21, 0x55, 0x64, 0x4b, 0x72, 0x73, - 0x25, 0x55, 0x26, 0x4f, 0x3a, 0x21, 0x54, 0x29, - 0x4f, 0x64, 0x51, 0x59, 0x60, 0x7b, 0x7c, 0x6f, - 0x3e, 0x65, 0x74, 0x6a, 0x5b, 0x52, 0x2c, 0x56, - 0x4e, 0x45, 0x53, 0x4b, 0x7c, 0x38, 0x49, 0x4b, - 0x4e, 0x4f, 0x4a, 0x47, 0x5e, 0x7c, 0x46, 0x3b, - 0x67, 0x2e, 0x43, 0x79, 0x35, 0x55, 0x59, 0x6d, - 0x38, 0x70, 0x2f, 0x59, 0x4f, 0x27, 0x63, 0x40, - 0x66, 0x2d, 0x39, 0x4f, 0x3d, 0x2e, 0x4c, 0x67, - 0x71, 0x7d, 0x34, 0x22, 0x52, 0x4e, 0x36, 0x7b, - 0x2c, 0x39, 0x4d, 0x42, 0x60, 0x75, 0x74, 0x72, - 0x4f, 0x72, 0x68, 0x3a, 0x51, 0x31, 0x2d, 0x21, - 0x4a, 0x35, 0x47, 0x6d, 0x69, 0x3c, 0x50, 0x4c, - 0x59, 0x66, 0x4c, 0x71, 0x24, 0x3a, 0x36, 0x67, - 0x24, 0x5a, 0x59, 0x28, 0x7c, 0x21, 0x5e, 0x77, - 0x68, 0x5e, 0x7b, 0x6e, 0x56, 0x62, 0x36, 0x29, - 0x6f, 0x4f, 0x5d, 0x57, 0x56, 0x2b, 0x75, 0x2a, - 0x2c, 0x69, 0x63, 0x51, 0x74, 0x6e, 0x5e, 0x46, - 0x50, 0x28, 0x2c, 0x3b, 0x32, 0x53, 0x28, 0x78, - 0x59, 0x72, 0x39, 0x5e, 0x44, 0x5c, 0x77, 0x60, - 0x72, 0x44, 0x3b, 0x75, 0x68, 0x39, 0x55, 0x3e, - 0x44, 0x50, 0x76, 0x3c, 0x48, 0x46, 0x43, 0x22, - 0x56, 0x27, 0x21, 0x31, 0x33, 0x4a, 0x5a, 0x74, - 0x41, 0x58, 0x3f, 0x39, 0x29, 0x71, 0x73, 0x30, - 0x57, 0x70, 0x33, 0x62, 0x7b, 0x4a, 0x75, 0x3e, - 0x4d, 0x4c, 0x4e, 0x55, 0x63, 0x38, 0x66, 0x7d, - 0x68, 0x7d, 0x6f, 0x23, 0x55, 0x50, 0x3d, 0x34, - 0x46, 0x5e, 0x2f, 0x55, 0x27, 0x62, 0x68, 0x7c, - 0x6c, 0x21, 0x2b, 0x63, 0x4b, 0x47, 0x6b, 0x6a, - 0x5b, 0x7b, 0x5c, 0x71, 0x37, 0x7c, 0x52, 0x2b, - 0x2f, 0x4a, 0x47, 0x70, 0x78, 0x50, 0x2f, 0x75, - 0x28, 0x4c, 0x60, 0x4c, 0x4c, 0x54, 0x6b, 0x68, - 0x63, 0x4f, 0x47, 0x39, 0x2a, 0x70, 0x51, 0x7d, - 0x28, 0x59, 0x52, 0x46, 0x4b, 0x38, 0x27, 0x49, - 0x50, 0x5d, 0x25, 0x22, 0x5f, 0x48, 0x2c, 0x2f, - 0x67, 0x59, 0x5d, 0x7d, 0x21, 0x3d, 0x72, 0x4f, - 0x5c, 0x5b, 0x41, 0x47, 0x5f, 0x56, 0x69, 0x42, - 0x55, 0x60, 0x68, 0x4b, 0x77, 0x44, 0x4c, 0x3b, - 0x7d, 0x5a, 0x58, 0x43, 0x7a, 0x33, 0x22, 0x58, - 0x58, 0x6f, 0x74, 0x53, 0x57, 0x6d, 0x6e, 0x29, - 0x6b, 0x33, 0x71, 0x68, 0x29, 0x48, 0x67, 0x35, - 0x52, 0x41, 0x6b, 0x36, 0x4f, 0x46, 0x31, 0x24, - 0x73, 0x56, 0x40, 0x48, 0x37, 0x51, 0x24, 0x2a, - 0x59, 0x21, 0x74, 0x76, 0x25, 0x2e, 0x4a, 0x74, - 0x32, 0x29, 0x5f, 0x57, 0x7c, 0x58, 0x30, 0x2c, - 0x7b, 0x70, 0x5b, 0x51, 0x73, 0x27, 0x4a, 0x28, - 0x77, 0x2a, 0x43, 0x28, 0x2e, 0x32, 0x3d, 0x38, - 0x36, 0x2e, 0x6b, 0x40, 0x6c, 0x76, 0x54, 0x66, - 0x4a, 0x5c, 0x25, 0x62, 0x2e, 0x61, 0x48, 0x30, - 0x28, 0x41, 0x40, 0x69, 0x3c, 0x39, 0x36, 0x4b, - 0x64, 0x50, 0x76, 0x3d, 0x52, 0x50, 0x77, 0x33, - 0x3b, 0x65, 0x59, 0x31, 0x5c, 0x48, 0x6a, 0x74, - 0x78, 0x5b, 0x74, 0x60, 0x47, 0x27, 0x60, 0x22, - 0x4a, 0x72, 0x25, 0x34, 0x5d, 0x3a, 0x21, 0x66, - 0x61, 0x7b, 0x34, 0x41, 0x3b, 0x3a, 0x27, 0x44, - 0x48, 0x7c, 0x7a, 0x74, 0x3a, 0x68, 0x59, 0x48, - 0x61, 0x32, 0x49, 0x61, 0x40, 0x22, 0x33, 0x75, - 0x29, 0x76, 0x5b, 0x24, 0x5b, 0x5c, 0x76, 0x5c, - 0x28, 0x75, 0x36, 0x26, 0x2c, 0x65, 0x5e, 0x51, - 0x7b, 0x3a, 0x7d, 0x4f, 0x35, 0x73, 0x6b, 0x5b, - 0x5c, 0x37, 0x35, 0x6b, 0x41, 0x35, 0x40, 0x3a, - 0x22, 0x28, 0x6c, 0x71, 0x46, 0x68, 0x7b, 0x66, - 0x56, 0x24, 0x7c, 0x54, 0x28, 0x30, 0x22, 0x4e, - 0x3c, 0x65, 0x69, 0x36, 0x44, 0x53, 0x3d, 0x6c, - 0x5f, 0x73, 0x6c, 0x6f, 0x5e, 0x27, 0x23, 0x4e, - 0x60, 0x45, 0x2f, 0x3d, 0x37, 0x28, 0x51, 0x29, - 0x77, 0x6a, 0x6b, 0x2a, 0x2a, 0x51, 0x26, 0x4c, - 0x4e, 0x71, 0x77, 0x73, 0x71, 0x2d, 0x5a, 0x2c, - 0x23, 0x3d, 0x5f, 0x62, 0x63, 0x2e, 0x72, 0x2a, - 0x75, 0x66, 0x43, 0x56, 0x5f, 0x21, 0x64, 0x66, - 0x35, 0x3b, 0x7a, 0x45, 0x3f, 0x4f, 0x57, 0x22, - 0x5a, 0x45, 0x65, 0x37, 0x58, 0x5b, 0x43, 0x66, - 0x4f, 0x5d, 0x6e, 0x41, 0x41, 0x62, 0x5e, 0x39, - 0x65, 0x6f, 0x43, 0x4b, 0x5e, 0x51, 0x42, 0x3f, - 0x2d, 0x68, 0x4b, 0x6e, 0x46, 0x6f, 0x21, 0x44, - 0x3c, 0x22, 0x46, 0x31, 0x31, 0x2e, 0x56, 0x2e, - 0x77, 0x48, 0x68, 0x23, 0x4a, 0x36, 0x52, 0x5d, - 0x61, 0x47, 0x71, 0x2e, 0x3a, 0x4a, 0x5b, 0x56, - 0x6b, 0x52, 0x2a, 0x4c, 0x4f, 0x24, 0x34, 0x60, - 0x70, 0x58, 0x7a, 0x76, 0x4b, 0x68, 0x24, 0x5f, - 0x51, 0x6d, 0x75, 0x45, 0x48, 0x21, 0x53, 0x4d, - 0x27, 0x75, 0x5f, 0x50, 0x3e, 0x40, 0x3f, 0x5e, - 0x64, 0x41, 0x5f, 0x68, 0x48, 0x30, 0x71, 0x4b, - 0x66, 0x2c, 0x2f, 0x76, 0x4b, 0x23, 0x46, 0x34, - 0x50, 0x58, 0x52, 0x69, 0x2b, 0x6e, 0x7a, 0x33, - 0x53, 0x43, 0x43, 0x35, 0x54, 0x30, 0x73, 0x63, - 0x3b, 0x43, 0x52, 0x29, 0x45, 0x37, 0x71, 0x79, - 0x5a, 0x26, 0x24, 0x72, 0x73, 0x4e, 0x44, 0x38, - 0x5b, 0x71, 0x36, 0x3a, 0x4f, 0x5b, 0x71, 0x28, - 0x71, 0x79, 0x72, 0x40, 0x6e, 0x51, 0x72, 0x29, - 0x3d, 0x4f, 0x33, 0x22, 0x73, 0x5a, 0x30, 0x71, - 0x58, 0x54, 0x59, 0x48, 0x29, 0x2b, 0x5c, 0x73, - 0x6f, 0x4e, 0x60, 0x2a, 0x72, 0x39, 0x50, 0x59, - 0x6f, 0x48, 0x3e, 0x62, 0x6c, 0x62, 0x49, 0x6c, - 0x2c, 0x3f, 0x43, 0x3f, 0x32, 0x7c, 0x6f, 0x6c, - 0x39, 0x26, 0x26, 0x7b, 0x5d, 0x65, 0x6f, 0x41, - 0x7c, 0x42, 0x2b, 0x65, 0x6f, 0x3e, 0x7b, 0x69, - 0x46, 0x4d, 0x68, 0x68, 0x5a, 0x33, 0x25, 0x5d, - 0x6f, 0x48, 0x7c, 0x77, 0x7d, 0x3f, 0x4e, 0x30, - 0x69, 0x65, 0x28, 0x2e, 0x34, 0x34, 0x41, 0x43, - 0x5e, 0x30, 0x23, 0x3b, 0x60, 0x79, 0x5b, 0x26, - 0x7c, 0x77, 0x3e, 0x43, 0x24, 0x31, 0x3a, 0x56, - 0x24, 0x3c, 0x60, 0x3f, 0x60, 0x55, 0x6a, 0x68 - }; - uint32_t request4_len = sizeof(request4); - - uint8_t request5[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x69, 0x3e, 0x72, 0x44, 0x31, 0x6b, 0x28, 0x2f, - 0x79, 0x37, 0x58, 0x5d, 0x5f, 0x68, 0x71, 0x47, - 0x7a, 0x68, 0x7c, 0x6c, 0x65, 0x3c, 0x74, 0x67, - 0x59, 0x5c, 0x3d, 0x28, 0x65, 0x28, 0x58, 0x74, - 0x44, 0x62, 0x2e, 0x36, 0x54, 0x2f, 0x24, 0x34, - 0x4b, 0x6d, 0x3a, 0x7b, 0x60, 0x71, 0x5a, 0x77, - 0x4a, 0x27, 0x25, 0x70, 0x75, 0x56, 0x78, 0x73, - 0x2e, 0x38, 0x6c, 0x70, 0x66, 0x7b, 0x7b, 0x2d, - 0x78, 0x27, 0x65, 0x63, 0x58, 0x4f, 0x7d, 0x5c, - 0x31, 0x3e, 0x36, 0x6e, 0x65, 0x61, 0x2e, 0x4e, - 0x26, 0x68, 0x2b, 0x33, 0x7d, 0x54, 0x2c, 0x28, - 0x47, 0x3a, 0x31, 0x47, 0x56, 0x32, 0x74, 0x51, - 0x79, 0x65, 0x42, 0x45, 0x60, 0x55, 0x6f, 0x48, - 0x61, 0x23, 0x72, 0x62, 0x74, 0x3a, 0x5a, 0x26, - 0x2d, 0x41, 0x58, 0x62, 0x75, 0x4b, 0x37, 0x2e, - 0x3f, 0x2a, 0x6e, 0x2e, 0x2c, 0x43, 0x6f, 0x53, - 0x5f, 0x48, 0x7a, 0x53, 0x7b, 0x54, 0x28, 0x30, - 0x2b, 0x7a, 0x34, 0x33, 0x28, 0x2b, 0x23, 0x23, - 0x72, 0x38, 0x25, 0x30, 0x35, 0x66, 0x76, 0x46, - 0x2a, 0x57, 0x7a, 0x60, 0x38, 0x5a, 0x26, 0x4f, - 0x78, 0x43, 0x2c, 0x7d, 0x3d, 0x76, 0x7d, 0x66, - 0x48, 0x7d, 0x3e, 0x59, 0x31, 0x58, 0x6b, 0x30, - 0x76, 0x45, 0x6e, 0x70, 0x72, 0x5f, 0x3c, 0x70, - 0x6d, 0x77, 0x42, 0x75, 0x42, 0x73, 0x68, 0x5e, - 0x5f, 0x72, 0x2b, 0x2a, 0x70, 0x38, 0x7a, 0x4c, - 0x58, 0x2e, 0x5e, 0x2d, 0x2d, 0x78, 0x67, 0x5a, - 0x77, 0x34, 0x5a, 0x50, 0x76, 0x2d, 0x2b, 0x77, - 0x37, 0x6e, 0x38, 0x2d, 0x7b, 0x44, 0x78, 0x67, - 0x52, 0x57, 0x79, 0x43, 0x7d, 0x6d, 0x4d, 0x32, - 0x23, 0x37, 0x51, 0x4b, 0x41, 0x60, 0x6e, 0x53, - 0x4e, 0x78, 0x37, 0x37, 0x60, 0x56, 0x64, 0x52, - 0x25, 0x46, 0x53, 0x5f, 0x2b, 0x56, 0x2b, 0x3b, - 0x40, 0x37, 0x33, 0x37, 0x23, 0x43, 0x36, 0x6b, - 0x6b, 0x5d, 0x35, 0x28, 0x7d, 0x6a, 0x2c, 0x68, - 0x28, 0x4b, 0x4a, 0x6c, 0x27, 0x35, 0x51, 0x66, - 0x30, 0x39, 0x28, 0x4d, 0x61, 0x2f, 0x64, 0x36, - 0x59, 0x39, 0x68, 0x4b, 0x24, 0x51, 0x7b, 0x6e, - 0x38, 0x49, 0x55, 0x72, 0x5f, 0x33, 0x5c, 0x26, - 0x45, 0x2f, 0x71, 0x66, 0x33, 0x3d, 0x36, 0x68, - 0x65, 0x48, 0x42, 0x40, 0x58, 0x61, 0x4f, 0x50, - 0x70, 0x5e, 0x3c, 0x5d, 0x56, 0x43, 0x4c, 0x41, - 0x45, 0x54, 0x76, 0x4b, 0x21, 0x25, 0x45, 0x4c, - 0x5e, 0x58, 0x23, 0x7d, 0x34, 0x61, 0x5c, 0x53, - 0x2a, 0x47, 0x37, 0x22, 0x6d, 0x31, 0x42, 0x6e, - 0x22, 0x72, 0x62, 0x55, 0x59, 0x66, 0x28, 0x73, - 0x55, 0x50, 0x5c, 0x6f, 0x52, 0x40, 0x3e, 0x3b, - 0x44, 0x2a, 0x51, 0x3d, 0x4d, 0x47, 0x3a, 0x57, - 0x3e, 0x29, 0x29, 0x7d, 0x40, 0x36, 0x41, 0x3f, - 0x58, 0x77, 0x3b, 0x41, 0x2d, 0x64, 0x5a, 0x72, - 0x7c, 0x7d, 0x30, 0x68, 0x54, 0x34, 0x40, 0x21, - 0x7d, 0x2b, 0x2d, 0x2b, 0x6d, 0x5f, 0x49, 0x57, - 0x68, 0x65, 0x79, 0x2c, 0x21, 0x41, 0x31, 0x55, - 0x27, 0x4d, 0x78, 0x55, 0x2f, 0x61, 0x62, 0x78, - 0x58, 0x25, 0x3a, 0x4b, 0x3e, 0x67, 0x44, 0x7c, - 0x7d, 0x52, 0x3d, 0x3e, 0x3b, 0x62, 0x2d, 0x28, - 0x48, 0x70, 0x2c, 0x79, 0x31, 0x5a, 0x5e, 0x3f, - 0x6a, 0x30, 0x78, 0x41, 0x44, 0x60, 0x4e, 0x63, - 0x63, 0x2e, 0x31, 0x79, 0x2b, 0x47, 0x57, 0x26, - 0x22, 0x6a, 0x46, 0x43, 0x70, 0x30, 0x51, 0x7d, - 0x21, 0x3c, 0x68, 0x74, 0x40, 0x5a, 0x6e, 0x71, - 0x3f, 0x76, 0x73, 0x2e, 0x29, 0x3f, 0x6a, 0x55, - 0x21, 0x72, 0x65, 0x75, 0x5e, 0x6b, 0x39, 0x6e, - 0x3e, 0x76, 0x42, 0x41, 0x65, 0x3f, 0x2b, 0x37, - 0x70, 0x7a, 0x7a, 0x29, 0x50, 0x66, 0x21, 0x67, - 0x3f, 0x54, 0x32, 0x5f, 0x73, 0x27, 0x59, 0x6f, - 0x39, 0x4b, 0x4e, 0x23, 0x54, 0x3b, 0x39, 0x21, - 0x38, 0x41, 0x33, 0x44, 0x57, 0x6b, 0x51, 0x30, - 0x6a, 0x76, 0x62, 0x2c, 0x5c, 0x5e, 0x49, 0x3e, - 0x59, 0x38, 0x5e, 0x4a, 0x59, 0x77, 0x34, 0x25, - 0x4f, 0x76, 0x6a, 0x68, 0x6f, 0x73, 0x7c, 0x3d, - 0x2d, 0x64, 0x6c, 0x7a, 0x3d, 0x2c, 0x26, 0x28, - 0x58, 0x2b, 0x4b, 0x45, 0x68, 0x38, 0x74, 0x63, - 0x7b, 0x4a, 0x63, 0x52, 0x26, 0x54, 0x3c, 0x46, - 0x77, 0x2d, 0x6b, 0x78, 0x63, 0x7b, 0x6a, 0x50, - 0x26, 0x42, 0x62, 0x63, 0x65, 0x6b, 0x63, 0x54, - 0x4d, 0x47, 0x59, 0x48, 0x2e, 0x60, 0x7c, 0x4d, - 0x33, 0x4d, 0x61, 0x72, 0x76, 0x72, 0x21, 0x4d, - 0x2b, 0x43, 0x58, 0x47, 0x4a, 0x36, 0x2d, 0x7b, - 0x32, 0x72, 0x21, 0x78, 0x22, 0x38, 0x2c, 0x7a, - 0x34, 0x44, 0x45, 0x66, 0x31, 0x7b, 0x37, 0x68, - 0x62, 0x65, 0x62, 0x6d, 0x4e, 0x7c, 0x75, 0x38, - 0x2a, 0x73, 0x27, 0x64, 0x33, 0x4f, 0x21, 0x41, - 0x7c, 0x41, 0x3f, 0x60, 0x68, 0x34, 0x72, 0x5b, - 0x38, 0x33, 0x6f, 0x65, 0x3e, 0x5a, 0x7d, 0x25, - 0x49, 0x50, 0x60, 0x36, 0x59, 0x5e, 0x6b, 0x25, - 0x66, 0x7a, 0x7d, 0x71, 0x40, 0x6c, 0x2c, 0x6e, - 0x6a, 0x5a, 0x24, 0x5a, 0x76, 0x21, 0x67, 0x39, - 0x4b, 0x4a, 0x31, 0x24, 0x66, 0x66, 0x2e, 0x58, - 0x43, 0x46, 0x75, 0x6c, 0x47, 0x28, 0x4f, 0x21, - 0x75, 0x77, 0x6f, 0x71, 0x48, 0x3f, 0x4d, 0x4c, - 0x51, 0x37, 0x3b, 0x41, 0x4d, 0x41, 0x48, 0x28, - 0x71, 0x24, 0x2f, 0x7a, 0x22, 0x49, 0x4a, 0x39, - 0x44, 0x43, 0x68, 0x21, 0x3a, 0x34, 0x4e, 0x52, - 0x7a, 0x60, 0x71, 0x61, 0x6d, 0x51, 0x58, 0x2a, - 0x59, 0x4c, 0x4a, 0x59, 0x6b, 0x77, 0x78, 0x2e, - 0x27, 0x78, 0x76, 0x48, 0x4f, 0x46, 0x79, 0x2c, - 0x54, 0x42, 0x7b, 0x2c, 0x52, 0x41, 0x54, 0x2b, - 0x2c, 0x33, 0x6b, 0x70, 0x77, 0x2e, 0x2e, 0x41, - 0x25, 0x7a, 0x48, 0x6e, 0x71, 0x55, 0x6a, 0x43, - 0x5a, 0x2c, 0x6c, 0x76, 0x6d, 0x71, 0x72, 0x4d, - 0x76, 0x5b, 0x7b, 0x22, 0x4b, 0x45, 0x31, 0x30, - 0x26, 0x53, 0x75, 0x3f, 0x26, 0x59, 0x36, 0x2f, - 0x68, 0x4f, 0x34, 0x5e, 0x2b, 0x30, 0x63, 0x68, - 0x7b, 0x32, 0x5e, 0x77, 0x7d, 0x7b, 0x53, 0x5f, - 0x63, 0x53, 0x77, 0x7a, 0x7d, 0x35, 0x28, 0x3e, - 0x41, 0x6f, 0x5b, 0x31, 0x78, 0x7b, 0x2b, 0x51, - 0x23, 0x43, 0x46, 0x6a, 0x32, 0x32, 0x25, 0x45, - 0x57, 0x43, 0x22, 0x50, 0x60, 0x32, 0x70, 0x2e, - 0x79, 0x2e, 0x6b, 0x33, 0x67, 0x6c, 0x43, 0x5b, - 0x3b, 0x68, 0x53, 0x53, 0x6a, 0x48, 0x59, 0x5f, - 0x30, 0x72, 0x7d, 0x6b, 0x37, 0x24, 0x75, 0x52, - 0x50, 0x2b, 0x75, 0x35, 0x24, 0x3b, 0x6e, 0x53, - 0x56, 0x34, 0x23, 0x54, 0x65, 0x4f, 0x78, 0x3e, - 0x46, 0x7d, 0x25, 0x3f, 0x2f, 0x49, 0x6b, 0x49, - 0x47, 0x45, 0x24, 0x38, 0x3b, 0x68, 0x6c, 0x4f, - 0x29, 0x21, 0x50, 0x32, 0x67, 0x47, 0x5a, 0x72, - 0x76, 0x21, 0x39, 0x67, 0x3c, 0x72, 0x47, 0x43, - 0x4a, 0x2e, 0x31, 0x32, 0x34, 0x3c, 0x53, 0x2d, - 0x22, 0x5b, 0x5b, 0x6a, 0x77, 0x75, 0x31, 0x68, - 0x30, 0x45, 0x43, 0x5f, 0x60, 0x5d, 0x56, 0x67, - 0x66, 0x55, 0x6a, 0x72, 0x77, 0x7b, 0x44, 0x61, - 0x22, 0x64, 0x36, 0x39, 0x6e, 0x44, 0x37, 0x54, - 0x45, 0x46, 0x6f, 0x58, 0x35, 0x51, 0x3c, 0x62, - 0x49, 0x3a, 0x50, 0x58, 0x56, 0x5d, 0x77, 0x6f, - 0x56, 0x64, 0x7b, 0x49, 0x39, 0x21, 0x31, 0x2d, - 0x5f, 0x56, 0x56, 0x33, 0x31, 0x69, 0x4a, 0x52, - 0x62, 0x5b, 0x6e, 0x65, 0x7c, 0x3d, 0x31, 0x55, - 0x3d, 0x75, 0x25, 0x61, 0x50, 0x71, 0x45, 0x29 - }; - uint32_t request5_len = sizeof(request5); - - uint8_t request6[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x5b, 0x56, 0x3d, 0x5a, 0x6b, 0x43, 0x73, 0x26, - 0x65, 0x3b, 0x38, 0x79, 0x26, 0x5e, 0x60, 0x59, - 0x40, 0x71, 0x7c, 0x72, 0x28, 0x29, 0x69, 0x32, - 0x72, 0x5a, 0x6c, 0x55, 0x43, 0x65, 0x3f, 0x4a, - 0x21, 0x66, 0x59, 0x30, 0x76, 0x39, 0x21, 0x69, - 0x4b, 0x25, 0x5d, 0x6e, 0x5f, 0x24, 0x2b, 0x38, - 0x70, 0x78, 0x35, 0x7d, 0x39, 0x36, 0x31, 0x72, - 0x44, 0x49, 0x45, 0x3d, 0x25, 0x50, 0x24, 0x3b, - 0x52, 0x27, 0x66, 0x46, 0x5d, 0x4f, 0x34, 0x50, - 0x26, 0x5a, 0x25, 0x3e, 0x3f, 0x34, 0x4b, 0x35, - 0x77, 0x3a, 0x3f, 0x3e, 0x23, 0x4e, 0x30, 0x23, - 0x70, 0x72, 0x33, 0x34, 0x60, 0x2a, 0x4a, 0x32, - 0x6e, 0x29, 0x54, 0x73, 0x5f, 0x26, 0x71, 0x3a, - 0x78, 0x5d, 0x3f, 0x31, 0x48, 0x59, 0x61, 0x44, - 0x5c, 0x38, 0x4f, 0x41, 0x73, 0x67, 0x62, 0x73, - 0x33, 0x52, 0x77, 0x73, 0x57, 0x49, 0x7a, 0x59, - 0x26, 0x21, 0x34, 0x38, 0x2b, 0x5f, 0x5f, 0x37, - 0x74, 0x28, 0x46, 0x3d, 0x43, 0x42, 0x26, 0x66, - 0x63, 0x37, 0x6d, 0x2a, 0x65, 0x3f, 0x71, 0x2d, - 0x4c, 0x72, 0x29, 0x4b, 0x3a, 0x77, 0x64, 0x6a, - 0x6b, 0x42, 0x70, 0x5c, 0x51, 0x38, 0x71, 0x25, - 0x4c, 0x7c, 0x6f, 0x74, 0x71, 0x39, 0x71, 0x25, - 0x3f, 0x62, 0x23, 0x45, 0x5f, 0x77, 0x59, 0x56, - 0x56, 0x67, 0x78, 0x3a, 0x2e, 0x4e, 0x27, 0x59, - 0x65, 0x2f, 0x64, 0x3c, 0x62, 0x40, 0x69, 0x52, - 0x36, 0x49, 0x3e, 0x3b, 0x2c, 0x47, 0x4f, 0x3e, - 0x61, 0x78, 0x2d, 0x45, 0x71, 0x3f, 0x7b, 0x55, - 0x34, 0x36, 0x47, 0x5e, 0x36, 0x51, 0x3d, 0x5a, - 0x4b, 0x75, 0x44, 0x72, 0x61, 0x44, 0x71, 0x4e, - 0x42, 0x6a, 0x2c, 0x34, 0x40, 0x3b, 0x40, 0x31, - 0x31, 0x75, 0x4b, 0x32, 0x71, 0x69, 0x3a, 0x5d, - 0x31, 0x25, 0x53, 0x2a, 0x61, 0x54, 0x68, 0x2a, - 0x76, 0x71, 0x57, 0x67, 0x56, 0x23, 0x7d, 0x70, - 0x7d, 0x28, 0x57, 0x5f, 0x2f, 0x4c, 0x71, 0x2e, - 0x40, 0x63, 0x49, 0x5b, 0x7c, 0x7b, 0x56, 0x76, - 0x77, 0x46, 0x69, 0x56, 0x3d, 0x75, 0x31, 0x3b, - 0x35, 0x40, 0x37, 0x2c, 0x51, 0x37, 0x49, 0x6a, - 0x79, 0x68, 0x53, 0x31, 0x4c, 0x6f, 0x57, 0x4c, - 0x48, 0x31, 0x6a, 0x30, 0x2b, 0x69, 0x30, 0x56, - 0x58, 0x4b, 0x76, 0x3b, 0x60, 0x6d, 0x35, 0x4d, - 0x74, 0x2f, 0x74, 0x2c, 0x54, 0x4f, 0x6e, 0x3f, - 0x38, 0x56, 0x5c, 0x67, 0x2b, 0x4a, 0x35, 0x30, - 0x67, 0x7d, 0x58, 0x24, 0x59, 0x54, 0x48, 0x2e, - 0x28, 0x7d, 0x6e, 0x51, 0x55, 0x68, 0x56, 0x54, - 0x59, 0x31, 0x4a, 0x65, 0x5a, 0x5e, 0x27, 0x76, - 0x76, 0x65, 0x6d, 0x2f, 0x75, 0x63, 0x67, 0x52, - 0x5e, 0x29, 0x58, 0x3d, 0x5c, 0x3f, 0x54, 0x7c, - 0x67, 0x21, 0x6e, 0x75, 0x67, 0x35, 0x77, 0x31, - 0x3d, 0x26, 0x3f, 0x60, 0x45, 0x2d, 0x2b, 0x45, - 0x5d, 0x3f, 0x55, 0x73, 0x59, 0x4c, 0x5e, 0x6c, - 0x30, 0x4a, 0x4e, 0x47, 0x55, 0x42, 0x6a, 0x4b, - 0x32, 0x3c, 0x75, 0x6e, 0x36, 0x51, 0x5f, 0x4c, - 0x68, 0x72, 0x72, 0x27, 0x3b, 0x51, 0x59, 0x7b, - 0x68, 0x7b, 0x3b, 0x54, 0x35, 0x37, 0x7c, 0x44, - 0x43, 0x36, 0x4c, 0x4f, 0x67, 0x62, 0x4e, 0x39, - 0x4b, 0x7a, 0x49, 0x36, 0x68, 0x38, 0x4c, 0x4a, - 0x64, 0x33, 0x35, 0x2f, 0x3e, 0x5c, 0x58, 0x61, - 0x23, 0x5b, 0x50, 0x6e, 0x34, 0x44, 0x60, 0x28, - 0x54, 0x41, 0x5c, 0x31, 0x53, 0x2d, 0x58, 0x58, - 0x54, 0x28, 0x77, 0x51, 0x6f, 0x64, 0x4c, 0x68, - 0x34, 0x79, 0x45, 0x66, 0x2c, 0x26, 0x77, 0x64, - 0x5f, 0x6c, 0x3b, 0x71, 0x28, 0x4d, 0x68, 0x2a, - 0x6b, 0x37, 0x6a, 0x34, 0x51, 0x27, 0x2a, 0x46, - 0x3a, 0x2e, 0x35, 0x21, 0x21, 0x79, 0x51, 0x44, - 0x58, 0x5d, 0x6f, 0x65, 0x6b, 0x76, 0x68, 0x3a, - 0x43, 0x70, 0x36, 0x41, 0x6b, 0x56, 0x64, 0x75, - 0x5b, 0x37, 0x24, 0x56, 0x7c, 0x6e, 0x6c, 0x41, - 0x3a, 0x60, 0x56, 0x38, 0x55, 0x63, 0x77, 0x4d, - 0x6e, 0x50, 0x3c, 0x3d, 0x7a, 0x44, 0x71, 0x42, - 0x4b, 0x55, 0x75, 0x72, 0x61, 0x60, 0x65, 0x6f, - 0x7a, 0x26, 0x64, 0x46, 0x67, 0x74, 0x29, 0x2a, - 0x5b, 0x62, 0x41, 0x28, 0x62, 0x30, 0x34, 0x33, - 0x40, 0x79, 0x7a, 0x38, 0x56, 0x38, 0x73, 0x22, - 0x7a, 0x7d, 0x73, 0x2a, 0x2a, 0x28, 0x2b, 0x63, - 0x27, 0x6f, 0x3d, 0x3e, 0x2c, 0x56, 0x23, 0x32, - 0x4b, 0x3b, 0x58, 0x4d, 0x72, 0x4c, 0x49, 0x6f, - 0x30, 0x76, 0x23, 0x21, 0x21, 0x3c, 0x49, 0x56, - 0x7a, 0x56, 0x79, 0x2f, 0x50, 0x7a, 0x5b, 0x21, - 0x21, 0x4a, 0x48, 0x61, 0x33, 0x52, 0x49, 0x2e, - 0x30, 0x7d, 0x2c, 0x2d, 0x67, 0x23, 0x55, 0x62, - 0x66, 0x52, 0x5a, 0x61, 0x75, 0x63, 0x3c, 0x39, - 0x69, 0x41, 0x31, 0x6b, 0x4e, 0x6f, 0x25, 0x34, - 0x74, 0x30, 0x21, 0x3a, 0x40, 0x72, 0x44, 0x40, - 0x60, 0x4c, 0x53, 0x74, 0x42, 0x64, 0x44, 0x49, - 0x76, 0x67, 0x21, 0x79, 0x36, 0x3c, 0x37, 0x70, - 0x4f, 0x58, 0x29, 0x71, 0x2a, 0x3a, 0x4d, 0x5d, - 0x67, 0x68, 0x52, 0x63, 0x23, 0x24, 0x4b, 0x21, - 0x3f, 0x68, 0x69, 0x6c, 0x66, 0x66, 0x42, 0x28, - 0x59, 0x35, 0x34, 0x6f, 0x2d, 0x6a, 0x25, 0x66, - 0x34, 0x54, 0x5d, 0x50, 0x26, 0x41, 0x22, 0x4f, - 0x34, 0x79, 0x3c, 0x50, 0x68, 0x2d, 0x5f, 0x7b, - 0x63, 0x7d, 0x58, 0x2e, 0x73, 0x46, 0x2f, 0x54, - 0x61, 0x27, 0x74, 0x45, 0x23, 0x72, 0x31, 0x7d, - 0x63, 0x4b, 0x43, 0x5e, 0x44, 0x54, 0x2c, 0x38, - 0x58, 0x24, 0x75, 0x6c, 0x50, 0x3c, 0x23, 0x5f, - 0x35, 0x57, 0x4f, 0x7b, 0x2f, 0x57, 0x29, 0x73, - 0x58, 0x2a, 0x66, 0x3e, 0x49, 0x42, 0x5a, 0x6b, - 0x75, 0x6a, 0x38, 0x3f, 0x73, 0x44, 0x42, 0x46, - 0x2d, 0x39, 0x66, 0x5b, 0x28, 0x3e, 0x63, 0x62, - 0x53, 0x75, 0x65, 0x64, 0x79, 0x32, 0x35, 0x71, - 0x22, 0x6a, 0x7b, 0x41, 0x2b, 0x26, 0x43, 0x79, - 0x58, 0x6f, 0x71, 0x25, 0x24, 0x34, 0x72, 0x5b, - 0x4a, 0x2c, 0x5c, 0x77, 0x23, 0x42, 0x27, 0x6a, - 0x67, 0x51, 0x5f, 0x3c, 0x75, 0x2c, 0x3f, 0x43, - 0x45, 0x5b, 0x48, 0x65, 0x6f, 0x6c, 0x27, 0x65, - 0x21, 0x3e, 0x33, 0x37, 0x5f, 0x2b, 0x2e, 0x24, - 0x22, 0x47, 0x4e, 0x33, 0x5b, 0x7b, 0x21, 0x3c, - 0x53, 0x69, 0x2e, 0x31, 0x3d, 0x48, 0x57, 0x3a, - 0x56, 0x48, 0x6b, 0x47, 0x5d, 0x33, 0x41, 0x6c, - 0x66, 0x4c, 0x61, 0x67, 0x32, 0x69, 0x53, 0x2c, - 0x2f, 0x3e, 0x36, 0x68, 0x37, 0x28, 0x40, 0x21, - 0x76, 0x27, 0x44, 0x26, 0x24, 0x6a, 0x30, 0x75, - 0x2a, 0x73, 0x48, 0x36, 0x52, 0x4a, 0x3b, 0x51, - 0x4e, 0x2f, 0x23, 0x36, 0x4b, 0x49, 0x33, 0x5a, - 0x70, 0x2c, 0x54, 0x5b, 0x67, 0x48, 0x53, 0x5d, - 0x21, 0x3e, 0x6b, 0x52, 0x6a, 0x3c, 0x48, 0x29, - 0x68, 0x27, 0x32, 0x75, 0x61, 0x7c, 0x51, 0x2e, - 0x7b, 0x49, 0x2f, 0x5b, 0x3d, 0x74, 0x5a, 0x28, - 0x26, 0x29, 0x2c, 0x30, 0x54, 0x74, 0x45, 0x55, - 0x4a, 0x3d, 0x39, 0x35, 0x66, 0x56, 0x28, 0x6d, - 0x6e, 0x38, 0x7b, 0x2b, 0x40, 0x31, 0x56, 0x61, - 0x74, 0x2b, 0x79, 0x5f, 0x63, 0x51, 0x53, 0x52, - 0x7d, 0x73, 0x4e, 0x2e, 0x45, 0x3b, 0x22, 0x28, - 0x6c, 0x2b, 0x47, 0x21, 0x50, 0x2a, 0x7c, 0x45, - 0x48, 0x57, 0x3e, 0x2f, 0x6d, 0x66, 0x6c, 0x51, - 0x23, 0x6c, 0x37, 0x4d, 0x4b, 0x4b, 0x66, 0x55, - 0x69, 0x2e, 0x4a, 0x69, 0x71, 0x7c, 0x71, 0x30, - 0x5c, 0x43, 0x46, 0x63, 0x5a, 0x23, 0x75, 0x40 - }; - uint32_t request6_len = sizeof(request6); - - uint8_t request7[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x5d, 0x32, 0x55, 0x71, 0x51, 0x45, 0x4e, 0x54, - 0x34, 0x21, 0x46, 0x77, 0x5e, 0x5b, 0x75, 0x62, - 0x2b, 0x5c, 0x34, 0x26, 0x72, 0x2b, 0x2c, 0x64, - 0x4b, 0x65, 0x56, 0x72, 0x31, 0x7d, 0x6a, 0x5f, - 0x70, 0x26, 0x32, 0x29, 0x7d, 0x21, 0x5b, 0x3e, - 0x5e, 0x53, 0x3d, 0x48, 0x5e, 0x2a, 0x4c, 0x37, - 0x3d, 0x59, 0x79, 0x21, 0x4f, 0x56, 0x79, 0x2a, - 0x4e, 0x28, 0x61, 0x7d, 0x2c, 0x58, 0x2f, 0x78, - 0x5c, 0x3f, 0x5c, 0x42, 0x6d, 0x2f, 0x71, 0x54, - 0x25, 0x31, 0x73, 0x38, 0x6c, 0x31, 0x5a, 0x2e, - 0x42, 0x5b, 0x2d, 0x41, 0x24, 0x4c, 0x37, 0x40, - 0x39, 0x7d, 0x2a, 0x67, 0x60, 0x6a, 0x7a, 0x62, - 0x24, 0x4e, 0x3f, 0x2e, 0x69, 0x35, 0x28, 0x65, - 0x77, 0x53, 0x23, 0x44, 0x59, 0x71, 0x31, 0x5c, - 0x40, 0x5d, 0x3a, 0x27, 0x46, 0x55, 0x30, 0x56, - 0x21, 0x74, 0x3e, 0x73, 0x41, 0x22, 0x52, 0x68, - 0x40, 0x6c, 0x37, 0x3e, 0x62, 0x5a, 0x2e, 0x21, - 0x23, 0x33, 0x27, 0x73, 0x68, 0x26, 0x60, 0x67, - 0x70, 0x58, 0x50, 0x42, 0x58, 0x27, 0x3a, 0x35, - 0x6f, 0x51, 0x62, 0x78, 0x25, 0x2c, 0x7b, 0x66, - 0x34, 0x6a, 0x5a, 0x39, 0x60, 0x70, 0x41, 0x2d, - 0x65, 0x26, 0x5a, 0x67, 0x58, 0x2d, 0x3e, 0x56, - 0x6d, 0x30, 0x4b, 0x4d, 0x5d, 0x45, 0x41, 0x3d, - 0x6e, 0x27, 0x4e, 0x5a, 0x7d, 0x2e, 0x62, 0x4d, - 0x42, 0x70, 0x31, 0x24, 0x73, 0x5c, 0x78, 0x77, - 0x50, 0x73, 0x27, 0x48, 0x3d, 0x35, 0x2c, 0x4b, - 0x40, 0x2d, 0x25, 0x77, 0x5d, 0x3d, 0x6b, 0x50, - 0x6f, 0x57, 0x73, 0x2f, 0x4f, 0x6e, 0x4c, 0x6e, - 0x56, 0x7b, 0x55, 0x3c, 0x6d, 0x60, 0x47, 0x53, - 0x56, 0x39, 0x3b, 0x51, 0x61, 0x71, 0x75, 0x73, - 0x6b, 0x70, 0x58, 0x5f, 0x2c, 0x27, 0x74, 0x49, - 0x2c, 0x2b, 0x53, 0x2d, 0x5b, 0x79, 0x43, 0x34, - 0x39, 0x5a, 0x38, 0x3e, 0x2d, 0x66, 0x70, 0x3d, - 0x49, 0x51, 0x29, 0x4d, 0x5d, 0x4c, 0x57, 0x4a, - 0x2f, 0x41, 0x69, 0x56, 0x57, 0x77, 0x49, 0x58, - 0x75, 0x28, 0x29, 0x4a, 0x6d, 0x54, 0x4f, 0x4f, - 0x3f, 0x58, 0x5f, 0x58, 0x6f, 0x39, 0x22, 0x4d, - 0x5d, 0x31, 0x75, 0x43, 0x2f, 0x7d, 0x31, 0x3d, - 0x4c, 0x4d, 0x76, 0x74, 0x4d, 0x57, 0x3b, 0x56, - 0x57, 0x48, 0x2b, 0x5d, 0x32, 0x67, 0x51, 0x6e, - 0x60, 0x39, 0x6f, 0x64, 0x38, 0x37, 0x52, 0x4b, - 0x52, 0x42, 0x32, 0x4f, 0x24, 0x53, 0x31, 0x6e, - 0x4a, 0x68, 0x2f, 0x28, 0x2e, 0x27, 0x49, 0x75, - 0x77, 0x75, 0x26, 0x47, 0x7c, 0x5d, 0x72, 0x5a, - 0x77, 0x50, 0x2e, 0x6c, 0x27, 0x68, 0x6b, 0x7b, - 0x27, 0x63, 0x21, 0x3d, 0x30, 0x2d, 0x5c, 0x67, - 0x4d, 0x41, 0x79, 0x47, 0x42, 0x50, 0x6d, 0x32, - 0x74, 0x39, 0x62, 0x4d, 0x5f, 0x65, 0x78, 0x4f, - 0x67, 0x3a, 0x60, 0x26, 0x45, 0x61, 0x7c, 0x61, - 0x63, 0x40, 0x46, 0x79, 0x52, 0x47, 0x57, 0x49, - 0x53, 0x4c, 0x48, 0x36, 0x67, 0x47, 0x5c, 0x71, - 0x50, 0x4d, 0x4f, 0x58, 0x26, 0x40, 0x6d, 0x54, - 0x55, 0x67, 0x66, 0x23, 0x70, 0x23, 0x68, 0x70, - 0x4d, 0x2c, 0x7a, 0x3d, 0x60, 0x51, 0x35, 0x64, - 0x56, 0x2f, 0x26, 0x6d, 0x72, 0x6a, 0x59, 0x34, - 0x3a, 0x73, 0x4b, 0x27, 0x33, 0x61, 0x26, 0x45, - 0x61, 0x28, 0x74, 0x22, 0x54, 0x50, 0x2e, 0x39, - 0x6a, 0x2c, 0x27, 0x59, 0x26, 0x73, 0x44, 0x71, - 0x67, 0x4c, 0x37, 0x74, 0x2c, 0x63, 0x52, 0x2a, - 0x60, 0x4f, 0x7b, 0x32, 0x39, 0x21, 0x79, 0x54, - 0x79, 0x6d, 0x28, 0x27, 0x3a, 0x6a, 0x7d, 0x40, - 0x6a, 0x4f, 0x4b, 0x46, 0x61, 0x36, 0x6a, 0x22, - 0x3f, 0x77, 0x2d, 0x6a, 0x3b, 0x73, 0x71, 0x72, - 0x3c, 0x21, 0x2e, 0x3f, 0x33, 0x25, 0x76, 0x64, - 0x64, 0x70, 0x43, 0x32, 0x44, 0x73, 0x61, 0x51, - 0x3c, 0x3b, 0x45, 0x3a, 0x68, 0x46, 0x5b, 0x6e, - 0x36, 0x47, 0x4d, 0x38, 0x26, 0x4f, 0x5c, 0x7d, - 0x73, 0x29, 0x24, 0x78, 0x44, 0x75, 0x40, 0x42, - 0x41, 0x2a, 0x73, 0x2b, 0x24, 0x38, 0x51, 0x67, - 0x36, 0x67, 0x2f, 0x70, 0x58, 0x54, 0x6e, 0x5d, - 0x3b, 0x41, 0x59, 0x76, 0x7d, 0x2d, 0x40, 0x70, - 0x29, 0x4a, 0x4a, 0x31, 0x79, 0x2c, 0x4e, 0x22, - 0x31, 0x59, 0x31, 0x3c, 0x2f, 0x21, 0x29, 0x3f, - 0x65, 0x6c, 0x38, 0x55, 0x4f, 0x27, 0x66, 0x66, - 0x34, 0x45, 0x49, 0x41, 0x56, 0x24, 0x2e, 0x40, - 0x36, 0x23, 0x5a, 0x46, 0x40, 0x23, 0x7b, 0x2d, - 0x69, 0x54, 0x6c, 0x51, 0x58, 0x73, 0x56, 0x60, - 0x5f, 0x60, 0x63, 0x5f, 0x77, 0x6a, 0x4c, 0x2c, - 0x35, 0x39, 0x60, 0x73, 0x63, 0x3e, 0x2d, 0x55, - 0x5a, 0x26, 0x4b, 0x43, 0x3b, 0x56, 0x33, 0x58, - 0x74, 0x51, 0x4f, 0x5c, 0x2a, 0x44, 0x78, 0x66, - 0x78, 0x71, 0x40, 0x29, 0x5e, 0x26, 0x57, 0x51, - 0x49, 0x30, 0x29, 0x73, 0x38, 0x56, 0x6c, 0x41, - 0x78, 0x3d, 0x61, 0x3d, 0x2c, 0x33, 0x46, 0x57, - 0x54, 0x63, 0x3e, 0x79, 0x55, 0x4a, 0x7d, 0x2e, - 0x2a, 0x3c, 0x77, 0x47, 0x35, 0x29, 0x5a, 0x6d, - 0x69, 0x48, 0x6b, 0x73, 0x7d, 0x4f, 0x5f, 0x6f, - 0x3a, 0x7a, 0x4e, 0x54, 0x59, 0x38, 0x62, 0x44, - 0x72, 0x51, 0x57, 0x6a, 0x74, 0x54, 0x4f, 0x77, - 0x6b, 0x66, 0x4a, 0x6b, 0x39, 0x29, 0x69, 0x60, - 0x71, 0x52, 0x6a, 0x32, 0x66, 0x6c, 0x25, 0x76, - 0x27, 0x7a, 0x2c, 0x38, 0x72, 0x4e, 0x5f, 0x40, - 0x26, 0x74, 0x6a, 0x5e, 0x42, 0x38, 0x78, 0x34, - 0x4f, 0x4f, 0x35, 0x27, 0x39, 0x62, 0x52, 0x61, - 0x37, 0x54, 0x47, 0x38, 0x70, 0x31, 0x7a, 0x66, - 0x69, 0x72, 0x24, 0x52, 0x2a, 0x2a, 0x78, 0x72, - 0x2b, 0x2e, 0x2a, 0x57, 0x4a, 0x21, 0x52, 0x3c, - 0x2a, 0x2f, 0x24, 0x58, 0x34, 0x3c, 0x42, 0x5c, - 0x5b, 0x78, 0x27, 0x55, 0x63, 0x58, 0x3e, 0x26, - 0x50, 0x2c, 0x72, 0x60, 0x36, 0x6c, 0x46, 0x58, - 0x63, 0x59, 0x23, 0x2a, 0x2d, 0x63, 0x6a, 0x68, - 0x69, 0x74, 0x3f, 0x49, 0x4f, 0x48, 0x4a, 0x3b, - 0x59, 0x56, 0x77, 0x43, 0x6d, 0x57, 0x28, 0x5f, - 0x39, 0x73, 0x28, 0x74, 0x3c, 0x4f, 0x43, 0x48, - 0x6a, 0x57, 0x5d, 0x41, 0x73, 0x3f, 0x41, 0x7c, - 0x65, 0x5e, 0x2d, 0x38, 0x72, 0x3a, 0x53, 0x3e, - 0x33, 0x47, 0x69, 0x6a, 0x6e, 0x78, 0x67, 0x5d, - 0x35, 0x3b, 0x3f, 0x23, 0x7c, 0x71, 0x3d, 0x7c, - 0x3a, 0x3c, 0x75, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x6a, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x6a, 0x40, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x80, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, - 0x9b, 0x78, 0x70, 0x43, 0xc5, 0x0a, 0x4d, 0x98, - 0x96, 0x02, 0x64, 0x92, 0xc1, 0xee, 0x70, 0x32 - }; - uint32_t request7_len = sizeof(request7); - - uint8_t request8[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0x65, 0xc1, 0xef, 0x7b, 0xd6, 0xaa, 0xd6, 0x09, - 0x21, 0xf6, 0xe7, 0xd1, 0x4c, 0xdf, 0x6a, 0x2d, - 0x0a, 0xfb, 0x43, 0xea, 0xda, 0x07, 0x24, 0x84, - 0x88, 0x52, 0x9e, 0xa8, 0xa1, 0x7f, 0x4b, 0x60, - 0xec, 0x94, 0x57, 0x33, 0x06, 0x93, 0x92, 0x25, - 0xd6, 0xac, 0xdc, 0x89, 0x68, 0x5e, 0xbb, 0x32, - 0x2b, 0x17, 0x68, 0xf2, 0x06, 0xb7, 0x86, 0xac, - 0x81, 0xfe, 0x52, 0x27, 0xf5, 0x80, 0x11, 0x0d, - 0x4e, 0x2e, 0x1b, 0xa3, 0x44, 0x8a, 0x58, 0xed, - 0xf3, 0x9c, 0xe9, 0x31, 0x01, 0x72, 0xa6, 0xab, - 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x6b, 0x81, - 0xef, 0xf4, 0x96, 0x9a, 0xf7, 0x67, 0x95, 0x27, - 0x7a, 0x25, 0xef, 0x6f, 0x0e, 0xff, 0x2d, 0x15, - 0x7f, 0x23, 0x1c, 0xa7, 0x56, 0x94, 0x4a, 0x18, - 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x5b, 0x57, 0xb8, - 0x5d, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0xe3, - 0xd1, 0x36, 0x87, 0xff, 0xe3, 0x94, 0x0f, 0x00, - 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, - 0xa3, 0x25, 0xce, 0xd4, 0xaf, 0x39, 0xeb, 0x17, - 0xcf, 0x22, 0x43, 0xd9, 0x0c, 0xce, 0x37, 0x86, - 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, - 0xf9, 0xb5, 0x2b, 0x11, 0xa0, 0xfe, 0xa3, 0x4b, - 0x2e, 0x05, 0xbe, 0x54, 0xa9, 0xd8, 0xa5, 0x76, - 0x83, 0x5b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x72, - 0xcd, 0xdc, 0x4a, 0x1d, 0x77, 0xda, 0x8a, 0x9e, - 0xba, 0xcb, 0x6c, 0xe8, 0x19, 0x5d, 0x68, 0xef, - 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, - 0x96, 0x84, 0x04, 0xd9, 0xda, 0x4c, 0x42, 0x31, - 0xd9, 0xbd, 0x99, 0x06, 0xf7, 0xa3, 0x0a, 0x19, - 0x49, 0x07, 0x77, 0xf0, 0xdb, 0x7c, 0x43, 0xfa, - 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, - 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, - 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, - 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x54, 0x6d, 0xed, - 0x53, 0xf9, 0x73, 0xc6, 0x6e, 0xa8, 0xc0, 0x97, - 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, - 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, - 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, - 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, - 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, - 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x24, 0x85, 0xe8, - 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, - 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, - 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x6c, 0x28, 0x42, - 0x07, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, - 0xfa, 0x25, 0xec, 0x35, 0x5e, 0x98, 0x71, 0x50, - 0x60, 0x35, 0x76, 0x53, 0x40, 0x1a, 0x34, 0xa5, - 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, - 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, - 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, - 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, - 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, - 0xbc, 0xe1, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, - 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, - 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, - 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, - 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, - 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, - 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x05, 0x59, - 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, - 0x89, 0xfd, 0x7f, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, - 0xd9, 0x44, 0xd5, 0xf9, 0x3a, 0x3c, 0xec, 0xd9, - 0x9b, 0x8c, 0x93, 0x93, 0x2b, 0x44, 0x86, 0x8b, - 0x80, 0x83, 0x23, 0x00, 0xdf, 0xaf, 0xff, 0x33, - 0x9b, 0x78, 0x70, 0x43, 0xf1, 0x55, 0x87, 0xb1, - 0xa1, 0xb3, 0x8e, 0x79, 0x02, 0x70, 0x82, 0x6c, - 0x0b, 0xc1, 0xef, 0x96, 0xf1, 0xef, 0xdd, 0xa2, - 0x69, 0x86, 0xc7, 0x85, 0x09, 0x7e, 0xf0, 0x2f, - 0x8e, 0xa0, 0x5f, 0xea, 0x39, 0x2e, 0x24, 0xf0, - 0x82, 0x30, 0x26, 0xa8, 0xa1, 0x4f, 0xc6, 0x5c, - 0xec, 0x94, 0x87, 0x52, 0x9b, 0x93, 0x92, 0xf3, - 0xa3, 0x1b, 0xc7, 0x8f, 0x9e, 0xb3, 0xbb, 0x32, - 0x2b, 0x17, 0x54, 0xf2, 0x06, 0x0c, 0x86, 0x92, - 0x0f, 0xb8, 0xe0, 0x27, 0x50, 0xaa, 0xeb, 0xf5, - 0x4e, 0x2b, 0x1b, 0xb2, 0x44, 0xe6, 0x58, 0x02, - 0xd7, 0x65, 0xdc, 0x31, 0x01, 0xec, 0xa6, 0xab, - 0xfa, 0xa8, 0x05, 0x00, 0x37, 0x60, 0x4f, 0xa1, - 0x3c, 0x4f, 0x7a, 0x9a, 0x10, 0x67, 0x95, 0xc2, - 0x5b, 0x25, 0xef, 0x76, 0x0e, 0xff, 0x2d, 0x15, - 0x7f, 0x23, 0x1c, 0x77, 0x56, 0x94, 0x4a, 0x18, - 0x98, 0xc6, 0xd8, 0xd2, 0x29, 0x44, 0x57, 0xb8, - 0x40, 0x3a, 0x93, 0x58, 0x45, 0x77, 0x36, 0x36, - 0x07, 0x35, 0x2a, 0xff, 0x00, 0x94, 0x5c, 0x80, - 0xe6, 0x7c, 0x1a, 0x92, 0xc1, 0x5f, 0x40, 0xc3, - 0xbc, 0xf8, 0xce, 0x05, 0x77, 0x39, 0x40, 0x17, - 0xcf, 0x63, 0x43, 0x77, 0x27, 0xce, 0x37, 0x86, - 0x46, 0x54, 0xd6, 0xce, 0x00, 0x30, 0x36, 0xae, - 0x9f, 0x24, 0x2b, 0x5a, 0xa0, 0xfe, 0xa3, 0x4b, - 0x2e, 0x7e, 0xf7, 0x54, 0xa9, 0xd8, 0xa5, 0x76, - 0x83, 0x7b, 0x63, 0x01, 0x1c, 0xd4, 0x56, 0x17, - 0x02, 0xdc, 0x4a, 0x89, 0x77, 0xda, 0x8f, 0x9e, - 0xba, 0xcb, 0x37, 0xe8, 0x19, 0x5d, 0x68, 0x38, - 0x8e, 0xbc, 0x6a, 0x05, 0x53, 0x0b, 0xc7, 0xc5, - 0x96, 0x84, 0x5a, 0xd9, 0x6d, 0x4c, 0x42, 0x31, - 0xd9, 0xf2, 0x99, 0x06, 0xf7, 0x0c, 0x99, 0xbe, - 0x49, 0x07, 0x77, 0xf0, 0x8b, 0x7c, 0x43, 0xfa, - 0xb2, 0xad, 0xb0, 0xfa, 0x87, 0x52, 0xba, 0xc9, - 0x94, 0x61, 0xdc, 0xcf, 0x16, 0xac, 0x0f, 0x4a, - 0xa3, 0x6b, 0x5b, 0x6e, 0x27, 0x86, 0x1f, 0xfe, - 0x4d, 0x28, 0x3a, 0xa5, 0x10, 0x98, 0x6d, 0xed, - 0x53, 0xf9, 0x73, 0xc6, 0xa5, 0xa8, 0xf7, 0x66, - 0xcf, 0x56, 0x3b, 0x61, 0xdf, 0xab, 0x83, 0x18, - 0xe8, 0x09, 0xee, 0x6a, 0xb7, 0xf5, 0xc9, 0x62, - 0x55, 0x2d, 0xc7, 0x0c, 0x0d, 0xa0, 0x22, 0xd8, - 0xd4, 0xd6, 0xb2, 0x12, 0x21, 0xd7, 0x73, 0x3e, - 0x41, 0xb0, 0x5c, 0xd4, 0xcf, 0x98, 0xf3, 0x70, - 0xe6, 0x08, 0xe6, 0x2a, 0x4f, 0x92, 0x85, 0xe8, - 0x74, 0xa8, 0x41, 0x5f, 0x0e, 0xfd, 0xf1, 0xf3, - 0xbe, 0x9b, 0x14, 0xfd, 0xc0, 0x73, 0x11, 0xff, - 0xa5, 0x5b, 0x06, 0x34, 0xc3, 0x5d, 0x28, 0x42, - 0x34, 0xfe, 0x8a, 0xa5, 0xbe, 0x72, 0x7a, 0xf7, - 0xfa, 0x25, 0x2b, 0x35, 0x5e, 0x98, 0x71, 0x50, - 0x2c, 0x35, 0x76, 0x53, 0x4e, 0x1a, 0x34, 0xa5, - 0x99, 0x09, 0xa2, 0xc6, 0xca, 0xa5, 0xce, 0x08, - 0x50, 0x45, 0xab, 0x8d, 0xfb, 0xe3, 0xb8, 0xe4, - 0x8a, 0x61, 0x48, 0x14, 0x6e, 0xf7, 0x58, 0x71, - 0xe5, 0x2e, 0xbc, 0x12, 0xd1, 0x25, 0xe9, 0x65, - 0x7a, 0xa1, 0x27, 0xbe, 0x3b, 0x8b, 0xe8, 0xe7, - 0xbc, 0x77, 0x05, 0xe7, 0x92, 0xeb, 0xb9, 0xdf, - 0x5d, 0x53, 0x74, 0xc0, 0x63, 0x97, 0x80, 0xb8, - 0x3c, 0xae, 0xf3, 0xf2, 0x09, 0x12, 0x81, 0x6c, - 0x69, 0x10, 0x6f, 0xf6, 0xbe, 0x03, 0x7b, 0x88, - 0xcf, 0x26, 0x6b, 0x51, 0x06, 0x23, 0x68, 0x03, - 0xa1, 0xb7, 0xd3, 0x0c, 0xca, 0xbf, 0x29, 0x01, - 0xa9, 0x61, 0x34, 0x75, 0x98, 0x1e, 0x6f, 0x59, - 0xb3, 0x46, 0x44, 0xff, 0x2b, 0x98, 0x04, 0x88, - 0x89, 0xfd, 0x1c, 0xd5, 0x19, 0x8a, 0xa6, 0xf3, - 0xd9, 0x44, 0xd5, 0xf9, 0x79, 0x26, 0x46, 0xf7 - }; - uint32_t request8_len = sizeof(request8); - - uint8_t request9[] = { - 0x05, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xbf, 0xa1, 0x12, 0x73, 0x23, 0x44, 0x86, 0x8b, - 0x50, 0x6a, 0x40, 0x00 - }; - uint32_t request9_len = sizeof(request9); - - TcpSession ssn; - Packet *p[11]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|26 d0 cf 80|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|43 5b 67 26 65|\"; distance:0; sid:2;)"; - char *sig3 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|71 69 75 3e|\"; distance:0; sid:3;)"; - char *sig4 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|6a 68 69 3e 72|\"; distance:0; sid:4;)"; - char *sig5 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|61 50 71 45 29 5b 56 3d 5a|\"; distance:0; sid:5;)"; - char *sig6 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|23 75 40 5d 32 55|\"; distance:0; sid:6;)"; - char *sig7 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|ee 70 32 65 c1|\"; distance:0; sid:7;)"; - char *sig8 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|79 26 46 f7 bf a1|\"; distance:0; sid:8;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 11; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig3); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig4); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig5); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig6); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig7); - s = s->next; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig8); - s = s->next; - if (s == NULL) - goto end; - - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 3))) { - printf("sid 3 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 4))) { - printf("sid 4 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 5))) { - printf("sid 5 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 6))) { - printf("sid 6 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 7))) { - printf("sid 7 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 8))) { - printf("sid 8 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 3))) { - printf("sid 3 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 4))) { - printf("sid 4 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 5))) { - printf("sid 5 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 6))) { - printf("sid 6 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 7))) { - printf("sid 7 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 8))) { - printf("sid 8 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 3))) { - printf("sid 3 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 4))) { - printf("sid 4 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 5))) { - printf("sid 5 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 6))) { - printf("sid 6 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 7))) { - printf("sid 7 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 8))) { - printf("sid 8 matched but shouldn't have for packet 2: "); - goto end; - } - - SCLogDebug("sending request 2"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if (!(PacketAlertCheck(p[3], 1))) { - printf("sid 1 didn't match but should have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 2))) { - printf("sid 2 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 3))) { - printf("sid 3 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 4))) { - printf("sid 4 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 5))) { - printf("sid 5 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 6))) { - printf("sid 6 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 7))) { - printf("sid 7 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 8))) { - printf("sid 8 matched but shouldn't have for packet 3: "); - goto end; - } - - SCLogDebug("sending request 3"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SCLogDebug("inspecting packet 4"); - SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); - if ((PacketAlertCheck(p[4], 1))) { - printf("sid 1 matched but shouldn't have for packet 4: "); - goto end; - } - if (!(PacketAlertCheck(p[4], 2))) { - printf("sid 2 didn't match but should have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 3))) { - printf("sid 3 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 4))) { - printf("sid 4 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 5))) { - printf("sid 5 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 6))) { - printf("sid 6 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 7))) { - printf("sid 7 matched but shouldn't have for packet 4: "); - goto end; - } - if ((PacketAlertCheck(p[4], 8))) { - printf("sid 8 matched but shouldn't have for packet 4: "); - goto end; - } - - SCLogDebug("sending request 4"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request4, request4_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); - if ((PacketAlertCheck(p[5], 1))) { - printf("sid 1 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 2))) { - printf("sid 2 matched but shouldn't have for packet 5: "); - goto end; - } - if (!(PacketAlertCheck(p[5], 3))) { - printf("sid 3 didn't match but should have packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 4))) { - printf("sid 4 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 5))) { - printf("sid 5 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 6))) { - printf("sid 6 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 7))) { - printf("sid 7 matched but shouldn't have for packet 5: "); - goto end; - } - if ((PacketAlertCheck(p[5], 8))) { - printf("sid 8 matched but shouldn't have for packet 5: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request5, request5_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[6]); - if ((PacketAlertCheck(p[6], 1))) { - printf("sid 1 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 2))) { - printf("sid 2 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 3))) { - printf("sid 3 matched but shouldn't have for packet 6: "); - goto end; - } - if (!(PacketAlertCheck(p[6], 4))) { - printf("sid 4 didn't match but should have packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 5))) { - printf("sid 5 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 6))) { - printf("sid 6 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 7))) { - printf("sid 7 matched but shouldn't have for packet 6: "); - goto end; - } - if ((PacketAlertCheck(p[6], 8))) { - printf("sid 8 matched but shouldn't have for packet 6: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request6, request6_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[7]); - if ((PacketAlertCheck(p[7], 1))) { - printf("sid 1 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 2))) { - printf("sid 2 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 3))) { - printf("sid 3 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 4))) { - printf("sid 4 matched but shouldn't have for packet 7: "); - goto end; - } - if (!(PacketAlertCheck(p[7], 5))) { - printf("sid 5 didn't match but should have paket 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 6))) { - printf("sid 6 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 7))) { - printf("sid 7 matched but shouldn't have for packet 7: "); - goto end; - } - if ((PacketAlertCheck(p[7], 8))) { - printf("sid 8 matched but shouldn't have for packet 7: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request7, request7_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[8]); - if ((PacketAlertCheck(p[8], 1))) { - printf("sid 1 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 2))) { - printf("sid 2 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 3))) { - printf("sid 3 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 4))) { - printf("sid 4 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 5))) { - printf("sid 5 matched but shouldn't have for packet 8: "); - goto end; - } - if (!(PacketAlertCheck(p[8], 6))) { - printf("sid 6 didn't match but should have paket 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 7))) { - printf("sid 7 matched but shouldn't have for packet 8: "); - goto end; - } - if ((PacketAlertCheck(p[8], 8))) { - printf("sid 8 matched but shouldn't have for packet 8: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request8, request8_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[9]); - if ((PacketAlertCheck(p[9], 1))) { - printf("sid 1 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 2))) { - printf("sid 2 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 3))) { - printf("sid 3 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 4))) { - printf("sid 4 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 5))) { - printf("sid 5 matched but shouldn't have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 6))) { - printf("sid 6 matched but shouldn't have for packet 9: "); - goto end; - } - if (!(PacketAlertCheck(p[9], 7))) { - printf("sid 7 didn't match but should have for packet 9: "); - goto end; - } - if ((PacketAlertCheck(p[9], 8))) { - printf("sid 8 matched but shouldn't have for packet 9: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request9, request9_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[10]); - if ((PacketAlertCheck(p[10], 1))) { - printf("sid 1 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 2))) { - printf("sid 2 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 3))) { - printf("sid 3 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 4))) { - printf("sid 4 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 5))) { - printf("sid 5 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 6))) { - printf("sid 6 matched but shouldn't have for packet 10: "); - goto end; - } - if ((PacketAlertCheck(p[10], 7))) { - printf("sid 7 matched but shouldn't have for packet 10: "); - goto end; - } - if (!(PacketAlertCheck(p[10], 8))) { - printf("sid 8 didn't match but should have for paket 10: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 11); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest02(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "dce_stub_data; content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - p[1]->flowflags &=~ FLOW_PKT_TOSERVER; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (PacketAlertCheck(p[0], 1)) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - if (PacketAlertCheck(p[0], 2)) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (!(PacketAlertCheck(p[2], 1))) { - printf("sid 1 didn't match but should have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest03(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef4; " - "dce_stub_data; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest04(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; content:\"|91 27 27 40|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (!(PacketAlertCheck(p[2], 1))) { - printf("sid 1 didn't match but should have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest05(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef4; " - "dce_stub_data; content:\"|91 27 27 40|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "dce_stub_data; content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 2 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest06(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; content:\"|91 27 27 30|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 2a 4c|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if (!(PacketAlertCheck(p[3], 2))) { - printf("sid 2 didn't match but should have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest07(void) -{ -#if 0 - int result = 0; - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x6a, 0x28, 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, - 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, - 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[4]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " - "dce_stub_data; content:\"|91 27 27 30|\"; distance:0; sid:1;)"; - char *sig2 = "alert tcp any any -> any any (dce_stub_data; " - "content:\"|2d 5e 63 35 25|\"; distance:0; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 4; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - s->next = SigInit(de_ctx, sig2); - s = s->next; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - if ((PacketAlertCheck(p[0], 2))) { - printf("sid 2 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - if ((PacketAlertCheck(p[1], 2))) { - printf("sid 2 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if ((PacketAlertCheck(p[2], 1))) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - if ((PacketAlertCheck(p[2], 2))) { - printf("sid 2 matched but shouldn't have for packet 2: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if ((PacketAlertCheck(p[3], 1))) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - if ((PacketAlertCheck(p[3], 2))) { - printf("sid 2 matched but shouldn't have for packet 3: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 4); - return result; -#else - return 1; -#endif -} - -/** - * \test Positive test, to test the working of distance and within. - */ -int DcePayloadTest08(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - Packet *p[1]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5d 5b 35|\"; distance:0; content:\"|9e a3|\"; " - "distance:0; within:2; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 1; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!(PacketAlertCheck(p[0], 1))) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 1); - return result; -#else - return 1; -#endif -} - -/** - * \test Positive test, to test the working of distance and within. - */ -int DcePayloadTest09(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x5d, 0x5b, 0x35, 0x46, 0x9e, 0xa3, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - Packet *p[1]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|5d 5b 35|\"; distance:0; content:\"|9e a3|\"; " - "distance:0; within:2; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 1; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!(PacketAlertCheck(p[0], 1))) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 1); - return result; -#else - return 1; -#endif -} - -/** - * \test Positive test, to test the working of distance and within. - */ -int DcePayloadTest10(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x5d, 0x5b, 0x35, 0x46, 0x9e, 0xa3, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - TcpSession ssn; - Packet *p[1]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|ad 0d|\"; distance:0; content:\"|ad 0d 00|\"; " - "distance:-10; within:3; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 1; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!(PacketAlertCheck(p[0], 1))) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 1); - return result; -#else - return 1; -#endif -} - -/** - * \test Postive test to check the working of disance and within across frags. - */ -int DcePayloadTest11(void) -{ -#if 0 - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[2]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|af, 26, d0|\"; distance:0; content:\"|80 98 6d|\"; " - "distance:1; within:3; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 2; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if (!(PacketAlertCheck(p[1], 1))) { - printf("sid 1 didn't match but should have for pacekt 1: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 2); - return result; -#else - return 1; -#endif -} - -/** - * \test Negative test the working of contents on stub data with invalid - * distance. - */ -int DcePayloadTest12(void) -{ -#if 0 /* payload ticks off clamav */ - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xad, 0x0d, 0x00, 0x00, 0x91, 0xfc, 0x27, 0x40, - 0x4a, 0x97, 0x4a, 0x98, 0x4b, 0x41, 0x3f, 0x48, - 0x99, 0x90, 0xf8, 0x27, 0xfd, 0x3f, 0x27, 0x37, - 0x40, 0xd6, 0x27, 0xfc, 0x3f, 0x9f, 0x4f, 0xfd, - 0x42, 0x47, 0x47, 0x49, 0x3f, 0xf9, 0x9b, 0xd6, - 0x48, 0x37, 0x27, 0x46, 0x93, 0x49, 0xfd, 0x93, - 0x91, 0xfd, 0x93, 0x90, 0x92, 0x96, 0xf5, 0x92, - 0x4e, 0x91, 0x98, 0x46, 0x4f, 0x4b, 0x46, 0xf5, - 0xf5, 0xfd, 0x40, 0xf9, 0x9b, 0x40, 0x9f, 0x93, - 0x4e, 0xf8, 0x40, 0x40, 0x4e, 0xf5, 0x4b, 0x98, - 0xf5, 0x91, 0xd6, 0x42, 0x99, 0x96, 0x27, 0x49, - 0x48, 0x47, 0x4f, 0x46, 0x99, 0x4b, 0x92, 0x92, - 0x90, 0x47, 0x46, 0x4e, 0x43, 0x9b, 0x43, 0x42, - 0x3f, 0x4b, 0x27, 0x97, 0x93, 0xf9, 0x42, 0x9b, - 0x46, 0x9b, 0x4b, 0x98, 0x41, 0x98, 0x37, 0x41, - 0x9f, 0x98, 0x4e, 0x93, 0x48, 0x46, 0x46, 0x9f, - 0x97, 0x9b, 0x42, 0x37, 0x90, 0x46, 0xf9, 0x97, - 0x91, 0xf5, 0x4e, 0x97, 0x4e, 0x99, 0xf8, 0x99, - 0x41, 0xf5, 0x41, 0x9f, 0x49, 0xfd, 0x92, 0x96, - 0x3f, 0x3f, 0x42, 0x27, 0x27, 0x93, 0x47, 0x49, - 0x91, 0x27, 0x27, 0x40, 0x42, 0x99, 0x9f, 0xfc, - 0x97, 0x47, 0x99, 0x4a, 0xf9, 0x3f, 0x48, 0x91, - 0x47, 0x97, 0x91, 0x42, 0x4b, 0x9b, 0x4a, 0x48, - 0x9f, 0x43, 0x43, 0x40, 0x99, 0xf9, 0x48, 0x4e, - 0x92, 0x93, 0x92, 0x41, 0x46, 0x4b, 0x4a, 0x4a, - 0x49, 0x96, 0x4a, 0x4f, 0xf5, 0x42, 0x47, 0x98, - 0x9b, 0xf5, 0x91, 0xf9, 0xd6, 0x9b, 0x48, 0x4e, - 0x9f, 0x91, 0xd6, 0x93, 0x4b, 0x37, 0x3f, 0x43, - 0xf5, 0x41, 0x41, 0xf5, 0x37, 0x4f, 0x43, 0x92, - 0x97, 0x27, 0x93, 0x92, 0x46, 0x47, 0x4b, 0x96, - 0x41, 0x90, 0x90, 0x3f, 0x96, 0x27, 0x41, 0xd6, - 0xd6, 0xd6, 0xf9, 0xf8, 0x47, 0x27, 0x46, 0x37, - 0x41, 0x90, 0x91, 0xfc, 0x46, 0x41, 0x43, 0x97, - 0x9f, 0x4a, 0x49, 0x92, 0x41, 0x91, 0x41, 0x92, - 0x42, 0x4a, 0x3f, 0x93, 0x99, 0x9b, 0x9f, 0x4e, - 0x47, 0x93, 0xd6, 0x37, 0x37, 0x40, 0x98, 0xfd, - 0x41, 0x42, 0x97, 0x4e, 0x4e, 0x98, 0x9f, 0x4e, - 0x48, 0x3f, 0x48, 0x42, 0x96, 0x9f, 0x99, 0x4f, - 0x4e, 0x42, 0x97, 0xf9, 0x3f, 0x37, 0x27, 0x46, - 0x41, 0xf9, 0x92, 0x96, 0x41, 0x93, 0x91, 0x4b, - 0x96, 0x4f, 0x43, 0xfd, 0xf5, 0x9f, 0x43, 0x27, - 0x99, 0xd6, 0xf5, 0x4e, 0xfd, 0x97, 0x4b, 0x47, - 0x47, 0x92, 0x98, 0x4f, 0x47, 0x49, 0x37, 0x97, - 0x3f, 0x4e, 0x40, 0x46, 0x4e, 0x9f, 0x4e, 0x4e, - 0xfc, 0x41, 0x47, 0xf8, 0x37, 0x9b, 0x41, 0x4e, - 0x96, 0x99, 0x46, 0x99, 0x46, 0xf9, 0x4e, 0x4f, - 0x48, 0x97, 0x97, 0x93, 0xd6, 0x9b, 0x41, 0x40, - 0x97, 0x97, 0x4f, 0x92, 0x91, 0xd6, 0x96, 0x40, - 0x4f, 0x4b, 0x91, 0x46, 0x27, 0x92, 0x3f, 0xf5, - 0xfc, 0x3f, 0x91, 0x97, 0xf8, 0x43, 0x4e, 0xfd, - 0x9b, 0x27, 0xfd, 0x9b, 0xf5, 0x27, 0x47, 0x42, - 0x46, 0x93, 0x37, 0x93, 0x91, 0x91, 0x91, 0xf8, - 0x4f, 0x92, 0x4f, 0xf8, 0x93, 0xf5, 0x49, 0x91, - 0x4b, 0x3f, 0xfc, 0x37, 0x4f, 0x46, 0x98, 0x97, - 0x9f, 0x40, 0xfd, 0x9f, 0x98, 0xfd, 0x4e, 0x97, - 0x4f, 0x47, 0x91, 0x27, 0x4a, 0x90, 0x96, 0x40, - 0x98, 0x97, 0x41, 0x3f, 0xd6, 0xfd, 0x41, 0xfd, - 0x42, 0x97, 0x4b, 0x9b, 0x46, 0x4e, 0xfc, 0x96, - 0xf9, 0x37, 0x4b, 0x96, 0x9f, 0x9b, 0x42, 0x9f, - 0x93, 0x40, 0x42, 0x43, 0xf5, 0x93, 0x48, 0x3f, - 0x4b, 0xfd, 0x9f, 0x4b, 0x41, 0x4a, 0x90, 0x9b, - 0x46, 0x97, 0x98, 0x96, 0x9b, 0x98, 0x92, 0xd6, - 0x4e, 0x4a, 0x27, 0x90, 0x96, 0x99, 0x91, 0x46, - 0x49, 0x41, 0x4b, 0x90, 0x43, 0x91, 0xd6, 0x48, - 0x42, 0x90, 0x4f, 0x96, 0x43, 0x9b, 0xf9, 0x9b, - 0x9f, 0x9f, 0x27, 0x47, 0x4b, 0xf5, 0x43, 0x99, - 0x99, 0x91, 0x4e, 0x41, 0x42, 0x46, 0x97, 0x46, - 0x47, 0xf9, 0xf5, 0x48, 0x4a, 0xf8, 0x4e, 0xd6, - 0x43, 0x4a, 0x27, 0x9b, 0x42, 0x90, 0x46, 0x46, - 0x3f, 0x99, 0x96, 0x9b, 0x91, 0x9f, 0xf5, 0x48, - 0x43, 0x9f, 0x4a, 0x99, 0x96, 0xfd, 0x92, 0x49, - 0x46, 0x91, 0x40, 0xfd, 0x4a, 0x48, 0x4f, 0x90, - 0x91, 0x98, 0x48, 0x4b, 0x9f, 0x42, 0x27, 0x93, - 0x47, 0xf8, 0x4f, 0x48, 0x3f, 0x90, 0x47, 0x41, - 0xf5, 0xfc, 0x27, 0xf8, 0x97, 0x4a, 0x49, 0x37, - 0x40, 0x4f, 0x40, 0x37, 0x41, 0x27, 0x96, 0x37, - 0xfc, 0x42, 0xd6, 0x4b, 0x48, 0x37, 0x42, 0xf5, - 0x27, 0xf9, 0xd6, 0x48, 0x9b, 0xfd, 0x40, 0x96, - 0x4e, 0x43, 0xf8, 0x90, 0x40, 0x40, 0x49, 0x3f, - 0xfc, 0x4a, 0x42, 0x47, 0xf8, 0x49, 0x42, 0x97, - 0x4f, 0x91, 0xfd, 0x4b, 0x46, 0x4b, 0xfc, 0x48, - 0x49, 0x96, 0x4b, 0x96, 0x43, 0x9f, 0x90, 0x37, - 0xd6, 0x4a, 0xd6, 0x3f, 0xd6, 0x90, 0x49, 0x27, - 0x4e, 0x96, 0x96, 0xf8, 0x49, 0x96, 0xf8, 0x37, - 0x90, 0x4e, 0x4b, 0x4f, 0x99, 0xf8, 0x6a, 0x52, - 0x59, 0xd9, 0xee, 0xd9, 0x74, 0x24, 0xf4, 0x5b, - 0x81, 0x73, 0x13, 0x30, 0x50, 0xf0, 0x82, 0x83, - 0xeb, 0xfc, 0xe2, 0xf4, 0xb1, 0x94, 0x0f, 0x6d, - 0xcf, 0xaf, 0xb4, 0x7e, 0x5a, 0xbb, 0xbf, 0x6a, - 0xc9, 0xaf, 0x0f, 0x7d, 0x50, 0xdb, 0x9c, 0xa6, - 0x14, 0xdb, 0xb5, 0xbe, 0xbb, 0x2c, 0xf5, 0xfa, - 0x31, 0xbf, 0x7b, 0xcd, 0x28, 0xdb, 0xaf, 0xa2, - 0x31, 0xbb, 0x13, 0xb2, 0x79, 0xdb, 0xc4, 0x09, - 0x31, 0xbe, 0xc1, 0x42, 0xa9, 0xfc, 0x74, 0x42, - 0x44, 0x57, 0x31, 0x48, 0x3d, 0x51, 0x32, 0x69, - 0xc4, 0x6b, 0xa4, 0xa6, 0x18, 0x25, 0x13, 0x09, - 0x6f, 0x74, 0xf1, 0x69, 0x56, 0xdb, 0xfc, 0xc9, - 0xbb, 0x0f, 0xec, 0x83, 0xdb, 0x53, 0xdc, 0x09, - 0xb9, 0x3c, 0xd4, 0x9e, 0x51, 0x93, 0xc1, 0x42, - 0x54, 0xdb, 0xb0, 0xb2, 0xbb, 0x10, 0xfc, 0x09, - 0x40, 0x4c, 0x5d, 0x09, 0x70, 0x58, 0xae, 0xea, - 0xbe, 0x1e, 0xfe, 0x6e, 0x60, 0xaf, 0x26, 0xb3, - 0xeb, 0x36, 0xa3, 0xe4, 0x58, 0x63, 0xc2, 0xea, - 0x47, 0x23, 0xc2, 0xdd, 0x64, 0xaf, 0x20, 0xea, - 0xfb, 0xbd, 0x0c, 0xb9, 0x60, 0xaf, 0x26, 0xdd, - 0xb9, 0xb5, 0x96, 0x03, 0xdd, 0x58, 0xf2, 0xd7, - 0x5a, 0x52, 0x0f, 0x52, 0x58, 0x89, 0xf9, 0x77, - 0x9d, 0x07, 0x0f, 0x54, 0x63, 0x03, 0xa3, 0xd1, - 0x63, 0x13, 0xa3, 0xc1, 0x63, 0xaf, 0x20, 0xe4, - 0x58, 0x41, 0xac, 0xe4, 0x63, 0xd9, 0x11, 0x17, - 0x58, 0xf4, 0xea, 0xf2, 0xf7, 0x07, 0x0f, 0x54, - 0x5a, 0x40, 0xa1, 0xd7, 0xcf, 0x80, 0x98, 0x26, - 0x9d, 0x7e, 0x19, 0xd5, 0xcf, 0x86, 0xa3, 0xd7, - 0xcf, 0x80, 0x98, 0x67, 0x79, 0xd6, 0xb9, 0xd5, - 0xcf, 0x86, 0xa0, 0xd6, 0x64, 0x05, 0x0f, 0x52, - 0xa3, 0x38, 0x17, 0xfb, 0xf6, 0x29, 0xa7, 0x7d, - 0xe6, 0x05, 0x0f, 0x52, 0x56, 0x3a, 0x94, 0xe4, - 0x58, 0x33, 0x9d, 0x0b, 0xd5, 0x3a, 0xa0, 0xdb, - 0x19, 0x9c, 0x79, 0x65, 0x5a, 0x14, 0x79, 0x60, - 0x01, 0x90, 0x03, 0x28, 0xce, 0x12, 0xdd, 0x7c, - 0x72, 0x7c, 0x63, 0x0f, 0x4a, 0x68, 0x5b, 0x29, - 0x9b, 0x38, 0x82, 0x7c, 0x83, 0x46, 0x0f, 0xf7, - 0x74, 0xaf, 0x26, 0xd9, 0x67, 0x02, 0xa1, 0xd3, - 0x61, 0x3a, 0xf1, 0xd3, 0x61, 0x05, 0xa1, 0x7d, - 0xe0, 0x38, 0x5d, 0x5b, 0x35, 0x9e, 0xa3, 0x7d, - 0xe6, 0x3a, 0x0f, 0x7d, 0x07, 0xaf, 0x20, 0x09, - 0x67, 0xac, 0x73, 0x46, 0x54, 0xaf, 0x26, 0xd0 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, - 0xcf, 0x80, 0x98, 0x6d, 0xfe, 0xb0, 0x90, 0xd1, - 0xcf, 0x86, 0x0f, 0x52, 0x2c, 0x23, 0x66, 0x28, - 0x27, 0x30, 0x48, 0x55, 0x42, 0x6a, 0x48, 0x4b, - 0x68, 0x22, 0x2e, 0x23, 0x64, 0x33, 0x2c, 0x2d, - 0x5c, 0x51, 0x48, 0x55, 0x24, 0x67, 0x6c, 0x4c, - 0x45, 0x71, 0x35, 0x72, 0x5a, 0x48, 0x5e, 0x35, - 0x61, 0x78, 0x35, 0x42, 0x2c, 0x7a, 0x75, 0x61, - 0x5b, 0x4e, 0x76, 0x30, 0x26, 0x2f, 0x2a, 0x34, - 0x48, 0x29, 0x25, 0x6e, 0x5c, 0x3a, 0x6c, 0x3e, - 0x79, 0x4e, 0x2a, 0x21, 0x6f, 0x6f, 0x34, 0x46, - 0x43, 0x26, 0x5b, 0x35, 0x78, 0x27, 0x69, 0x23, - 0x72, 0x21, 0x69, 0x56, 0x6a, 0x7d, 0x4b, 0x5e, - 0x65, 0x37, 0x60, 0x44, 0x7c, 0x5d, 0x5b, 0x72, - 0x7d, 0x73, 0x7b, 0x47, 0x57, 0x21, 0x41, 0x38, - 0x76, 0x38, 0x76, 0x5c, 0x58, 0x32, 0x4a, 0x37, - 0x2f, 0x40, 0x4b, 0x4c, 0x3d, 0x41, 0x33, 0x56, - 0x73, 0x38, 0x61, 0x71, 0x24, 0x49, 0x4c, 0x4a, - 0x44, 0x2e, 0x3a, 0x3f, 0x74, 0x54, 0x4c, 0x65, - 0x54, 0x2d, 0x3b, 0x28, 0x41, 0x45, 0x49, 0x2c, - 0x6e, 0x48, 0x44, 0x43, 0x37, 0x3d, 0x7b, 0x6d, - 0x2b, 0x4b, 0x32, 0x5a, 0x31, 0x61, 0x6e, 0x2b, - 0x27, 0x50, 0x6b, 0x66, 0x76, 0x4e, 0x55, 0x35, - 0x2b, 0x72, 0x2d, 0x5e, 0x42, 0x3e, 0x5a, 0x5d, - 0x36, 0x45, 0x32, 0x3a, 0x58, 0x78, 0x78, 0x3e, - 0x60, 0x6c, 0x5d, 0x63, 0x41, 0x7c, 0x52, 0x21, - 0x75, 0x6a, 0x5a, 0x70, 0x55, 0x45, 0x76, 0x58, - 0x33, 0x40, 0x38, 0x39, 0x21, 0x37, 0x7d, 0x77, - 0x21, 0x70, 0x2b, 0x72, 0x29, 0x6a, 0x31, 0x5f, - 0x38, 0x4a, 0x66, 0x65, 0x62, 0x2c, 0x39, 0x52, - 0x5f, 0x2a, 0x2b, 0x63, 0x4f, 0x76, 0x43, 0x25, - 0x6a, 0x50, 0x37, 0x52, 0x5e, 0x23, 0x3c, 0x42, - 0x28, 0x75, 0x75, 0x42, 0x25, 0x23, 0x28, 0x56, - 0x6c, 0x46, 0x5c, 0x5e, 0x6b, 0x7d, 0x48, 0x24, - 0x77, 0x6c, 0x70, 0x62, 0x2e, 0x28, 0x7d, 0x6b, - 0x69, 0x4a, 0x75, 0x3d, 0x5d, 0x56, 0x21, 0x49, - 0x56, 0x47, 0x64, 0x2b, 0x4c, 0x52, 0x43, 0x60, - 0x77, 0x49, 0x46, 0x46, 0x33, 0x2c, 0x4b, 0x4b, - 0x3d, 0x63, 0x5d, 0x33, 0x78, 0x76, 0x51, 0x56, - 0x77, 0x3c, 0x72, 0x74, 0x52, 0x27, 0x40, 0x6c, - 0x42, 0x79, 0x49, 0x24, 0x62, 0x5e, 0x26, 0x31, - 0x5c, 0x22, 0x2b, 0x4c, 0x64, 0x49, 0x52, 0x45, - 0x47, 0x49, 0x3a, 0x2a, 0x51, 0x71, 0x22, 0x22, - 0x70, 0x24, 0x34, 0x67, 0x4b, 0x6d, 0x58, 0x29, - 0x63, 0x26, 0x7b, 0x6f, 0x38, 0x78, 0x25, 0x62, - 0x4d, 0x3a, 0x7d, 0x40, 0x23, 0x57, 0x67, 0x33, - 0x38, 0x31, 0x4e, 0x54, 0x3c, 0x4b, 0x48, 0x69, - 0x3c, 0x39, 0x31, 0x2b, 0x26, 0x70, 0x44, 0x66, - 0x4a, 0x37, 0x2b, 0x75, 0x36, 0x45, 0x59, 0x34, - 0x3e, 0x3e, 0x29, 0x70, 0x71, 0x5a, 0x55, 0x49, - 0x3e, 0x4b, 0x68, 0x4e, 0x75, 0x70, 0x3c, 0x5c, - 0x50, 0x58, 0x28, 0x75, 0x3c, 0x2a, 0x41, 0x70, - 0x2f, 0x2b, 0x37, 0x26, 0x75, 0x71, 0x55, 0x22, - 0x3a, 0x44, 0x30, 0x48, 0x5d, 0x2f, 0x6c, 0x44, - 0x28, 0x4b, 0x34, 0x45, 0x21, 0x60, 0x44, 0x36, - 0x7b, 0x32, 0x39, 0x5f, 0x6d, 0x3f, 0x68, 0x73, - 0x25, 0x45, 0x56, 0x7c, 0x78, 0x7a, 0x49, 0x6a, - 0x46, 0x3d, 0x2d, 0x33, 0x6c, 0x6f, 0x23, 0x77, - 0x38, 0x33, 0x36, 0x74, 0x7b, 0x57, 0x4b, 0x6d, - 0x27, 0x75, 0x24, 0x6e, 0x43, 0x61, 0x4d, 0x44, - 0x6d, 0x27, 0x48, 0x58, 0x5e, 0x7b, 0x26, 0x6a, - 0x50, 0x7c, 0x51, 0x23, 0x3c, 0x4f, 0x37, 0x4c, - 0x47, 0x3e, 0x45, 0x56, 0x22, 0x33, 0x7c, 0x66, - 0x35, 0x54, 0x7a, 0x6e, 0x5a, 0x24, 0x70, 0x62, - 0x29, 0x3f, 0x69, 0x79, 0x24, 0x43, 0x41, 0x24, - 0x65, 0x25, 0x62, 0x4f, 0x73, 0x3e, 0x2b, 0x36, - 0x46, 0x69, 0x27, 0x55, 0x2a, 0x6e, 0x24, 0x6c, - 0x7d, 0x64, 0x7c, 0x61, 0x26, 0x67, 0x2a, 0x53, - 0x73, 0x60, 0x28, 0x2d, 0x6b, 0x44, 0x54, 0x61, - 0x34, 0x53, 0x22, 0x59, 0x6d, 0x73, 0x56, 0x55, - 0x25, 0x2c, 0x38, 0x4a, 0x3b, 0x4e, 0x78, 0x46, - 0x54, 0x6e, 0x6d, 0x4f, 0x47, 0x4f, 0x4f, 0x5a, - 0x67, 0x77, 0x39, 0x66, 0x28, 0x29, 0x4e, 0x43, - 0x55, 0x6e, 0x60, 0x59, 0x28, 0x3b, 0x65, 0x62, - 0x61, 0x5a, 0x29, 0x6e, 0x79, 0x60, 0x41, 0x53, - 0x2f, 0x5d, 0x44, 0x36, 0x7b, 0x3e, 0x7c, 0x2b, - 0x77, 0x36, 0x70, 0x3f, 0x40, 0x55, 0x48, 0x67, - 0x4b, 0x4d, 0x5d, 0x51, 0x79, 0x76, 0x48, 0x4a, - 0x2d, 0x21, 0x60, 0x40, 0x46, 0x55, 0x7a, 0x60, - 0x22, 0x25, 0x3f, 0x4b, 0x54, 0x6a, 0x6a, 0x3c, - 0x77, 0x22, 0x5b, 0x43, 0x67, 0x58, 0x71, 0x22, - 0x79, 0x4b, 0x32, 0x61, 0x44, 0x4d, 0x6f, 0x42, - 0x33, 0x2d, 0x53, 0x35, 0x3d, 0x6f, 0x57, 0x48, - 0x33, 0x3b, 0x5a, 0x53, 0x3f, 0x4e, 0x3f, 0x6b, - 0x4c, 0x27, 0x26, 0x3b, 0x73, 0x49, 0x22, 0x55, - 0x79, 0x2f, 0x47, 0x2f, 0x55, 0x5a, 0x7a, 0x71, - 0x6c, 0x31, 0x43, 0x40, 0x56, 0x7b, 0x21, 0x7a, - 0x6d, 0x4c, 0x43, 0x5e, 0x38, 0x47, 0x29, 0x38, - 0x62, 0x49, 0x45, 0x78, 0x70, 0x2b, 0x2e, 0x65, - 0x47, 0x71, 0x58, 0x79, 0x39, 0x67, 0x7d, 0x6d, - 0x6a, 0x67, 0x4a, 0x71, 0x27, 0x35, 0x2a, 0x4c, - 0x3e, 0x58, 0x55, 0x30, 0x4d, 0x75, 0x77, 0x48, - 0x5f, 0x4b, 0x59, 0x34, 0x65, 0x68, 0x57, 0x59, - 0x63, 0x23, 0x47, 0x38, 0x47, 0x5e, 0x56, 0x28, - 0x79, 0x58, 0x3e, 0x39, 0x66, 0x77, 0x67, 0x33, - 0x29, 0x61, 0x24, 0x7d, 0x37, 0x44, 0x37, 0x67, - 0x3a, 0x58, 0x76, 0x21, 0x51, 0x59, 0x61, 0x73, - 0x66, 0x75, 0x71, 0x53, 0x4d, 0x24, 0x2d, 0x4b, - 0x29, 0x30, 0x32, 0x26, 0x59, 0x64, 0x27, 0x55, - 0x2c, 0x5a, 0x4c, 0x3c, 0x6c, 0x53, 0x56, 0x4b, - 0x3e, 0x55, 0x2e, 0x44, 0x38, 0x6b, 0x47, 0x76, - 0x2d, 0x2c, 0x3f, 0x4d, 0x22, 0x7b, 0x6d, 0x61, - 0x34, 0x6b, 0x50, 0x73, 0x28, 0x6d, 0x41, 0x71, - 0x21, 0x76, 0x52, 0x2a, 0x6d, 0x53, 0x2a, 0x74, - 0x28, 0x27, 0x62, 0x2a, 0x66, 0x25, 0x6e, 0x5e, - 0x37, 0x4f, 0x27, 0x72, 0x28, 0x47, 0x63, 0x6e, - 0x5a, 0x6a, 0x41, 0x35, 0x3a, 0x42, 0x3f, 0x27, - 0x75, 0x3e, 0x26, 0x3e, 0x6b, 0x55, 0x59, 0x60, - 0x24, 0x70, 0x49, 0x3c, 0x4e, 0x2c, 0x39, 0x7a, - 0x36, 0x6c, 0x27, 0x3e, 0x6a, 0x4a, 0x59, 0x5a, - 0x3e, 0x21, 0x73, 0x4e, 0x59, 0x6e, 0x3d, 0x32, - 0x27, 0x45, 0x49, 0x58, 0x7d, 0x37, 0x39, 0x77, - 0x28, 0x51, 0x79, 0x54, 0x2b, 0x78, 0x46, 0x5a, - 0x21, 0x75, 0x33, 0x21, 0x63, 0x5a, 0x7b, 0x3e, - 0x33, 0x4f, 0x67, 0x75, 0x3a, 0x50, 0x48, 0x60, - 0x26, 0x64, 0x76, 0x5c, 0x42, 0x5c, 0x72, 0x38, - 0x6c, 0x52, 0x21, 0x2b, 0x25, 0x6b, 0x7c, 0x6b, - 0x2d, 0x5e, 0x63, 0x2a, 0x4c, 0x26, 0x5b, 0x4c, - 0x58, 0x52, 0x51, 0x55, 0x31, 0x79, 0x6c, 0x53, - 0x62, 0x3a, 0x36, 0x46, 0x7a, 0x29, 0x27, 0x78, - 0x1a, 0xbf, 0x49, 0x74, 0x68, 0x24, 0x51, 0x44, - 0x5b, 0x3e, 0x34, 0x44, 0x29, 0x5e, 0x4f, 0x2a, - 0xe9, 0x3f, 0xf8, 0xff, 0xff, 0x52, 0x7d, 0x47, - 0x67, 0x40, 0x27, 0x5e, 0x47, 0x46, 0x6d, 0x72, - 0x5d, 0x49, 0x26, 0x45, 0x33, 0x6b, 0x4d, 0x4a, - 0x6f, 0x62, 0x60, 0x45, 0x62, 0x27, 0x27, 0x7d, - 0x6a, 0x41, 0x2c, 0x6c, 0x5b, 0x2a, 0x2b, 0x36, - 0x29, 0x58, 0x7a, 0x4c, 0x6e, 0x2d, 0x74, 0x5c, - 0x38, 0x22, 0x5f, 0x49, 0x63, 0x43, 0x5b, 0x67 - }; - uint32_t request2_len = sizeof(request2); - - TcpSession ssn; - Packet *p[2]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|af, 26, d0|\"; distance:0; content:\"|80 98 6d|\"; " - "distance:2; within:3; sid:1;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 2; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, sig1); - s = de_ctx->sig_list; - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if ((PacketAlertCheck(p[0], 1))) { - printf("sid 1 matched but shouldn't have for packet 0: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if ((PacketAlertCheck(p[1], 1))) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 2); - return result; -#else - return 1; -#endif -} - -/* Disabled because of bug_753. Would be enabled, once we rewrite - * dce parser */ -#if 0 - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest13(void) -{ - int result = 0; - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x2c, 0xfd, 0xb5, 0x00, 0x40, 0xaa, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02, - }; - uint32_t request1_len = sizeof(request1); - - uint8_t response1[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, - }; - uint32_t response1_len = sizeof(response1); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf6, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x5c, 0x00, 0x5c, 0x00, - 0xa8, 0xb9, 0x14, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x54, 0x00, - 0x57, 0x00, 0x41, 0x00, 0x52, 0x00, 0x45, 0x00, - 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, - 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, - 0x66, 0x00, 0x74, 0x00, 0x5c, 0x00, 0x57, 0x00, - 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, - 0x77, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x43, 0x00, - 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, - 0x6e, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, - 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, - 0x6e, 0x00, 0x5c, 0x00, 0x52, 0x00, 0x75, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, - }; - uint32_t request2_len = sizeof(request2); - - uint8_t response2[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x00, 0x00, 0x00, 0x00, - }; - uint32_t response2_len = sizeof(response2); - - uint8_t request3[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf7, 0x72, 0x28, 0x9c, - 0xf0, 0x57, 0xd8, 0x11, 0xb0, 0x05, 0x00, 0x0c, - 0x29, 0x87, 0xea, 0xe9, 0x0c, 0x00, 0x0c, 0x00, - 0x98, 0xda, 0x14, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x73, 0x00, 0x61, 0x00, 0x33, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, - 0x4f, 0x00, 0x53, 0x00, 0x41, 0x00, 0x33, 0x00, - 0x32, 0x00, 0x2e, 0x00, 0x45, 0x00, 0x58, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - }; - uint32_t request3_len = sizeof(request3); - - uint8_t response3[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - uint32_t response3_len = sizeof(response3); - - TcpSession ssn; - Packet *p[8]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|00 02|\"; sid:1;)"; - char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|00 75|\"; sid:2;)"; - char *sig3 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|00 18|\"; sid:3;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - /* let the 7 and the 8th packet be dummy packets the client sends to the server */ - for (i = 0; i < 8; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[1]->flowflags |= FLOW_PKT_TOCLIENT; - p[1]->flowflags &=~ FLOW_PKT_TOSERVER; - p[3]->flowflags |= FLOW_PKT_TOCLIENT; - p[3]->flowflags &=~ FLOW_PKT_TOSERVER; - p[5]->flowflags |= FLOW_PKT_TOCLIENT; - p[5]->flowflags &=~ FLOW_PKT_TOSERVER; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, sig1); - if (s == NULL) - goto end; - s = de_ctx->sig_list->next = SigInit(de_ctx, sig2); - if (s == NULL) - goto end; - s = de_ctx->sig_list->next->next = SigInit(de_ctx, sig3); - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!PacketAlertCheck(p[0], 1) || PacketAlertCheck(p[0], 2) || PacketAlertCheck(p[0], 3)) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[6]); - if (PacketAlertCheck(p[6], 1) || PacketAlertCheck(p[6], 2) || PacketAlertCheck(p[6], 3)) { - printf("sid 1 matched but shouldn't have for packet 6: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response1, response1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if (PacketAlertCheck(p[1], 1) || PacketAlertCheck(p[1], 2) || PacketAlertCheck(p[1], 3)) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - /* we should have a match for the sig once again for the same flow, since - * the detection engine state for the flow has been reset because of a - * fresh transaction */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (PacketAlertCheck(p[2], 1) || !PacketAlertCheck(p[2], 2) || PacketAlertCheck(p[2], 3)) { - printf("sid 1 didn't match but should have for packet 2: "); - goto end; - } - - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[7]); - if (PacketAlertCheck(p[7], 1) || PacketAlertCheck(p[7], 2) || PacketAlertCheck(p[7], 3)) { - printf("sid 1 matched but shouldn't have for packet 7: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response2, response2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if (PacketAlertCheck(p[3], 1) || PacketAlertCheck(p[3], 2) || PacketAlertCheck(p[3], 3)) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request3, request3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - /* we should have a match for the sig once again for the same flow, since - * the detection engine state for the flow has been reset because of a - * fresh transaction */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); - if (PacketAlertCheck(p[4], 1) || PacketAlertCheck(p[4], 2) || !PacketAlertCheck(p[4], 3)) { - printf("sid 1 didn't match but should have for packet 4: "); - goto end; - } - - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response3, response3_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); - if (PacketAlertCheck(p[5], 1) || PacketAlertCheck(p[5], 2) || PacketAlertCheck(p[5], 3)) { - printf("sid 1 matched but shouldn't have for packet 5: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - StreamTcpFreeConfig(TRUE); - - UTHFreePackets(p, 8); - return result; -} - -/** - * \test Test the working of detection engien with respect to dce keywords. - */ -int DcePayloadTest14(void) -{ - int result = 0; - - uint8_t request1[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, - 0x76, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x37, 0x00, - 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x31, 0x00, - 0x2e, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2e, 0x00, - 0x36, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x84, 0xf9, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x14, 0xfa, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00 - }; - uint32_t request1_len = sizeof(request1); - - uint8_t bind[] = { - 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x81, 0xbb, 0x7a, 0x36, 0x44, 0x98, 0xf1, 0x35, - 0xad, 0x32, 0x98, 0xf0, 0x38, 0x00, 0x10, 0x03, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, - 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_len = sizeof(bind); - - uint8_t bind_ack[] = { - 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xb8, 0x10, 0xb8, 0x10, 0x74, 0x73, 0x00, 0x00, - 0x0d, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, - 0x6e, 0x74, 0x73, 0x76, 0x63, 0x73, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, - 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, - 0x02, 0x00, 0x00, 0x00 - }; - uint32_t bind_ack_len = sizeof(bind_ack); - - uint8_t request2[] = { - 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, - 0x64, 0x7e, 0x32, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x5c, 0x5c, 0x31, 0x37, 0x31, 0x2e, 0x37, 0x31, - 0x2e, 0x38, 0x34, 0x2e, 0x36, 0x37, 0x00, 0x8a, - 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0f, 0x00 - }; - uint32_t request2_len = sizeof(request2); - - uint8_t response2[] = { - 0x05, 0x00, 0x02, 0x03, 0x10, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd2, 0xc4, 0x88, 0x14, - 0xef, 0x31, 0xbb, 0x4d, 0xa8, 0x13, 0xb7, 0x1b, - 0x47, 0x49, 0xb5, 0xd7, 0x00, 0x00, 0x00, 0x00 - }; - uint32_t response2_len = sizeof(response2); - - TcpSession ssn; - Packet *p[6]; - ThreadVars tv; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - int r; - int i = 0; - - char *sig1 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|7f 01|\"; sid:1;)"; - char *sig2 = "alert tcp any any -> any any " - "(dce_stub_data; content:\"|3f 00|\"; sid:2;)"; - - Signature *s; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - for (i = 0; i < 6; i++) { - p[i] = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p[i]->flow = &f; - p[i]->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p[i]->flowflags |= FLOW_PKT_TOSERVER; - p[i]->flowflags |= FLOW_PKT_ESTABLISHED; - } - p[3]->flowflags |= FLOW_PKT_TOCLIENT; - p[3]->flowflags &=~ FLOW_PKT_TOSERVER; - p[5]->flowflags |= FLOW_PKT_TOCLIENT; - p[5]->flowflags &=~ FLOW_PKT_TOSERVER; - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_DCERPC; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->flags |= DE_QUIET; - - s = de_ctx->sig_list = SigInit(de_ctx, sig1); - if (s == NULL) - goto end; - s = de_ctx->sig_list->next = SigInit(de_ctx, sig2); - if (s == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - /* request 1 */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[0]); - if (!PacketAlertCheck(p[0], 1) || PacketAlertCheck(p[0], 2)) { - printf("sid 1 didn't match but should have for packet 0: "); - goto end; - } - - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[1]); - if (PacketAlertCheck(p[1], 1) || PacketAlertCheck(p[1], 2)) { - printf("sid 1 matched but shouldn't have for packet 1: "); - goto end; - } - - /* bind */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, bind, bind_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[2]); - if (PacketAlertCheck(p[2], 1) || PacketAlertCheck(p[2], 2)) { - printf("sid 1 matched but shouldn't have for packet 2: "); - goto end; - } - - /* bind_ack. A new transaction initiation */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, bind_ack, bind_ack_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[3]); - if (PacketAlertCheck(p[3], 1) || PacketAlertCheck(p[3], 2)) { - printf("sid 1 matched but shouldn't have for packet 3: "); - goto end; - } - - /* we should have a match for the sig once again for the same flow, since - * the detection engine state for the flow has been reset because of a - * fresh transaction */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request2, request2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[4]); - if (PacketAlertCheck(p[4], 1) || !PacketAlertCheck(p[4], 2)) { - printf("sid 1 didn't match but should have for packet 4: "); - goto end; - } - - /* response */ - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOCLIENT, response2, response2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } - /* detection phase */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p[5]); - if (PacketAlertCheck(p[5], 1) || PacketAlertCheck(p[5], 2)) { - printf("sid 1 matched but shouldn't have for packet 5: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); +#include "detect-dce-iface.h" - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } +static int g_dce_stub_data_buffer_id = 0; - StreamTcpFreeConfig(TRUE); - UTHFreePackets(p, 6); - return result; -} +/**************************************Unittests*******************************/ -#endif +#ifdef UNITTESTS /** * \test Test the working of byte_test endianness. */ -int DcePayloadTest15(void) +static int DcePayloadTest15(void) { int result = 0; @@ -6538,15 +133,16 @@ int DcePayloadTest15(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6580,7 +176,7 @@ int DcePayloadTest15(void) /** * \test Test the working of byte_test endianness. */ -int DcePayloadTest16(void) +static int DcePayloadTest16(void) { int result = 0; @@ -6654,15 +250,16 @@ int DcePayloadTest16(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6696,7 +293,7 @@ int DcePayloadTest16(void) /** * \test Test the working of byte_test endianness. */ -int DcePayloadTest17(void) +static int DcePayloadTest17(void) { int result = 0; @@ -6770,15 +367,16 @@ int DcePayloadTest17(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6812,7 +410,7 @@ int DcePayloadTest17(void) /** * \test Test the working of byte_jump endianness. */ -int DcePayloadTest18(void) +static int DcePayloadTest18(void) { int result = 0; @@ -6886,15 +484,16 @@ int DcePayloadTest18(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -6928,7 +527,7 @@ int DcePayloadTest18(void) /** * \test Test the working of byte_jump endianness. */ -int DcePayloadTest19(void) +static int DcePayloadTest19(void) { int result = 0; @@ -7002,15 +601,16 @@ int DcePayloadTest19(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7044,7 +644,7 @@ int DcePayloadTest19(void) /** * \test Test the working of byte_jump endianness. */ -int DcePayloadTest20(void) +static int DcePayloadTest20(void) { int result = 0; @@ -7118,15 +718,16 @@ int DcePayloadTest20(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7160,7 +761,7 @@ int DcePayloadTest20(void) /** * \test Test the working of consecutive relative matches. */ -int DcePayloadTest21(void) +static int DcePayloadTest21(void) { int result = 0; @@ -7223,15 +824,16 @@ int DcePayloadTest21(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7261,7 +863,7 @@ int DcePayloadTest21(void) /** * \test Test the working of consecutive relative matches. */ -int DcePayloadTest22(void) +static int DcePayloadTest22(void) { int result = 0; @@ -7324,15 +926,16 @@ int DcePayloadTest22(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7362,7 +965,7 @@ int DcePayloadTest22(void) /** * \test Test the working of consecutive relative matches. */ -int DcePayloadTest23(void) +static int DcePayloadTest23(void) { int result = 0; @@ -7426,15 +1029,16 @@ int DcePayloadTest23(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -7464,7 +1068,7 @@ int DcePayloadTest23(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest25(void) +static int DcePayloadParseTest25(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7489,16 +1093,16 @@ int DcePayloadParseTest25(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7585,7 +1189,7 @@ int DcePayloadParseTest25(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest26(void) +static int DcePayloadParseTest26(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7612,16 +1216,16 @@ int DcePayloadParseTest26(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7712,7 +1316,7 @@ int DcePayloadParseTest26(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest27(void) +static int DcePayloadParseTest27(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7738,16 +1342,16 @@ int DcePayloadParseTest27(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] != NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7838,7 +1442,7 @@ int DcePayloadParseTest27(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest28(void) +static int DcePayloadParseTest28(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7865,16 +1469,16 @@ int DcePayloadParseTest28(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7914,7 +1518,7 @@ int DcePayloadParseTest28(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -7965,7 +1569,7 @@ int DcePayloadParseTest28(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest29(void) +static int DcePayloadParseTest29(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -7994,16 +1598,16 @@ int DcePayloadParseTest29(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8107,7 +1711,7 @@ int DcePayloadParseTest29(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest30(void) +static int DcePayloadParseTest30(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8136,16 +1740,16 @@ int DcePayloadParseTest30(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8254,7 +1858,7 @@ int DcePayloadParseTest30(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest31(void) +static int DcePayloadParseTest31(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8283,16 +1887,16 @@ int DcePayloadParseTest31(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8350,7 +1954,7 @@ int DcePayloadParseTest31(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8401,7 +2005,7 @@ int DcePayloadParseTest31(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest32(void) +static int DcePayloadParseTest32(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8430,16 +2034,16 @@ int DcePayloadParseTest32(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -8497,7 +2101,7 @@ int DcePayloadParseTest32(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8548,7 +2152,7 @@ int DcePayloadParseTest32(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest33(void) +static int DcePayloadParseTest33(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8577,16 +2181,16 @@ int DcePayloadParseTest33(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8639,7 +2243,7 @@ int DcePayloadParseTest33(void) if (result == 0) goto end; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8690,7 +2294,7 @@ int DcePayloadParseTest33(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest34(void) +static int DcePayloadParseTest34(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8720,16 +2324,16 @@ int DcePayloadParseTest34(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -8781,7 +2385,7 @@ int DcePayloadParseTest34(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8814,7 +2418,7 @@ int DcePayloadParseTest34(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest35(void) +static int DcePayloadParseTest35(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8841,16 +2445,16 @@ int DcePayloadParseTest35(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; @@ -8868,7 +2472,7 @@ int DcePayloadParseTest35(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -8901,7 +2505,7 @@ int DcePayloadParseTest35(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest36(void) +static int DcePayloadParseTest36(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -8929,16 +2533,16 @@ int DcePayloadParseTest36(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_ISDATAAT) { result = 0; goto end; @@ -8972,7 +2576,7 @@ int DcePayloadParseTest36(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9005,7 +2609,7 @@ int DcePayloadParseTest36(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest37(void) +static int DcePayloadParseTest37(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9034,16 +2638,16 @@ int DcePayloadParseTest37(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -9079,7 +2683,7 @@ int DcePayloadParseTest37(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9112,7 +2716,7 @@ int DcePayloadParseTest37(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest38(void) +static int DcePayloadParseTest38(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9143,16 +2747,16 @@ int DcePayloadParseTest38(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_PCRE) { result = 0; goto end; @@ -9201,7 +2805,7 @@ int DcePayloadParseTest38(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9234,7 +2838,7 @@ int DcePayloadParseTest38(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest39(void) +static int DcePayloadParseTest39(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9259,16 +2863,16 @@ int DcePayloadParseTest39(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9290,7 +2894,7 @@ int DcePayloadParseTest39(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; data = (DetectContentData *)sm->ctx; if (data->flags & DETECT_CONTENT_RAWBYTES || data->flags & DETECT_CONTENT_NOCASE || @@ -9319,7 +2923,7 @@ int DcePayloadParseTest39(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest40(void) +static int DcePayloadParseTest40(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9348,16 +2952,16 @@ int DcePayloadParseTest40(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9416,7 +3020,7 @@ int DcePayloadParseTest40(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9449,7 +3053,7 @@ int DcePayloadParseTest40(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest41(void) +static int DcePayloadParseTest41(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9478,16 +3082,16 @@ int DcePayloadParseTest41(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9509,7 +3113,7 @@ int DcePayloadParseTest41(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -9578,7 +3182,7 @@ int DcePayloadParseTest41(void) /** * \test Test the working of consecutive relative matches with a negated content. */ -int DcePayloadTest42(void) +static int DcePayloadTest42(void) { int result = 0; @@ -9642,15 +3246,16 @@ int DcePayloadTest42(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -9680,7 +3285,7 @@ int DcePayloadTest42(void) /** * \test Test the working of consecutive relative pcres. */ -int DcePayloadTest43(void) +static int DcePayloadTest43(void) { int result = 0; @@ -9744,15 +3349,16 @@ int DcePayloadTest43(void) DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); /* request 1 */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_DCERPC, STREAM_TOSERVER, request1, request1_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DCERPC, + STREAM_TOSERVER, request1, request1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* detection phase */ SigMatchSignatures(&tv, de_ctx, det_ctx, p); if ( !(PacketAlertCheck(p, 1))) { @@ -9782,134 +3388,97 @@ int DcePayloadTest43(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest44(void) +static int DcePayloadParseTest44(void) { DetectEngineCtx *de_ctx = NULL; - int result = 1; Signature *s = NULL; SigMatch *sm = NULL; DetectContentData *data = NULL; DetectIsdataatData *isd = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; " - "dce_iface:12345678-1234-1234-1234-123456789012; " - "dce_opnum:10; dce_stub_data; " - "isdataat:10,relative; " - "content:\"one\"; within:4; distance:8; " - "pkt_data; " - "content:\"two\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { - result = 0; - goto end; - } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; - if (sm->type != DETECT_ISDATAAT) { - result = 0; - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (" + "content:\"one\"; " + "dce_iface:12345678-1234-1234-1234-123456789012; " + "dce_opnum:10; dce_stub_data; " + "isdataat:10,relative; " + "content:\"one\"; within:4; distance:8; " + "pkt_data; " + "content:\"two\"; " + "sid:1;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NULL(s->init_data->smlists_tail[g_dce_stub_data_buffer_id]); + FAIL_IF_NULL(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]); + + /* isdataat:10,relative; */ + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; + FAIL_IF(sm->type != DETECT_ISDATAAT); isd = (DetectIsdataatData *)sm->ctx; - if ( isd->flags & ISDATAAT_RAWBYTES || - !(isd->flags & ISDATAAT_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(isd->flags & ISDATAAT_RAWBYTES); + FAIL_IF_NOT(isd->flags & ISDATAAT_RELATIVE); + FAIL_IF_NULL(sm->next); sm = sm->next; - if (sm->type != DETECT_CONTENT) { - result = 0; - goto end; - } + + /* content:\"one\"; within:4; distance:8; */ + FAIL_IF(sm->type != DETECT_CONTENT); data = (DetectContentData *)sm->ctx; - if (data->flags & DETECT_CONTENT_RAWBYTES || - data->flags & DETECT_CONTENT_NOCASE || - !(data->flags & DETECT_CONTENT_WITHIN) || - !(data->flags & DETECT_CONTENT_DISTANCE) || - data->flags & DETECT_CONTENT_FAST_PATTERN || - data->flags & DETECT_CONTENT_RELATIVE_NEXT || - data->flags & DETECT_CONTENT_NEGATED ) { - result = 0; - printf("two failed\n"); - goto end; - } - result &= (strncmp((char *)data->content, "one", 3) == 0); - if (result == 0) - goto end; + FAIL_IF (data->flags & DETECT_CONTENT_RAWBYTES || + data->flags & DETECT_CONTENT_NOCASE || + !(data->flags & DETECT_CONTENT_WITHIN) || + !(data->flags & DETECT_CONTENT_DISTANCE) || + data->flags & DETECT_CONTENT_FAST_PATTERN || + data->flags & DETECT_CONTENT_RELATIVE_NEXT || + data->flags & DETECT_CONTENT_NEGATED ); + + FAIL_IF_NOT(strncmp((char *)data->content, "one", 3) == 0); + FAIL_IF_NOT(sm->next == NULL); + + /* first content:\"one\"; */ + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; + FAIL_IF(sm->type != DETECT_CONTENT); + data = (DetectContentData *)sm->ctx; + FAIL_IF(data->flags & DETECT_CONTENT_RAWBYTES); + FAIL_IF(data->flags & DETECT_CONTENT_NOCASE); + FAIL_IF(data->flags & DETECT_CONTENT_WITHIN); + FAIL_IF(data->flags & DETECT_CONTENT_DISTANCE); + FAIL_IF(data->flags & DETECT_CONTENT_FAST_PATTERN); + FAIL_IF(data->flags & DETECT_CONTENT_RELATIVE_NEXT); + FAIL_IF(data->flags & DETECT_CONTENT_NEGATED ); + FAIL_IF_NOT(strncmp((char *)data->content, "one", 3) == 0); + + FAIL_IF_NULL(sm->next); + sm = sm->next; - result &= (sm->next == NULL); + FAIL_IF(sm->type != DETECT_CONTENT); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm->type != DETECT_CONTENT) { - result = 0; - goto end; - } data = (DetectContentData *)sm->ctx; - if (data->flags & DETECT_CONTENT_RAWBYTES || - data->flags & DETECT_CONTENT_NOCASE || - data->flags & DETECT_CONTENT_WITHIN || - data->flags & DETECT_CONTENT_DISTANCE || - data->flags & DETECT_CONTENT_FAST_PATTERN || - data->flags & DETECT_CONTENT_RELATIVE_NEXT || - data->flags & DETECT_CONTENT_NEGATED ) { - printf("three failed\n"); - result = 0; - goto end; - } - result &= (strncmp((char *)data->content, "one", 3) == 0); - if (result == 0) - goto end; + FAIL_IF(data->flags & DETECT_CONTENT_RAWBYTES || + data->flags & DETECT_CONTENT_NOCASE || + data->flags & DETECT_CONTENT_WITHIN || + data->flags & DETECT_CONTENT_DISTANCE || + data->flags & DETECT_CONTENT_FAST_PATTERN || + data->flags & DETECT_CONTENT_NEGATED ); - sm = sm->next; - if (sm->type != DETECT_CONTENT) { - result = 0; - goto end; - } - data = (DetectContentData *)sm->ctx; - if (data->flags & DETECT_CONTENT_RAWBYTES || - data->flags & DETECT_CONTENT_NOCASE || - data->flags & DETECT_CONTENT_WITHIN || - data->flags & DETECT_CONTENT_DISTANCE || - data->flags & DETECT_CONTENT_FAST_PATTERN || - data->flags & DETECT_CONTENT_NEGATED ) { - printf("two failed\n"); - result = 0; - goto end; - } - result &= (strncmp((char *)data->content, "two", 3) == 0); - if (result == 0) - goto end; + FAIL_IF_NOT(strncmp((char *)data->content, "two", 3) == 0); - result &= (sm->next == NULL); + FAIL_IF_NOT(sm->next == NULL); - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** * \test Test content for dce sig. */ -int DcePayloadParseTest45(void) +static int DcePayloadParseTest45(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -9937,16 +3506,16 @@ int DcePayloadParseTest45(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTEJUMP) { result = 0; goto end; @@ -9966,7 +3535,7 @@ int DcePayloadParseTest45(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -10021,7 +3590,7 @@ int DcePayloadParseTest45(void) /** * \test Test content for dce sig. */ -int DcePayloadParseTest46(void) +static int DcePayloadParseTest46(void) { DetectEngineCtx *de_ctx = NULL; int result = 1; @@ -10049,16 +3618,16 @@ int DcePayloadParseTest46(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->init_data->smlists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL) { result = 0; goto end; } - sm = s->sm_lists[DETECT_SM_LIST_DMATCH]; + sm = s->init_data->smlists[g_dce_stub_data_buffer_id]; if (sm->type != DETECT_BYTETEST) { result = 0; goto end; @@ -10076,7 +3645,7 @@ int DcePayloadParseTest46(void) result &= (sm->next == NULL); - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; if (sm->type != DETECT_CONTENT) { result = 0; goto end; @@ -10132,60 +3701,43 @@ int DcePayloadParseTest46(void) void DcePayloadRegisterTests(void) { + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); #ifdef UNITTESTS - UtRegisterTest("DcePayloadTest01", DcePayloadTest01, 1); - UtRegisterTest("DcePayloadTest02", DcePayloadTest02, 1); - UtRegisterTest("DcePayloadTest03", DcePayloadTest03, 1); - UtRegisterTest("DcePayloadTest04", DcePayloadTest04, 1); - UtRegisterTest("DcePayloadTest05", DcePayloadTest05, 1); - UtRegisterTest("DcePayloadTest06", DcePayloadTest06, 1); - UtRegisterTest("DcePayloadTest07", DcePayloadTest07, 1); - UtRegisterTest("DcePayloadTest08", DcePayloadTest08, 1); - UtRegisterTest("DcePayloadTest09", DcePayloadTest09, 1); - UtRegisterTest("DcePayloadTest10", DcePayloadTest10, 1); - UtRegisterTest("DcePayloadTest11", DcePayloadTest11, 1); - UtRegisterTest("DcePayloadTest12", DcePayloadTest12, 1); - /* Disabled because of bug_753. Would be enabled, once we rewrite - * dce parser */ -#if 0 - UtRegisterTest("DcePayloadTest13", DcePayloadTest13, 1); - UtRegisterTest("DcePayloadTest14", DcePayloadTest14, 1); -#endif - UtRegisterTest("DcePayloadTest15", DcePayloadTest15, 1); - UtRegisterTest("DcePayloadTest16", DcePayloadTest16, 1); - UtRegisterTest("DcePayloadTest17", DcePayloadTest17, 1); - UtRegisterTest("DcePayloadTest18", DcePayloadTest18, 1); - UtRegisterTest("DcePayloadTest19", DcePayloadTest19, 1); - UtRegisterTest("DcePayloadTest20", DcePayloadTest20, 1); - UtRegisterTest("DcePayloadTest21", DcePayloadTest21, 1); - UtRegisterTest("DcePayloadTest22", DcePayloadTest22, 1); - UtRegisterTest("DcePayloadTest23", DcePayloadTest23, 1); - - UtRegisterTest("DcePayloadParseTest25", DcePayloadParseTest25, 1); - UtRegisterTest("DcePayloadParseTest26", DcePayloadParseTest26, 1); - UtRegisterTest("DcePayloadParseTest27", DcePayloadParseTest27, 1); - UtRegisterTest("DcePayloadParseTest28", DcePayloadParseTest28, 1); - UtRegisterTest("DcePayloadParseTest29", DcePayloadParseTest29, 1); - UtRegisterTest("DcePayloadParseTest30", DcePayloadParseTest30, 1); - UtRegisterTest("DcePayloadParseTest31", DcePayloadParseTest31, 1); - UtRegisterTest("DcePayloadParseTest32", DcePayloadParseTest32, 1); - UtRegisterTest("DcePayloadParseTest33", DcePayloadParseTest33, 1); - UtRegisterTest("DcePayloadParseTest34", DcePayloadParseTest34, 1); - UtRegisterTest("DcePayloadParseTest35", DcePayloadParseTest35, 1); - UtRegisterTest("DcePayloadParseTest36", DcePayloadParseTest36, 1); - UtRegisterTest("DcePayloadParseTest37", DcePayloadParseTest37, 1); - UtRegisterTest("DcePayloadParseTest38", DcePayloadParseTest38, 1); - UtRegisterTest("DcePayloadParseTest39", DcePayloadParseTest39, 1); - UtRegisterTest("DcePayloadParseTest40", DcePayloadParseTest40, 1); - UtRegisterTest("DcePayloadParseTest41", DcePayloadParseTest41, 1); - - UtRegisterTest("DcePayloadTest42", DcePayloadTest42, 1); - UtRegisterTest("DcePayloadTest43", DcePayloadTest43, 1); - - UtRegisterTest("DcePayloadParseTest44", DcePayloadParseTest44, 1); - UtRegisterTest("DcePayloadParseTest45", DcePayloadParseTest45, 1); - UtRegisterTest("DcePayloadParseTest46", DcePayloadParseTest46, 1); + UtRegisterTest("DcePayloadTest15", DcePayloadTest15); + UtRegisterTest("DcePayloadTest16", DcePayloadTest16); + UtRegisterTest("DcePayloadTest17", DcePayloadTest17); + UtRegisterTest("DcePayloadTest18", DcePayloadTest18); + UtRegisterTest("DcePayloadTest19", DcePayloadTest19); + UtRegisterTest("DcePayloadTest20", DcePayloadTest20); + UtRegisterTest("DcePayloadTest21", DcePayloadTest21); + UtRegisterTest("DcePayloadTest22", DcePayloadTest22); + UtRegisterTest("DcePayloadTest23", DcePayloadTest23); + + UtRegisterTest("DcePayloadParseTest25", DcePayloadParseTest25); + UtRegisterTest("DcePayloadParseTest26", DcePayloadParseTest26); + UtRegisterTest("DcePayloadParseTest27", DcePayloadParseTest27); + UtRegisterTest("DcePayloadParseTest28", DcePayloadParseTest28); + UtRegisterTest("DcePayloadParseTest29", DcePayloadParseTest29); + UtRegisterTest("DcePayloadParseTest30", DcePayloadParseTest30); + UtRegisterTest("DcePayloadParseTest31", DcePayloadParseTest31); + UtRegisterTest("DcePayloadParseTest32", DcePayloadParseTest32); + UtRegisterTest("DcePayloadParseTest33", DcePayloadParseTest33); + UtRegisterTest("DcePayloadParseTest34", DcePayloadParseTest34); + UtRegisterTest("DcePayloadParseTest35", DcePayloadParseTest35); + UtRegisterTest("DcePayloadParseTest36", DcePayloadParseTest36); + UtRegisterTest("DcePayloadParseTest37", DcePayloadParseTest37); + UtRegisterTest("DcePayloadParseTest38", DcePayloadParseTest38); + UtRegisterTest("DcePayloadParseTest39", DcePayloadParseTest39); + UtRegisterTest("DcePayloadParseTest40", DcePayloadParseTest40); + UtRegisterTest("DcePayloadParseTest41", DcePayloadParseTest41); + + UtRegisterTest("DcePayloadTest42", DcePayloadTest42); + UtRegisterTest("DcePayloadTest43", DcePayloadTest43); + + UtRegisterTest("DcePayloadParseTest44", DcePayloadParseTest44); + UtRegisterTest("DcePayloadParseTest45", DcePayloadParseTest45); + UtRegisterTest("DcePayloadParseTest46", DcePayloadParseTest46); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-dcepayload.h b/src/detect-engine-dcepayload.h index ccc4794ba303..d67a3cffe093 100644 --- a/src/detect-engine-dcepayload.h +++ b/src/detect-engine-dcepayload.h @@ -24,8 +24,8 @@ #ifndef __DETECT_ENGINE_DCEPAYLOAD_H__ #define __DETECT_ENGINE_DCEPAYLOAD_H__ -int DetectEngineInspectDcePayload(DetectEngineCtx *, DetectEngineThreadCtx *, - Signature *, Flow *, uint8_t, void *); +//int DetectEngineInspectDcePayload(DetectEngineCtx *, DetectEngineThreadCtx *, +// const Signature *, Flow *, uint8_t, void *); void DcePayloadRegisterTests(void); diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c index 946f7412fea9..314b095685c1 100644 --- a/src/detect-engine-dns.c +++ b/src/detect-engine-dns.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Open Information Security Foundation +/* Copyright (C) 2013-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -31,6 +31,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -44,6 +45,7 @@ #include "util-unittest.h" #include "util-unittest-helper.h" +#include "util-validate.h" /** \brief Do the content inspection & validation for a signature * @@ -59,10 +61,10 @@ * \retval 1 match */ int DetectEngineInspectDnsQueryName(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) { DNSTransaction *tx = (DNSTransaction *)txv; DNSQueryEntry *query = NULL; @@ -84,11 +86,72 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv, //PrintRawDataFp(stdout, buffer, buffer_len); r = DetectEngineContentInspection(de_ctx, det_ctx, - s, s->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH], + s, smd, f, buffer, buffer_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) break; } return r; } + +/** \brief DNS Query Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + DNSTransaction *tx = (DNSTransaction *)txv; + DNSQueryEntry *query = NULL; + + TAILQ_FOREACH(query, &tx->query_list, next) { + SCLogDebug("tx %p query %p", tx, query); + + const uint8_t *buffer = + (const uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); + const uint32_t buffer_len = query->len; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, + buffer, buffer_len); + } + } +} + +int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxDnsQuery, + ALPROTO_DNS, 1, + mpm_ctx, NULL, "dns_query"); +} + +int DetectEngineInspectDnsRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} + +int DetectEngineInspectDnsResponse(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h index 419f0fed0339..ed7ef51df730 100644 --- a/src/detect-engine-dns.h +++ b/src/detect-engine-dns.h @@ -23,8 +23,19 @@ #ifndef __DETECT_ENGINE_DNS_H__ #define __DETECT_ENGINE_DNS_H__ -int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *, Signature *, - Flow *, uint8_t, void *, void *, uint64_t); +int PrefilterTxDnsQueryRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + +int DetectEngineInspectDnsQueryName(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatchData *smd, + Flow *, uint8_t, void *, void *, uint64_t); +int DetectEngineInspectDnsRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +int DetectEngineInspectDnsResponse(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); #endif /* __DETECT_ENGINE_DNS_H__ */ diff --git a/src/detect-engine-enip.c b/src/detect-engine-enip.c new file mode 100644 index 000000000000..8d873196172c --- /dev/null +++ b/src/detect-engine-enip.c @@ -0,0 +1,378 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Kevin Wong + * + * Based on detect-engine-modbus.c + */ + +#include "suricata-common.h" + +#include "app-layer.h" + +#include "detect.h" +#include "detect-cipservice.h" +#include "detect-engine-enip.h" + +#include "flow.h" + +#include "util-debug.h" + +#if 0 +/** + * \brief Print fields from ENIP Packet + * @param enip_data + */ +void PrintENIPAL(ENIPTransaction *enip_data) +{ + SCLogDebug("============================================"); + SCLogDebug("ENCAP HEADER cmd 0x%x, length %d, session 0x%x, status 0x%x", + enip_data->header.command, enip_data->header.length, + enip_data->header.session, enip_data->header.status); + //SCLogDebug("context 0x%x option 0x%x", enip_data->header.context, enip_data->header.option); + SCLogDebug("ENCAP DATA HEADER handle 0x%x, timeout %d, count %d", + enip_data->encap_data_header.interface_handle, + enip_data->encap_data_header.timeout, + enip_data->encap_data_header.item_count); + SCLogDebug("ENCAP ADDR ITEM type 0x%x, length %d", + enip_data->encap_addr_item.type, enip_data->encap_addr_item.length); + SCLogDebug("ENCAP DATA ITEM type 0x%x, length %d sequence 0x%x", + enip_data->encap_data_item.type, enip_data->encap_data_item.length, + enip_data->encap_data_item.sequence_count); + + CIPServiceEntry *svc = NULL; + + int count = 0; + TAILQ_FOREACH(svc, &enip_data->service_list, next) + { + //SCLogDebug("CIP Service #%d : 0x%x", count, svc->service); + count++; + } +} +#endif + +/** + * \brief Matches the rule to the CIP segment in ENIP Packet + * @param svc - the CIP service entry + * * @param cipserviced - the CIP service rule + */ +int CIPPathMatch(CIPServiceEntry *svc, DetectCipServiceData *cipserviced) +{ + uint16_t class = 0; + uint16_t attrib = 0; + int found_class = 0; + + SegmentEntry *seg = NULL; + TAILQ_FOREACH(seg, &svc->segment_list, next) + { + switch(seg->segment) + { + case PATH_CLASS_8BIT: + class = seg->value; + if (cipserviced->cipclass == class) + { + if (cipserviced->tokens == 2) + {// if rule only has class + return 1; + } else + { + found_class = 1; + } + } + break; + case PATH_INSTANCE_8BIT: + break; + case PATH_ATTR_8BIT: //single attribute + attrib = seg->value; + if ((cipserviced->tokens == 3) && + (cipserviced->cipclass == class) && + (cipserviced->cipattribute == attrib) && + (cipserviced->matchattribute == 1)) + { // if rule has class & attribute, matched all here + return 1; + } + if ((cipserviced->tokens == 3) && + (cipserviced->cipclass == class) && + (cipserviced->matchattribute == 0)) + { // for negation rule on attribute + return 1; + } + break; + case PATH_CLASS_16BIT: + class = seg->value; + if (cipserviced->cipclass == class) + { + if (cipserviced->tokens == 2) + {// if rule only has class + return 1; + } else + { + found_class = 1; + } + } + break; + case PATH_INSTANCE_16BIT: + break; + default: + return 0; + } + } + + if (found_class == 0) + { // if haven't matched class yet, no need to check attribute + return 0; + } + + if ((svc->service == CIP_SET_ATTR_LIST) || + (svc->service == CIP_GET_ATTR_LIST)) + { + AttributeEntry *attr = NULL; + TAILQ_FOREACH (attr, &svc->attrib_list, next) + { + if (cipserviced->cipattribute == attr->attribute) + { + return 1; + } + } + } + + return 0; +} + +/** + * \brief Matches the rule to the ENIP Transaction + * @param enip_data - the ENIP transation + * * @param cipserviced - the CIP service rule + */ + +int CIPServiceMatch(ENIPTransaction *enip_data, + DetectCipServiceData *cipserviced) +{ + int count = 1; + CIPServiceEntry *svc = NULL; + //SCLogDebug("CIPServiceMatchAL"); + TAILQ_FOREACH(svc, &enip_data->service_list, next) + { + SCLogDebug("CIPServiceMatchAL service #%d : 0x%x dir %d", + count, svc->service, svc->direction); + + if (cipserviced->cipservice == svc->service) + { // compare service + //SCLogDebug("Rule Match for cip service %d",cipserviced->cipservice ); + + if (cipserviced->tokens > 1) + { //if rule params have class and attribute + + + if ((svc->service == CIP_SET_ATTR_LIST) || (svc->service + == CIP_SET_ATTR_SINGLE) || (svc->service + == CIP_GET_ATTR_LIST) || (svc->service + == CIP_GET_ATTR_SINGLE)) + { //decode path + if (CIPPathMatch(svc, cipserviced) == 1) + { + if (svc->direction == 1) return 0; //don't match responses + + return 1; + } + } + } else + { + if (svc->direction == 1) return 0; //don't match responses + + // SCLogDebug("CIPServiceMatchAL found"); + return 1; + } + } + count++; + } + return 0; +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect ( and sm: SigMatch to inspect) + * \param f Flow + * \param flags App layer flags + * \param alstate App layer state + * \param txv Pointer to ENIP Transaction structure + * + * \retval 0 no match or 1 match + */ +int DetectEngineInspectCIP(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + + + ENIPTransaction *tx = (ENIPTransaction *) txv; + DetectCipServiceData *cipserviced = (DetectCipServiceData *) smd->ctx; + + if (cipserviced == NULL) + { + SCLogDebug("no cipservice state, no match"); + SCReturnInt(0); + } + //SCLogDebug("DetectEngineInspectCIP %d", cipserviced->cipservice); + + if (CIPServiceMatch(tx, cipserviced) == 1) + { + //SCLogDebug("DetectCIPServiceMatchAL found"); + SCReturnInt(1); + } + + SCReturnInt(0); +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect ( and sm: SigMatch to inspect) + * \param f Flow + * \param flags App layer flags + * \param alstate App layer state + * \param txv Pointer to ENIP Transaction structure + * + * \retval 0 no match or 1 match + */ + +int DetectEngineInspectENIP(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + SCEnter(); + + ENIPTransaction *tx = (ENIPTransaction *) txv; + DetectEnipCommandData *enipcmdd = (DetectEnipCommandData *) smd->ctx; + + if (enipcmdd == NULL) + { + SCLogDebug("no enipcommand state, no match"); + SCReturnInt(0); + } + + //SCLogDebug("DetectEngineInspectENIP %d, %d", enipcmdd->enipcommand, tx->header.command); + + if (enipcmdd->enipcommand == tx->header.command) + { + // SCLogDebug("DetectENIPCommandMatchAL found!"); + SCReturnInt(1); + } + + SCReturnInt(0); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "app-layer-parser.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "flow-util.h" +#include "stream-tcp.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static uint8_t listIdentity[] = {/* List ID */ 0x00, 0x63, + /* Length */ 0x00, 0x00, + /* Session */ 0x00, 0x00, 0x00, 0x00, + /* Status */ 0x00, 0x00, 0x00, 0x00, + /* Delay*/ 0x00, + /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00,}; + +/** \test Test code function. */ +static int DetectEngineInspectENIPTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(listIdentity, sizeof(listIdentity), IPPROTO_TCP); + FAIL_IF_NULL(p); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_ENIP; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + s = de_ctx->sig_list = SigInit(de_ctx, "alert enip any any -> any any " + "(msg:\"Testing enip command\"; " + "enipcommand:99 ; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER, + listIdentity, sizeof(listIdentity)); + FAIL_IF(r != 0); + + ENIPState *enip_state = f.alstate; + FAIL_IF_NULL(enip_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF(!(PacketAlertCheck(p, 1))); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + PASS; +} + +#endif /* UNITTESTS */ + +void DetectEngineInspectENIPRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectEngineInspectENIPTest01", DetectEngineInspectENIPTest01); +#endif /* UNITTESTS */ + return; +} diff --git a/src/detect-engine-enip.h b/src/detect-engine-enip.h new file mode 100644 index 000000000000..23864201d2f1 --- /dev/null +++ b/src/detect-engine-enip.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Kevin Wong + */ + +#ifndef __DETECT_ENGINE_ENIP_H__ +#define __DETECT_ENGINE_ENIP_H__ + +int DetectEngineInspectCIP(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatchData *smd, + Flow *, uint8_t, void *, void *, uint64_t); + +int DetectEngineInspectENIP(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatchData *smd, + Flow *, uint8_t, void *, void *, uint64_t); + +void DetectEngineInspectENIPRegisterTests(void); +#endif /* __DETECT_ENGINE_ENIP_H__ */ diff --git a/src/detect-engine-event.c b/src/detect-engine-event.c index d0badb5eceb5..06fcfe1086d9 100644 --- a/src/detect-engine-event.c +++ b/src/detect-engine-event.c @@ -38,17 +38,17 @@ /* Need to get the DEvents[] array */ -#define DETECT_EVENTS #include "detect-engine-event.h" #include "util-unittest.h" -#define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+]+$" +#define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+.]+$" static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectEngineEventMatch (ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectEngineEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectDecodeEventSetup (DetectEngineCtx *, Signature *, char *); static int DetectStreamEventSetup (DetectEngineCtx *, Signature *, char *); @@ -78,28 +78,7 @@ void DetectEngineEventRegister (void) sigmatch_table[DETECT_STREAM_EVENT].Setup = DetectStreamEventSetup; sigmatch_table[DETECT_STREAM_EVENT].Free = DetectEngineEventFree; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s\n", eb); - goto error; - } - return; - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -114,11 +93,12 @@ void DetectEngineEventRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectEngineEventMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); - DetectEngineEventData *de = (DetectEngineEventData *)m->ctx; + const DetectEngineEventData *de = (const DetectEngineEventData *)ctx; if (ENGINE_ISSET_EVENT(p, de->event)) { SCLogDebug("de->event matched %u", de->event); @@ -151,16 +131,17 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) goto error; } - const char *str_ptr; - res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, &str_ptr); + char copy_str[128] = ""; + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } for (i = 0; DEvents[i].event_name != NULL; i++) { - if (strcasecmp(DEvents[i].event_name,str_ptr) == 0) { + if (strcasecmp(DEvents[i].event_name,copy_str) == 0) { found = 1; break; } @@ -168,7 +149,7 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) if (found == 0) { SCLogError(SC_ERR_UNKNOWN_DECODE_EVENT, "unknown decode event \"%s\"", - str_ptr); + copy_str); goto error; } @@ -184,7 +165,8 @@ DetectEngineEventData *DetectEngineEventParse (char *rawstr) return de; error: - if (de) SCFree(de); + if (de) + SCFree(de); return NULL; } @@ -214,7 +196,7 @@ static int _DetectEngineEventSetup (DetectEngineCtx *de_ctx, Signature *s, char goto error; sm->type = smtype; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); return 0; @@ -250,7 +232,12 @@ static void DetectEngineEventFree(void *ptr) */ static int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { - return _DetectEngineEventSetup(de_ctx, s, rawstr, DETECT_DECODE_EVENT); + char drawstr[MAX_SUBSTRINGS * 2] = "decoder."; + + /* decoder:$EVENT alias command develop as decode-event:decoder.$EVENT */ + strlcat(drawstr, rawstr, 2 * MAX_SUBSTRINGS - strlen("decoder.") - 1); + + return _DetectEngineEventSetup(de_ctx, s, drawstr, DETECT_DECODE_EVENT); } /** @@ -277,7 +264,7 @@ static int DetectStreamEventSetup (DetectEngineCtx *de_ctx, Signature *s, char * int EngineEventTestParse01 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("ipv4.pkt_too_small"); + de = DetectEngineEventParse("decoder.ipv4.pkt_too_small"); if (de) { DetectEngineEventFree(de); return 1; @@ -293,7 +280,7 @@ int EngineEventTestParse01 (void) int EngineEventTestParse02 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("PPP.pkt_too_small"); + de = DetectEngineEventParse("decoder.PPP.pkt_too_small"); if (de) { DetectEngineEventFree(de); return 1; @@ -308,7 +295,7 @@ int EngineEventTestParse02 (void) int EngineEventTestParse03 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("IPV6.PKT_TOO_SMALL"); + de = DetectEngineEventParse("decoder.IPV6.PKT_TOO_SMALL"); if (de) { DetectEngineEventFree(de); return 1; @@ -323,13 +310,13 @@ int EngineEventTestParse03 (void) int EngineEventTestParse04 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("IPV6.INVALID_EVENT"); + de = DetectEngineEventParse("decoder.IPV6.INVALID_EVENT"); if (de) { DetectEngineEventFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -338,13 +325,13 @@ int EngineEventTestParse04 (void) int EngineEventTestParse05 (void) { DetectEngineEventData *de = NULL; - de = DetectEngineEventParse("IPV-6,INVALID_CHAR"); + de = DetectEngineEventParse("decoder.IPV-6,INVALID_CHAR"); if (de) { DetectEngineEventFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -366,7 +353,7 @@ int EngineEventTestParse06 (void) ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); - de = DetectEngineEventParse("ppp.pkt_too_small"); + de = DetectEngineEventParse("decoder.ppp.pkt_too_small"); if (de == NULL) goto error; @@ -377,9 +364,9 @@ int EngineEventTestParse06 (void) goto error; sm->type = DETECT_DECODE_EVENT; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectEngineEventMatch(&tv,NULL,p,NULL,sm); + ret = DetectEngineEventMatch(&tv,NULL,p,NULL,sm->ctx); if(ret) { SCFree(p); @@ -400,11 +387,11 @@ int EngineEventTestParse06 (void) void EngineEventRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01, 1); - UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02, 1); - UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03, 1); - UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04, 0); - UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05, 0); - UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06, 1); + UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01); + UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02); + UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03); + UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04); + UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05); + UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-event.h b/src/detect-engine-event.h index 1057399cc1e2..3f52753bc546 100644 --- a/src/detect-engine-event.h +++ b/src/detect-engine-event.h @@ -33,214 +33,5 @@ typedef struct DetectEngineEventData_ { /* prototypes */ void DetectEngineEventRegister (void); -/* supported decoder events */ - -#ifdef DETECT_EVENTS -struct DetectEngineEvents_ { - char *event_name; - uint8_t code; -} DEvents[] = { - /* IPV4 EVENTS */ - { "ipv4.pkt_too_small", IPV4_PKT_TOO_SMALL, }, - { "ipv4.hlen_too_small", IPV4_HLEN_TOO_SMALL, }, - { "ipv4.iplen_smaller_than_hlen", IPV4_IPLEN_SMALLER_THAN_HLEN, }, - { "ipv4.trunc_pkt", IPV4_TRUNC_PKT, }, - - /* IPV4 OPTIONS */ - { "ipv4.opt_invalid", IPV4_OPT_INVALID, }, - { "ipv4.opt_invalid_len", IPV4_OPT_INVALID_LEN, }, - { "ipv4.opt_malformed", IPV4_OPT_MALFORMED, }, - { "ipv4.opt_pad_required", IPV4_OPT_PAD_REQUIRED, }, - { "ipv4.opt_eol_required", IPV4_OPT_EOL_REQUIRED, }, - { "ipv4.opt_duplicate", IPV4_OPT_DUPLICATE, }, - { "ipv4.opt_unknown", IPV4_OPT_UNKNOWN, }, - { "ipv4.wrong_ip_version", IPV4_WRONG_IP_VER, }, - { "ipv4.icmpv6", IPV4_WITH_ICMPV6, }, - - /* ICMP EVENTS */ - { "icmpv4.pkt_too_small", ICMPV4_PKT_TOO_SMALL, }, - { "icmpv4.unknown_type", ICMPV4_UNKNOWN_TYPE, }, - { "icmpv4.unknown_code", ICMPV4_UNKNOWN_CODE, }, - { "icmpv4.ipv4_trunc_pkt", ICMPV4_IPV4_TRUNC_PKT, }, - { "icmpv4.ipv4_unknown_ver", ICMPV4_IPV4_UNKNOWN_VER, }, - - /* ICMPv6 EVENTS */ - { "icmpv6.unknown_type", ICMPV6_UNKNOWN_TYPE,}, - { "icmpv6.unknown_code", ICMPV6_UNKNOWN_CODE,}, - { "icmpv6.pkt_too_small", ICMPV6_PKT_TOO_SMALL,}, - { "icmpv6.ipv6_unknown_version", ICMPV6_IPV6_UNKNOWN_VER,}, - { "icmpv6.ipv6_trunc_pkt", ICMPV6_IPV6_TRUNC_PKT,}, - - /* IPV6 EVENTS */ - { "ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, - { "ipv6.trunc_pkt", IPV6_TRUNC_PKT, }, - { "ipv6.trunc_exthdr", IPV6_TRUNC_EXTHDR, }, - { "ipv6.exthdr_dupl_fh", IPV6_EXTHDR_DUPL_FH, }, - { "ipv6.exthdr_useless_fh", IPV6_EXTHDR_USELESS_FH, }, - { "ipv6.exthdr_dupl_rh", IPV6_EXTHDR_DUPL_RH, }, - { "ipv6.exthdr_dupl_hh", IPV6_EXTHDR_DUPL_HH, }, - { "ipv6.exthdr_dupl_dh", IPV6_EXTHDR_DUPL_DH, }, - { "ipv6.exthdr_dupl_ah", IPV6_EXTHDR_DUPL_AH, }, - { "ipv6.exthdr_dupl_eh", IPV6_EXTHDR_DUPL_EH, }, - { "ipv6.exthdr_invalid_optlen", IPV6_EXTHDR_INVALID_OPTLEN, }, - { "ipv6.wrong_ip_version", IPV6_WRONG_IP_VER, }, - { "ipv6.exthdr_ah_res_not_null", IPV6_EXTHDR_AH_RES_NOT_NULL, }, - { "ipv6.hopopts_unknown_opt", IPV6_HOPOPTS_UNKNOWN_OPT, }, - { "ipv6.hopopts_only_padding", IPV6_HOPOPTS_ONLY_PADDING, }, - { "ipv6.dstopts_unknown_opt", IPV6_DSTOPTS_UNKNOWN_OPT, }, - { "ipv6.dstopts_only_padding", IPV6_DSTOPTS_ONLY_PADDING, }, - { "ipv6.rh_type_0", IPV6_EXTHDR_RH_TYPE_0, }, - { "ipv6.zero_len_padn", IPV6_EXTHDR_ZERO_LEN_PADN, }, - { "ipv6.fh_non_zero_reserved_field", IPV6_FH_NON_ZERO_RES_FIELD, }, - { "ipv6.data_after_none_header", IPV6_DATA_AFTER_NONE_HEADER, }, - { "ipv6.unknown_next_header", IPV6_UNKNOWN_NEXT_HEADER, }, - { "ipv6.icmpv4", IPV6_WITH_ICMPV4, }, - - /* TCP EVENTS */ - { "tcp.pkt_too_small", TCP_PKT_TOO_SMALL, }, - { "tcp.hlen_too_small", TCP_HLEN_TOO_SMALL, }, - { "tcp.invalid_optlen", TCP_INVALID_OPTLEN, }, - - /* TCP OPTIONS */ - { "tcp.opt_invalid_len", TCP_OPT_INVALID_LEN, }, - { "tcp.opt_duplicate", TCP_OPT_DUPLICATE, }, - - /* UDP EVENTS */ - { "udp.pkt_too_small", UDP_PKT_TOO_SMALL, }, - { "udp.hlen_too_small", UDP_HLEN_TOO_SMALL, }, - { "udp.hlen_invalid", UDP_HLEN_INVALID, }, - - /* SLL EVENTS */ - { "sll.pkt_too_small", SLL_PKT_TOO_SMALL, }, - - /* ETHERNET EVENTS */ - { "ethernet.pkt_too_small", ETHERNET_PKT_TOO_SMALL, }, - - /* PPP EVENTS */ - { "ppp.pkt_too_small", PPP_PKT_TOO_SMALL, }, - { "ppp.vju_pkt_too_small", PPPVJU_PKT_TOO_SMALL, }, - { "ppp.ip4_pkt_too_small", PPPIPV4_PKT_TOO_SMALL, }, - { "ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, }, - { "ppp.wrong_type", PPP_WRONG_TYPE, }, /** unknown & invalid protocol */ - { "ppp.unsup_proto", PPP_UNSUP_PROTO, }, /** unsupported but valid protocol */ - - /* PPPOE EVENTS */ - { "pppoe.pkt_too_small", PPPOE_PKT_TOO_SMALL, }, - { "pppoe.wrong_code", PPPOE_WRONG_CODE, }, - { "pppoe.malformed_tags", PPPOE_MALFORMED_TAGS, }, - - /* GRE EVENTS */ - { "gre.pkt_too_small", GRE_PKT_TOO_SMALL, }, - { "gre.wrong_version", GRE_WRONG_VERSION, }, - { "gre.version0_recur", GRE_VERSION0_RECUR, }, - { "gre.version0_flags", GRE_VERSION0_FLAGS, }, - { "gre.version0_hdr_too_big", GRE_VERSION0_HDR_TOO_BIG, }, - { "gre.version0_malformed_sre_hdr", GRE_VERSION0_MALFORMED_SRE_HDR, }, - { "gre.version1_chksum", GRE_VERSION1_CHKSUM, }, - { "gre.version1_route", GRE_VERSION1_ROUTE, }, - { "gre.version1_ssr", GRE_VERSION1_SSR, }, - { "gre.version1_recur", GRE_VERSION1_RECUR, }, - { "gre.version1_flags", GRE_VERSION1_FLAGS, }, - { "gre.version1_no_key", GRE_VERSION1_NO_KEY, }, - { "gre.version1_wrong_protocol", GRE_VERSION1_WRONG_PROTOCOL, }, - { "gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, }, - { "gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, }, - - /* VLAN EVENTS */ - { "vlan.header_too_small",VLAN_HEADER_TOO_SMALL, }, - { "vlan.unknown_type",VLAN_UNKNOWN_TYPE, }, - { "vlan.too_many_layers", VLAN_HEADER_TOO_MANY_LAYERS, }, - - /* RAW EVENTS */ - { "ipraw.invalid_ip_version",IPRAW_INVALID_IPV, }, - - /* STREAM EVENTS */ - { "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, }, - { "stream.3whs_async_wrong_seq", STREAM_3WHS_ASYNC_WRONG_SEQ, }, - { "stream.3whs_right_seq_wrong_ack_evasion", STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION, }, - { "stream.3whs_synack_in_wrong_direction", STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION, }, - { "stream.3whs_synack_resend_with_different_ack", STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, - { "stream.3whs_synack_resend_with_diff_seq", STREAM_3WHS_SYNACK_RESEND_WITH_DIFF_SEQ, }, - { "stream.3whs_synack_toserver_on_syn_recv", STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV, }, - { "stream.3whs_synack_with_wrong_ack", STREAM_3WHS_SYNACK_WITH_WRONG_ACK, }, - { "stream.3whs_synack_flood", STREAM_3WHS_SYNACK_FLOOD, }, - { "stream.3whs_syn_resend_diff_seq_on_syn_recv", STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV, }, - { "stream.3whs_syn_toclient_on_syn_recv", STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV, }, - { "stream.3whs_wrong_seq_wrong_ack", STREAM_3WHS_WRONG_SEQ_WRONG_ACK, }, - { "stream.4whs_synack_with_wrong_ack", STREAM_4WHS_SYNACK_WITH_WRONG_ACK, }, - { "stream.4whs_synack_with_wrong_syn", STREAM_4WHS_SYNACK_WITH_WRONG_SYN, }, - { "stream.4whs_wrong_seq", STREAM_4WHS_WRONG_SEQ, }, - { "stream.4whs_invalid_ack", STREAM_4WHS_INVALID_ACK, }, - { "stream.closewait_ack_out_of_window", STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW, }, - { "stream.closewait_fin_out_of_window", STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW, }, - { "stream.closewait_pkt_before_last_ack", STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK, }, - { "stream.closewait_invalid_ack", STREAM_CLOSEWAIT_INVALID_ACK, }, - { "stream.closing_ack_wrong_seq", STREAM_CLOSING_ACK_WRONG_SEQ, }, - { "stream.closing_invalid_ack", STREAM_CLOSING_INVALID_ACK, }, - { "stream.est_packet_out_of_window", STREAM_EST_PACKET_OUT_OF_WINDOW, }, - { "stream.est_pkt_before_last_ack", STREAM_EST_PKT_BEFORE_LAST_ACK, }, - { "stream.est_synack_resend", STREAM_EST_SYNACK_RESEND, }, - { "stream.est_synack_resend_with_different_ack", STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK, }, - { "stream.est_synack_resend_with_diff_seq", STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ, }, - { "stream.est_synack_toserver", STREAM_EST_SYNACK_TOSERVER, }, - { "stream.est_syn_resend", STREAM_EST_SYN_RESEND, }, - { "stream.est_syn_resend_diff_seq", STREAM_EST_SYN_RESEND_DIFF_SEQ, }, - { "stream.est_syn_toclient", STREAM_EST_SYN_TOCLIENT, }, - { "stream.est_invalid_ack", STREAM_EST_INVALID_ACK, }, - { "stream.fin_invalid_ack", STREAM_FIN_INVALID_ACK, }, - { "stream.fin1_ack_wrong_seq", STREAM_FIN1_ACK_WRONG_SEQ, }, - { "stream.fin1_fin_wrong_seq", STREAM_FIN1_FIN_WRONG_SEQ, }, - { "stream.fin1_invalid_ack", STREAM_FIN1_INVALID_ACK, }, - { "stream.fin2_ack_wrong_seq", STREAM_FIN2_ACK_WRONG_SEQ, }, - { "stream.fin2_fin_wrong_seq", STREAM_FIN2_FIN_WRONG_SEQ, }, - { "stream.fin2_invalid_ack", STREAM_FIN2_INVALID_ACK, }, - { "stream.fin_but_no_session", STREAM_FIN_BUT_NO_SESSION, }, - { "stream.fin_out_of_window", STREAM_FIN_OUT_OF_WINDOW, }, - { "stream.lastack_ack_wrong_seq", STREAM_LASTACK_ACK_WRONG_SEQ, }, - { "stream.lastack_invalid_ack", STREAM_LASTACK_INVALID_ACK, }, - { "stream.rst_but_no_session", STREAM_RST_BUT_NO_SESSION, }, - { "stream.timewait_ack_wrong_seq", STREAM_TIMEWAIT_ACK_WRONG_SEQ, }, - { "stream.timewait_invalid_ack", STREAM_TIMEWAIT_INVALID_ACK, }, - { "stream.pkt_invalid_timestamp", STREAM_PKT_INVALID_TIMESTAMP, }, - { "stream.pkt_invalid_ack", STREAM_PKT_INVALID_ACK, }, - { "stream.pkt_broken_ack", STREAM_PKT_BROKEN_ACK, }, - { "stream.rst_invalid_ack", STREAM_RST_INVALID_ACK, }, - { "stream.shutdown_syn_resend", STREAM_SHUTDOWN_SYN_RESEND, }, - { "stream.pkt_retransmission", STREAM_PKT_RETRANSMISSION, }, - { "stream.reassembly_segment_before_base_seq", STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ, }, - { "stream.reassembly_no_segment", STREAM_REASSEMBLY_NO_SEGMENT, }, - { "stream.reassembly_seq_gap", STREAM_REASSEMBLY_SEQ_GAP, }, - { "stream.reassembly_overlap_different_data", STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA, }, - { "stream.pkt_bad_window_update", STREAM_PKT_BAD_WINDOW_UPDATE, }, - - /* SCTP EVENTS */ - { "sctp.pkt_too_small", SCTP_PKT_TOO_SMALL, }, - - /* Fragmentation reasembly events. */ - { "ipv4.frag_too_large", IPV4_FRAG_PKT_TOO_LARGE, }, - { "ipv6.frag_too_large", IPV6_FRAG_PKT_TOO_LARGE, }, - { "ipv4.frag_overlap", IPV4_FRAG_OVERLAP, }, - { "ipv6.frag_overlap", IPV6_FRAG_OVERLAP, }, - /* Fragment ignored due to internal error */ - { "ipv4.frag_ignored", IPV4_FRAG_IGNORED, }, - { "ipv6.frag_ignored", IPV6_FRAG_IGNORED, }, - - /* IPv4 in IPv6 events */ - { "ipv6.ipv4_in_ipv6_too_small", IPV4_IN_IPV6_PKT_TOO_SMALL, }, - { "ipv6.ipv4_in_ipv6_wrong_version", IPV4_IN_IPV6_WRONG_IP_VER, }, - /* IPv6 in IPv6 events */ - { "ipv6.ipv6_in_ipv6_too_small", IPV6_IN_IPV6_PKT_TOO_SMALL, }, - { "ipv6.ipv6_in_ipv6_wrong_version", IPV6_IN_IPV6_WRONG_IP_VER, }, - - /* MPLS events */ - { "mpls.bad_label_router_alert", MPLS_BAD_LABEL_ROUTER_ALERT, }, - { "mpls.bad_label_implicit_null", MPLS_BAD_LABEL_IMPLICIT_NULL, }, - { "mpls.bad_label_reserved", MPLS_BAD_LABEL_RESERVED, }, - { "mpls.unknown_payload_type", MPLS_UNKNOWN_PAYLOAD_TYPE, }, - - { NULL, 0 }, -}; -#endif /* DETECT_EVENTS */ - #endif /*__DETECT_ENGINE_EVENT_H__ */ diff --git a/src/detect-engine-file.c b/src/detect-engine-file.c index ca502c9b758c..771a4c2983bf 100644 --- a/src/detect-engine-file.c +++ b/src/detect-engine-file.c @@ -34,7 +34,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" @@ -51,6 +50,7 @@ #include "app-layer-smb.h" #include "app-layer-dcerpc-common.h" #include "app-layer-dcerpc.h" +#include "app-layer-smtp.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -73,14 +73,13 @@ * \note flow is not locked at this time */ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Flow *f, Signature *s, uint8_t flags, FileContainer *ffc) + Flow *f, Signature *s, const SigMatchData *smd, + uint8_t flags, FileContainer *ffc) { - SigMatch *sm = NULL; int r = 0; int match = 0; int store_r = 0; - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_FILEMATCH); SCLogDebug("file inspection... %p", ffc); if (ffc != NULL) { @@ -105,63 +104,79 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if ((s->file_flags & FILE_SIG_NEED_FILENAME) && file->name == NULL) { SCLogDebug("sig needs filename, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } - if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file->chunks_head == NULL) { + uint64_t file_size = FileDataSize(file); + if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file_size == 0) { SCLogDebug("sig needs file content, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } - if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file->chunks_head == NULL) { + if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file_size == 0) { SCLogDebug("sig needs file content, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } if ((s->file_flags & FILE_SIG_NEED_MD5) && (!(file->flags & FILE_MD5))) { SCLogDebug("sig needs file md5, but we don't have any"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + break; + } + + if ((s->file_flags & FILE_SIG_NEED_SHA1) && (!(file->flags & FILE_SHA1))) { + SCLogDebug("sig needs file sha1, but we don't have any"); + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + break; + } + + if ((s->file_flags & FILE_SIG_NEED_SHA256) && (!(file->flags & FILE_SHA256))) { + SCLogDebug("sig needs file sha256, but we don't have any"); + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) { SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED"); - r = 0; + r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; break; } /* run the file match functions. */ - for (sm = s->sm_lists[DETECT_SM_LIST_FILEMATCH]; sm != NULL; sm = sm->next) { - SCLogDebug("sm %p, sm->next %p", sm, sm->next); + while (1) { + SCLogDebug("smd %p", smd); - if (sigmatch_table[sm->type].FileMatch != NULL) { + if (sigmatch_table[smd->type].FileMatch != NULL) { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - FileMatch(tv, det_ctx, f, flags, file, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + match = sigmatch_table[smd->type]. + FileMatch(tv, det_ctx, f, flags, file, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); if (match == 0) { - r = 2; + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; break; - } else if (sm->next == NULL) { - r = 1; + } else if (smd->is_last) { + r = DETECT_ENGINE_INSPECT_SIG_MATCH; break; } } + if (smd->is_last) + break; + smd++; } /* continue inspection for other files as we may want to store * those as well. We'll return 1 (match) regardless of their * results though */ - if (r == 1) - store_r = 1; + if (r == DETECT_ENGINE_INSPECT_SIG_MATCH) + store_r = DETECT_ENGINE_INSPECT_SIG_MATCH; /* if this is a filestore sig, and the sig can't match * return 3 so we can distinguish */ - if ((s->flags & SIG_FLAG_FILESTORE) && r == 2) - r = 3; + if ((s->flags & SIG_FLAG_FILESTORE) && r == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; /* continue, this file may (or may not) be unable to match * maybe we have more that can :) */ @@ -169,26 +184,30 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } else { /* if we have a filestore sm with a scope > file (so tx, ssn) we * run it here */ - sm = s->sm_lists[DETECT_SM_LIST_FILEMATCH]; - if (sm != NULL && sm->next == NULL && sm->type == DETECT_FILESTORE && - sm->ctx != NULL) + if (smd != NULL && smd->is_last && smd->type == DETECT_FILESTORE && + smd->ctx != NULL) { - DetectFilestoreData *fd = sm->ctx; + DetectFilestoreData *fd = (DetectFilestoreData *)smd->ctx; if (fd->scope > FILESTORE_SCOPE_DEFAULT) { KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + match = sigmatch_table[smd->type]. + FileMatch(tv, det_ctx, f, flags, /* no file */NULL, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0)); if (match == 1) { - r = 1; + r = DETECT_ENGINE_INSPECT_SIG_MATCH; } } } } - if (store_r == 1) - r = 1; + if (r == DETECT_ENGINE_INSPECT_SIG_NO_MATCH && store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) { + SCLogDebug("stored MATCH, current file NOMATCH"); + SCReturnInt(DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES); + } + + if (store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) + r = DETECT_ENGINE_INSPECT_SIG_MATCH; SCReturnInt(r); } @@ -210,9 +229,9 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, * \note flow should be locked when this function's called. */ int DetectFileInspectHttp(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { int r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; FileContainer *ffc; @@ -223,20 +242,72 @@ int DetectFileInspectHttp(ThreadVars *tv, else ffc = htp_state->files_ts; - int match = DetectFileInspect(tv, det_ctx, f, s, flags, ffc); - if (match == 1) { + int match = DetectFileInspect(tv, det_ctx, f, s, smd, flags, ffc); + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { r = DETECT_ENGINE_INSPECT_SIG_MATCH; - } else if (match == 2) { - if (r != 1) { - SCLogDebug("sid %u can't match on this transaction", s->id); - r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - } else if (match == 3) { - if (r != 1) { - SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); - r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; - } + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + SCLogDebug("sid %u can't match on this transaction", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; } return r; } + +/** + * \brief Inspect the file inspecting keywords against the SMTP transactions. + * + * \param tv thread vars + * \param det_ctx detection engine thread ctx + * \param f flow + * \param s signature to inspect + * \param alstate state + * \param flags direction flag + * + * \retval 0 no match + * \retval 1 match + * \retval 2 can't match + * \retval 3 can't match filestore signature + * + * \note flow is not locked at this time + */ +int DetectFileInspectSmtp(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + SCEnter(); + int r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + SMTPState *smtp_state = NULL; + FileContainer *ffc; + + smtp_state = (SMTPState *)alstate; + if (smtp_state == NULL) { + SCLogDebug("no SMTP state"); + goto end; + } + + if (flags & STREAM_TOSERVER) + ffc = smtp_state->files_ts; + else + goto end; + + int match = DetectFileInspect(tv, det_ctx, f, s, smd, flags, ffc); + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { + r = DETECT_ENGINE_INSPECT_SIG_MATCH; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + SCLogDebug("sid %u can't match on this transaction", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + SCLogDebug("sid %u can't match on this transaction (filestore sig)", s->id); + r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE; + } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { + SCLogDebug("match with more files ahead"); + r = match; + } + +end: + SCReturnInt(r); +} diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index 91e2f21ebf1d..180b2edd293e 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -25,7 +25,13 @@ #define __DETECT_ENGINE_FILE_H__ int DetectFileInspectHttp(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + +int DetectFileInspectSmtp(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + #endif /* __DETECT_ENGINE_FILE_H__ */ diff --git a/src/detect-engine-filedata-smtp.c b/src/detect-engine-filedata-smtp.c new file mode 100644 index 000000000000..60f24d62e922 --- /dev/null +++ b/src/detect-engine-filedata-smtp.c @@ -0,0 +1,561 @@ +/* Copyright (C) 2015-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +/** \file + * + * \author Giuseppe Longo + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "stream-tcp.h" + +#include "app-layer-parser.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer.h" +#include "app-layer-smtp.h" +#include "app-layer-protos.h" + +#include "util-validate.h" + +#include "conf.h" +#include "conf-yaml-loader.h" + +#define BUFFER_STEP 50 + +static inline int SMTPCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +{ + void *ptmp; + if (size > det_ctx->smtp_buffers_size) { + ptmp = SCRealloc(det_ctx->smtp, + (det_ctx->smtp_buffers_size + BUFFER_STEP) * sizeof(FiledataReassembledBody)); + if (ptmp == NULL) { + SCFree(det_ctx->smtp); + det_ctx->smtp = NULL; + det_ctx->smtp_buffers_size = 0; + det_ctx->smtp_buffers_list_len = 0; + return -1; + } + det_ctx->smtp = ptmp; + + memset(det_ctx->smtp + det_ctx->smtp_buffers_size, 0, BUFFER_STEP * sizeof(FiledataReassembledBody)); + det_ctx->smtp_buffers_size += BUFFER_STEP; + } + for (int i = det_ctx->smtp_buffers_list_len; i < (size); i++) { + det_ctx->smtp[i].buffer_len = 0; + det_ctx->smtp[i].offset = 0; + } + + return 0; +} + +static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Flow *f, File *curr_file, + uint8_t flags, + uint32_t *buffer_len, + uint32_t *stream_start_offset) +{ + SCEnter(); + int index = 0; + const uint8_t *buffer = NULL; + *buffer_len = 0; + *stream_start_offset = 0; + uint64_t file_size = FileDataSize(curr_file); + + if (det_ctx->smtp_buffers_list_len == 0) { + if (SMTPCreateSpace(det_ctx, 1) < 0) + goto end; + index = 0; + + if (det_ctx->smtp_buffers_list_len == 0) { + det_ctx->smtp_start_tx_id = tx_id; + } + det_ctx->smtp_buffers_list_len++; + } else { + if ((tx_id - det_ctx->smtp_start_tx_id) < det_ctx->smtp_buffers_list_len) { + if (det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len != 0) { + *buffer_len = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len; + *stream_start_offset = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].offset; + buffer = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer; + + SCReturnPtr(buffer, "uint8_t"); + } + } else { + if (SMTPCreateSpace(det_ctx, (tx_id - det_ctx->smtp_start_tx_id) + 1) < 0) + goto end; + + if (det_ctx->smtp_buffers_list_len == 0) { + det_ctx->smtp_start_tx_id = tx_id; + } + det_ctx->smtp_buffers_list_len++; + } + index = (tx_id - det_ctx->smtp_start_tx_id); + } + + SCLogDebug("smtp_config.content_limit %u, smtp_config.content_inspect_min_size %u", + smtp_config.content_limit, smtp_config.content_inspect_min_size); + + SCLogDebug("file %p size %"PRIu64", state %d", curr_file, file_size, curr_file->state); + + /* no new data */ + if (curr_file->content_inspected == file_size) { + SCLogDebug("no new data"); + goto end; + } + + if (file_size == 0) { + SCLogDebug("no data to inspect for this transaction"); + goto end; + } + + if ((smtp_config.content_limit == 0 || file_size < smtp_config.content_limit) && + file_size < smtp_config.content_inspect_min_size && + !(flags & STREAM_EOF) && !(curr_file->state > FILE_STATE_OPENED)) { + SCLogDebug("we still haven't seen the entire content. " + "Let's defer content inspection till we see the " + "entire content."); + goto end; + } + + StreamingBufferGetDataAtOffset(curr_file->sb, + &det_ctx->smtp[index].buffer, &det_ctx->smtp[index].buffer_len, + curr_file->content_inspected); + + det_ctx->smtp[index].offset = curr_file->content_inspected; + + /* updat inspected tracker */ + curr_file->content_inspected = FileDataSize(curr_file); + + SCLogDebug("content_inspected %u, offset %u", (uint)curr_file->content_inspected, (uint)det_ctx->smtp[index].offset); + + buffer = det_ctx->smtp[index].buffer; + *buffer_len = det_ctx->smtp[index].buffer_len; + *stream_start_offset = det_ctx->smtp[index].offset; + +end: + SCLogDebug("buffer %p, len %u", buffer, *buffer_len); + SCReturnPtr(buffer, "uint8_t"); +} + +int DetectEngineInspectSMTPFiledata(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + SMTPState *smtp_state = (SMTPState *)alstate; + FileContainer *ffc = smtp_state->files_ts; + int r = 0; + int match = 0; + uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; + const uint8_t *buffer = 0; + + if (ffc != NULL) { + File *file = ffc->head; + for (; file != NULL; file = file->next) { + buffer = DetectEngineSMTPGetBufferForTX(tx_id, + de_ctx, det_ctx, + f, file, + flags, + &buffer_len, + &stream_start_offset); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + match = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + (uint8_t *)buffer, + buffer_len, + stream_start_offset, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (match == 1) + r = 1; + } + } + +end: + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->smtp_buffers_list_len > 0) { + for (int i = 0; i < det_ctx->smtp_buffers_list_len; i++) { + det_ctx->smtp[i].buffer_len = 0; + det_ctx->smtp[i].offset = 0; + } + } + det_ctx->smtp_buffers_list_len = 0; + det_ctx->smtp_start_tx_id = 0; + + return; +} + +/** \brief SMTP Filedata Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + * + * \todo check files against actual tx + */ +static void PrefilterTxSmtpFiledata(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SMTPState *smtp_state = f->alstate; + FileContainer *ffc = smtp_state->files_ts; + if (ffc != NULL) { + File *file = ffc->head; + for (; file != NULL; file = file->next) { + uint32_t buffer_len = 0; + uint32_t stream_start_offset = 0; + + const uint8_t *buffer = DetectEngineSMTPGetBufferForTX(idx, + NULL, det_ctx, + f, file, + flags, + &buffer_len, + &stream_start_offset); + if (buffer != NULL && buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } + } + } +} + +int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxSmtpFiledata, + ALPROTO_SMTP, 0, + mpm_ctx, NULL, "file_data (smtp)"); +} + +#ifdef UNITTESTS + +static int DetectEngineSMTPFiledataTest01(void) +{ + uint8_t mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, + 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, + 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, + 0x20, 0x74, 0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, + 0x61, 0x69, 0x6E, 0x3B, 0x20, 0x63, 0x68, 0x61, + 0x72, 0x73, 0x65, 0x74, 0x3D, 0x55, 0x54, 0x46, + 0x2D, 0x38, 0x3B, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, + 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, + 0x6E, 0x73, 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, + 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, + 0x37, 0x62, 0x69, 0x74, 0x0D, 0x0A, 0x43, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69, + 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D, + 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x74, 0x78, + 0x74, 0x22, 0x0D, 0x0A, 0x0D, 0x0A, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65,}; + uint32_t mimemsg_len = sizeof(mimemsg) - 1; + TcpSession ssn; + Packet *p; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + SMTPState *smtp_state = NULL; + Flow f; + int result = 0; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alstate = SMTPStateAlloc(); + + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + + if (SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) + goto end; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST|PKT_STREAM_EOF; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert smtp any any -> any any " + "(msg:\"file_data smtp test\"; " + "file_data; content:\"message\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + mimemsg, + mimemsg_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %d", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have\n"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +static int DetectEngineSMTPFiledataTest02(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert smtp any any -> any any " + "(msg:\"file_data smtp test\"; " + "file_data; content:\"message\"; sid:1;)"); + if (s == NULL) + goto end; + + if (s->flags & SIG_FLAG_TOSERVER) + result = 1; + else if (s->flags & SIG_FLAG_TOCLIENT) + printf("s->flags & SIG_FLAG_TOCLIENT"); + +end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; + +} + +static int DetectEngineSMTPFiledataTest03(void) +{ + uint8_t mimemsg1[] = {0x65, 0x76,}; + uint8_t mimemsg2[] = {0x69, 0x6C,}; + uint32_t mimemsg1_len = sizeof(mimemsg1) - 1; + uint32_t mimemsg2_len = sizeof(mimemsg2) - 1; + TcpSession ssn; + Packet *p; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + SMTPState *smtp_state = NULL; + Flow f; + int result = 1; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alstate = SMTPStateAlloc(); + + MimeDecParseState *state = MimeDecInitParser(&f, NULL); + ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT; + state->body_begin = 1; + + if (SMTPProcessDataChunk((uint8_t *)mimemsg1, sizeof(mimemsg1), state) != 0) + goto end; + + if (SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) + goto end; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_SMTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert smtp any any -> any any " + "(msg:\"file_data smtp test\"; " + "file_data; content:\"evil\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = 0; + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, mimemsg1, mimemsg1_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %d", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP, + STREAM_TOSERVER, mimemsg2, mimemsg2_len); + if (r != 0) { + printf("AppLayerParse for smtp failed. Returned %d", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + smtp_state = f.alstate; + if (smtp_state == NULL) { + printf("no smtp state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 0; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result == 0; +} + +#endif /* UNITTESTS */ + +void DetectEngineSMTPFiledataRegisterTests(void) +{ + #ifdef UNITTESTS + UtRegisterTest("DetectEngineSMTPFiledataTest01", + DetectEngineSMTPFiledataTest01); + UtRegisterTest("DetectEngineSMTPFiledataTest02", + DetectEngineSMTPFiledataTest02); + UtRegisterTest("DetectEngineSMTPFiledataTest03", + DetectEngineSMTPFiledataTest03); + #endif /* UNITTESTS */ + + return; +} diff --git a/src/detect-engine-filedata-smtp.h b/src/detect-engine-filedata-smtp.h new file mode 100644 index 000000000000..a6f3fc4fa88d --- /dev/null +++ b/src/detect-engine-filedata-smtp.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Giuseppe Longo + */ + +#ifndef __DETECT_ENGINE_FILEDATA_SMTP_H__ +#define __DETECT_ENGINE_FILEDATA_SMTP_H__ + +#include "app-layer-smtp.h" + +int PrefilterTxSmtpFiledataRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + +int DetectEngineInspectSMTPFiledata(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + +void DetectEngineCleanSMTPBuffers(DetectEngineThreadCtx *det_ctx); + +void DetectEngineSMTPFiledataRegisterTests(void); + +#endif /* __DETECT_ENGINE_FILEDATA_SMTP_H__ */ diff --git a/src/detect-engine-hcbd.c b/src/detect-engine-hcbd.c index fccafada5f1d..eb00951bfc9a 100644 --- a/src/detect-engine-hcbd.c +++ b/src/detect-engine-hcbd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP request body match corresponding to http_client_body * keyword. @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -60,10 +62,15 @@ #include "conf.h" #include "conf-yaml-loader.h" +#include "util-validate.h" + #define BUFFER_STEP 50 -static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { + if (size >= (USHRT_MAX - BUFFER_STEP)) + return -1; + void *ptmp; if (size > det_ctx->hcbd_buffers_size) { ptmp = SCRealloc(det_ctx->hcbd, @@ -80,7 +87,8 @@ static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) memset(det_ctx->hcbd + det_ctx->hcbd_buffers_size, 0, BUFFER_STEP * sizeof(HttpReassembledBody)); det_ctx->hcbd_buffers_size += BUFFER_STEP; - for (int i = det_ctx->hcbd_buffers_list_len; i < (size); i++) { + uint16_t i; + for (i = det_ctx->hcbd_buffers_list_len; i < ((uint16_t)size); i++) { det_ctx->hcbd[i].buffer_len = 0; det_ctx->hcbd[i].offset = 0; } @@ -91,7 +99,7 @@ static inline int HCBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) /** */ -static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, +static const uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, @@ -100,19 +108,22 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint32_t *stream_start_offset) { int index = 0; - uint8_t *buffer = NULL; + const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; if (det_ctx->hcbd_buffers_list_len == 0) { - if (HCBDCreateSpace(det_ctx, 1) < 0) - goto end; /* let's consider it as stage not done for now */ - index = 0; - - if (det_ctx->hcbd_buffers_list_len == 0) { - det_ctx->hcbd_start_tx_id = tx_id; - } - det_ctx->hcbd_buffers_list_len++; + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint64_t txs = (tx_id - base_inspect_id) + 1; + if (HCBDCreateSpace(det_ctx, txs) < 0) + goto end; + + index = (tx_id - base_inspect_id); + det_ctx->hcbd_start_tx_id = base_inspect_id; + det_ctx->hcbd_buffers_list_len = txs; } else { if ((tx_id - det_ctx->hcbd_start_tx_id) < det_ctx->hcbd_buffers_list_len) { if (det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer_len != 0) { @@ -121,13 +132,11 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return det_ctx->hcbd[(tx_id - det_ctx->hcbd_start_tx_id)].buffer; } } else { - if (HCBDCreateSpace(det_ctx, (tx_id - det_ctx->hcbd_start_tx_id) + 1) < 0) + uint64_t txs = (tx_id - det_ctx->hcbd_start_tx_id) + 1; + if (HCBDCreateSpace(det_ctx, txs) < 0) goto end; /* let's consider it as stage not done for now */ - if (det_ctx->hcbd_buffers_list_len == 0) { - det_ctx->hcbd_start_tx_id = tx_id; - } - det_ctx->hcbd_buffers_list_len++; + det_ctx->hcbd_buffers_list_len = txs; } index = (tx_id - det_ctx->hcbd_start_tx_id); } @@ -150,103 +159,112 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, goto end; } - /* inspect the body if the transfer is complete or we have hit - * our body size limit */ - if ((htp_state->cfg->request_body_limit == 0 || - htud->request_body.content_len_so_far < htp_state->cfg->request_body_limit) && - htud->request_body.content_len_so_far < htp_state->cfg->request_inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_BODY) && - !(flags & STREAM_EOF)) { - SCLogDebug("we still haven't seen the entire request body. " - "Let's defer body inspection till we see the " - "entire body."); - goto end; - } - - int first = 1; - while (cur != NULL) { - /* see if we can filter out chunks */ - if (htud->request_body.body_inspected > 0) { - if (cur->stream_offset < htud->request_body.body_inspected) { - if ((htud->request_body.body_inspected - cur->stream_offset) > htp_state->cfg->request_inspect_min_size) { - cur = cur->next; - continue; - } else { - /* include this one */ - } - } else { - /* include this one */ - } - } - - if (first) { - det_ctx->hcbd[index].offset = cur->stream_offset; - first = 0; + if (!htp_state->cfg->http_body_inline) { + /* inspect the body if the transfer is complete or we have hit + * our body size limit */ + if ((htp_state->cfg->request.body_limit == 0 || + htud->request_body.content_len_so_far < htp_state->cfg->request.body_limit) && + htud->request_body.content_len_so_far < htp_state->cfg->request.inspect_min_size && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) && + !(flags & STREAM_EOF)) { + SCLogDebug("we still haven't seen the entire request body. " + "Let's defer body inspection till we see the " + "entire body."); + goto end; } + } - /* see if we need to grow the buffer */ - if (det_ctx->hcbd[index].buffer == NULL || (det_ctx->hcbd[index].buffer_len + cur->len) > det_ctx->hcbd[index].buffer_size) { - void *ptmp; - det_ctx->hcbd[index].buffer_size += cur->len * 2; - - if ((ptmp = SCRealloc(det_ctx->hcbd[index].buffer, det_ctx->hcbd[index].buffer_size)) == NULL) { - SCFree(det_ctx->hcbd[index].buffer); - det_ctx->hcbd[index].buffer = NULL; - det_ctx->hcbd[index].buffer_size = 0; - det_ctx->hcbd[index].buffer_len = 0; - goto end; - } - det_ctx->hcbd[index].buffer = ptmp; + /* get the inspect buffer + * + * make sure that we have at least the configured inspect_win size. + * If we have more, take at least 1/4 of the inspect win size before + * the new data. + */ + uint64_t offset = 0; + if (htud->request_body.body_inspected > htp_state->cfg->request.inspect_min_size) { + BUG_ON(htud->request_body.content_len_so_far < htud->request_body.body_inspected); + uint64_t inspect_win = htud->request_body.content_len_so_far - htud->request_body.body_inspected; + SCLogDebug("inspect_win %u", (uint)inspect_win); + if (inspect_win < htp_state->cfg->request.inspect_window) { + uint64_t inspect_short = htp_state->cfg->request.inspect_window - inspect_win; + if (htud->request_body.body_inspected < inspect_short) + offset = 0; + else + offset = htud->request_body.body_inspected - inspect_short; + } else { + offset = htud->request_body.body_inspected - (htp_state->cfg->request.inspect_window / 4); } - memcpy(det_ctx->hcbd[index].buffer + det_ctx->hcbd[index].buffer_len, cur->data, cur->len); - det_ctx->hcbd[index].buffer_len += cur->len; - - cur = cur->next; } - /* update inspected tracker */ - htud->request_body.body_inspected = htud->request_body.last->stream_offset + htud->request_body.last->len; + StreamingBufferGetDataAtOffset(htud->request_body.sb, + &det_ctx->hcbd[index].buffer, &det_ctx->hcbd[index].buffer_len, + offset); + det_ctx->hcbd[index].offset = offset; + + /* move inspected tracker to end of the data. HtpBodyPrune will consider + * the window sizes when freeing data */ + htud->request_body.body_inspected = htud->request_body.content_len_so_far; buffer = det_ctx->hcbd[index].buffer; *buffer_len = det_ctx->hcbd[index].buffer_len; *stream_start_offset = det_ctx->hcbd[index].offset; + + SCLogDebug("buffer_len %u (%u)", *buffer_len, (uint)htud->request_body.content_len_so_far); end: return buffer; } -int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx) +/** \brief HTTP Client Body Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestBody(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, idx, - de_ctx, det_ctx, + const uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); - if (buffer_len == 0) - goto end; - cnt = HttpClientBodyPatternSearch(det_ctx, buffer, buffer_len, flags); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); - end: - return cnt; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestBody, + ALPROTO_HTTP, HTP_REQUEST_BODY, + mpm_ctx, NULL, "http_client_body"); } int DetectEngineInspectHttpClientBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, tx_id, + const uint8_t *buffer = DetectEngineHCBDGetBufferForTX(tx, tx_id, de_ctx, det_ctx, f, htp_state, flags, @@ -258,18 +276,18 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCBDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, - buffer, + (uint8_t *)buffer, buffer_len, stream_start_offset, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCBD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_BODY) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -293,52 +311,35 @@ void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *det_ctx) #ifdef UNITTESTS -static int DetectEngineHttpClientBodyTest01(void) +struct TestSteps { + const uint8_t *input; + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + int expect; +}; + +static int RunTest (struct TestSteps *steps, const char *sig, const char *yaml) { TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; + Flow f; + Packet *p = NULL; ThreadVars th_v; DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.1\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); memset(&ssn, 0, sizeof(ssn)); - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; + if (yaml) { + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; + ConfYamlLoadString(yaml, strlen(yaml)); + HTPConfigure(); + } StreamTcpInitConfig(TRUE); @@ -346,64 +347,64 @@ static int DetectEngineHttpClientBodyTest01(void) if (de_ctx == NULL) goto end; + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alproto = ALPROTO_HTTP; + + SCLogDebug("sig %s", sig); + DetectEngineAppendSig(de_ctx, (char *)sig); + de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1This\"; http_client_body; " - "sid:1;)"); if (de_ctx->sig_list == NULL) goto end; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if ((PacketAlertCheck(p1, 1))) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } + struct TestSteps *b = steps; + int i = 0; + while (b->input != NULL) { + SCLogDebug("chunk %p %d", b, i); + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + if (p == NULL) + goto end; + p->flow = &f; + p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + b->direction, (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); + if (r != 0) { + printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + int match = PacketAlertCheck(p, 1); + if (b->expect != match) { + printf("rule matching mismatch: "); + goto end; + } - if (!(PacketAlertCheck(p2, 1))) { - printf("sid 1 didn't match but should have"); - goto end; + UTHFreePackets(&p, 1); + p = NULL; + b++; + i++; } - result = 1; -end: + end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -415,3300 +416,575 @@ static int DetectEngineHttpClientBodyTest01(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); + UTHFreePackets(&p, 1); + + if (yaml) { + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + } return result; } -static int DetectEngineHttpClientBodyTest02(void) +static int DetectEngineHttpClientBodyTest01(void) { - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 19\r\n" - "\r\n" - "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1This\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; +static int DetectEngineHttpClientBodyTest02(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - StreamTcpInitConfig(TRUE); +static int DetectEngineHttpClientBodyTest03(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; offset:16; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; +static int DetectEngineHttpClientBodyTest04(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; offset:16; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->flags |= DE_QUIET; +static int DetectEngineHttpClientBodyTest05(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; depth:25; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; offset:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; +static int DetectEngineHttpClientBodyTest06(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:25; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); +static int DetectEngineHttpClientBodyTest07(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:!\"body1\"; http_client_body; depth:15; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); +static int DetectEngineHttpClientBodyTest08(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"This is dummy body1This is dummy message body2\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } +static int DetectEngineHttpClientBodyTest09(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"This\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); +static int DetectEngineHttpClientBodyTest10(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"boom\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match but should have\n"); - goto end; - } +static int DetectEngineHttpClientBodyTest11(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"boom\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - result = 1; +static int DetectEngineHttpClientBodyTest12(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"This\"; http_client_body; within:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); +static int DetectEngineHttpClientBodyTest13(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; +static int DetectEngineHttpClientBodyTest14(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:10; sid:1;)"; + return RunTest(steps, sig, NULL); } -static int DetectEngineHttpClientBodyTest03(void) +static int DetectEngineHttpClientBodyTest15(void) { - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"dummy\"; http_client_body; distance:10; sid:1;)"; + return RunTest(steps, sig, NULL); +} - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); +static int DetectEngineHttpClientBodyTest16(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:!\"dummy\"; http_client_body; distance:5; sid:1;)"; + return RunTest(steps, sig, NULL); +} - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); +static int DetectEngineHttpClientBodyTest17(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; +static int DetectEngineHttpClientBodyTest18(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"body1\"; http_client_body; content:\"bambu\"; http_client_body; fast_pattern; sid:1;)"; + return RunTest(steps, sig, NULL); +} - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; +static int DetectEngineHttpClientBodyTest19(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bambu\"; http_client_body; content:\"is\"; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - StreamTcpInitConfig(TRUE); +static int DetectEngineHttpClientBodyTest20(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 19\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"is\"; http_client_body; fast_pattern; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; +static int DetectEngineHttpClientBodyTest21(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; http_client_body; within:7; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->flags |= DE_QUIET; +static int DetectEngineHttpClientBodyTest22(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; within:7; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; offset:16; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; +static int DetectEngineHttpClientBodyTest23(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:3; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); +static int DetectEngineHttpClientBodyTest24(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:!\"dummy\"; distance:13; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); +static int DetectEngineHttpClientBodyTest25(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:15; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } +static int DetectEngineHttpClientBodyTest26(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; within:10; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); +static int DetectEngineHttpClientBodyTest27(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:8; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } +static int DetectEngineHttpClientBodyTest28(void) +{ + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (pcre:/body1/P; content:\"dummy\"; distance:14; http_client_body; sid:1;)"; + return RunTest(steps, sig, NULL); +} - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; +static int DetectEngineHttpClientBodyTest29(void) +{ + const char *request_buffer = "GET /one HTTP/1.0\r\n" + "Host: localhost\r\n\r\n"; +#define TOTAL_REQUESTS 45 + uint8_t *http_buf = SCMalloc(TOTAL_REQUESTS * strlen(request_buffer)); + if (unlikely(http_buf == NULL)) + return 0; + for (int i = 0; i < TOTAL_REQUESTS; i++) { + memcpy(http_buf + i * strlen(request_buffer), request_buffer, + strlen(request_buffer)); } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); +#undef TOTAL_REQUESTS - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } + struct TestSteps steps[] = { + { (const uint8_t *)http_buf, + (size_t)http_buf_len, STREAM_TOSERVER, 0 }, - result = 1; + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "dummy", + 0, STREAM_TOCLIENT, 0 }, -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + { NULL, 0, 0, 0 }, + }; - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); + const char *sig = "alert http any any -> any any (content:\"dummyone\"; fast_pattern:0,3; http_server_body; sid:1;)"; + int result = RunTest(steps, sig, NULL); + SCFree(http_buf); return result; } -static int DetectEngineHttpClientBodyTest04(void) +static int DetectEngineHttpClientBodyTest30(void) { - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; offset:16; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest05(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; depth:25; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest06(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; depth:25; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest07(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; depth:15; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest08(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:!\"body1\"; http_client_body; depth:25; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest09(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"This\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest10(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"boom\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest11(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"boom\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest12(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"This\"; http_client_body; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest13(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"dummy\"; http_client_body; distance:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest14(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"dummy\"; http_client_body; distance:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest15(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"dummy\"; http_client_body; distance:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest16(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:!\"dummy\"; http_client_body; distance:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest17(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"bambu\"; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest18(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"body1\"; http_client_body; " - "content:\"bambu\"; http_client_body; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 0) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest19(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bambu\"; http_client_body; " - "content:\"is\"; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 0) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest20(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This is dummy body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bambu\"; http_client_body; " - "content:\"is\"; http_client_body; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpClientBodyPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest21(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; http_client_body; within:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest22(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; within:7; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest23(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; distance:3; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest24(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:!\"dummy\"; distance:13; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest25(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; within:15; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest26(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; within:10; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest27(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; distance:8; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest28(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "This is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/P; " - "content:\"dummy\"; distance:14; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest29(void) -{ - int result = 0; - Packet *p = NULL; - TcpSession ssn; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - void *alp_tctx = NULL; - const char *request_buffer = "GET /one HTTP/1.0\r\n" - "Host: localhost\r\n" - "\r\n"; - -#define TOTAL_REQUESTS 45 - uint8_t *http_buf = SCMalloc(TOTAL_REQUESTS * strlen(request_buffer)); - if (unlikely(http_buf == NULL)) - goto end; - for (int i = 0; i < TOTAL_REQUESTS; i++) { - memcpy(http_buf + i * strlen(request_buffer), request_buffer, - strlen(request_buffer)); - } - uint32_t http_buf_len = TOTAL_REQUESTS * strlen(request_buffer); - alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"dummyone\"; fast_pattern:0,3; http_server_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - uint8_t response_buf[] = "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 5\r\n" - "\r\n" - "dummy"; - uint32_t response_buf_len = strlen((char *)response_buf); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, - response_buf, response_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOCLIENT; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -static int DetectEngineHttpClientBodyTest30(void) -{ - char input[] = "\ + const char yaml[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ @@ -3723,144 +999,26 @@ libhtp:\n\ request-body-minimal-inspect-size: 0\n\ response-body-minimal-inspect-size: 0\n\ "; - - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "bags is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bags\"; within:4; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HtpConfigRestoreBackup(); - ConfRestoreContextBackup(); - - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bags\"; within:4; http_client_body; sid:1;)"; + return RunTest(steps, sig, yaml); } static int DetectEngineHttpClientBodyTest31(void) { - char input[] = "\ + const char yaml[] = "\ %YAML 1.1\n\ ---\n\ libhtp:\n\ @@ -3876,138 +1034,21 @@ libhtp:\n\ response-body-minimal-inspect-size: 0\n\ "; - ConfCreateContextBackup(); - ConfInit(); - HtpConfigCreateBackup(); - - ConfYamlLoadString(input, strlen(input)); - HTPConfigure(); - - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 46\r\n" - "\r\n" - "This is dummy body1"; - uint8_t http2_buf[] = - "bags is dummy message body2"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "content:\"bags\"; depth:4; http_client_body; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - HtpConfigRestoreBackup(); - ConfRestoreContextBackup(); - - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.1\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 46\r\n" + "\r\n" + "This is dummy body1", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"This is dummy message body2", + 0, STREAM_TOSERVER, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (content:\"bags\"; depth:4; http_client_body; sid:1;)"; + return RunTest(steps, sig, yaml); } #endif /* UNITTESTS */ @@ -4017,68 +1058,68 @@ void DetectEngineHttpClientBodyRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpClientBodyTest01", - DetectEngineHttpClientBodyTest01, 1); + DetectEngineHttpClientBodyTest01); UtRegisterTest("DetectEngineHttpClientBodyTest02", - DetectEngineHttpClientBodyTest02, 1); + DetectEngineHttpClientBodyTest02); UtRegisterTest("DetectEngineHttpClientBodyTest03", - DetectEngineHttpClientBodyTest03, 1); + DetectEngineHttpClientBodyTest03); UtRegisterTest("DetectEngineHttpClientBodyTest04", - DetectEngineHttpClientBodyTest04, 1); + DetectEngineHttpClientBodyTest04); UtRegisterTest("DetectEngineHttpClientBodyTest05", - DetectEngineHttpClientBodyTest05, 1); + DetectEngineHttpClientBodyTest05); UtRegisterTest("DetectEngineHttpClientBodyTest06", - DetectEngineHttpClientBodyTest06, 1); + DetectEngineHttpClientBodyTest06); UtRegisterTest("DetectEngineHttpClientBodyTest07", - DetectEngineHttpClientBodyTest07, 1); + DetectEngineHttpClientBodyTest07); UtRegisterTest("DetectEngineHttpClientBodyTest08", - DetectEngineHttpClientBodyTest08, 1); + DetectEngineHttpClientBodyTest08); UtRegisterTest("DetectEngineHttpClientBodyTest09", - DetectEngineHttpClientBodyTest09, 1); + DetectEngineHttpClientBodyTest09); UtRegisterTest("DetectEngineHttpClientBodyTest10", - DetectEngineHttpClientBodyTest10, 1); + DetectEngineHttpClientBodyTest10); UtRegisterTest("DetectEngineHttpClientBodyTest11", - DetectEngineHttpClientBodyTest11, 1); + DetectEngineHttpClientBodyTest11); UtRegisterTest("DetectEngineHttpClientBodyTest12", - DetectEngineHttpClientBodyTest12, 1); + DetectEngineHttpClientBodyTest12); UtRegisterTest("DetectEngineHttpClientBodyTest13", - DetectEngineHttpClientBodyTest13, 1); + DetectEngineHttpClientBodyTest13); UtRegisterTest("DetectEngineHttpClientBodyTest14", - DetectEngineHttpClientBodyTest14, 1); + DetectEngineHttpClientBodyTest14); UtRegisterTest("DetectEngineHttpClientBodyTest15", - DetectEngineHttpClientBodyTest15, 1); + DetectEngineHttpClientBodyTest15); UtRegisterTest("DetectEngineHttpClientBodyTest16", - DetectEngineHttpClientBodyTest16, 1); + DetectEngineHttpClientBodyTest16); UtRegisterTest("DetectEngineHttpClientBodyTest17", - DetectEngineHttpClientBodyTest17, 1); + DetectEngineHttpClientBodyTest17); UtRegisterTest("DetectEngineHttpClientBodyTest18", - DetectEngineHttpClientBodyTest18, 1); + DetectEngineHttpClientBodyTest18); UtRegisterTest("DetectEngineHttpClientBodyTest19", - DetectEngineHttpClientBodyTest19, 1); + DetectEngineHttpClientBodyTest19); UtRegisterTest("DetectEngineHttpClientBodyTest20", - DetectEngineHttpClientBodyTest20, 1); + DetectEngineHttpClientBodyTest20); UtRegisterTest("DetectEngineHttpClientBodyTest21", - DetectEngineHttpClientBodyTest21, 1); + DetectEngineHttpClientBodyTest21); UtRegisterTest("DetectEngineHttpClientBodyTest22", - DetectEngineHttpClientBodyTest22, 1); + DetectEngineHttpClientBodyTest22); UtRegisterTest("DetectEngineHttpClientBodyTest23", - DetectEngineHttpClientBodyTest23, 1); + DetectEngineHttpClientBodyTest23); UtRegisterTest("DetectEngineHttpClientBodyTest24", - DetectEngineHttpClientBodyTest24, 1); + DetectEngineHttpClientBodyTest24); UtRegisterTest("DetectEngineHttpClientBodyTest25", - DetectEngineHttpClientBodyTest25, 1); + DetectEngineHttpClientBodyTest25); UtRegisterTest("DetectEngineHttpClientBodyTest26", - DetectEngineHttpClientBodyTest26, 1); + DetectEngineHttpClientBodyTest26); UtRegisterTest("DetectEngineHttpClientBodyTest27", - DetectEngineHttpClientBodyTest27, 1); + DetectEngineHttpClientBodyTest27); UtRegisterTest("DetectEngineHttpClientBodyTest28", - DetectEngineHttpClientBodyTest28, 1); + DetectEngineHttpClientBodyTest28); UtRegisterTest("DetectEngineHttpClientBodyTest29", - DetectEngineHttpClientBodyTest29, 1); + DetectEngineHttpClientBodyTest29); UtRegisterTest("DetectEngineHttpClientBodyTest30", - DetectEngineHttpClientBodyTest30, 1); + DetectEngineHttpClientBodyTest30); UtRegisterTest("DetectEngineHttpClientBodyTest31", - DetectEngineHttpClientBodyTest31, 1); + DetectEngineHttpClientBodyTest31); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hcbd.h b/src/detect-engine-hcbd.h index 6dce3230c9a2..c3c91a76a35b 100644 --- a/src/detect-engine-hcbd.h +++ b/src/detect-engine-hcbd.h @@ -27,16 +27,13 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpClientBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxHttpRequestBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpClientBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineCleanHCBDBuffers(DetectEngineThreadCtx *); void DetectEngineHttpClientBodyRegisterTests(void); diff --git a/src/detect-engine-hcd.c b/src/detect-engine-hcd.c index 513507e4e111..8f06cda19247 100644 --- a/src/detect-engine-hcd.c +++ b/src/detect-engine-hcd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP cookie match * @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -56,38 +58,98 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" -int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +/** \brief HTTP Cookie Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxRequestCookie(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; + if (tx->request_headers == NULL) - goto end; + return; - htp_header_t *h = NULL; - if (flags & STREAM_TOSERVER) { - h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Cookie"); - if (h == NULL) { - SCLogDebug("HTTP cookie header not present in this request"); - goto end; - } - } else { - h = (htp_header_t *)htp_table_get_c(tx->response_headers, - "Set-Cookie"); - if (h == NULL) { - SCLogDebug("HTTP Set-Cookie header not present in this request"); - goto end; - } + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, + "Cookie"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP cookie header not present in this request"); + return; } - cnt = HttpCookiePatternSearch(det_ctx, - (uint8_t *)bstr_ptr(h->value), - bstr_len(h->value), flags); - end: - return cnt; + const uint32_t buffer_len = bstr_len(h->value); + const uint8_t *buffer = bstr_ptr(h->value); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxRequestCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxRequestCookie, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, "http_cookie (request)"); +} + +/** \brief HTTP Cookie Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxResponseCookie(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->response_headers, + "Set-Cookie"); + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP cookie header not present in this request"); + return; + } + + const uint32_t buffer_len = bstr_len(h->value); + const uint8_t *buffer = bstr_ptr(h->value); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxResponseCookie, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, "http_cookie (response)"); } /** @@ -104,11 +166,9 @@ int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpCookie(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; htp_header_t *h = NULL; @@ -131,21 +191,21 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HCDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HCD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -210,15 +270,16 @@ static int DetectEngineHttpCookieTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -308,15 +369,16 @@ static int DetectEngineHttpCookieTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -406,15 +468,16 @@ static int DetectEngineHttpCookieTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -504,15 +567,16 @@ static int DetectEngineHttpCookieTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -602,15 +666,16 @@ static int DetectEngineHttpCookieTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -700,15 +765,16 @@ static int DetectEngineHttpCookieTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -798,15 +864,16 @@ static int DetectEngineHttpCookieTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -896,15 +963,16 @@ static int DetectEngineHttpCookieTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -994,15 +1062,16 @@ static int DetectEngineHttpCookieTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1093,15 +1162,16 @@ static int DetectEngineHttpCookieTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1192,15 +1262,16 @@ static int DetectEngineHttpCookieTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1291,15 +1362,16 @@ static int DetectEngineHttpCookieTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1390,15 +1462,16 @@ static int DetectEngineHttpCookieTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1489,15 +1562,16 @@ static int DetectEngineHttpCookieTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1588,15 +1662,16 @@ static int DetectEngineHttpCookieTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1687,15 +1762,16 @@ static int DetectEngineHttpCookieTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1786,15 +1862,16 @@ static int DetectEngineHttpCookieTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1836,39 +1913,39 @@ void DetectEngineHttpCookieRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpCookieTest01", - DetectEngineHttpCookieTest01, 1); + DetectEngineHttpCookieTest01); UtRegisterTest("DetectEngineHttpCookieTest02", - DetectEngineHttpCookieTest02, 1); + DetectEngineHttpCookieTest02); UtRegisterTest("DetectEngineHttpCookieTest03", - DetectEngineHttpCookieTest03, 1); + DetectEngineHttpCookieTest03); UtRegisterTest("DetectEngineHttpCookieTest04", - DetectEngineHttpCookieTest04, 1); + DetectEngineHttpCookieTest04); UtRegisterTest("DetectEngineHttpCookieTest05", - DetectEngineHttpCookieTest05, 1); + DetectEngineHttpCookieTest05); UtRegisterTest("DetectEngineHttpCookieTest06", - DetectEngineHttpCookieTest06, 1); + DetectEngineHttpCookieTest06); UtRegisterTest("DetectEngineHttpCookieTest07", - DetectEngineHttpCookieTest07, 1); + DetectEngineHttpCookieTest07); UtRegisterTest("DetectEngineHttpCookieTest08", - DetectEngineHttpCookieTest08, 1); + DetectEngineHttpCookieTest08); UtRegisterTest("DetectEngineHttpCookieTest09", - DetectEngineHttpCookieTest09, 1); + DetectEngineHttpCookieTest09); UtRegisterTest("DetectEngineHttpCookieTest10", - DetectEngineHttpCookieTest10, 1); + DetectEngineHttpCookieTest10); UtRegisterTest("DetectEngineHttpCookieTest11", - DetectEngineHttpCookieTest11, 1); + DetectEngineHttpCookieTest11); UtRegisterTest("DetectEngineHttpCookieTest12", - DetectEngineHttpCookieTest12, 1); + DetectEngineHttpCookieTest12); UtRegisterTest("DetectEngineHttpCookieTest13", - DetectEngineHttpCookieTest13, 1); + DetectEngineHttpCookieTest13); UtRegisterTest("DetectEngineHttpCookieTest14", - DetectEngineHttpCookieTest14, 1); + DetectEngineHttpCookieTest14); UtRegisterTest("DetectEngineHttpCookieTest15", - DetectEngineHttpCookieTest15, 1); + DetectEngineHttpCookieTest15); UtRegisterTest("DetectEngineHttpCookieTest16", - DetectEngineHttpCookieTest16, 1); + DetectEngineHttpCookieTest16); UtRegisterTest("DetectEngineHttpCookieTest17", - DetectEngineHttpCookieTest17, 1); + DetectEngineHttpCookieTest17); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hcd.h b/src/detect-engine-hcd.h index 78f92407f256..bdf9c498d4e9 100644 --- a/src/detect-engine-hcd.h +++ b/src/detect-engine-hcd.h @@ -25,15 +25,14 @@ #include "app-layer-htp.h" +int PrefilterTxRequestCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxResponseCookieRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpCookie(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpCookieMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpCookieRegisterTests(void); #endif /* __DETECT_ENGINE_HCD_H__ */ diff --git a/src/detect-engine-hhd.c b/src/detect-engine-hhd.c deleted file mode 100644 index 6672895b4829..000000000000 --- a/src/detect-engine-hhd.c +++ /dev/null @@ -1,3897 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \ingroup httplayer - * - * @{ - */ - - -/** \file - * - * \author Anoop Saldanha - * - * \brief Handle HTTP header match - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "decode.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-hhd.h" -#include "detect-engine-mpm.h" -#include "detect-parse.h" -#include "detect-engine-state.h" -#include "detect-engine-content-inspection.h" - -#include "flow-util.h" -#include "util-debug.h" -#include "util-print.h" -#include "util-memcmp.h" -#include "flow.h" - -#include "stream-tcp.h" - -#include "app-layer-parser.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "app-layer.h" -#include "app-layer-htp.h" -#include "app-layer-protos.h" - -#define BUFFER_STEP 50 - -static inline int HHDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) -{ - void *ptmp; - if (size > det_ctx->hhd_buffers_size) { - ptmp = SCRealloc(det_ctx->hhd_buffers, - (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint8_t *)); - if (ptmp == NULL) { - SCFree(det_ctx->hhd_buffers); - det_ctx->hhd_buffers = NULL; - det_ctx->hhd_buffers_size = 0; - det_ctx->hhd_buffers_list_len = 0; - return -1; - } - det_ctx->hhd_buffers = ptmp; - - memset(det_ctx->hhd_buffers + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint8_t *)); - ptmp = SCRealloc(det_ctx->hhd_buffers_len, - (det_ctx->hhd_buffers_size + BUFFER_STEP) * sizeof(uint32_t)); - if (ptmp == NULL) { - SCFree(det_ctx->hhd_buffers_len); - det_ctx->hhd_buffers_len = NULL; - det_ctx->hhd_buffers_size = 0; - det_ctx->hhd_buffers_list_len = 0; - return -1; - } - det_ctx->hhd_buffers_len = ptmp; - - memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_size, 0, BUFFER_STEP * sizeof(uint32_t)); - det_ctx->hhd_buffers_size += BUFFER_STEP; - } - memset(det_ctx->hhd_buffers_len + det_ctx->hhd_buffers_list_len, 0, (size - det_ctx->hhd_buffers_list_len) * sizeof(uint32_t)); - - return 0; -} - -static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Flow *f, HtpState *htp_state, - uint8_t flags, - uint32_t *buffer_len) -{ - uint8_t *headers_buffer = NULL; - int index = 0; - *buffer_len = 0; - - if (det_ctx->hhd_buffers_list_len == 0) { - if (HHDCreateSpace(det_ctx, 1) < 0) - goto end; - index = 0; - - if (det_ctx->hhd_buffers_list_len == 0) { - det_ctx->hhd_start_tx_id = tx_id; - } - det_ctx->hhd_buffers_list_len++; - } else { - if ((tx_id - det_ctx->hhd_start_tx_id) < det_ctx->hhd_buffers_list_len) { - if (det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)] != 0) { - *buffer_len = det_ctx->hhd_buffers_len[(tx_id - det_ctx->hhd_start_tx_id)]; - return det_ctx->hhd_buffers[(tx_id - det_ctx->hhd_start_tx_id)]; - } - } else { - if (HHDCreateSpace(det_ctx, (tx_id - det_ctx->hhd_start_tx_id) + 1) < 0) - goto end; - - if (det_ctx->hhd_buffers_list_len == 0) { - det_ctx->hhd_start_tx_id = tx_id; - } - det_ctx->hhd_buffers_list_len++; - } - index = (tx_id - det_ctx->hhd_start_tx_id); - } - - htp_table_t *headers; - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS) - goto end; - headers = tx->request_headers; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS) - goto end; - headers = tx->response_headers; - } - if (headers == NULL) - goto end; - - htp_header_t *h = NULL; - headers_buffer = det_ctx->hhd_buffers[index]; - size_t headers_buffer_len = 0; - size_t i = 0; - - size_t no_of_headers = htp_table_size(headers); - for (; i < no_of_headers; i++) { - h = htp_table_get_index(headers, i, NULL); - size_t size1 = bstr_size(h->name); - size_t size2 = bstr_size(h->value); - - if (flags & STREAM_TOSERVER) { - if (size1 == 6 && - SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { - continue; - } - } else { - if (size1 == 10 && - SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { - continue; - } - } - - /* the extra 4 bytes if for ": " and "\r\n" */ - uint8_t *new_headers_buffer = SCRealloc(headers_buffer, headers_buffer_len + size1 + size2 + 4); - if (unlikely(new_headers_buffer == NULL)) { - if (headers_buffer != NULL) { - SCFree(headers_buffer); - headers_buffer = NULL; - } - det_ctx->hhd_buffers[index] = NULL; - det_ctx->hhd_buffers_len[index] = 0; - goto end; - } - headers_buffer = new_headers_buffer; - - memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->name), size1); - headers_buffer_len += size1; - headers_buffer[headers_buffer_len] = ':'; - headers_buffer[headers_buffer_len + 1] = ' '; - headers_buffer_len += 2; - memcpy(headers_buffer + headers_buffer_len, bstr_ptr(h->value), size2); - headers_buffer_len += size2 + 2; - /* \r */ - headers_buffer[headers_buffer_len - 2] = '\r'; - /* \n */ - headers_buffer[headers_buffer_len - 1] = '\n'; - } - - /* store the buffers. We will need it for further inspection */ - det_ctx->hhd_buffers[index] = headers_buffer; - det_ctx->hhd_buffers_len[index] = headers_buffer_len; - - *buffer_len = (uint32_t)headers_buffer_len; - end: - return headers_buffer; -} - -int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx) -{ - uint32_t cnt = 0; - uint32_t buffer_len = 0; - uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, - NULL, det_ctx, - f, htp_state, - flags, - &buffer_len); - if (buffer_len == 0) - goto end; - - cnt = HttpHeaderPatternSearch(det_ctx, buffer, buffer_len, flags); - - end: - return cnt; -} - -int DetectEngineInspectHttpHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - HtpState *htp_state = (HtpState *)alstate; - uint32_t buffer_len = 0; - uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, tx_id, - de_ctx, det_ctx, - f, htp_state, - flags, - &buffer_len); - if (buffer_len == 0) - goto end; - - det_ctx->buffer_offset = 0; - det_ctx->discontinue_matching = 0; - det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHDMATCH], - f, - buffer, - buffer_len, - 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHD, NULL); - if (r == 1) - return DETECT_ENGINE_INSPECT_SIG_MATCH; - - end: - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS) - return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; - } - return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; -} - -void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx) -{ - if (det_ctx->hhd_buffers_list_len != 0) { - int i; - for (i = 0; i < det_ctx->hhd_buffers_list_len; i++) { - det_ctx->hhd_buffers_len[i] = 0; - } - det_ctx->hhd_buffers_list_len = 0; - } - det_ctx->hhd_start_tx_id = 0; - - return; -} - -/***********************************Unittests**********************************/ - -#ifdef UNITTESTS - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest01(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest02(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; depth:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest03(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; depth:5; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest04(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; depth:5; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest05(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; depth:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest06(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; offset:10; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest07(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; offset:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest08(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; offset:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest09(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:!\"one\"; offset:10; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest10(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest11(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest12(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest13(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest14(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest15(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest16(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest17(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - printf("sid 1 matched but shouldn't have: "); - goto end; - } - - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest18(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; content:\"five\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected result 2, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpHeaderTest19(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"one\"; http_header; fast_pattern; content:\"five\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected result 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -static int DetectEngineHttpHeaderTest20(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; http_header; within:7; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest21(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; within:7; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest22(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; distance:3; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest23(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:!\"dummy\"; distance:13; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest24(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; within:15; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest25(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; within:10; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest26(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; distance:8; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest27(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Host: This_is_dummy_body1"; - uint8_t http2_buf[] = - "This_is_dummy_message_body2\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http client body test\"; " - "pcre:/body1/H; " - "content:\"dummy\"; distance:14; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest28(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 6\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -static int DetectEngineHttpHeaderTest29(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 7\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -#if 0 - -static int DetectEngineHttpHeaderTest30(void) -{ - int result = 0; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } - - de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"Content-Length: 6\"; http_header; " - "content:\"User-Agent: Mozilla\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list != NULL) { - goto end; - } - - result = 1; - - end: - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - return result; -} - -#endif /* #if 0 */ - -static int DetectEngineHttpHeaderTest30(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http_buf1[] = - "GET /index.html HTTP/1.0\r\n" - "Host: www.openinfosecfoundation.org\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" - "\r\n"; - uint32_t http_buf1_len = sizeof(http_buf1) - 1; - uint8_t http_buf2[] = - "HTTP/1.0 200 ok\r\n" - "Set-Cookie: dummycookieset\r\n" - "Content-Type: text/html\r\n" - "Content-Length: 6\r\n" - "\r\n" - "abcdef"; - uint32_t http_buf2_len = sizeof(http_buf2) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; " - "content:\"dummycookieset\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -/** \test reassembly bug where headers with names of length 6 were - * skipped - */ -static int DetectEngineHttpHeaderTest31(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "Accept: blah\r\n" - "Cookie: blah\r\n" - "Crazy6: blah\r\n" - "SixZix: blah\r\n\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Accept|3a|\"; http_header; " - "content:!\"Cookie|3a|\"; http_header; " - "content:\"Crazy6|3a|\"; http_header; " - "content:\"SixZix|3a|\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -/** - * \test Trailing headers. - */ -static int DetectEngineHttpHeaderTest32(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n" - "Dummy-Header: kaboom\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -/** - * \test Trailing headers. - */ -static int DetectEngineHttpHeaderTest33(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - Packet *p2 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - HtpState *http_state = NULL; - Flow f; - uint8_t http1_buf[] = - "GET /index.html HTTP/1.0\r\n" - "host: boom\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "13\r\n" - "This is dummy body1\r\n" - "0\r\n"; - uint8_t http2_buf[] = - "Dummy-Header: kaboom\r\n" - "\r\n"; - uint32_t http1_len = sizeof(http1_buf) - 1; - uint32_t http2_len = sizeof(http2_buf) - 1; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2->flow = &f; - p2->flowflags |= FLOW_PKT_TOSERVER; - p2->flowflags |= FLOW_PKT_ESTABLISHED; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(content:\"Dummy\"; http_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched but shouldn't have\n"); - goto end; - } - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - - if (!PacketAlertCheck(p2, 1)) { - printf("sid 1 didn't match but should have\n"); - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - return result; -} - -#endif /* UNITTESTS */ - -void DetectEngineHttpHeaderRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpHeaderTest01", - DetectEngineHttpHeaderTest01, 1); - UtRegisterTest("DetectEngineHttpHeaderTest02", - DetectEngineHttpHeaderTest02, 1); - UtRegisterTest("DetectEngineHttpHeaderTest03", - DetectEngineHttpHeaderTest03, 1); - UtRegisterTest("DetectEngineHttpHeaderTest04", - DetectEngineHttpHeaderTest04, 1); - UtRegisterTest("DetectEngineHttpHeaderTest05", - DetectEngineHttpHeaderTest05, 1); - UtRegisterTest("DetectEngineHttpHeaderTest06", - DetectEngineHttpHeaderTest06, 1); - UtRegisterTest("DetectEngineHttpHeaderTest07", - DetectEngineHttpHeaderTest07, 1); - UtRegisterTest("DetectEngineHttpHeaderTest08", - DetectEngineHttpHeaderTest08, 1); - UtRegisterTest("DetectEngineHttpHeaderTest09", - DetectEngineHttpHeaderTest09, 1); - UtRegisterTest("DetectEngineHttpHeaderTest10", - DetectEngineHttpHeaderTest10, 1); - UtRegisterTest("DetectEngineHttpHeaderTest11", - DetectEngineHttpHeaderTest11, 1); - UtRegisterTest("DetectEngineHttpHeaderTest12", - DetectEngineHttpHeaderTest12, 1); - UtRegisterTest("DetectEngineHttpHeaderTest13", - DetectEngineHttpHeaderTest13, 1); - UtRegisterTest("DetectEngineHttpHeaderTest14", - DetectEngineHttpHeaderTest14, 1); - UtRegisterTest("DetectEngineHttpHeaderTest15", - DetectEngineHttpHeaderTest15, 1); - UtRegisterTest("DetectEngineHttpHeaderTest16", - DetectEngineHttpHeaderTest16, 1); - UtRegisterTest("DetectEngineHttpHeaderTest17", - DetectEngineHttpHeaderTest17, 1); - UtRegisterTest("DetectEngineHttpHeaderTest18", - DetectEngineHttpHeaderTest18, 1); - UtRegisterTest("DetectEngineHttpHeaderTest19", - DetectEngineHttpHeaderTest19, 1); - UtRegisterTest("DetectEngineHttpHeaderTest20", - DetectEngineHttpHeaderTest20, 1); - UtRegisterTest("DetectEngineHttpHeaderTest21", - DetectEngineHttpHeaderTest21, 1); - UtRegisterTest("DetectEngineHttpHeaderTest22", - DetectEngineHttpHeaderTest22, 1); - UtRegisterTest("DetectEngineHttpHeaderTest23", - DetectEngineHttpHeaderTest23, 1); - UtRegisterTest("DetectEngineHttpHeaderTest24", - DetectEngineHttpHeaderTest24, 1); - UtRegisterTest("DetectEngineHttpHeaderTest25", - DetectEngineHttpHeaderTest25, 1); - UtRegisterTest("DetectEngineHttpHeaderTest26", - DetectEngineHttpHeaderTest26, 1); - UtRegisterTest("DetectEngineHttpHeaderTest27", - DetectEngineHttpHeaderTest27, 1); - UtRegisterTest("DetectEngineHttpHeaderTest28", - DetectEngineHttpHeaderTest28, 1); - UtRegisterTest("DetectEngineHttpHeaderTest29", - DetectEngineHttpHeaderTest29, 1); - UtRegisterTest("DetectEngineHttpHeaderTest30", - DetectEngineHttpHeaderTest30, 1); - UtRegisterTest("DetectEngineHttpHeaderTest31", - DetectEngineHttpHeaderTest31, 1); -#if 0 - UtRegisterTest("DetectEngineHttpHeaderTest30", - DetectEngineHttpHeaderTest30, 1); -#endif - UtRegisterTest("DetectEngineHttpHeaderTest32", - DetectEngineHttpHeaderTest32, 1); - UtRegisterTest("DetectEngineHttpHeaderTest33", - DetectEngineHttpHeaderTest33, 1); - -#endif /* UNITTESTS */ - - return; -} -/** - * @} - */ diff --git a/src/detect-engine-hhd.h b/src/detect-engine-hhd.h deleted file mode 100644 index e163000c71af..000000000000 --- a/src/detect-engine-hhd.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** \file - * - * \author Anoop Saldanha - */ - -#ifndef __DETECT_ENGINE_HHD_H__ -#define __DETECT_ENGINE_HHD_H__ - -#include "app-layer-htp.h" - -int DetectEngineInspectHttpHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); -void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); - -void DetectEngineHttpHeaderRegisterTests(void); - -#endif /* __DETECT_ENGINE_HHD_H__ */ diff --git a/src/detect-engine-hhhd.c b/src/detect-engine-hhhd.c index 77a9791d8314..f884d7a85a1e 100644 --- a/src/detect-engine-hhhd.c +++ b/src/detect-engine-hhhd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP host header. * HHHD - Http Host Header Data @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -58,24 +60,45 @@ #include "app-layer-protos.h" #include "detect-engine-hhhd.h" +#include "util-validate.h" -int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +/** \brief HTTP Host Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHostname(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; + if (tx->request_hostname == NULL) - goto end; - uint8_t *hname = (uint8_t *)bstr_ptr(tx->request_hostname); - if (hname == NULL) - goto end; - uint32_t hname_len = bstr_len(tx->request_hostname); + return; - cnt += HttpHHPatternSearch(det_ctx, hname, hname_len, flags); + const uint32_t buffer_len = bstr_len(tx->request_hostname); + const uint8_t *buffer = bstr_ptr(tx->request_hostname); - end: - return cnt; + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHostname, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, "http_host"); } /** @@ -92,11 +115,9 @@ int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpHH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->parsed_uri == NULL || tx->request_hostname == NULL) @@ -109,16 +130,16 @@ int DetectEngineInspectHttpHH(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HHHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, hname, hname_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -183,15 +204,16 @@ static int DetectEngineHttpHHTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -281,15 +303,16 @@ static int DetectEngineHttpHHTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -379,15 +402,16 @@ static int DetectEngineHttpHHTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -477,15 +501,16 @@ static int DetectEngineHttpHHTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -575,15 +600,16 @@ static int DetectEngineHttpHHTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -673,15 +699,16 @@ static int DetectEngineHttpHHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -771,15 +798,16 @@ static int DetectEngineHttpHHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -869,15 +897,16 @@ static int DetectEngineHttpHHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -967,15 +996,16 @@ static int DetectEngineHttpHHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1066,15 +1096,16 @@ static int DetectEngineHttpHHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1165,15 +1196,16 @@ static int DetectEngineHttpHHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1264,15 +1296,16 @@ static int DetectEngineHttpHHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1363,15 +1396,16 @@ static int DetectEngineHttpHHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1462,15 +1496,16 @@ static int DetectEngineHttpHHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1561,15 +1596,16 @@ static int DetectEngineHttpHHTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1660,15 +1696,16 @@ static int DetectEngineHttpHHTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1759,15 +1796,16 @@ static int DetectEngineHttpHHTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1853,15 +1891,16 @@ static int DetectEngineHttpHHTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1947,15 +1986,16 @@ static int DetectEngineHttpHHTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2041,15 +2081,16 @@ static int DetectEngineHttpHHTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2134,15 +2175,16 @@ static int DetectEngineHttpHHTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2227,15 +2269,16 @@ static int DetectEngineHttpHHTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2320,15 +2363,16 @@ static int DetectEngineHttpHHTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2414,15 +2458,16 @@ static int DetectEngineHttpHHTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2508,15 +2553,16 @@ static int DetectEngineHttpHHTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2557,56 +2603,31 @@ void DetectEngineHttpHHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpHHTest01", - DetectEngineHttpHHTest01, 1); - UtRegisterTest("DetectEngineHttpHHTest02", - DetectEngineHttpHHTest02, 1); - UtRegisterTest("DetectEngineHttpHHTest03", - DetectEngineHttpHHTest03, 1); - UtRegisterTest("DetectEngineHttpHHTest04", - DetectEngineHttpHHTest04, 1); - UtRegisterTest("DetectEngineHttpHHTest05", - DetectEngineHttpHHTest05, 1); - UtRegisterTest("DetectEngineHttpHHTest06", - DetectEngineHttpHHTest06, 1); - UtRegisterTest("DetectEngineHttpHHTest07", - DetectEngineHttpHHTest07, 1); - UtRegisterTest("DetectEngineHttpHHTest08", - DetectEngineHttpHHTest08, 1); - UtRegisterTest("DetectEngineHttpHHTest09", - DetectEngineHttpHHTest09, 1); - UtRegisterTest("DetectEngineHttpHHTest10", - DetectEngineHttpHHTest10, 1); - UtRegisterTest("DetectEngineHttpHHTest11", - DetectEngineHttpHHTest11, 1); - UtRegisterTest("DetectEngineHttpHHTest12", - DetectEngineHttpHHTest12, 1); - UtRegisterTest("DetectEngineHttpHHTest13", - DetectEngineHttpHHTest13, 1); - UtRegisterTest("DetectEngineHttpHHTest14", - DetectEngineHttpHHTest14, 1); - UtRegisterTest("DetectEngineHttpHHTest15", - DetectEngineHttpHHTest15, 1); - UtRegisterTest("DetectEngineHttpHHTest16", - DetectEngineHttpHHTest16, 1); - UtRegisterTest("DetectEngineHttpHHTest17", - DetectEngineHttpHHTest17, 1); - UtRegisterTest("DetectEngineHttpHHTest18", - DetectEngineHttpHHTest18, 1); - UtRegisterTest("DetectEngineHttpHHTest19", - DetectEngineHttpHHTest19, 1); - UtRegisterTest("DetectEngineHttpHHTest20", - DetectEngineHttpHHTest20, 1); - UtRegisterTest("DetectEngineHttpHHTest21", - DetectEngineHttpHHTest21, 1); - UtRegisterTest("DetectEngineHttpHHTest22", - DetectEngineHttpHHTest22, 1); - UtRegisterTest("DetectEngineHttpHHTest23", - DetectEngineHttpHHTest23, 1); - UtRegisterTest("DetectEngineHttpHHTest24", - DetectEngineHttpHHTest24, 1); - UtRegisterTest("DetectEngineHttpHHTest25", - DetectEngineHttpHHTest25, 1); + UtRegisterTest("DetectEngineHttpHHTest01", DetectEngineHttpHHTest01); + UtRegisterTest("DetectEngineHttpHHTest02", DetectEngineHttpHHTest02); + UtRegisterTest("DetectEngineHttpHHTest03", DetectEngineHttpHHTest03); + UtRegisterTest("DetectEngineHttpHHTest04", DetectEngineHttpHHTest04); + UtRegisterTest("DetectEngineHttpHHTest05", DetectEngineHttpHHTest05); + UtRegisterTest("DetectEngineHttpHHTest06", DetectEngineHttpHHTest06); + UtRegisterTest("DetectEngineHttpHHTest07", DetectEngineHttpHHTest07); + UtRegisterTest("DetectEngineHttpHHTest08", DetectEngineHttpHHTest08); + UtRegisterTest("DetectEngineHttpHHTest09", DetectEngineHttpHHTest09); + UtRegisterTest("DetectEngineHttpHHTest10", DetectEngineHttpHHTest10); + UtRegisterTest("DetectEngineHttpHHTest11", DetectEngineHttpHHTest11); + UtRegisterTest("DetectEngineHttpHHTest12", DetectEngineHttpHHTest12); + UtRegisterTest("DetectEngineHttpHHTest13", DetectEngineHttpHHTest13); + UtRegisterTest("DetectEngineHttpHHTest14", DetectEngineHttpHHTest14); + UtRegisterTest("DetectEngineHttpHHTest15", DetectEngineHttpHHTest15); + UtRegisterTest("DetectEngineHttpHHTest16", DetectEngineHttpHHTest16); + UtRegisterTest("DetectEngineHttpHHTest17", DetectEngineHttpHHTest17); + UtRegisterTest("DetectEngineHttpHHTest18", DetectEngineHttpHHTest18); + UtRegisterTest("DetectEngineHttpHHTest19", DetectEngineHttpHHTest19); + UtRegisterTest("DetectEngineHttpHHTest20", DetectEngineHttpHHTest20); + UtRegisterTest("DetectEngineHttpHHTest21", DetectEngineHttpHHTest21); + UtRegisterTest("DetectEngineHttpHHTest22", DetectEngineHttpHHTest22); + UtRegisterTest("DetectEngineHttpHHTest23", DetectEngineHttpHHTest23); + UtRegisterTest("DetectEngineHttpHHTest24", DetectEngineHttpHHTest24); + UtRegisterTest("DetectEngineHttpHHTest25", DetectEngineHttpHHTest25); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hhhd.h b/src/detect-engine-hhhd.h index e6cec9071ca9..39e16493a33c 100644 --- a/src/detect-engine-hhhd.h +++ b/src/detect-engine-hhhd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,15 +25,13 @@ #include "app-layer-htp.h" +int PrefilterTxHostnameRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpHH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpHHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpHHRegisterTests(void); #endif /* __DETECT_ENGINE_HHHD_H__ */ diff --git a/src/detect-engine-hmd.c b/src/detect-engine-hmd.c index c33cfd967d55..27dcb16567c7 100644 --- a/src/detect-engine-hmd.c +++ b/src/detect-engine-hmd.c @@ -41,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -56,22 +57,45 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" -int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +/** \brief HTTP Method Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + * + * \retval ret number of matches + */ +static void PrefilterTxMethod(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; + if (tx->request_method == NULL) - goto end; - cnt = HttpMethodPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->request_method), - bstr_len(tx->request_method), - flags); + return; - end: - return cnt; + const uint32_t buffer_len = bstr_len(tx->request_method); + const uint8_t *buffer = bstr_ptr(tx->request_method); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + return PrefilterAppendTxEngine(sgh, PrefilterTxMethod, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, "http_method"); } /** @@ -88,15 +112,13 @@ int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpMethod(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_method == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -105,12 +127,12 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HMDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HMD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else @@ -175,15 +197,16 @@ static int DetectEngineHttpMethodTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -272,15 +295,16 @@ static int DetectEngineHttpMethodTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -369,15 +393,16 @@ static int DetectEngineHttpMethodTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -466,15 +491,16 @@ static int DetectEngineHttpMethodTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -563,15 +589,16 @@ static int DetectEngineHttpMethodTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -660,15 +687,16 @@ static int DetectEngineHttpMethodTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -757,15 +785,16 @@ static int DetectEngineHttpMethodTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -854,15 +883,16 @@ static int DetectEngineHttpMethodTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -951,15 +981,16 @@ static int DetectEngineHttpMethodTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1049,15 +1080,16 @@ static int DetectEngineHttpMethodTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1147,15 +1179,16 @@ static int DetectEngineHttpMethodTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1245,15 +1278,16 @@ static int DetectEngineHttpMethodTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1343,15 +1377,16 @@ static int DetectEngineHttpMethodTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1441,15 +1476,16 @@ static int DetectEngineHttpMethodTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1539,15 +1575,16 @@ static int DetectEngineHttpMethodTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1637,15 +1674,16 @@ static int DetectEngineHttpMethodTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1735,15 +1773,16 @@ static int DetectEngineHttpMethodTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1785,39 +1824,39 @@ void DetectEngineHttpMethodRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpMethodTest01", - DetectEngineHttpMethodTest01, 1); + DetectEngineHttpMethodTest01); UtRegisterTest("DetectEngineHttpMethodTest02", - DetectEngineHttpMethodTest02, 1); + DetectEngineHttpMethodTest02); UtRegisterTest("DetectEngineHttpMethodTest03", - DetectEngineHttpMethodTest03, 1); + DetectEngineHttpMethodTest03); UtRegisterTest("DetectEngineHttpMethodTest04", - DetectEngineHttpMethodTest04, 1); + DetectEngineHttpMethodTest04); UtRegisterTest("DetectEngineHttpMethodTest05", - DetectEngineHttpMethodTest05, 1); + DetectEngineHttpMethodTest05); UtRegisterTest("DetectEngineHttpMethodTest06", - DetectEngineHttpMethodTest06, 1); + DetectEngineHttpMethodTest06); UtRegisterTest("DetectEngineHttpMethodTest07", - DetectEngineHttpMethodTest07, 1); + DetectEngineHttpMethodTest07); UtRegisterTest("DetectEngineHttpMethodTest08", - DetectEngineHttpMethodTest08, 1); + DetectEngineHttpMethodTest08); UtRegisterTest("DetectEngineHttpMethodTest09", - DetectEngineHttpMethodTest09, 1); + DetectEngineHttpMethodTest09); UtRegisterTest("DetectEngineHttpMethodTest10", - DetectEngineHttpMethodTest10, 1); + DetectEngineHttpMethodTest10); UtRegisterTest("DetectEngineHttpMethodTest11", - DetectEngineHttpMethodTest11, 1); + DetectEngineHttpMethodTest11); UtRegisterTest("DetectEngineHttpMethodTest12", - DetectEngineHttpMethodTest12, 1); + DetectEngineHttpMethodTest12); UtRegisterTest("DetectEngineHttpMethodTest13", - DetectEngineHttpMethodTest13, 1); + DetectEngineHttpMethodTest13); UtRegisterTest("DetectEngineHttpMethodTest14", - DetectEngineHttpMethodTest14, 1); + DetectEngineHttpMethodTest14); UtRegisterTest("DetectEngineHttpMethodTest15", - DetectEngineHttpMethodTest15, 1); + DetectEngineHttpMethodTest15); UtRegisterTest("DetectEngineHttpMethodTest16", - DetectEngineHttpMethodTest16, 1); + DetectEngineHttpMethodTest16); UtRegisterTest("DetectEngineHttpMethodTest17", - DetectEngineHttpMethodTest17, 1); + DetectEngineHttpMethodTest17); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hmd.h b/src/detect-engine-hmd.h index faf26aa2e2b6..d3fe192f58ea 100644 --- a/src/detect-engine-hmd.h +++ b/src/detect-engine-hmd.h @@ -26,14 +26,12 @@ #include "app-layer-htp.h" int DetectEngineInspectHttpMethod(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpMethodMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + +int PrefilterTxMethodRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + void DetectEngineHttpMethodRegisterTests(void); #endif /* __DETECT_ENGINE_HMD_H__ */ diff --git a/src/detect-engine-hrhd.c b/src/detect-engine-hrhd.c index b6b86a3772f9..9cdfbf2385a2 100644 --- a/src/detect-engine-hrhd.c +++ b/src/detect-engine-hrhd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP raw header match. * @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -57,42 +59,94 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" -int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +/** \brief HTTP Raw Header Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxRequestHeadersRaw(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t cnt = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud == NULL) - SCReturnInt(cnt); + if (tx_ud == NULL || tx_ud->request_headers_raw == NULL) + return; - if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS) - SCReturnInt(cnt); - - if (tx_ud->request_headers_raw != NULL) { - cnt = HttpRawHeaderPatternSearch(det_ctx, - tx_ud->request_headers_raw, - tx_ud->request_headers_raw_len, - flags); - } - } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS) - SCReturnInt(cnt); + const uint32_t buffer_len = tx_ud->request_headers_raw_len; + const uint8_t *buffer = tx_ud->request_headers_raw; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxRequestHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxRequestHeadersRaw, + ALPROTO_HTTP, HTP_REQUEST_HEADERS+1, /* inspect when headers complete */ + mpm_ctx, NULL, "http_raw_header (request)"); + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxRequestHeadersRaw, + ALPROTO_HTTP, HTP_REQUEST_TRAILER+1, /* inspect when trailer complete */ + mpm_ctx, NULL, "http_raw_header (request)"); +} + +/** \brief HTTP Raw Header Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxResponseHeadersRaw(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + if (tx_ud == NULL || tx_ud->response_headers_raw == NULL) + return; + + const uint32_t buffer_len = tx_ud->response_headers_raw_len; + const uint8_t *buffer = tx_ud->response_headers_raw; - if (tx_ud->response_headers_raw != NULL) { - cnt += HttpRawHeaderPatternSearch(det_ctx, - tx_ud->response_headers_raw, - tx_ud->response_headers_raw_len, - flags); - } + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); } +} + +int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); - SCReturnInt(cnt); + int r = PrefilterAppendTxEngine(sgh, PrefilterTxResponseHeadersRaw, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS+1, /* inspect when headers complete */ + mpm_ctx, NULL, "http_raw_header (response)"); + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxResponseHeadersRaw, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER+1, /* inspect when trailer complete */ + mpm_ctx, NULL, "http_raw_header (response)"); } /** @@ -109,21 +163,19 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { HtpTxUserData *tx_ud = NULL; uint8_t *headers_raw = NULL; uint32_t headers_raw_len = 0; if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } @@ -143,21 +195,21 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, headers_raw, headers_raw_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: if (flags & STREAM_TOSERVER) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } else { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -221,15 +273,16 @@ static int DetectEngineHttpRawHeaderTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -317,15 +370,16 @@ static int DetectEngineHttpRawHeaderTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -413,15 +467,16 @@ static int DetectEngineHttpRawHeaderTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -509,15 +564,16 @@ static int DetectEngineHttpRawHeaderTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -605,15 +661,16 @@ static int DetectEngineHttpRawHeaderTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -701,15 +758,16 @@ static int DetectEngineHttpRawHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -797,15 +855,16 @@ static int DetectEngineHttpRawHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -893,15 +952,16 @@ static int DetectEngineHttpRawHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -989,15 +1049,16 @@ static int DetectEngineHttpRawHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1085,15 +1146,16 @@ static int DetectEngineHttpRawHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1181,15 +1243,16 @@ static int DetectEngineHttpRawHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1277,15 +1340,16 @@ static int DetectEngineHttpRawHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1373,15 +1437,16 @@ static int DetectEngineHttpRawHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1469,15 +1534,16 @@ static int DetectEngineHttpRawHeaderTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1565,15 +1631,16 @@ static int DetectEngineHttpRawHeaderTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1661,15 +1728,16 @@ static int DetectEngineHttpRawHeaderTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1757,15 +1825,16 @@ static int DetectEngineHttpRawHeaderTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1799,156 +1868,6 @@ static int DetectEngineHttpRawHeaderTest17(void) return result; } -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpRawHeaderTest18(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; content:\"five\"; http_raw_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected result 2, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - -/** - *\test Test that the http_header content matches against a http request - * which holds the content. - */ -static int DetectEngineHttpRawHeaderTest19(void) -{ - TcpSession ssn; - Packet *p = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http_buf[] = - "Host: www.onetwothreefourfivesixsevenfive.org\r\n\r\n"; - uint32_t http_len = sizeof(http_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http header test\"; flow:to_server; " - "content:\"one\"; http_raw_header; fast_pattern; content:\"five\"; http_raw_header; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = HttpRawHeaderPatternSearch(det_ctx, http_buf, http_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected result 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p, 1); - return result; -} - static int DetectEngineHttpRawHeaderTest20(void) { TcpSession ssn; @@ -2011,15 +1930,16 @@ static int DetectEngineHttpRawHeaderTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2036,15 +1956,16 @@ static int DetectEngineHttpRawHeaderTest20(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2135,15 +2056,16 @@ static int DetectEngineHttpRawHeaderTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2160,15 +2082,16 @@ static int DetectEngineHttpRawHeaderTest21(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2259,15 +2182,16 @@ static int DetectEngineHttpRawHeaderTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2284,15 +2208,16 @@ static int DetectEngineHttpRawHeaderTest22(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2383,15 +2308,16 @@ static int DetectEngineHttpRawHeaderTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2408,15 +2334,16 @@ static int DetectEngineHttpRawHeaderTest23(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2507,15 +2434,16 @@ static int DetectEngineHttpRawHeaderTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2532,15 +2460,16 @@ static int DetectEngineHttpRawHeaderTest24(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2631,15 +2560,16 @@ static int DetectEngineHttpRawHeaderTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2656,15 +2586,16 @@ static int DetectEngineHttpRawHeaderTest25(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2755,15 +2686,16 @@ static int DetectEngineHttpRawHeaderTest26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2780,15 +2712,16 @@ static int DetectEngineHttpRawHeaderTest26(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2877,15 +2810,16 @@ static int DetectEngineHttpRawHeaderTest27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2902,15 +2836,16 @@ static int DetectEngineHttpRawHeaderTest27(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3005,16 +2940,16 @@ static int DetectEngineHttpRawHeaderTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3031,15 +2966,16 @@ static int DetectEngineHttpRawHeaderTest28(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3134,16 +3070,16 @@ static int DetectEngineHttpRawHeaderTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, - http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3160,15 +3096,16 @@ static int DetectEngineHttpRawHeaderTest29(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3290,15 +3227,16 @@ static int DetectEngineHttpRawHeaderTest31(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3402,15 +3340,16 @@ static int DetectEngineHttpRawHeaderTest32(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3427,15 +3366,16 @@ static int DetectEngineHttpRawHeaderTest32(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3471,71 +3411,67 @@ void DetectEngineHttpRawHeaderRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpRawHeaderTest01", - DetectEngineHttpRawHeaderTest01, 1); + DetectEngineHttpRawHeaderTest01); UtRegisterTest("DetectEngineHttpRawHeaderTest02", - DetectEngineHttpRawHeaderTest02, 1); + DetectEngineHttpRawHeaderTest02); UtRegisterTest("DetectEngineHttpRawHeaderTest03", - DetectEngineHttpRawHeaderTest03, 1); + DetectEngineHttpRawHeaderTest03); UtRegisterTest("DetectEngineHttpRawHeaderTest04", - DetectEngineHttpRawHeaderTest04, 1); + DetectEngineHttpRawHeaderTest04); UtRegisterTest("DetectEngineHttpRawHeaderTest05", - DetectEngineHttpRawHeaderTest05, 1); + DetectEngineHttpRawHeaderTest05); UtRegisterTest("DetectEngineHttpRawHeaderTest06", - DetectEngineHttpRawHeaderTest06, 1); + DetectEngineHttpRawHeaderTest06); UtRegisterTest("DetectEngineHttpRawHeaderTest07", - DetectEngineHttpRawHeaderTest07, 1); + DetectEngineHttpRawHeaderTest07); UtRegisterTest("DetectEngineHttpRawHeaderTest08", - DetectEngineHttpRawHeaderTest08, 1); + DetectEngineHttpRawHeaderTest08); UtRegisterTest("DetectEngineHttpRawHeaderTest09", - DetectEngineHttpRawHeaderTest09, 1); + DetectEngineHttpRawHeaderTest09); UtRegisterTest("DetectEngineHttpRawHeaderTest10", - DetectEngineHttpRawHeaderTest10, 1); + DetectEngineHttpRawHeaderTest10); UtRegisterTest("DetectEngineHttpRawHeaderTest11", - DetectEngineHttpRawHeaderTest11, 1); + DetectEngineHttpRawHeaderTest11); UtRegisterTest("DetectEngineHttpRawHeaderTest12", - DetectEngineHttpRawHeaderTest12, 1); + DetectEngineHttpRawHeaderTest12); UtRegisterTest("DetectEngineHttpRawHeaderTest13", - DetectEngineHttpRawHeaderTest13, 1); + DetectEngineHttpRawHeaderTest13); UtRegisterTest("DetectEngineHttpRawHeaderTest14", - DetectEngineHttpRawHeaderTest14, 1); + DetectEngineHttpRawHeaderTest14); UtRegisterTest("DetectEngineHttpRawHeaderTest15", - DetectEngineHttpRawHeaderTest15, 1); + DetectEngineHttpRawHeaderTest15); UtRegisterTest("DetectEngineHttpRawHeaderTest16", - DetectEngineHttpRawHeaderTest16, 1); + DetectEngineHttpRawHeaderTest16); UtRegisterTest("DetectEngineHttpRawHeaderTest17", - DetectEngineHttpRawHeaderTest17, 1); - UtRegisterTest("DetectEngineHttpRawHeaderTest18", - DetectEngineHttpRawHeaderTest18, 1); - UtRegisterTest("DetectEngineHttpRawHeaderTest19", - DetectEngineHttpRawHeaderTest19, 1); + DetectEngineHttpRawHeaderTest17); UtRegisterTest("DetectEngineHttpRawHeaderTest20", - DetectEngineHttpRawHeaderTest20, 1); + DetectEngineHttpRawHeaderTest20); UtRegisterTest("DetectEngineHttpRawHeaderTest21", - DetectEngineHttpRawHeaderTest21, 1); + DetectEngineHttpRawHeaderTest21); UtRegisterTest("DetectEngineHttpRawHeaderTest22", - DetectEngineHttpRawHeaderTest22, 1); + DetectEngineHttpRawHeaderTest22); UtRegisterTest("DetectEngineHttpRawHeaderTest23", - DetectEngineHttpRawHeaderTest23, 1); + DetectEngineHttpRawHeaderTest23); UtRegisterTest("DetectEngineHttpRawHeaderTest24", - DetectEngineHttpRawHeaderTest24, 1); + DetectEngineHttpRawHeaderTest24); UtRegisterTest("DetectEngineHttpRawHeaderTest25", - DetectEngineHttpRawHeaderTest25, 1); + DetectEngineHttpRawHeaderTest25); UtRegisterTest("DetectEngineHttpRawHeaderTest26", - DetectEngineHttpRawHeaderTest26, 1); + DetectEngineHttpRawHeaderTest26); UtRegisterTest("DetectEngineHttpRawHeaderTest27", - DetectEngineHttpRawHeaderTest27, 1); + DetectEngineHttpRawHeaderTest27); UtRegisterTest("DetectEngineHttpRawHeaderTest28", - DetectEngineHttpRawHeaderTest28, 1); + DetectEngineHttpRawHeaderTest28); UtRegisterTest("DetectEngineHttpRawHeaderTest29", - DetectEngineHttpRawHeaderTest29, 1); + DetectEngineHttpRawHeaderTest29); #if 0 UtRegisterTest("DetectEngineHttpRawHeaderTest30", DetectEngineHttpRawHeaderTest30, 1); #endif UtRegisterTest("DetectEngineHttpRawHeaderTest31", - DetectEngineHttpRawHeaderTest31, 1); + DetectEngineHttpRawHeaderTest31); UtRegisterTest("DetectEngineHttpRawHeaderTest32", - DetectEngineHttpRawHeaderTest32, 1); + DetectEngineHttpRawHeaderTest32); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrhd.h b/src/detect-engine-hrhd.h index c33d57e7d7e4..132ca642ba44 100644 --- a/src/detect-engine-hrhd.h +++ b/src/detect-engine-hrhd.h @@ -25,15 +25,14 @@ #include "app-layer-htp.h" +int PrefilterTxRequestHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxResponseHeadersRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpRawHeader(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpRawHeaderRegisterTests(void); #endif /* __DETECT_ENGINE_HHD_H__ */ diff --git a/src/detect-engine-hrhhd.c b/src/detect-engine-hrhhd.c index 273c8b6d6a8b..455b98c76737 100644 --- a/src/detect-engine-hrhhd.c +++ b/src/detect-engine-hrhhd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP host header. * HRHHD - Http Raw Host Header Data @@ -41,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -58,40 +60,57 @@ #include "app-layer-protos.h" #include "detect-engine-hrhhd.h" +#include "util-validate.h" -int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +/** \brief HTTP Host (Raw) Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHostnameRaw(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; - uint8_t *hname = NULL; + const uint8_t *hname = NULL; uint32_t hname_len = 0; if (tx->parsed_uri == NULL || tx->parsed_uri->hostname == NULL) { if (tx->request_headers == NULL) - goto end; - htp_header_t *h = NULL; - h = (htp_header_t *)htp_table_get_c(tx->request_headers, "Host"); - if (h != NULL) { - SCLogDebug("HTTP host header not present in this request"); - hname = (uint8_t *)bstr_ptr(h->value); - hname_len = bstr_len(h->value); - } else { - goto end; - } + return; + + htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, + "Host"); + if (h == NULL || h->value == NULL) + return; + + hname = (const uint8_t *)bstr_ptr(h->value); + hname_len = bstr_len(h->value); } else { - hname = (uint8_t *)bstr_ptr(tx->parsed_uri->hostname); - if (hname != NULL) - hname_len = bstr_len(tx->parsed_uri->hostname); - else - goto end; + hname = (const uint8_t *)bstr_ptr(tx->parsed_uri->hostname); + hname_len = bstr_len(tx->parsed_uri->hostname); } - cnt = HttpHRHPatternSearch(det_ctx, hname, hname_len, flags); + if (hname != NULL && hname_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, hname, hname_len); + } +} - end: - return cnt; +int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHostnameRaw, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, "http_raw_host"); } /** @@ -108,11 +127,9 @@ int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpHRH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { uint8_t *hname; uint32_t hname_len; @@ -136,16 +153,16 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRHHDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, hname, hname_len, 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -210,15 +227,16 @@ static int DetectEngineHttpHRHTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -308,15 +326,16 @@ static int DetectEngineHttpHRHTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -406,15 +425,16 @@ static int DetectEngineHttpHRHTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -504,15 +524,16 @@ static int DetectEngineHttpHRHTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -602,15 +623,16 @@ static int DetectEngineHttpHRHTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -700,15 +722,16 @@ static int DetectEngineHttpHRHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -798,15 +821,16 @@ static int DetectEngineHttpHRHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -896,15 +920,16 @@ static int DetectEngineHttpHRHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -994,15 +1019,16 @@ static int DetectEngineHttpHRHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1093,15 +1119,16 @@ static int DetectEngineHttpHRHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1192,15 +1219,16 @@ static int DetectEngineHttpHRHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1291,15 +1319,16 @@ static int DetectEngineHttpHRHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1390,15 +1419,16 @@ static int DetectEngineHttpHRHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1489,15 +1519,16 @@ static int DetectEngineHttpHRHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1588,15 +1619,16 @@ static int DetectEngineHttpHRHTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1687,15 +1719,16 @@ static int DetectEngineHttpHRHTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1786,15 +1819,16 @@ static int DetectEngineHttpHRHTest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1880,15 +1914,16 @@ static int DetectEngineHttpHRHTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1974,15 +2009,16 @@ static int DetectEngineHttpHRHTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2068,15 +2104,16 @@ static int DetectEngineHttpHRHTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2161,15 +2198,16 @@ static int DetectEngineHttpHRHTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2254,15 +2292,16 @@ static int DetectEngineHttpHRHTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2347,15 +2386,16 @@ static int DetectEngineHttpHRHTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2441,15 +2481,16 @@ static int DetectEngineHttpHRHTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2535,15 +2576,16 @@ static int DetectEngineHttpHRHTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2584,56 +2626,31 @@ void DetectEngineHttpHRHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpHRHTest01", - DetectEngineHttpHRHTest01, 1); - UtRegisterTest("DetectEngineHttpHRHTest02", - DetectEngineHttpHRHTest02, 1); - UtRegisterTest("DetectEngineHttpHRHTest03", - DetectEngineHttpHRHTest03, 1); - UtRegisterTest("DetectEngineHttpHRHTest04", - DetectEngineHttpHRHTest04, 1); - UtRegisterTest("DetectEngineHttpHRHTest05", - DetectEngineHttpHRHTest05, 1); - UtRegisterTest("DetectEngineHttpHRHTest06", - DetectEngineHttpHRHTest06, 1); - UtRegisterTest("DetectEngineHttpHRHTest07", - DetectEngineHttpHRHTest07, 1); - UtRegisterTest("DetectEngineHttpHRHTest08", - DetectEngineHttpHRHTest08, 1); - UtRegisterTest("DetectEngineHttpHRHTest09", - DetectEngineHttpHRHTest09, 1); - UtRegisterTest("DetectEngineHttpHRHTest10", - DetectEngineHttpHRHTest10, 1); - UtRegisterTest("DetectEngineHttpHRHTest11", - DetectEngineHttpHRHTest11, 1); - UtRegisterTest("DetectEngineHttpHRHTest12", - DetectEngineHttpHRHTest12, 1); - UtRegisterTest("DetectEngineHttpHRHTest13", - DetectEngineHttpHRHTest13, 1); - UtRegisterTest("DetectEngineHttpHRHTest14", - DetectEngineHttpHRHTest14, 1); - UtRegisterTest("DetectEngineHttpHRHTest15", - DetectEngineHttpHRHTest15, 1); - UtRegisterTest("DetectEngineHttpHRHTest16", - DetectEngineHttpHRHTest16, 1); - UtRegisterTest("DetectEngineHttpHRHTest17", - DetectEngineHttpHRHTest17, 1); - UtRegisterTest("DetectEngineHttpHRHTest18", - DetectEngineHttpHRHTest18, 1); - UtRegisterTest("DetectEngineHttpHRHTest19", - DetectEngineHttpHRHTest19, 1); - UtRegisterTest("DetectEngineHttpHRHTest20", - DetectEngineHttpHRHTest20, 1); - UtRegisterTest("DetectEngineHttpHRHTest21", - DetectEngineHttpHRHTest21, 1); - UtRegisterTest("DetectEngineHttpHRHTest22", - DetectEngineHttpHRHTest22, 1); - UtRegisterTest("DetectEngineHttpHRHTest23", - DetectEngineHttpHRHTest23, 1); - UtRegisterTest("DetectEngineHttpHRHTest24", - DetectEngineHttpHRHTest24, 1); - UtRegisterTest("DetectEngineHttpHRHTest25", - DetectEngineHttpHRHTest25, 1); + UtRegisterTest("DetectEngineHttpHRHTest01", DetectEngineHttpHRHTest01); + UtRegisterTest("DetectEngineHttpHRHTest02", DetectEngineHttpHRHTest02); + UtRegisterTest("DetectEngineHttpHRHTest03", DetectEngineHttpHRHTest03); + UtRegisterTest("DetectEngineHttpHRHTest04", DetectEngineHttpHRHTest04); + UtRegisterTest("DetectEngineHttpHRHTest05", DetectEngineHttpHRHTest05); + UtRegisterTest("DetectEngineHttpHRHTest06", DetectEngineHttpHRHTest06); + UtRegisterTest("DetectEngineHttpHRHTest07", DetectEngineHttpHRHTest07); + UtRegisterTest("DetectEngineHttpHRHTest08", DetectEngineHttpHRHTest08); + UtRegisterTest("DetectEngineHttpHRHTest09", DetectEngineHttpHRHTest09); + UtRegisterTest("DetectEngineHttpHRHTest10", DetectEngineHttpHRHTest10); + UtRegisterTest("DetectEngineHttpHRHTest11", DetectEngineHttpHRHTest11); + UtRegisterTest("DetectEngineHttpHRHTest12", DetectEngineHttpHRHTest12); + UtRegisterTest("DetectEngineHttpHRHTest13", DetectEngineHttpHRHTest13); + UtRegisterTest("DetectEngineHttpHRHTest14", DetectEngineHttpHRHTest14); + UtRegisterTest("DetectEngineHttpHRHTest15", DetectEngineHttpHRHTest15); + UtRegisterTest("DetectEngineHttpHRHTest16", DetectEngineHttpHRHTest16); + UtRegisterTest("DetectEngineHttpHRHTest17", DetectEngineHttpHRHTest17); + UtRegisterTest("DetectEngineHttpHRHTest18", DetectEngineHttpHRHTest18); + UtRegisterTest("DetectEngineHttpHRHTest19", DetectEngineHttpHRHTest19); + UtRegisterTest("DetectEngineHttpHRHTest20", DetectEngineHttpHRHTest20); + UtRegisterTest("DetectEngineHttpHRHTest21", DetectEngineHttpHRHTest21); + UtRegisterTest("DetectEngineHttpHRHTest22", DetectEngineHttpHRHTest22); + UtRegisterTest("DetectEngineHttpHRHTest23", DetectEngineHttpHRHTest23); + UtRegisterTest("DetectEngineHttpHRHTest24", DetectEngineHttpHRHTest24); + UtRegisterTest("DetectEngineHttpHRHTest25", DetectEngineHttpHRHTest25); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrhhd.h b/src/detect-engine-hrhhd.h index 24c3b43e219a..4523cbc4253a 100644 --- a/src/detect-engine-hrhhd.h +++ b/src/detect-engine-hrhhd.h @@ -25,15 +25,13 @@ #include "app-layer-htp.h" +int PrefilterTxHostnameRawRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpHRH(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpHRHMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpHRHRegisterTests(void); #endif /* __DETECT_ENGINE_HRHHD_H__ */ diff --git a/src/detect-engine-hrud.c b/src/detect-engine-hrud.c index 343054b9ad8e..e41c4fdff3ea 100644 --- a/src/detect-engine-hrud.c +++ b/src/detect-engine-hrud.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP raw uri match */ @@ -40,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -56,28 +58,44 @@ #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" -/** - * \brief Run the mpm against raw http uris. +/** \brief HTTP URI Raw Mpm prefilter callback * - * \retval cnt Number of matches reported by the mpm algo. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +static void PrefilterTxRawUri(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; - uint32_t cnt = 0; - if (tx->request_uri == NULL) - goto end; - cnt = HttpRawUriPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->request_uri), - bstr_len(tx->request_uri), flags); -end: - SCReturnInt(cnt); + if (likely(tx->request_uri != NULL)) { + const uint32_t uri_len = bstr_len(tx->request_uri); + const uint8_t *uri = bstr_ptr(tx->request_uri); + + if (uri_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + } + } +} + +int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxRawUri, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, "http_raw_uri"); } /** @@ -94,15 +112,13 @@ int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpRawUri(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->request_uri == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -113,12 +129,12 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv, det_ctx->inspection_recursion_counter = 0; /* Inspect all the uricontents fetched on each * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HRUDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRUD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else @@ -195,15 +211,16 @@ static int DetectEngineHttpRawUriTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -220,15 +237,16 @@ static int DetectEngineHttpRawUriTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -319,15 +337,16 @@ static int DetectEngineHttpRawUriTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -429,15 +448,16 @@ static int DetectEngineHttpRawUriTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -454,15 +474,16 @@ static int DetectEngineHttpRawUriTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -557,15 +578,16 @@ static int DetectEngineHttpRawUriTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -582,15 +604,16 @@ static int DetectEngineHttpRawUriTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -684,15 +707,16 @@ static int DetectEngineHttpRawUriTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -709,15 +733,16 @@ static int DetectEngineHttpRawUriTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -811,15 +836,16 @@ static int DetectEngineHttpRawUriTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -836,15 +862,16 @@ static int DetectEngineHttpRawUriTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -938,15 +965,16 @@ static int DetectEngineHttpRawUriTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -963,15 +991,16 @@ static int DetectEngineHttpRawUriTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1065,15 +1094,16 @@ static int DetectEngineHttpRawUriTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1090,15 +1120,16 @@ static int DetectEngineHttpRawUriTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1193,15 +1224,16 @@ static int DetectEngineHttpRawUriTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1218,15 +1250,16 @@ static int DetectEngineHttpRawUriTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1321,15 +1354,16 @@ static int DetectEngineHttpRawUriTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1346,15 +1380,16 @@ static int DetectEngineHttpRawUriTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1449,15 +1484,16 @@ static int DetectEngineHttpRawUriTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1474,15 +1510,16 @@ static int DetectEngineHttpRawUriTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1577,15 +1614,16 @@ static int DetectEngineHttpRawUriTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1602,15 +1640,16 @@ static int DetectEngineHttpRawUriTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1705,15 +1744,16 @@ static int DetectEngineHttpRawUriTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1730,15 +1770,16 @@ static int DetectEngineHttpRawUriTest13(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1833,15 +1874,16 @@ static int DetectEngineHttpRawUriTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1858,15 +1900,16 @@ static int DetectEngineHttpRawUriTest14(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1961,15 +2004,16 @@ static int DetectEngineHttpRawUriTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1986,15 +2030,16 @@ static int DetectEngineHttpRawUriTest15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2089,15 +2134,16 @@ static int DetectEngineHttpRawUriTest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2114,15 +2160,16 @@ static int DetectEngineHttpRawUriTest16(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2151,294 +2198,6 @@ static int DetectEngineHttpRawUriTest16(void) return result; } -static int DetectEngineHttpRawUriTest17(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"body1\"; http_raw_uri; " - "content:\"bambu\"; http_raw_uri; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 1) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpRawUriTest18(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"body1\"; http_raw_uri; " - "content:\"bambu\"; http_raw_uri; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 0) { - printf("expected 0 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpRawUriTest19(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"bambu\"; http_raw_uri; " - "content:\"is\"; http_raw_uri; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 0) { - printf("expected 0 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - -static int DetectEngineHttpRawUriTest20(void) -{ - TcpSession ssn; - Packet *p1 = NULL; - ThreadVars th_v; - DetectEngineCtx *de_ctx = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - uint8_t http1_buf[] = "This_is_dummy_body1"; - uint32_t http1_len = sizeof(http1_buf) - 1; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - - p1->flow = &f; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->flowflags |= FLOW_PKT_ESTABLISHED; - p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " - "(msg:\"http raw uri test\"; " - "content:\"bambu\"; http_raw_uri; " - "content:\"is\"; http_raw_uri; fast_pattern; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p1); - uint32_t r = HttpRawUriPatternSearch(det_ctx, http1_buf, http1_len, STREAM_TOSERVER); - if (r != 2) { - printf("expected 2 result, got %"PRIu32": ", r); - goto end; - } - - result = 1; - -end: - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - UTHFreePackets(&p1, 1); - return result; -} - static int DetectEngineHttpRawUriTest21(void) { TcpSession ssn; @@ -2505,15 +2264,16 @@ static int DetectEngineHttpRawUriTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2530,15 +2290,16 @@ static int DetectEngineHttpRawUriTest21(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2633,15 +2394,16 @@ static int DetectEngineHttpRawUriTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2658,15 +2420,16 @@ static int DetectEngineHttpRawUriTest22(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2761,15 +2524,16 @@ static int DetectEngineHttpRawUriTest23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2786,15 +2550,16 @@ static int DetectEngineHttpRawUriTest23(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2889,15 +2654,16 @@ static int DetectEngineHttpRawUriTest24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2914,15 +2680,16 @@ static int DetectEngineHttpRawUriTest24(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3017,15 +2784,16 @@ static int DetectEngineHttpRawUriTest25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3042,15 +2810,16 @@ static int DetectEngineHttpRawUriTest25(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3145,15 +2914,16 @@ static int DetectEngineHttpRawUriTest26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3170,15 +2940,16 @@ static int DetectEngineHttpRawUriTest26(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3273,15 +3044,16 @@ static int DetectEngineHttpRawUriTest27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3298,15 +3070,16 @@ static int DetectEngineHttpRawUriTest27(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3401,15 +3174,16 @@ static int DetectEngineHttpRawUriTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3426,15 +3200,16 @@ static int DetectEngineHttpRawUriTest28(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3503,7 +3278,6 @@ static int DetectEngineHttpRawUriTest29(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3517,14 +3291,15 @@ static int DetectEngineHttpRawUriTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3598,7 +3373,6 @@ static int DetectEngineHttpRawUriTest30(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3611,14 +3385,15 @@ static int DetectEngineHttpRawUriTest30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3658,65 +3433,57 @@ void DetectEngineHttpRawUriRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpRawUriTest01", - DetectEngineHttpRawUriTest01, 1); + DetectEngineHttpRawUriTest01); UtRegisterTest("DetectEngineHttpRawUriTest02", - DetectEngineHttpRawUriTest02, 1); + DetectEngineHttpRawUriTest02); UtRegisterTest("DetectEngineHttpRawUriTest03", - DetectEngineHttpRawUriTest03, 1); + DetectEngineHttpRawUriTest03); UtRegisterTest("DetectEngineHttpRawUriTest04", - DetectEngineHttpRawUriTest04, 1); + DetectEngineHttpRawUriTest04); UtRegisterTest("DetectEngineHttpRawUriTest05", - DetectEngineHttpRawUriTest05, 1); + DetectEngineHttpRawUriTest05); UtRegisterTest("DetectEngineHttpRawUriTest06", - DetectEngineHttpRawUriTest06, 1); + DetectEngineHttpRawUriTest06); UtRegisterTest("DetectEngineHttpRawUriTest07", - DetectEngineHttpRawUriTest07, 1); + DetectEngineHttpRawUriTest07); UtRegisterTest("DetectEngineHttpRawUriTest08", - DetectEngineHttpRawUriTest08, 1); + DetectEngineHttpRawUriTest08); UtRegisterTest("DetectEngineHttpRawUriTest09", - DetectEngineHttpRawUriTest09, 1); + DetectEngineHttpRawUriTest09); UtRegisterTest("DetectEngineHttpRawUriTest10", - DetectEngineHttpRawUriTest10, 1); + DetectEngineHttpRawUriTest10); UtRegisterTest("DetectEngineHttpRawUriTest11", - DetectEngineHttpRawUriTest11, 1); + DetectEngineHttpRawUriTest11); UtRegisterTest("DetectEngineHttpRawUriTest12", - DetectEngineHttpRawUriTest12, 1); + DetectEngineHttpRawUriTest12); UtRegisterTest("DetectEngineHttpRawUriTest13", - DetectEngineHttpRawUriTest13, 1); + DetectEngineHttpRawUriTest13); UtRegisterTest("DetectEngineHttpRawUriTest14", - DetectEngineHttpRawUriTest14, 1); + DetectEngineHttpRawUriTest14); UtRegisterTest("DetectEngineHttpRawUriTest15", - DetectEngineHttpRawUriTest15, 1); + DetectEngineHttpRawUriTest15); UtRegisterTest("DetectEngineHttpRawUriTest16", - DetectEngineHttpRawUriTest16, 1); - UtRegisterTest("DetectEngineHttpRawUriTest17", - DetectEngineHttpRawUriTest17, 1); - UtRegisterTest("DetectEngineHttpRawUriTest18", - DetectEngineHttpRawUriTest18, 1); - UtRegisterTest("DetectEngineHttpRawUriTest19", - DetectEngineHttpRawUriTest19, 1); - UtRegisterTest("DetectEngineHttpRawUriTest20", - DetectEngineHttpRawUriTest20, 1); + DetectEngineHttpRawUriTest16); UtRegisterTest("DetectEngineHttpRawUriTest21", - DetectEngineHttpRawUriTest21, 1); + DetectEngineHttpRawUriTest21); UtRegisterTest("DetectEngineHttpRawUriTest22", - DetectEngineHttpRawUriTest22, 1); + DetectEngineHttpRawUriTest22); UtRegisterTest("DetectEngineHttpRawUriTest23", - DetectEngineHttpRawUriTest23, 1); + DetectEngineHttpRawUriTest23); UtRegisterTest("DetectEngineHttpRawUriTest24", - DetectEngineHttpRawUriTest24, 1); + DetectEngineHttpRawUriTest24); UtRegisterTest("DetectEngineHttpRawUriTest25", - DetectEngineHttpRawUriTest25, 1); + DetectEngineHttpRawUriTest25); UtRegisterTest("DetectEngineHttpRawUriTest26", - DetectEngineHttpRawUriTest26, 1); + DetectEngineHttpRawUriTest26); UtRegisterTest("DetectEngineHttpRawUriTest27", - DetectEngineHttpRawUriTest27, 1); + DetectEngineHttpRawUriTest27); UtRegisterTest("DetectEngineHttpRawUriTest28", - DetectEngineHttpRawUriTest28, 1); + DetectEngineHttpRawUriTest28); UtRegisterTest("DetectEngineHttpRawUriTest29", - DetectEngineHttpRawUriTest29, 1); + DetectEngineHttpRawUriTest29); UtRegisterTest("DetectEngineHttpRawUriTest30", - DetectEngineHttpRawUriTest30, 1); + DetectEngineHttpRawUriTest30); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hrud.h b/src/detect-engine-hrud.h index 85ad88e1f687..2d41f69650cc 100644 --- a/src/detect-engine-hrud.h +++ b/src/detect-engine-hrud.h @@ -26,15 +26,13 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpRawUriMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxRawUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpRawUri(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpRawUriRegisterTests(void); #endif /* __DETECT_ENGINE_HRUD_H__ */ diff --git a/src/detect-engine-hsbd.c b/src/detect-engine-hsbd.c index 05583727c9c7..58727dca0138 100644 --- a/src/detect-engine-hsbd.c +++ b/src/detect-engine-hsbd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -42,6 +42,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -56,15 +57,21 @@ #include "util-unittest-helper.h" #include "app-layer.h" #include "app-layer-htp.h" +#include "app-layer-htp-mem.h" #include "app-layer-protos.h" #include "conf.h" #include "conf-yaml-loader.h" +#include "util-validate.h" + #define BUFFER_STEP 50 -static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) +static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint64_t size) { + if (size >= (USHRT_MAX - BUFFER_STEP)) + return -1; + void *ptmp; if (size > det_ctx->hsbd_buffers_size) { ptmp = SCRealloc(det_ctx->hsbd, @@ -81,7 +88,8 @@ static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) memset(det_ctx->hsbd + det_ctx->hsbd_buffers_size, 0, BUFFER_STEP * sizeof(HttpReassembledBody)); det_ctx->hsbd_buffers_size += BUFFER_STEP; } - for (int i = det_ctx->hsbd_buffers_list_len; i < (size); i++) { + uint16_t i; + for (i = det_ctx->hsbd_buffers_list_len; i < ((uint16_t)size); i++) { det_ctx->hsbd[i].buffer_len = 0; det_ctx->hsbd[i].offset = 0; } @@ -89,8 +97,7 @@ static inline int HSBDCreateSpace(DetectEngineThreadCtx *det_ctx, uint16_t size) return 0; } - -static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, +static const uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Flow *f, HtpState *htp_state, @@ -99,19 +106,21 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, uint32_t *stream_start_offset) { int index = 0; - uint8_t *buffer = NULL; + const uint8_t *buffer = NULL; *buffer_len = 0; *stream_start_offset = 0; if (det_ctx->hsbd_buffers_list_len == 0) { - if (HSBDCreateSpace(det_ctx, 1) < 0) + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint64_t txs = (tx_id - base_inspect_id) + 1; + if (HSBDCreateSpace(det_ctx, txs) < 0) goto end; - index = 0; - - if (det_ctx->hsbd_buffers_list_len == 0) { - det_ctx->hsbd_start_tx_id = tx_id; - } - det_ctx->hsbd_buffers_list_len++; + index = (tx_id - base_inspect_id); + det_ctx->hsbd_start_tx_id = base_inspect_id; + det_ctx->hsbd_buffers_list_len = txs; } else { if ((tx_id - det_ctx->hsbd_start_tx_id) < det_ctx->hsbd_buffers_list_len) { if (det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer_len != 0) { @@ -120,13 +129,11 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return det_ctx->hsbd[(tx_id - det_ctx->hsbd_start_tx_id)].buffer; } } else { - if (HSBDCreateSpace(det_ctx, (tx_id - det_ctx->hsbd_start_tx_id) + 1) < 0) + uint64_t txs = (tx_id - det_ctx->hsbd_start_tx_id) + 1; + if (HSBDCreateSpace(det_ctx, txs) < 0) goto end; - if (det_ctx->hsbd_buffers_list_len == 0) { - det_ctx->hsbd_start_tx_id = tx_id; - } - det_ctx->hsbd_buffers_list_len++; + det_ctx->hsbd_buffers_list_len = txs; } index = (tx_id - det_ctx->hsbd_start_tx_id); } @@ -149,70 +156,60 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, goto end; } - SCLogDebug("response_body_limit %u response_body.content_len_so_far %"PRIu64 - ", response_inspect_min_size %"PRIu32", EOF %s, progress > body? %s", - htp_state->cfg->response_body_limit, + SCLogDebug("response.body_limit %u response_body.content_len_so_far %"PRIu64 + ", response.inspect_min_size %"PRIu32", EOF %s, progress > body? %s", + htp_state->cfg->response.body_limit, htud->response_body.content_len_so_far, - htp_state->cfg->response_inspect_min_size, + htp_state->cfg->response.inspect_min_size, flags & STREAM_EOF ? "true" : "false", - (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) ? "true" : "false"); - - /* inspect the body if the transfer is complete or we have hit - * our body size limit */ - if ((htp_state->cfg->response_body_limit == 0 || - htud->response_body.content_len_so_far < htp_state->cfg->response_body_limit) && - htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size && - !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) && - !(flags & STREAM_EOF)) { - SCLogDebug("we still haven't seen the entire response body. " - "Let's defer body inspection till we see the " - "entire body."); - goto end; - } - - int first = 1; - while (cur != NULL) { - /* see if we can filter out chunks */ - if (htud->response_body.body_inspected > 0) { - if (cur->stream_offset < htud->response_body.body_inspected) { - if ((htud->response_body.body_inspected - cur->stream_offset) > htp_state->cfg->response_inspect_window) { - cur = cur->next; - continue; - } else { - /* include this one */ - } - } else { - /* include this one */ - } - } - - if (first) { - det_ctx->hsbd[index].offset = cur->stream_offset; - first = 0; + (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) ? "true" : "false"); + + if (!htp_state->cfg->http_body_inline) { + /* inspect the body if the transfer is complete or we have hit + * our body size limit */ + if ((htp_state->cfg->response.body_limit == 0 || + htud->response_body.content_len_so_far < htp_state->cfg->response.body_limit) && + htud->response_body.content_len_so_far < htp_state->cfg->response.inspect_min_size && + !(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) && + !(flags & STREAM_EOF)) { + SCLogDebug("we still haven't seen the entire response body. " + "Let's defer body inspection till we see the " + "entire body."); + goto end; } + } - /* see if we need to grow the buffer */ - if (det_ctx->hsbd[index].buffer == NULL || (det_ctx->hsbd[index].buffer_len + cur->len) > det_ctx->hsbd[index].buffer_size) { - void *ptmp; - det_ctx->hsbd[index].buffer_size += cur->len * 2; - - if ((ptmp = SCRealloc(det_ctx->hsbd[index].buffer, det_ctx->hsbd[index].buffer_size)) == NULL) { - SCFree(det_ctx->hsbd[index].buffer); - det_ctx->hsbd[index].buffer = NULL; - det_ctx->hsbd[index].buffer_size = 0; - det_ctx->hsbd[index].buffer_len = 0; - goto end; - } - det_ctx->hsbd[index].buffer = ptmp; + /* get the inspect buffer + * + * make sure that we have at least the configured inspect_win size. + * If we have more, take at least 1/4 of the inspect win size before + * the new data. + */ + uint64_t offset = 0; + if (htud->response_body.body_inspected > htp_state->cfg->response.inspect_min_size) { + BUG_ON(htud->response_body.content_len_so_far < htud->response_body.body_inspected); + uint64_t inspect_win = htud->response_body.content_len_so_far - htud->response_body.body_inspected; + SCLogDebug("inspect_win %u", (uint)inspect_win); + if (inspect_win < htp_state->cfg->response.inspect_window) { + uint64_t inspect_short = htp_state->cfg->response.inspect_window - inspect_win; + if (htud->response_body.body_inspected < inspect_short) + offset = 0; + else + offset = htud->response_body.body_inspected - inspect_short; + } else { + offset = htud->response_body.body_inspected - (htp_state->cfg->response.inspect_window / 4); } - memcpy(det_ctx->hsbd[index].buffer + det_ctx->hsbd[index].buffer_len, cur->data, cur->len); - det_ctx->hsbd[index].buffer_len += cur->len; - - cur = cur->next; } - /* update inspected tracker */ - htud->response_body.body_inspected = htud->response_body.last->stream_offset + htud->response_body.last->len; + StreamingBufferGetDataAtOffset(htud->response_body.sb, + &det_ctx->hsbd[index].buffer, &det_ctx->hsbd[index].buffer_len, + offset); + det_ctx->hsbd[index].offset = offset; + + /* move inspected tracker to end of the data. HtpBodyPrune will consider + * the window sizes when freeing data */ + htud->response_body.body_inspected = htud->response_body.content_len_so_far; + SCLogDebug("htud->response_body.body_inspected now: %"PRIu64, htud->response_body.body_inspected); buffer = det_ctx->hsbd[index].buffer; *buffer_len = det_ctx->hsbd[index].buffer_len; @@ -221,40 +218,58 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id, return buffer; } -int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx) +/** \brief HTTP Server Body Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseBody(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpState *htp_state = f->alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, idx, - de_ctx, det_ctx, + const uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, flags, &buffer_len, &stream_start_offset); - if (buffer_len == 0) - goto end; - cnt = HttpServerBodyPatternSearch(det_ctx, buffer, buffer_len, flags); + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); - end: - return cnt; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseBody, + ALPROTO_HTTP, HTP_RESPONSE_BODY, + mpm_ctx, NULL, "file_data (http response)"); } + int DetectEngineInspectHttpServerBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) { HtpState *htp_state = (HtpState *)alstate; uint32_t buffer_len = 0; uint32_t stream_start_offset = 0; - uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, tx_id, + const uint8_t *buffer = DetectEngineHSBDGetBufferForTX(tx, tx_id, de_ctx, det_ctx, f, htp_state, flags, @@ -266,17 +281,17 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HSBDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, - buffer, + (uint8_t *)buffer, buffer_len, stream_start_offset, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSBD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -300,6 +315,123 @@ void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx) #ifdef UNITTESTS +struct TestSteps { + const uint8_t *input; + size_t input_size; /**< if 0 strlen will be used */ + int direction; /**< STREAM_TOSERVER, STREAM_TOCLIENT */ + int expect; +}; + +static int RunTest(struct TestSteps *steps, const char *sig, const char *yaml) +{ + TcpSession ssn; + Flow f; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + int i = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + if (yaml) { + ConfCreateContextBackup(); + ConfInit(); + HtpConfigCreateBackup(); + + ConfYamlLoadString(yaml, strlen(yaml)); + HTPConfigure(); + EngineModeSetIPS(); + } + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + f.alproto = ALPROTO_HTTP; + + SCLogDebug("sig %s", sig); + DetectEngineAppendSig(de_ctx, (char *)sig); + + de_ctx->flags |= DE_QUIET; + + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + struct TestSteps *b = steps; + i = 0; + while (b->input != NULL) { + SCLogDebug("chunk %p %d", b, i); + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + if (p == NULL) + goto end; + p->flow = &f; + p->flowflags = (b->direction == STREAM_TOSERVER) ? FLOW_PKT_TOSERVER : FLOW_PKT_TOCLIENT; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + b->direction, (uint8_t *)b->input, + b->input_size ? b->input_size : strlen((const char *)b->input)); + if (r != 0) { + printf("toserver chunk %d returned %" PRId32 ", expected 0: ", i+1, r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + int match = PacketAlertCheck(p, 1); + if (b->expect != match) { + printf("rule matching mismatch: "); + goto end; + } + + UTHFreePackets(&p, 1); + p = NULL; + b++; + i++; + } + result = 1; + + end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + + if (yaml) { + HtpConfigRestoreBackup(); + ConfRestoreContextBackup(); + EngineModeSetIDS(); + } + return result; +} + static int DetectEngineHttpServerBodyTest01(void) { TcpSession ssn; @@ -366,15 +498,16 @@ static int DetectEngineHttpServerBodyTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -391,15 +524,16 @@ static int DetectEngineHttpServerBodyTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -488,25 +622,27 @@ static int DetectEngineHttpServerBodyTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -610,15 +746,16 @@ static int DetectEngineHttpServerBodyTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -635,25 +772,27 @@ static int DetectEngineHttpServerBodyTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -748,15 +887,16 @@ static int DetectEngineHttpServerBodyTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -773,15 +913,16 @@ static int DetectEngineHttpServerBodyTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -876,15 +1017,16 @@ static int DetectEngineHttpServerBodyTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -901,15 +1043,16 @@ static int DetectEngineHttpServerBodyTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1004,15 +1147,16 @@ static int DetectEngineHttpServerBodyTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1029,15 +1173,16 @@ static int DetectEngineHttpServerBodyTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1132,15 +1277,16 @@ static int DetectEngineHttpServerBodyTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1157,15 +1303,16 @@ static int DetectEngineHttpServerBodyTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1260,15 +1407,16 @@ static int DetectEngineHttpServerBodyTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1285,15 +1433,16 @@ static int DetectEngineHttpServerBodyTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1389,15 +1538,16 @@ static int DetectEngineHttpServerBodyTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1414,15 +1564,16 @@ static int DetectEngineHttpServerBodyTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1518,15 +1669,16 @@ static int DetectEngineHttpServerBodyTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1543,15 +1695,16 @@ static int DetectEngineHttpServerBodyTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1647,15 +1800,16 @@ static int DetectEngineHttpServerBodyTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1672,15 +1826,16 @@ static int DetectEngineHttpServerBodyTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1776,15 +1931,16 @@ static int DetectEngineHttpServerBodyTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1801,15 +1957,16 @@ static int DetectEngineHttpServerBodyTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1905,15 +2062,16 @@ static int DetectEngineHttpServerBodyTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1930,15 +2088,16 @@ static int DetectEngineHttpServerBodyTest13(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2034,15 +2193,16 @@ static int DetectEngineHttpServerBodyTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2059,15 +2219,16 @@ static int DetectEngineHttpServerBodyTest14(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2163,15 +2324,16 @@ static int DetectEngineHttpServerBodyTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2188,15 +2350,16 @@ static int DetectEngineHttpServerBodyTest15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2317,15 +2480,16 @@ libhtp:\n\ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2342,15 +2506,16 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2360,15 +2525,16 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2493,15 +2659,16 @@ libhtp:\n\ SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2518,15 +2685,16 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2536,15 +2704,16 @@ libhtp:\n\ goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2653,7 +2822,8 @@ static int DetectEngineHttpServerBodyTest18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2675,7 +2845,8 @@ static int DetectEngineHttpServerBodyTest18(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2783,7 +2954,8 @@ static int DetectEngineHttpServerBodyTest19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2805,7 +2977,8 @@ static int DetectEngineHttpServerBodyTest19(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2913,7 +3086,8 @@ static int DetectEngineHttpServerBodyTest20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -2935,7 +3109,8 @@ static int DetectEngineHttpServerBodyTest20(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -2945,10 +3120,9 @@ static int DetectEngineHttpServerBodyTest20(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + FAIL_IF(!(PacketAlertCheck(p2, 1))); +#endif result = 1; @@ -3045,7 +3219,8 @@ static int DetectEngineHttpServerBodyTest21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3067,7 +3242,8 @@ static int DetectEngineHttpServerBodyTest21(void) goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; @@ -3077,10 +3253,9 @@ static int DetectEngineHttpServerBodyTest21(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + FAIL_IF(!(PacketAlertCheck(p2, 1))); +#endif result = 1; @@ -3179,7 +3354,8 @@ static int DetectEngineHttpServerBodyTest22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; @@ -3197,13 +3373,14 @@ static int DetectEngineHttpServerBodyTest22(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if ((PacketAlertCheck(p1, 1))) { - printf("sid 1 matched but shouldn't have\n"); + printf("sid 1 matched but shouldn't have: "); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + printf("toserver chunk 2 returned %" PRId32 ", expected 0: \n", r); result = 0; goto end; } @@ -3211,10 +3388,9 @@ static int DetectEngineHttpServerBodyTest22(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 1)) { - printf("sid 1 matched but shouldn't have"); - goto end; - } +#ifdef HAVE_HTP_CONFIG_SET_RESPONSE_DECOMPRESSION_LAYER_LIMIT + FAIL_IF(!(PacketAlertCheck(p2, 1))); +#endif result = 1; @@ -3302,15 +3478,16 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3327,15 +3504,16 @@ static int DetectEngineHttpServerBodyFileDataTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3431,15 +3609,16 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3456,15 +3635,16 @@ static int DetectEngineHttpServerBodyFileDataTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3564,15 +3744,16 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3589,15 +3770,16 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3630,6 +3812,585 @@ static int DetectEngineHttpServerBodyFileDataTest03(void) return result; } +static int DetectEngineHttpServerBodyFileDataTest04(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"ef", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"abcd\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest05(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ef", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"abcdef\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest06(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ef", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"bcdef\"; offset:1; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest07(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"123456789", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"bc\"; offset:1; depth:2; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest08(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 14\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"1234567890", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"d123456789\"; offset:3; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest09(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"cd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"123456789", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"abcd12\"; depth:6; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest10(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"de", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"abc\"; depth:3; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest11(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 5\r\n" + "\r\n" + "ab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"de", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"bcde\"; offset:1; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest12(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 6\n\ + response-body-inspect-window: 3\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"b", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"d", + 0, STREAM_TOCLIENT, 1 }, + { (const uint8_t *)"efghijklm", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"abcd\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest13(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 13\r\n" + "\r\n" + "a", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"b", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"c", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"d", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"efghijklm", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"abcdefghijklm\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest14(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "1234567890", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"abcdefghi", + 0, STREAM_TOCLIENT, 1 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"890abcdefghi\"; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest15(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "1234567890", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"abcdefghi", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"7890ab\"; depth:6; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest16(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 9\n\ + response-body-inspect-window: 12\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"aabb\"; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest17(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 8\n\ + response-body-inspect-window: 4\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"bbbc\"; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} + +static int DetectEngineHttpServerBodyFileDataTest18(void) +{ + + const char yaml[] = "\ +%YAML 1.1\n\ +---\n\ +libhtp:\n\ +\n\ + default-config:\n\ +\n\ + http-body-inline: yes\n\ + response-body-minimal-inspect-size: 8\n\ + response-body-inspect-window: 4\n\ +"; + + struct TestSteps steps[] = { + { (const uint8_t *)"GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n", + 0, STREAM_TOSERVER, 0 }, + { (const uint8_t *)"HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 20\r\n" + "\r\n" + "aaaab", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"bbbbc", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"ccccd", + 0, STREAM_TOCLIENT, 0 }, + { (const uint8_t *)"dddde", + 0, STREAM_TOCLIENT, 0 }, + { NULL, 0, 0, 0 }, + }; + + const char *sig = "alert http any any -> any any (file_data; content:\"bccd\"; depth:4; sid:1;)"; + return RunTest(steps, sig, yaml); +} #endif /* UNITTESTS */ void DetectEngineHttpServerBodyRegisterTests(void) @@ -3637,56 +4398,87 @@ void DetectEngineHttpServerBodyRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpServerBodyTest01", - DetectEngineHttpServerBodyTest01, 1); + DetectEngineHttpServerBodyTest01); UtRegisterTest("DetectEngineHttpServerBodyTest02", - DetectEngineHttpServerBodyTest02, 1); + DetectEngineHttpServerBodyTest02); UtRegisterTest("DetectEngineHttpServerBodyTest03", - DetectEngineHttpServerBodyTest03, 1); + DetectEngineHttpServerBodyTest03); UtRegisterTest("DetectEngineHttpServerBodyTest04", - DetectEngineHttpServerBodyTest04, 1); + DetectEngineHttpServerBodyTest04); UtRegisterTest("DetectEngineHttpServerBodyTest05", - DetectEngineHttpServerBodyTest05, 1); + DetectEngineHttpServerBodyTest05); UtRegisterTest("DetectEngineHttpServerBodyTest06", - DetectEngineHttpServerBodyTest06, 1); + DetectEngineHttpServerBodyTest06); UtRegisterTest("DetectEngineHttpServerBodyTest07", - DetectEngineHttpServerBodyTest07, 1); + DetectEngineHttpServerBodyTest07); UtRegisterTest("DetectEngineHttpServerBodyTest08", - DetectEngineHttpServerBodyTest08, 1); + DetectEngineHttpServerBodyTest08); UtRegisterTest("DetectEngineHttpServerBodyTest09", - DetectEngineHttpServerBodyTest09, 1); + DetectEngineHttpServerBodyTest09); UtRegisterTest("DetectEngineHttpServerBodyTest10", - DetectEngineHttpServerBodyTest10, 1); + DetectEngineHttpServerBodyTest10); UtRegisterTest("DetectEngineHttpServerBodyTest11", - DetectEngineHttpServerBodyTest11, 1); + DetectEngineHttpServerBodyTest11); UtRegisterTest("DetectEngineHttpServerBodyTest12", - DetectEngineHttpServerBodyTest12, 1); + DetectEngineHttpServerBodyTest12); UtRegisterTest("DetectEngineHttpServerBodyTest13", - DetectEngineHttpServerBodyTest13, 1); + DetectEngineHttpServerBodyTest13); UtRegisterTest("DetectEngineHttpServerBodyTest14", - DetectEngineHttpServerBodyTest14, 1); + DetectEngineHttpServerBodyTest14); UtRegisterTest("DetectEngineHttpServerBodyTest15", - DetectEngineHttpServerBodyTest15, 1); + DetectEngineHttpServerBodyTest15); UtRegisterTest("DetectEngineHttpServerBodyTest16", - DetectEngineHttpServerBodyTest16, 1); + DetectEngineHttpServerBodyTest16); UtRegisterTest("DetectEngineHttpServerBodyTest17", - DetectEngineHttpServerBodyTest17, 1); + DetectEngineHttpServerBodyTest17); UtRegisterTest("DetectEngineHttpServerBodyTest18", - DetectEngineHttpServerBodyTest18, 1); + DetectEngineHttpServerBodyTest18); UtRegisterTest("DetectEngineHttpServerBodyTest19", - DetectEngineHttpServerBodyTest19, 1); + DetectEngineHttpServerBodyTest19); UtRegisterTest("DetectEngineHttpServerBodyTest20", - DetectEngineHttpServerBodyTest20, 1); + DetectEngineHttpServerBodyTest20); UtRegisterTest("DetectEngineHttpServerBodyTest21", - DetectEngineHttpServerBodyTest21, 1); + DetectEngineHttpServerBodyTest21); UtRegisterTest("DetectEngineHttpServerBodyTest22", - DetectEngineHttpServerBodyTest22, 1); + DetectEngineHttpServerBodyTest22); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest01", - DetectEngineHttpServerBodyFileDataTest01, 1); + DetectEngineHttpServerBodyFileDataTest01); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest02", - DetectEngineHttpServerBodyFileDataTest02, 1); + DetectEngineHttpServerBodyFileDataTest02); UtRegisterTest("DetectEngineHttpServerBodyFileDataTest03", - DetectEngineHttpServerBodyFileDataTest03, 1); + DetectEngineHttpServerBodyFileDataTest03); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest04", + DetectEngineHttpServerBodyFileDataTest04); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest05", + DetectEngineHttpServerBodyFileDataTest05); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest06", + DetectEngineHttpServerBodyFileDataTest06); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest07", + DetectEngineHttpServerBodyFileDataTest07); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest08", + DetectEngineHttpServerBodyFileDataTest08); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest09", + DetectEngineHttpServerBodyFileDataTest09); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest10", + DetectEngineHttpServerBodyFileDataTest10); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest11", + DetectEngineHttpServerBodyFileDataTest11); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest12", + DetectEngineHttpServerBodyFileDataTest12); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest13", + DetectEngineHttpServerBodyFileDataTest13); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest14", + DetectEngineHttpServerBodyFileDataTest14); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest15", + DetectEngineHttpServerBodyFileDataTest15); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest16", + DetectEngineHttpServerBodyFileDataTest16); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest17", + DetectEngineHttpServerBodyFileDataTest17); + UtRegisterTest("DetectEngineHttpServerBodyFileDataTest18", + DetectEngineHttpServerBodyFileDataTest18); + #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hsbd.h b/src/detect-engine-hsbd.h index a44248245fce..1187f936ef48 100644 --- a/src/detect-engine-hsbd.h +++ b/src/detect-engine-hsbd.h @@ -27,16 +27,14 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpServerBodyMpm(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxHttpResponseBodyRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpServerBody(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + void DetectEngineCleanHSBDBuffers(DetectEngineThreadCtx *det_ctx); void DetectEngineHttpServerBodyRegisterTests(void); diff --git a/src/detect-engine-hscd.c b/src/detect-engine-hscd.c index b54c79511d89..8a563235b167 100644 --- a/src/detect-engine-hscd.c +++ b/src/detect-engine-hscd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien */ #include "suricata-common.h" @@ -38,6 +39,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -53,29 +55,46 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" -/** - * \brief Run the mpm against http stat code. +/** \brief HTTP Status Code Mpm prefilter callback * - * \retval cnt Number of matches reported by the mpm algo. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +static void PrefilterTxHttpStatCode(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t cnt = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; + if (tx->response_status == NULL) - goto end; + return; - cnt = HttpStatCodePatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->response_status), - bstr_len(tx->response_status), flags); + const uint32_t buffer_len = bstr_len(tx->response_status); + const uint8_t *buffer = bstr_ptr(tx->response_status); -end: - SCReturnInt(cnt); + if (buffer != NULL && buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpStatCode, + ALPROTO_HTTP, + HTP_RESPONSE_LINE+1, /* inspect when response line completely parsed */ + mpm_ctx, NULL, "http_stat_code"); } /** @@ -92,15 +111,13 @@ int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpStatCode(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_status == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_RESPONSE_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -109,13 +126,12 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv, det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_HSCDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSCD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else @@ -192,15 +208,16 @@ static int DetectEngineHttpStatCodeTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -217,15 +234,16 @@ static int DetectEngineHttpStatCodeTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -314,25 +332,27 @@ static int DetectEngineHttpStatCodeTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -436,15 +456,16 @@ static int DetectEngineHttpStatCodeTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -461,25 +482,27 @@ static int DetectEngineHttpStatCodeTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -574,15 +597,16 @@ static int DetectEngineHttpStatCodeTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -599,15 +623,16 @@ static int DetectEngineHttpStatCodeTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -702,15 +727,16 @@ static int DetectEngineHttpStatCodeTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -727,15 +753,16 @@ static int DetectEngineHttpStatCodeTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -830,15 +857,16 @@ static int DetectEngineHttpStatCodeTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -855,15 +883,16 @@ static int DetectEngineHttpStatCodeTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -958,15 +987,16 @@ static int DetectEngineHttpStatCodeTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -983,15 +1013,16 @@ static int DetectEngineHttpStatCodeTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1086,15 +1117,16 @@ static int DetectEngineHttpStatCodeTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1111,15 +1143,16 @@ static int DetectEngineHttpStatCodeTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1215,15 +1248,16 @@ static int DetectEngineHttpStatCodeTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1240,15 +1274,16 @@ static int DetectEngineHttpStatCodeTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1344,15 +1379,16 @@ static int DetectEngineHttpStatCodeTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1369,15 +1405,16 @@ static int DetectEngineHttpStatCodeTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1473,15 +1510,16 @@ static int DetectEngineHttpStatCodeTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1498,15 +1536,16 @@ static int DetectEngineHttpStatCodeTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1602,15 +1641,16 @@ static int DetectEngineHttpStatCodeTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1627,15 +1667,16 @@ static int DetectEngineHttpStatCodeTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1731,15 +1772,16 @@ static int DetectEngineHttpStatCodeTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1756,15 +1798,16 @@ static int DetectEngineHttpStatCodeTest13(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1860,15 +1903,16 @@ static int DetectEngineHttpStatCodeTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1885,15 +1929,16 @@ static int DetectEngineHttpStatCodeTest14(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1989,15 +2034,16 @@ static int DetectEngineHttpStatCodeTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2014,15 +2060,16 @@ static int DetectEngineHttpStatCodeTest15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2058,35 +2105,35 @@ void DetectEngineHttpStatCodeRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpStatCodeTest01", - DetectEngineHttpStatCodeTest01, 1); + DetectEngineHttpStatCodeTest01); UtRegisterTest("DetectEngineHttpStatCodeTest02", - DetectEngineHttpStatCodeTest02, 1); + DetectEngineHttpStatCodeTest02); UtRegisterTest("DetectEngineHttpStatCodeTest03", - DetectEngineHttpStatCodeTest03, 1); + DetectEngineHttpStatCodeTest03); UtRegisterTest("DetectEngineHttpStatCodeTest04", - DetectEngineHttpStatCodeTest04, 1); + DetectEngineHttpStatCodeTest04); UtRegisterTest("DetectEngineHttpStatCodeTest05", - DetectEngineHttpStatCodeTest05, 1); + DetectEngineHttpStatCodeTest05); UtRegisterTest("DetectEngineHttpStatCodeTest06", - DetectEngineHttpStatCodeTest06, 1); + DetectEngineHttpStatCodeTest06); UtRegisterTest("DetectEngineHttpStatCodeTest07", - DetectEngineHttpStatCodeTest07, 1); + DetectEngineHttpStatCodeTest07); UtRegisterTest("DetectEngineHttpStatCodeTest08", - DetectEngineHttpStatCodeTest08, 1); + DetectEngineHttpStatCodeTest08); UtRegisterTest("DetectEngineHttpStatCodeTest09", - DetectEngineHttpStatCodeTest09, 1); + DetectEngineHttpStatCodeTest09); UtRegisterTest("DetectEngineHttpStatCodeTest10", - DetectEngineHttpStatCodeTest10, 1); + DetectEngineHttpStatCodeTest10); UtRegisterTest("DetectEngineHttpStatCodeTest11", - DetectEngineHttpStatCodeTest11, 1); + DetectEngineHttpStatCodeTest11); UtRegisterTest("DetectEngineHttpStatCodeTest12", - DetectEngineHttpStatCodeTest12, 1); + DetectEngineHttpStatCodeTest12); UtRegisterTest("DetectEngineHttpStatCodeTest13", - DetectEngineHttpStatCodeTest13, 1); + DetectEngineHttpStatCodeTest13); UtRegisterTest("DetectEngineHttpStatCodeTest14", - DetectEngineHttpStatCodeTest14, 1); + DetectEngineHttpStatCodeTest14); UtRegisterTest("DetectEngineHttpStatCodeTest15", - DetectEngineHttpStatCodeTest15, 1); + DetectEngineHttpStatCodeTest15); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hscd.h b/src/detect-engine-hscd.h index 2a97c2ff0de0..d2e4d2fff870 100644 --- a/src/detect-engine-hscd.h +++ b/src/detect-engine-hscd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,15 +25,13 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpStatCodeMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxHttpStatCodeRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpStatCode(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpStatCodeRegisterTests(void); #endif /* __DETECT_ENGINE_HSCD_H__ */ diff --git a/src/detect-engine-hsmd.c b/src/detect-engine-hsmd.c index 8881f3cf06dc..cb52c03535a3 100644 --- a/src/detect-engine-hsmd.c +++ b/src/detect-engine-hsmd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ * \file * * \author Anoop Saldanha + * \author Victor Julien */ #include "suricata-common.h" @@ -38,6 +39,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -53,29 +55,46 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" -/** - * \brief Run the mpm against http stat msg. +/** \brief HTTP Status Message Mpm prefilter callback * - * \retval cnt Number of matches reported by the mpm algo. + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +static void PrefilterTxHttpStatMsg(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { SCEnter(); - uint32_t cnt = 0; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; + if (tx->response_message == NULL) - goto end; + return; - cnt = HttpStatMsgPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(tx->response_message), - bstr_len(tx->response_message), flags); + const uint32_t buffer_len = bstr_len(tx->response_message); + const uint8_t *buffer = bstr_ptr(tx->response_message); -end: - SCReturnInt(cnt); + if (buffer != NULL && buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpStatMsg, + ALPROTO_HTTP, + HTP_RESPONSE_LINE+1, /* inspect when response line completely parsed */ + mpm_ctx, NULL, "http_stat_msg"); } /** @@ -92,15 +111,13 @@ int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; if (tx->response_message == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_RESPONSE_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -109,13 +126,12 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv, det_ctx->discontinue_matching = 0; det_ctx->buffer_offset = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, - s->sm_lists[DETECT_SM_LIST_HSMDMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(tx->response_message), bstr_len(tx->response_message), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HSMD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; else @@ -192,15 +208,16 @@ static int DetectEngineHttpStatMsgTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -217,15 +234,16 @@ static int DetectEngineHttpStatMsgTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -314,25 +332,27 @@ static int DetectEngineHttpStatMsgTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -436,15 +456,16 @@ static int DetectEngineHttpStatMsgTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -461,25 +482,27 @@ static int DetectEngineHttpStatMsgTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf3, http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -574,15 +597,16 @@ static int DetectEngineHttpStatMsgTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -599,15 +623,16 @@ static int DetectEngineHttpStatMsgTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -702,15 +727,16 @@ static int DetectEngineHttpStatMsgTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -727,15 +753,16 @@ static int DetectEngineHttpStatMsgTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -830,15 +857,16 @@ static int DetectEngineHttpStatMsgTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -855,15 +883,16 @@ static int DetectEngineHttpStatMsgTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -958,15 +987,16 @@ static int DetectEngineHttpStatMsgTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -983,15 +1013,16 @@ static int DetectEngineHttpStatMsgTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1086,15 +1117,16 @@ static int DetectEngineHttpStatMsgTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1111,15 +1143,16 @@ static int DetectEngineHttpStatMsgTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1215,15 +1248,16 @@ static int DetectEngineHttpStatMsgTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1240,15 +1274,16 @@ static int DetectEngineHttpStatMsgTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1344,15 +1379,16 @@ static int DetectEngineHttpStatMsgTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1369,15 +1405,16 @@ static int DetectEngineHttpStatMsgTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1473,15 +1510,16 @@ static int DetectEngineHttpStatMsgTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1498,15 +1536,16 @@ static int DetectEngineHttpStatMsgTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1602,15 +1641,16 @@ static int DetectEngineHttpStatMsgTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1627,15 +1667,16 @@ static int DetectEngineHttpStatMsgTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1731,15 +1772,16 @@ static int DetectEngineHttpStatMsgTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1756,15 +1798,16 @@ static int DetectEngineHttpStatMsgTest13(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1860,15 +1903,16 @@ static int DetectEngineHttpStatMsgTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1885,15 +1929,16 @@ static int DetectEngineHttpStatMsgTest14(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1989,15 +2034,16 @@ static int DetectEngineHttpStatMsgTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2014,15 +2060,16 @@ static int DetectEngineHttpStatMsgTest15(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2058,35 +2105,35 @@ void DetectEngineHttpStatMsgRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("DetectEngineHttpStatMsgTest01", - DetectEngineHttpStatMsgTest01, 1); + DetectEngineHttpStatMsgTest01); UtRegisterTest("DetectEngineHttpStatMsgTest02", - DetectEngineHttpStatMsgTest02, 1); + DetectEngineHttpStatMsgTest02); UtRegisterTest("DetectEngineHttpStatMsgTest03", - DetectEngineHttpStatMsgTest03, 1); + DetectEngineHttpStatMsgTest03); UtRegisterTest("DetectEngineHttpStatMsgTest04", - DetectEngineHttpStatMsgTest04, 1); + DetectEngineHttpStatMsgTest04); UtRegisterTest("DetectEngineHttpStatMsgTest05", - DetectEngineHttpStatMsgTest05, 1); + DetectEngineHttpStatMsgTest05); UtRegisterTest("DetectEngineHttpStatMsgTest06", - DetectEngineHttpStatMsgTest06, 1); + DetectEngineHttpStatMsgTest06); UtRegisterTest("DetectEngineHttpStatMsgTest07", - DetectEngineHttpStatMsgTest07, 1); + DetectEngineHttpStatMsgTest07); UtRegisterTest("DetectEngineHttpStatMsgTest08", - DetectEngineHttpStatMsgTest08, 1); + DetectEngineHttpStatMsgTest08); UtRegisterTest("DetectEngineHttpStatMsgTest09", - DetectEngineHttpStatMsgTest09, 1); + DetectEngineHttpStatMsgTest09); UtRegisterTest("DetectEngineHttpStatMsgTest10", - DetectEngineHttpStatMsgTest10, 1); + DetectEngineHttpStatMsgTest10); UtRegisterTest("DetectEngineHttpStatMsgTest11", - DetectEngineHttpStatMsgTest11, 1); + DetectEngineHttpStatMsgTest11); UtRegisterTest("DetectEngineHttpStatMsgTest12", - DetectEngineHttpStatMsgTest12, 1); + DetectEngineHttpStatMsgTest12); UtRegisterTest("DetectEngineHttpStatMsgTest13", - DetectEngineHttpStatMsgTest13, 1); + DetectEngineHttpStatMsgTest13); UtRegisterTest("DetectEngineHttpStatMsgTest14", - DetectEngineHttpStatMsgTest14, 1); + DetectEngineHttpStatMsgTest14); UtRegisterTest("DetectEngineHttpStatMsgTest15", - DetectEngineHttpStatMsgTest15, 1); + DetectEngineHttpStatMsgTest15); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hsmd.h b/src/detect-engine-hsmd.h index 01fc3612b772..36eee9024f49 100644 --- a/src/detect-engine-hsmd.h +++ b/src/detect-engine-hsmd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,15 +25,13 @@ #include "app-layer-htp.h" -int DetectEngineRunHttpStatMsgMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); +int PrefilterTxHttpStatMsgRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpStatMsg(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpStatMsgRegisterTests(void); #endif /* __DETECT_ENGINE_HSMD_H__ */ diff --git a/src/detect-engine-hua.c b/src/detect-engine-hua.c index d1bd0c2ff1ee..2511767c944e 100644 --- a/src/detect-engine-hua.c +++ b/src/detect-engine-hua.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,6 +25,7 @@ /** \file * * \author Anoop Saldanha + * \author Victor Julien * * \brief Handle HTTP user agent match * @@ -40,6 +41,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -57,28 +59,51 @@ #include "app-layer-protos.h" #include "detect-engine-hua.h" +#include "util-validate.h" -int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) +/** \brief HTTP UA Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxUA(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - uint32_t cnt = 0; + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; htp_tx_t *tx = (htp_tx_t *)txv; + if (tx->request_headers == NULL) - goto end; + return; htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, "User-Agent"); - if (h == NULL) { - SCLogDebug("HTTP user agent header not present in this request"); - goto end; + if (h == NULL || h->value == NULL) { + SCLogDebug("HTTP UA header not present in this request"); + return; } - cnt = HttpUAPatternSearch(det_ctx, - (uint8_t *)bstr_ptr(h->value), - bstr_len(h->value), flags); - end: - return cnt; + const uint32_t buffer_len = bstr_len(h->value); + const uint8_t *buffer = bstr_ptr(h->value); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxUA, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, "http_user_agent"); } /** @@ -95,11 +120,9 @@ int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, * \retval 1 Match. */ int DetectEngineInspectHttpUA(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { htp_tx_t *tx = (htp_tx_t *)txv; htp_header_t *h = (htp_header_t *)htp_table_get_c(tx->request_headers, @@ -112,17 +135,17 @@ int DetectEngineInspectHttpUA(ThreadVars *tv, det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_HUADMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, (uint8_t *)bstr_ptr(h->value), bstr_len(h->value), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) return DETECT_ENGINE_INSPECT_SIG_MATCH; end: - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -187,15 +210,16 @@ static int DetectEngineHttpUATest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -285,15 +309,16 @@ static int DetectEngineHttpUATest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -383,15 +408,16 @@ static int DetectEngineHttpUATest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -481,15 +507,16 @@ static int DetectEngineHttpUATest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -579,15 +606,16 @@ static int DetectEngineHttpUATest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -677,15 +705,16 @@ static int DetectEngineHttpUATest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -775,15 +804,16 @@ static int DetectEngineHttpUATest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -873,15 +903,16 @@ static int DetectEngineHttpUATest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -971,15 +1002,16 @@ static int DetectEngineHttpUATest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1070,15 +1102,16 @@ static int DetectEngineHttpUATest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1169,15 +1202,16 @@ static int DetectEngineHttpUATest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1268,15 +1302,16 @@ static int DetectEngineHttpUATest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1367,15 +1402,16 @@ static int DetectEngineHttpUATest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1466,15 +1502,16 @@ static int DetectEngineHttpUATest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1565,15 +1602,16 @@ static int DetectEngineHttpUATest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1664,15 +1702,16 @@ static int DetectEngineHttpUATest16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1763,15 +1802,16 @@ static int DetectEngineHttpUATest17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1812,40 +1852,23 @@ void DetectEngineHttpUARegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectEngineHttpUATest01", - DetectEngineHttpUATest01, 1); - UtRegisterTest("DetectEngineHttpUATest02", - DetectEngineHttpUATest02, 1); - UtRegisterTest("DetectEngineHttpUATest03", - DetectEngineHttpUATest03, 1); - UtRegisterTest("DetectEngineHttpUATest04", - DetectEngineHttpUATest04, 1); - UtRegisterTest("DetectEngineHttpUATest05", - DetectEngineHttpUATest05, 1); - UtRegisterTest("DetectEngineHttpUATest06", - DetectEngineHttpUATest06, 1); - UtRegisterTest("DetectEngineHttpUATest07", - DetectEngineHttpUATest07, 1); - UtRegisterTest("DetectEngineHttpUATest08", - DetectEngineHttpUATest08, 1); - UtRegisterTest("DetectEngineHttpUATest09", - DetectEngineHttpUATest09, 1); - UtRegisterTest("DetectEngineHttpUATest10", - DetectEngineHttpUATest10, 1); - UtRegisterTest("DetectEngineHttpUATest11", - DetectEngineHttpUATest11, 1); - UtRegisterTest("DetectEngineHttpUATest12", - DetectEngineHttpUATest12, 1); - UtRegisterTest("DetectEngineHttpUATest13", - DetectEngineHttpUATest13, 1); - UtRegisterTest("DetectEngineHttpUATest14", - DetectEngineHttpUATest14, 1); - UtRegisterTest("DetectEngineHttpUATest15", - DetectEngineHttpUATest15, 1); - UtRegisterTest("DetectEngineHttpUATest16", - DetectEngineHttpUATest16, 1); - UtRegisterTest("DetectEngineHttpUATest17", - DetectEngineHttpUATest17, 1); + UtRegisterTest("DetectEngineHttpUATest01", DetectEngineHttpUATest01); + UtRegisterTest("DetectEngineHttpUATest02", DetectEngineHttpUATest02); + UtRegisterTest("DetectEngineHttpUATest03", DetectEngineHttpUATest03); + UtRegisterTest("DetectEngineHttpUATest04", DetectEngineHttpUATest04); + UtRegisterTest("DetectEngineHttpUATest05", DetectEngineHttpUATest05); + UtRegisterTest("DetectEngineHttpUATest06", DetectEngineHttpUATest06); + UtRegisterTest("DetectEngineHttpUATest07", DetectEngineHttpUATest07); + UtRegisterTest("DetectEngineHttpUATest08", DetectEngineHttpUATest08); + UtRegisterTest("DetectEngineHttpUATest09", DetectEngineHttpUATest09); + UtRegisterTest("DetectEngineHttpUATest10", DetectEngineHttpUATest10); + UtRegisterTest("DetectEngineHttpUATest11", DetectEngineHttpUATest11); + UtRegisterTest("DetectEngineHttpUATest12", DetectEngineHttpUATest12); + UtRegisterTest("DetectEngineHttpUATest13", DetectEngineHttpUATest13); + UtRegisterTest("DetectEngineHttpUATest14", DetectEngineHttpUATest14); + UtRegisterTest("DetectEngineHttpUATest15", DetectEngineHttpUATest15); + UtRegisterTest("DetectEngineHttpUATest16", DetectEngineHttpUATest16); + UtRegisterTest("DetectEngineHttpUATest17", DetectEngineHttpUATest17); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-hua.h b/src/detect-engine-hua.h index c18ac76183c2..40c85887c7fe 100644 --- a/src/detect-engine-hua.h +++ b/src/detect-engine-hua.h @@ -25,15 +25,13 @@ #include "app-layer-htp.h" +int PrefilterTxUARegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectHttpUA(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -int DetectEngineRunHttpUAMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void DetectEngineHttpUARegisterTests(void); #endif /* __DETECT_ENGINE_HUA_H__ */ diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index a44c5bb8eb3e..bd47567781d1 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -73,7 +73,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRItemNew() item = SCMalloc(sizeof(IPOnlyCIDRItem)); if (unlikely(item == NULL)) - SCReturnPtr(NULL, "NULL"); + SCReturnPtr(NULL, "IPOnlyCIDRItem"); memset(item, 0, sizeof(IPOnlyCIDRItem)); SCReturnPtr(item, "IPOnlyCIDRItem"); @@ -423,7 +423,7 @@ void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead) while (it != NULL) { i++; SCFree(it); - SCLogDebug("Item(%p) %"PRIu32" removed\n", it, i); + SCLogDebug("Item(%p) %"PRIu32" removed", it, i); it = next; if (next != NULL) @@ -484,7 +484,7 @@ static void SigNumArrayPrint(void *tmp) for (; i < 8; i++) { if (bitarray & 0x01) - printf(", %"PRIu16"", u * 8 + i); + printf(", %"PRIu32"", u * 8 + i); else printf(", "); @@ -581,7 +581,8 @@ static void SigNumArrayFree(void *tmp) * \retval 0 if success * \retval -1 if fails */ -static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) +static IPOnlyCIDRItem *IPOnlyCIDRListParse2(const DetectEngineCtx *de_ctx, + char *s, int negate) { size_t x = 0; size_t u = 0; @@ -615,7 +616,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) address[x - 1] = '\0'; x = 0; - if ( (subhead = IPOnlyCIDRListParse2(address, + if ( (subhead = IPOnlyCIDRListParse2(de_ctx, address, (negate + n_set) % 2)) == NULL) goto error; @@ -629,7 +630,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) } else if (d_set == 1) { address[x - 1] = '\0'; - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -646,7 +647,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) "[%s]", rule_var_address); } - subhead = IPOnlyCIDRListParse2(temp_rule_var_address, + subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); @@ -689,7 +690,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) x = 0; if (d_set == 1) { - rule_var_address = SCRuleVarsGetConfVar(address, + rule_var_address = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_ADDRESS_GROUPS); if (rule_var_address == NULL) goto error; @@ -703,7 +704,7 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) snprintf(temp_rule_var_address, strlen(rule_var_address) + 3, "[%s]", rule_var_address); } - subhead = IPOnlyCIDRListParse2(temp_rule_var_address, + subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address, (negate + n_set) % 2); head = IPOnlyCIDRItemInsert(head, subhead); @@ -751,14 +752,15 @@ static IPOnlyCIDRItem *IPOnlyCIDRListParse2(char *s, int negate) * \retval 0 On success. * \retval -1 On failure. */ -static int IPOnlyCIDRListParse(IPOnlyCIDRItem **gh, char *str) +static int IPOnlyCIDRListParse(const DetectEngineCtx *de_ctx, + IPOnlyCIDRItem **gh, char *str) { SCLogDebug("gh %p, str %s", gh, str); if (gh == NULL) goto error; - *gh = IPOnlyCIDRListParse2(str, 0); + *gh = IPOnlyCIDRListParse2(de_ctx, str, 0); if (*gh == NULL) { SCLogDebug("DetectAddressParse2 returned null"); goto error; @@ -782,7 +784,8 @@ static int IPOnlyCIDRListParse(IPOnlyCIDRItem **gh, char *str) * \retval 0 On success. * \retval -1 On failure. */ -int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) +int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, + Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); IPOnlyCIDRItem *tmp = NULL; @@ -792,15 +795,15 @@ int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) if (strcasecmp(addrstr, "any") == 0) { s->flags |= SIG_FLAG_SRC_ANY; - if (IPOnlyCIDRListParse(&s->CidrSrc, (char *)"0.0.0.0/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &s->CidrSrc, (char *)"0.0.0.0/0") < 0) goto error; - if (IPOnlyCIDRListParse(&tmp, (char *)"::/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &tmp, (char *)"::/0") < 0) goto error; s->CidrSrc = IPOnlyCIDRItemInsert(s->CidrSrc, tmp); - } else if (IPOnlyCIDRListParse(&s->CidrSrc, (char *)addrstr) < 0) { + } else if (IPOnlyCIDRListParse(de_ctx, &s->CidrSrc, (char *)addrstr) < 0) { goto error; } @@ -809,15 +812,15 @@ int IPOnlySigParseAddress(Signature *s, const char *addrstr, char flag) if (strcasecmp(addrstr, "any") == 0) { s->flags |= SIG_FLAG_DST_ANY; - if (IPOnlyCIDRListParse(&tmp, (char *)"0.0.0.0/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &tmp, (char *)"0.0.0.0/0") < 0) goto error; - if (IPOnlyCIDRListParse(&s->CidrDst, (char *)"::/0") < 0) + if (IPOnlyCIDRListParse(de_ctx, &s->CidrDst, (char *)"::/0") < 0) goto error; s->CidrDst = IPOnlyCIDRItemInsert(s->CidrDst, tmp); - } else if (IPOnlyCIDRListParse(&s->CidrDst, (char *)addrstr) < 0) { + } else if (IPOnlyCIDRListParse(de_ctx, &s->CidrDst, (char *)addrstr) < 0) { goto error; } @@ -938,20 +941,22 @@ int IPOnlyMatchCompatSMs(ThreadVars *tv, Signature *s, Packet *p) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; - - while (sm != NULL) { - BUG_ON(!(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)); - KEYWORD_PROFILING_START; - if (sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm) > 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); - sm = sm->next; - continue; + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH]; + if (smd) { + while (1) { + BUG_ON(!(sigmatch_table[smd->type].flags & SIGMATCH_IPONLY_COMPAT)); + KEYWORD_PROFILING_START; + if (sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx) > 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + continue; + } + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + return 0; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - return 0; } - return 1; } @@ -1062,16 +1067,21 @@ void IPOnlyMatchPacket(ThreadVars *tv, SCLogDebug("Signum %"PRIu16" match (sid: %"PRIu16", msg: %s)", u * 8 + i, s->id, s->msg); - if (s->sm_lists[DETECT_SM_LIST_POSTMATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH); - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_POSTMATCH]; - - SCLogDebug("running match functions, sm %p", sm); - - for ( ; sm != NULL; sm = sm->next) { - KEYWORD_PROFILING_START; - (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; + + SCLogDebug("running match functions, sm %p", smd); + + if (smd != NULL) { + while (1) { + KEYWORD_PROFILING_START; + (void)sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; + } } } if (!(s->flags & SIG_FLAG_NOALERT)) { @@ -1081,7 +1091,7 @@ void IPOnlyMatchPacket(ThreadVars *tv, PacketAlertAppend(det_ctx, s, p, 0, 0); } else { /* apply actions for noalert/rule suppressed as well */ - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } } } @@ -1553,25 +1563,17 @@ void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, static int IPOnlyTestSig01(void) { - int result = 0; - DetectEngineCtx de_ctx; - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-01 sig is IPOnly \"; sid:400001; rev:1;)"); - if (s == NULL) { - goto end; - } - if(SignatureIsIPOnly(&de_ctx, s)) - result = 1; - else - printf("expected a IPOnly signature: "); + Signature *s = SigInit(de_ctx,"alert tcp any any -> any any (sid:400001; rev:1;)"); + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); SigFree(s); -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -1581,27 +1583,17 @@ static int IPOnlyTestSig01(void) static int IPOnlyTestSig02 (void) { - int result = 0; - DetectEngineCtx de_ctx; - memset (&de_ctx, 0, sizeof(DetectEngineCtx)); - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx,"alert tcp any any -> any 80 (msg:\"SigTest40-02 sig is not IPOnly \"; sid:400001; rev:1;)"); - if (s == NULL) { - goto end; - } - if ((SignatureIsIPOnly(&de_ctx, s))) - result = 1; - else - printf("got a non-IPOnly signature: "); + Signature *s = SigInit(de_ctx,"alert tcp any any -> any 80 (sid:400001; rev:1;)"); + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); SigFree(s); - -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -1805,7 +1797,7 @@ static int IPOnlyTestSig04 (void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ -int IPOnlyTestSig05(void) +static int IPOnlyTestSig05(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1842,7 +1834,7 @@ int IPOnlyTestSig05(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ -int IPOnlyTestSig06(void) +static int IPOnlyTestSig06(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1883,7 +1875,7 @@ int IPOnlyTestSig06(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ -int IPOnlyTestSig07(void) +static int IPOnlyTestSig07(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1921,7 +1913,7 @@ int IPOnlyTestSig07(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ -int IPOnlyTestSig08(void) +static int IPOnlyTestSig08(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1958,7 +1950,7 @@ int IPOnlyTestSig08(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) */ -int IPOnlyTestSig09(void) +static int IPOnlyTestSig09(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -1995,7 +1987,7 @@ int IPOnlyTestSig09(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) */ -int IPOnlyTestSig10(void) +static int IPOnlyTestSig10(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2036,7 +2028,7 @@ int IPOnlyTestSig10(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (all should match) with ipv4 and ipv6 mixed */ -int IPOnlyTestSig11(void) +static int IPOnlyTestSig11(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2075,7 +2067,7 @@ int IPOnlyTestSig11(void) * \test Test a set of ip only signatures making use a lot of * addresses for src and dst (none should match) with ipv4 and ipv6 mixed */ -int IPOnlyTestSig12(void) +static int IPOnlyTestSig12(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2111,55 +2103,39 @@ int IPOnlyTestSig12(void) static int IPOnlyTestSig13(void) { - int result = 0; - DetectEngineCtx de_ctx; - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx, + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " "flowbits:set,myflow1; sid:1; rev:1;)"); - if (s == NULL) { - goto end; - } - if (SignatureIsIPOnly(&de_ctx, s)) - result = 1; - else - printf("expected a IPOnly signature: "); + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0); SigFree(s); -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } static int IPOnlyTestSig14(void) { - int result = 0; - DetectEngineCtx de_ctx; - - memset(&de_ctx, 0, sizeof(DetectEngineCtx)); - - de_ctx.flags |= DE_QUIET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + de_ctx->flags |= DE_QUIET; - Signature *s = SigInit(&de_ctx, + Signature *s = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; " "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)"); - if (s == NULL) { - goto end; - } - if (SignatureIsIPOnly(&de_ctx, s)) - printf("expected a IPOnly signature: "); - else - result = 1; + FAIL_IF(s == NULL); + FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 1); SigFree(s); -end: - return result; + DetectEngineCtxFree(de_ctx); + PASS; } -int IPOnlyTestSig15(void) +static int IPOnlyTestSig15(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2213,7 +2189,7 @@ int IPOnlyTestSig15(void) /** * \brief Unittest to show #599. We fail to match if we have negated addresses. */ -int IPOnlyTestSig16(void) +static int IPOnlyTestSig16(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2244,7 +2220,7 @@ int IPOnlyTestSig16(void) /** * \brief Unittest to show #611. Ports on portless protocols. */ -int IPOnlyTestSig17(void) +static int IPOnlyTestSig17(void) { int result = 0; uint8_t *buf = (uint8_t *)"Hi all!"; @@ -2276,36 +2252,36 @@ int IPOnlyTestSig17(void) void IPOnlyRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01, 1); - UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02, 1); - UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03, 1); - UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04, 1); + UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01); + UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02); + UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03); + UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04); - UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05, 1); - UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06, 1); + UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05); + UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06); /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 UtRegisterTest("IPOnlyTestSig07", IPOnlyTestSig07, 1); #endif - UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08, 1); + UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08); - UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09, 1); - UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10, 1); + UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09); + UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10); /* \todo fix it. We have disabled this unittest because 599 exposes 608, * which is why these unittests fail. When we fix 608, we need to renable * these sigs */ #if 0 UtRegisterTest("IPOnlyTestSig11", IPOnlyTestSig11, 1); #endif - UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12, 1); - UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13, 1); - UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14, 1); - UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15, 1); - UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16, 1); + UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12); + UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13); + UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14); + UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15); + UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16); - UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17, 1); + UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17); #endif return; diff --git a/src/detect-engine-iponly.h b/src/detect-engine-iponly.h index 599a11157e4d..b71a59337dcd 100644 --- a/src/detect-engine-iponly.h +++ b/src/detect-engine-iponly.h @@ -36,7 +36,7 @@ typedef struct SigNumArray_ { } SigNumArray; void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead); -int IPOnlySigParseAddress(Signature *, const char *, char); +int IPOnlySigParseAddress(const DetectEngineCtx *, Signature *, const char *, char); void IPOnlyMatchPacket(ThreadVars *tv, DetectEngineCtx *, DetectEngineThreadCtx *, DetectEngineIPOnlyCtx *, DetectEngineIPOnlyThreadCtx *, Packet *); diff --git a/src/detect-engine-loader.c b/src/detect-engine-loader.c new file mode 100644 index 000000000000..1c4ad0872be3 --- /dev/null +++ b/src/detect-engine-loader.c @@ -0,0 +1,302 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "conf.h" +#include "debug.h" +#include "detect.h" +#include "runmodes.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "queue.h" +#include "util-signal.h" + +#include "detect-engine-loader.h" + +#define NLOADERS 4 +static DetectLoaderControl *loaders = NULL; +static int cur_loader = 0; +void TmThreadWakeupDetectLoaderThreads(void); +static int num_loaders = NLOADERS; + +/** \param loader -1 for auto select + * \retval loader_id or negative in case of error */ +int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx) +{ + if (loader_id == -1) { + loader_id = cur_loader; + cur_loader++; + if (cur_loader >= num_loaders) + cur_loader = 0; + } + if (loader_id >= num_loaders || loader_id < 0) { + return -ERANGE; + } + + DetectLoaderControl *loader = &loaders[loader_id]; + + DetectLoaderTask *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->Func = Func; + t->ctx = func_ctx; + + SCMutexLock(&loader->m); + TAILQ_INSERT_TAIL(&loader->task_list, t, next); + SCMutexUnlock(&loader->m); + + TmThreadWakeupDetectLoaderThreads(); + + SCLogDebug("%d %p %p", loader_id, Func, func_ctx); + return loader_id; +} + +/** \brief wait for loader tasks to complete + * \retval result 0 for ok, -1 for errors */ +int DetectLoadersSync(void) +{ + SCLogDebug("waiting"); + int errors = 0; + int i; + for (i = 0; i < num_loaders; i++) { + int done = 0; + DetectLoaderControl *loader = &loaders[i]; + while (!done) { + SCMutexLock(&loader->m); + if (TAILQ_EMPTY(&loader->task_list)) { + done = 1; + } + SCMutexUnlock(&loader->m); + } + SCMutexLock(&loader->m); + if (loader->result != 0) { + errors++; + loader->result = 0; + } + SCMutexUnlock(&loader->m); + + } + if (errors) { + SCLogError(SC_ERR_INITIALIZATION, "%d loaders reported errors", errors); + return -1; + } + SCLogDebug("done"); + return 0; +} + +static void DetectLoaderInit(DetectLoaderControl *loader) +{ + memset(loader, 0x00, sizeof(*loader)); + SCMutexInit(&loader->m, NULL); + TAILQ_INIT(&loader->task_list); +} + +void DetectLoadersInit(void) +{ + intmax_t setting = NLOADERS; + (void)ConfGetInt("multi-detect.loaders", &setting); + + if (setting < 1 || setting > 1024) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "invalid multi-detect.loaders setting %"PRIdMAX, setting); + exit(EXIT_FAILURE); + } + num_loaders = (int32_t)setting; + + SCLogInfo("using %d detect loader threads", num_loaders); + + BUG_ON(loaders != NULL); + loaders = SCCalloc(num_loaders, sizeof(DetectLoaderControl)); + BUG_ON(loaders == NULL); + + int i; + for (i = 0; i < num_loaders; i++) { + DetectLoaderInit(&loaders[i]); + } +} + +/** + * \brief Unpauses all threads present in tv_root + */ +void TmThreadWakeupDetectLoaderThreads() +{ + ThreadVars *tv = NULL; + int i = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if (strncmp(tv->name,"DL#",3) == 0) { + BUG_ON(tv->ctrl_cond == NULL); + pthread_cond_broadcast(tv->ctrl_cond); + } + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + + return; +} + +/** + * \brief Unpauses all threads present in tv_root + */ +void TmThreadContinueDetectLoaderThreads() +{ + ThreadVars *tv = NULL; + int i = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if (strncmp(tv->name,"DL#",3) == 0) + TmThreadContinue(tv); + + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + + return; +} + + +SC_ATOMIC_DECLARE(int, detect_loader_cnt); + +typedef struct DetectLoaderThreadData_ { + uint32_t instance; +} DetectLoaderThreadData; + +static TmEcode DetectLoaderThreadInit(ThreadVars *t, void *initdata, void **data) +{ + DetectLoaderThreadData *ftd = SCCalloc(1, sizeof(DetectLoaderThreadData)); + if (ftd == NULL) + return TM_ECODE_FAILED; + + ftd->instance = SC_ATOMIC_ADD(detect_loader_cnt, 1) - 1; /* id's start at 0 */ + SCLogDebug("detect loader instance %u", ftd->instance); + + /* pass thread data back to caller */ + *data = ftd; + + return TM_ECODE_OK; +} + +static TmEcode DetectLoaderThreadDeinit(ThreadVars *t, void *data) +{ + SCFree(data); + return TM_ECODE_OK; +} + + +static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data) +{ + /* block usr2. usr2 to be handled by the main thread only */ + UtilSignalBlock(SIGUSR2); + + DetectLoaderThreadData *ftd = (DetectLoaderThreadData *)thread_data; + BUG_ON(ftd == NULL); + + SCLogDebug("loader thread started"); + while (1) + { + if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { + TmThreadsSetFlag(th_v, THV_PAUSED); + TmThreadTestThreadUnPaused(th_v); + TmThreadsUnsetFlag(th_v, THV_PAUSED); + } + + /* see if we have tasks */ + + DetectLoaderControl *loader = &loaders[ftd->instance]; + SCMutexLock(&loader->m); + + DetectLoaderTask *task = NULL, *tmptask = NULL; + TAILQ_FOREACH_SAFE(task, &loader->task_list, next, tmptask) { + int r = task->Func(task->ctx, ftd->instance); + loader->result |= r; + TAILQ_REMOVE(&loader->task_list, task, next); + SCFree(task->ctx); + SCFree(task); + } + + SCMutexUnlock(&loader->m); + + if (TmThreadsCheckFlag(th_v, THV_KILL)) { + break; + } + + /* just wait until someone wakes us up */ + SCCtrlMutexLock(th_v->ctrl_mutex); + SCCtrlCondWait(th_v->ctrl_cond, th_v->ctrl_mutex); + SCCtrlMutexUnlock(th_v->ctrl_mutex); + + SCLogDebug("woke up..."); + } + + return TM_ECODE_OK; +} + +/** \brief spawn the detect loader manager thread */ +void DetectLoaderThreadSpawn() +{ + int i; + for (i = 0; i < num_loaders; i++) { + ThreadVars *tv_loader = NULL; + + char name[TM_THREAD_NAME_MAX]; + snprintf(name, sizeof(name), "%s#%02d", thread_name_detect_loader, i+1); + + tv_loader = TmThreadCreateCmdThreadByName(name, + "DetectLoader", 1); + BUG_ON(tv_loader == NULL); + + if (tv_loader == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(1); + } + if (TmThreadSpawn(tv_loader) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(1); + } + } + return; +} + +void TmModuleDetectLoaderRegister (void) +{ + tmm_modules[TMM_DETECTLOADER].name = "DetectLoader"; + tmm_modules[TMM_DETECTLOADER].ThreadInit = DetectLoaderThreadInit; + tmm_modules[TMM_DETECTLOADER].ThreadDeinit = DetectLoaderThreadDeinit; + tmm_modules[TMM_DETECTLOADER].Management = DetectLoader; + tmm_modules[TMM_DETECTLOADER].cap_flags = 0; + tmm_modules[TMM_DETECTLOADER].flags = TM_FLAG_MANAGEMENT_TM; + SCLogDebug("%s registered", tmm_modules[TMM_DETECTLOADER].name); + + SC_ATOMIC_INIT(detect_loader_cnt); +} diff --git a/src/detect-engine-loader.h b/src/detect-engine-loader.h new file mode 100644 index 000000000000..de28bdaf7751 --- /dev/null +++ b/src/detect-engine-loader.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Detect loader API, for using multiple 'loader' threads + * that can load multiple detection engines in parallel. + */ + +#ifndef __DETECT_ENGINE_LOADER_H__ +#define __DETECT_ENGINE_LOADER_H__ + +/** + * \param ctx function specific data + * \param loader_id id of the loader that executed the task + */ +typedef int (*LoaderFunc)(void *ctx, int loader_id); + +typedef struct DetectLoaderTask_ { + LoaderFunc Func; + void *ctx; + TAILQ_ENTRY(DetectLoaderTask_) next; +} DetectLoaderTask; + +typedef struct DetectLoaderControl_ { + int id; + int result; /* 0 for ok, error otherwise */ + SCMutex m; + TAILQ_HEAD(, DetectLoaderTask_) task_list; +} DetectLoaderControl; + +int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx); +int DetectLoadersSync(void); +void DetectLoadersInit(void); + +void TmThreadContinueDetectLoaderThreads(); +void DetectLoaderThreadSpawn(); +void TmModuleDetectLoaderRegister (void); + +#endif /* __DETECT_ENGINE_LOADER_H__ */ diff --git a/src/detect-engine-modbus.c b/src/detect-engine-modbus.c new file mode 100644 index 000000000000..9e1f8537c4dd --- /dev/null +++ b/src/detect-engine-modbus.c @@ -0,0 +1,1369 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file + * + * \author David DIALLO + * + * Based on detect-engine-dns.c + */ + +#include "suricata-common.h" + +#include "app-layer.h" +#include "app-layer-modbus.h" + +#include "detect.h" +#include "detect-modbus.h" + +#include "detect-engine-modbus.h" + +#include "flow.h" + +#include "util-debug.h" + +/** \internal + * + * \brief Value match detection code + * + * \param value Modbus value context (min, max and mode) + * \param min Minimum value to compare + * \param inter Interval or maximum (min + inter) value to compare + * + * \retval 1 match or 0 no match + */ +static int DetectEngineInspectModbusValueMatch(DetectModbusValue *value, + uint16_t min, + uint16_t inter) +{ + SCEnter(); + uint16_t max = min + inter; + + int ret = 0; + + switch (value->mode) { + case DETECT_MODBUS_EQ: + if ((value->min >= min) && (value->min <= max)) + ret = 1; + break; + + case DETECT_MODBUS_LT: + if (value->min > min) + ret = 1; + break; + + case DETECT_MODBUS_GT: + if (value->min < max) + ret = 1; + break; + + case DETECT_MODBUS_RA: + if ((value->max > min) && (value->min < max)) + ret = 1; + break; + } + + SCReturnInt(ret); +} + +/** \internal + * + * \brief Do data (and address) inspection & validation for a signature + * + * \param tx Pointer to Modbus Transaction + * \param address Address inspection + * \param data Pointer to data signature structure to match + * + * \retval 0 no match or 1 match + */ +static int DetectEngineInspectModbusData(ModbusTransaction *tx, + uint16_t address, + DetectModbusValue *data) +{ + SCEnter(); + uint16_t offset, value = 0, type = tx->type; + + if (type & MODBUS_TYP_SINGLE) { + /* Output/Register(s) Value */ + if (type & MODBUS_TYP_COILS) + value = (tx->data[0])? 1 : 0; + else + value = tx->data[0]; + } else if (type & MODBUS_TYP_MULTIPLE) { + int i, size = (int) sizeof(tx->data); + + offset = address - (tx->write.address + 1); + + /* In case of Coils, offset is in bit (convert in byte) */ + if (type & MODBUS_TYP_COILS) + offset >>= 3; + + for (i=0; i< size; i++) { + /* Select the correct register/coils amongst the output value */ + if (!(offset--)) { + value = tx->data[i]; + break; + } + } + + /* In case of Coils, offset is now in the bit is the rest of previous convert */ + if (type & MODBUS_TYP_COILS) { + offset = (address - (tx->write.address + 1)) & 0x7; + value = (value >> offset) & 0x1; + } + } else { + /* It is not possible to define the value that is writing for Mask */ + /* Write Register function because the current content is not available.*/ + SCReturnInt(0); + } + + SCReturnInt(DetectEngineInspectModbusValueMatch(data, value, 0)); +} + +/** \internal + * + * \brief Do address inspection & validation for a signature + * + * \param tx Pointer to Modbus Transaction + * \param address Pointer to address signature structure to match + * \param access Access mode (READ or WRITE) + * + * \retval 0 no match or 1 match + */ +static int DetectEngineInspectModbusAddress(ModbusTransaction *tx, + DetectModbusValue *address, + uint8_t access) +{ + SCEnter(); + int ret = 0; + + /* Check if read/write address of request is at/in the address range of signature */ + if (access == MODBUS_TYP_READ) { + /* In the PDU Coils are addresses starting at zero */ + /* therefore Coils numbered 1-16 are addressed as 0-15 */ + ret = DetectEngineInspectModbusValueMatch(address, + tx->read.address + 1, + tx->read.quantity - 1); + } else { + /* In the PDU Registers are addresses starting at zero */ + /* therefore Registers numbered 1-16 are addressed as 0-15 */ + if (tx->type & MODBUS_TYP_SINGLE) + ret = DetectEngineInspectModbusValueMatch(address, + tx->write.address + 1, + 0); + else + ret = DetectEngineInspectModbusValueMatch(address, + tx->write.address + 1, + tx->write.quantity - 1); + } + + SCReturnInt(ret); +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect ( and sm: SigMatch to inspect) + * \param f Flow + * \param flags App layer flags + * \param alstate App layer state + * \param txv Pointer to Modbus Transaction structure + * + * \retval 0 no match or 1 match + */ +int DetectEngineInspectModbus(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + const Signature *s, + const SigMatchData *smd, + Flow *f, + uint8_t flags, + void *alstate, + void *txv, + uint64_t tx_id) +{ + SCEnter(); + ModbusTransaction *tx = (ModbusTransaction *)txv; + DetectModbus *modbus = (DetectModbus *) smd->ctx; + + int ret = 0; + + if (modbus == NULL) { + SCLogDebug("no modbus state, no match"); + SCReturnInt(0); + } + + if (modbus->type == MODBUS_TYP_NONE) { + if (modbus->category == MODBUS_CAT_NONE) { + if (modbus->function == tx->function) { + if (modbus->subfunction != NULL) { + SCLogDebug("looking for Modbus server function %d and subfunction %d", + modbus->function, *(modbus->subfunction)); + ret = (*(modbus->subfunction) == (tx->subFunction))? 1 : 0; + } else { + SCLogDebug("looking for Modbus server function %d", modbus->function); + ret = 1; + } + } + } else { + SCLogDebug("looking for Modbus category function %d", modbus->category); + ret = (tx->category & modbus->category)? 1 : 0; + } + } else { + uint8_t access = modbus->type & MODBUS_TYP_ACCESS_MASK; + uint8_t function = modbus->type & MODBUS_TYP_ACCESS_FUNCTION_MASK; + + if ((access & tx->type) && ((function == MODBUS_TYP_NONE) || (function & tx->type))) { + if (modbus->address != NULL) { + ret = DetectEngineInspectModbusAddress(tx, modbus->address, access); + + if (ret && (modbus->data != NULL)) { + ret = DetectEngineInspectModbusData(tx, modbus->address->min, modbus->data); + } + } else { + SCLogDebug("looking for Modbus access type %d and function type %d", access, function); + ret = 1; + } + } + } + + SCReturnInt(ret); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "app-layer-parser.h" + +#include "detect-parse.h" + +#include "detect-engine.h" + +#include "flow-util.h" + +#include "stream-tcp.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */ +/* Example of a request to read discrete outputs 20-38 */ +static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x01, + /* Starting Address */ 0x78, 0x90, + /* Quantity of coils */ 0x00, 0x13 }; + +/* Modbus Application Protocol Specification V1.1b3 6.4: Read Input Registers */ +/* Example of a request to read input register 9 */ +static uint8_t readInputsRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x04, + /* Starting Address */ 0x00, 0x08, + /* Quantity of Registers */ 0x00, 0x60}; + +/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */ +/* Example of a request to read six registers starting at register 4, */ +/* and to write three registers starting at register 15 */ +static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x11, + /* Unit ID */ 0x00, + /* Function code */ 0x17, + /* Read Starting Address */ 0x00, 0x03, + /* Quantity to Read */ 0x00, 0x06, + /* Write Starting Address */ 0x00, 0x0E, + /* Quantity to Write */ 0x00, 0x03, + /* Write Byte count */ 0x06, + /* Write Registers Value */ 0x12, 0x34, /* 15 */ + 0x56, 0x78, /* 16 */ + 0x9A, 0xBC};/* 17 */ + +/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */ +/* Example of a request to to remote device to its Listen Only MOde for Modbus Communications. */ +static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x06, + /* Unit ID */ 0x00, + /* Function code */ 0x08, + /* Sub-function code */ 0x00, 0x04, + /* Data */ 0x00, 0x00}; + +/* Modbus Application Protocol Specification V1.1b3 Annex A */ +/* Modbus Reserved Function codes, Subcodes and MEI types */ +static uint8_t encapsulatedInterfaceTransport[] = { + /* Transaction ID */ 0x00, 0x10, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x05, + /* Unit ID */ 0x00, + /* Function code */ 0x2B, + /* MEI Type */ 0x0F, + /* Data */ 0x00, 0x00}; + +static uint8_t unassigned[] = {/* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0x00, 0x02, + /* Unit ID */ 0x00, + /* Function code */ 0x12}; + +/** \test Test code function. */ +static int DetectEngineInspectModbusTest01(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus code function\"; " + "modbus: function 23; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + readWriteMultipleRegistersReq, + sizeof(readWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test code function and code subfunction. */ +static int DetectEngineInspectModbusTest02(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function and subfunction\"; " + "modbus: function 8, subfunction 4; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, forceListenOnlyMode, + sizeof(forceListenOnlyMode)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test function category. */ +static int DetectEngineInspectModbusTest03(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus category function\"; " + "modbus: function reserved; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + encapsulatedInterfaceTransport, + sizeof(encapsulatedInterfaceTransport)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test negative function category. */ +static int DetectEngineInspectModbusTest04(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus category function\"; " + "modbus: function !assigned; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, unassigned, + sizeof(unassigned)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test access type. */ +static int DetectEngineInspectModbusTest05(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access type\"; " + "modbus: access read; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test access function. */ +static int DetectEngineInspectModbusTest06(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access type\"; " + "modbus: access read input; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readInputsRegistersReq, + sizeof(readInputsRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test read access at an address. */ +static int DetectEngineInspectModbusTest07(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus address access\"; " + "modbus: access read, address 30870; sid:1;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readCoilsReq, + sizeof(readCoilsReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test read access at a range of address. */ +static int DetectEngineInspectModbusTest08(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + /* readInputsRegistersReq, Starting Address = 0x08, Quantity of Registers = 0x60 */ + /* Read access address from 9 to 104 */ + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address <9; sid:1;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 9; sid:2;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 5<>9; sid:3;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address <10; sid:4;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 5<>10; sid:5;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address >103; sid:6;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 103<>110; sid:7;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 104; sid:8;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address >104; sid:9;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus access\"; " + "modbus: access read input, " + "address 104<>110; sid:10;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, readInputsRegistersReq, + sizeof(readInputsRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 2))) { + printf("sid 2 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 3)) { + printf("sid 3 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 4))) { + printf("sid 4 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 5))) { + printf("sid 5 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 6))) { + printf("sid 6 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 7))) { + printf("sid 7 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 8))) { + printf("sid 8 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 9)) { + printf("sid 9 did match but should not have: "); + goto end; + } + + if (PacketAlertCheck(p, 10)) { + printf("sid 10 did match but should not have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} + +/** \test write access at a address in a range of value. */ +static int DetectEngineInspectModbusTest09(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */ + /* Write access register address 15 = 0x1234 (4660) */ + /* Write access register address 16 = 0x5678 (22136) */ + /* Write access register address 17 = 0x9ABC (39612) */ + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value <4660; sid:1;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 16, value <22137; sid:2;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 17, value 39612; sid:3;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value 4661; sid:4;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 16, value 20000<>22136; sid:5;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 17, value 30000<>39613; sid:6;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value 4659<>5000; sid:7;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 16, value 22136<>30000; sid:8;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 17, value >39611; sid:9;)"); + + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus write access\"; " + "modbus: access write holding, " + "address 15, value >4660; sid:10;)"); + + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, + STREAM_TOSERVER, + readWriteMultipleRegistersReq, + sizeof(readWriteMultipleRegistersReq)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 2))) { + printf("sid 2 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 3))) { + printf("sid 3 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 4)) { + printf("sid 4 did match but should not have: "); + goto end; + } + + if (PacketAlertCheck(p, 5)) { + printf("sid 5 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 6))) { + printf("sid 6 didn't match but should have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 7))) { + printf("sid 7 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 8)) { + printf("sid 8 did match but should not have: "); + goto end; + } + + if (!(PacketAlertCheck(p, 9))) { + printf("sid 9 didn't match but should have: "); + goto end; + } + + if (PacketAlertCheck(p, 10)) { + printf("sid 10 did match but should not have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + return result; +} +#endif /* UNITTESTS */ + +void DetectEngineInspectModbusRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectEngineInspectModbusTest01 - Code function", + DetectEngineInspectModbusTest01); + UtRegisterTest("DetectEngineInspectModbusTest02 - code function and code subfunction", + DetectEngineInspectModbusTest02); + UtRegisterTest("DetectEngineInspectModbusTest03 - Function category", + DetectEngineInspectModbusTest03); + UtRegisterTest("DetectEngineInspectModbusTest04 - Negative function category", + DetectEngineInspectModbusTest04); + UtRegisterTest("DetectEngineInspectModbusTest05 - Access type", + DetectEngineInspectModbusTest05); + UtRegisterTest("DetectEngineInspectModbusTest06 - Access function", + DetectEngineInspectModbusTest06); + UtRegisterTest("DetectEngineInspectModbusTest07 - Read access at an address", + DetectEngineInspectModbusTest07); + UtRegisterTest("DetectEngineInspectModbusTest08 - Read access at a range of address", + DetectEngineInspectModbusTest08); + UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value", + DetectEngineInspectModbusTest09); +#endif /* UNITTESTS */ + return; +} diff --git a/src/detect-engine-modbus.h b/src/detect-engine-modbus.h new file mode 100644 index 000000000000..4ffe45ca6811 --- /dev/null +++ b/src/detect-engine-modbus.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** \file + * + * \author David DIALLO + */ + +#ifndef __DETECT_ENGINE_MODBUS_H__ +#define __DETECT_ENGINE_MODBUS_H__ + +int DetectEngineInspectModbus(ThreadVars *, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + const Signature *, const SigMatchData *, + Flow *, uint8_t, void *, void *, uint64_t); + +void DetectEngineInspectModbusRegisterTests(void); +#endif /* __DETECT_ENGINE_MODBUS_H__ */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 6a81fde277e6..40ec280f8e79 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -47,24 +47,226 @@ #include "detect-flow.h" #include "detect-content.h" -#include "detect-uricontent.h" + +#include "detect-engine-payload.h" +#include "detect-engine-uri.h" +#include "detect-engine-hrud.h" +#include "detect-engine-hmd.h" +#include "detect-engine-hrhd.h" +#include "detect-engine-hcd.h" +#include "detect-engine-hua.h" +#include "detect-engine-hhhd.h" +#include "detect-engine-hrhhd.h" +#include "detect-engine-hsmd.h" +#include "detect-engine-hscd.h" +#include "detect-engine-hcbd.h" +#include "detect-engine-hsbd.h" +#include "detect-engine-dns.h" +#include "detect-engine-filedata-smtp.h" +#include "detect-engine-tls.h" #include "stream.h" #include "util-enum.h" #include "util-debug.h" #include "util-print.h" -#include "util-memcmp.h" -#ifdef __SC_CUDA_SUPPORT__ -#include "util-mpm-ac.h" -#endif +#include "util-validate.h" + +const char *builtin_mpms[] = { + "toserver TCP packet", + "toclient TCP packet", + "toserver TCP stream", + "toclient TCP stream", + "toserver UDP packet", + "toclient UDP packet", + "other IP packet", + + NULL }; + +/* Registery for mpm keywords + * + * Keywords are registered at engine start up + */ + +static DetectMpmAppLayerRegistery *g_app_mpms_list = NULL; +static int g_app_mpms_list_cnt = 0; + +void DetectAppLayerMpmRegister(const char *name, + int direction, int priority, + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)) +{ + DetectBufferTypeSupportsMpm(name); + int sm_list = DetectBufferTypeGetByName(name); + BUG_ON(sm_list == -1); + + DetectMpmAppLayerRegistery *am = SCCalloc(1, sizeof(*am)); + BUG_ON(am == NULL); + am->name = name; + am->direction = direction; + am->sm_list = sm_list; + am->PrefilterRegister = PrefilterRegister; + + if (g_app_mpms_list == NULL) { + g_app_mpms_list = am; + } else { + DetectMpmAppLayerRegistery *t = g_app_mpms_list; + while (t->next != NULL) { + t = t->next; + } + + t->next = am; + am->id = t->id + 1; + } + g_app_mpms_list_cnt++; + + SupportFastPatternForSigMatchList(sm_list, priority); +} + +void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx) +{ + BUG_ON(g_app_mpms_list_cnt == 0); + + de_ctx->app_mpms = SCCalloc(g_app_mpms_list_cnt + 1, sizeof(DetectMpmAppLayerKeyword)); + BUG_ON(de_ctx->app_mpms == NULL); + + DetectMpmAppLayerRegistery *list = g_app_mpms_list; + while (list != NULL) { + DetectMpmAppLayerKeyword *am = &de_ctx->app_mpms[list->id]; + am->reg = list; + + /* default to whatever the global setting is */ + int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE); + + /* see if we use a unique or shared mpm ctx for this type */ + int confshared = 0; + char confstring[256] = "detect.mpm."; + strlcat(confstring, am->reg->name, sizeof(confstring)); + strlcat(confstring, ".shared", sizeof(confstring)); + if (ConfGetBool(confstring, &confshared) == 1) + shared = confshared; + + if (shared == 0) { + if (!(de_ctx->flags & DE_QUIET)) { + SCLogPerf("using unique mpm ctx' for %s", am->reg->name); + } + am->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + } else { + if (!(de_ctx->flags & DE_QUIET)) { + SCLogPerf("using shared mpm ctx' for %s", am->reg->name); + } + am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->reg->name); + } + + SCLogDebug("AppLayer MPM %s: %u", am->reg->name, am->sgh_mpm_context); + + list = list->next; + } +} + +/** + * \brief initialize mpm contexts for applayer buffers that are in + * "single or "shared" mode. + */ +void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx) +{ + DetectMpmAppLayerKeyword *am = de_ctx->app_mpms; + while (am->reg != NULL) { + int dir = (am->reg->direction == SIG_FLAG_TOSERVER) ? 1 : 0; + + if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT) + { + MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir); + if (mpm_ctx != NULL) { + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } + } + am++; + } +} + +static int32_t SetupBuiltinMpm(DetectEngineCtx *de_ctx, const char *name) +{ + /* default to whatever the global setting is */ + int shared = (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE); + + /* see if we use a unique or shared mpm ctx for this type */ + int confshared = 0; + char confstring[256] = "detect.mpm."; + strlcat(confstring, name, sizeof(confstring)); + strlcat(confstring, ".shared", sizeof(confstring)); + if (ConfGetBool(confstring, &confshared) == 1) + shared = confshared; + + int32_t ctx; + if (shared == 0) { + ctx = MPM_CTX_FACTORY_UNIQUE_CONTEXT; + SCLogPerf("using unique mpm ctx' for %s", name); + } else { + ctx = MpmFactoryRegisterMpmCtxProfile(de_ctx, name); + SCLogPerf("using shared mpm ctx' for %s", name); + } + return ctx; +} + +void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx) +{ + de_ctx->sgh_mpm_context_proto_tcp_packet = SetupBuiltinMpm(de_ctx, "tcp-packet"); + de_ctx->sgh_mpm_context_stream = SetupBuiltinMpm(de_ctx, "tcp-stream"); + + de_ctx->sgh_mpm_context_proto_udp_packet = SetupBuiltinMpm(de_ctx, "udp-packet"); + de_ctx->sgh_mpm_context_proto_other_packet = SetupBuiltinMpm(de_ctx, "other-ip"); +} + +/** + * \brief initialize mpm contexts for builtin buffers that are in + * "single or "shared" mode. + */ +void DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx) +{ + MpmCtx *mpm_ctx = NULL; + + if (de_ctx->sgh_mpm_context_proto_tcp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } -/** \todo make it possible to use multiple pattern matcher algorithms next to - each other. */ + if (de_ctx->sgh_mpm_context_proto_udp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } + + if (de_ctx->sgh_mpm_context_proto_other_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } -#define POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS 0x01 -#define POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS 0x02 -#define POPULATE_MPM_AVOID_URI_MPM_PATTERNS 0x04 + if (de_ctx->sgh_mpm_context_stream != MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); + if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { + mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); + } + } +} /** * \brief check if a signature has patterns that are to be inspected @@ -75,7 +277,7 @@ * \retval 1 true * \retval 0 false */ -int SignatureHasPacketContent(Signature *s) +int SignatureHasPacketContent(const Signature *s) { SCEnter(); @@ -83,11 +285,13 @@ int SignatureHasPacketContent(Signature *s) SCReturnInt(0); } - if (!(s->proto.proto[6 / 8] & 1 << (6 % 8))) { + if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) { SCReturnInt(1); } - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) || + (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) + { SCLogDebug("no mpm"); SCReturnInt(0); } @@ -109,7 +313,7 @@ int SignatureHasPacketContent(Signature *s) * \retval 1 true * \retval 0 false */ -int SignatureHasStreamContent(Signature *s) +int SignatureHasStreamContent(const Signature *s) { SCEnter(); @@ -117,11 +321,13 @@ int SignatureHasStreamContent(Signature *s) SCReturnInt(0); } - if (!(s->proto.proto[6 / 8] & 1 << (6 % 8))) { + if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) { SCReturnInt(0); } - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) || + (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL)) + { SCLogDebug("no mpm"); SCReturnInt(0); } @@ -144,13 +350,23 @@ int SignatureHasStreamContent(Signature *s) uint16_t PatternMatchDefaultMatcher(void) { char *mpm_algo; - uint16_t mpm_algo_val = DEFAULT_MPM; + uint16_t mpm_algo_val = mpm_default_matcher; /* Get the mpm algo defined in config file by the user */ if ((ConfGet("mpm-algo", &mpm_algo)) == 1) { uint16_t u; if (mpm_algo != NULL) { +#if __BYTE_ORDER == __BIG_ENDIAN + if (strcmp(mpm_algo, "ac-ks") == 0) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "ac-ks does " + "not work on big endian systems at this time."); + exit(EXIT_FAILURE); + } +#endif + if (strcmp("auto", mpm_algo) == 0) { + goto done; + } for (u = 0; u < MPM_TABLE_SIZE; u++) { if (mpm_table[u].name == NULL) continue; @@ -170,1680 +386,246 @@ uint16_t PatternMatchDefaultMatcher(void) done: #ifdef __tile__ if (mpm_algo_val == MPM_AC) - mpm_algo_val = MPM_AC_TILE; + mpm_algo_val = MPM_AC_TILE; #endif return mpm_algo_val; } -uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *det_ctx, - Packet *p) +/** \brief cleans up the mpm instance after a match */ +void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) { - SCEnter(); - - uint32_t ret = 0; - - if (p->flowflags & FLOW_PKT_TOSERVER) { - if (det_ctx->sgh->mpm_stream_ctx_ts == NULL) - SCReturnInt(0); + PmqReset(&det_ctx->pmq); +} - ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); - } else { - if (det_ctx->sgh->mpm_stream_ctx_tc == NULL) - SCReturnInt(0); +void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) +{ + SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); + mpm_table[mpm_matcher].DestroyCtx(mpm_ctx); +} - ret = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtc, &det_ctx->pmq, - p->payload, p->payload_len); - } +void PatternMatchPrepare(MpmCtx *mpm_ctx, uint16_t mpm_matcher) +{ + SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); + MpmInitCtx(mpm_ctx, mpm_matcher); +} - SCReturnInt(ret); +void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) +{ + SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher); + //mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx); +} +void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) +{ + SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher); + if (mpm_table[mpm_matcher].DestroyThreadCtx != NULL) + mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); +} +void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) +{ + SCLogDebug("mpm_thread_ctx %p, type %"PRIu16, mpm_thread_ctx, mpm_matcher); + MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher); } -/** \brief Pattern match -- searches for only one pattern per signature. +/** \brief Predict a strength value for patterns + * + * Patterns with high character diversity score higher. + * Alpha chars score not so high + * Other printable + a few common codes a little higher + * Everything else highest. + * Longer patterns score better than short patters. * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect + * \param pat pattern + * \param patlen length of the patternn * - * \retval ret number of matches + * \retval s pattern score */ -uint32_t PacketPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p) +uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) { - SCEnter(); + uint8_t a[256]; + memset(&a, 0 ,sizeof(a)); - uint32_t ret; - MpmCtx *mpm_ctx = NULL; + uint32_t s = 0; + uint16_t u = 0; + for (u = 0; u < patlen; u++) { + if (a[pat[u]] == 0) { + if (isalpha(pat[u])) + s += 3; + else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF) + s += 4; + else + s += 6; - if (p->proto == IPPROTO_TCP) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_ts; - } else { - mpm_ctx = det_ctx->sgh->mpm_proto_tcp_ctx_tc; - } - } else if (p->proto == IPPROTO_UDP) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_ts; + a[pat[u]] = 1; } else { - mpm_ctx = det_ctx->sgh->mpm_proto_udp_ctx_tc; + s++; } - } else { - mpm_ctx = det_ctx->sgh->mpm_proto_other_ctx; } - if (mpm_ctx == NULL) - SCReturnInt(0); - -#ifdef __SC_CUDA_SUPPORT__ - if (p->cuda_pkt_vars.cuda_mpm_enabled && p->pkt_src == PKT_SRC_WIRE) { - ret = SCACCudaPacketResultsProcessing(p, mpm_ctx, &det_ctx->pmq); - } else { - ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, - &det_ctx->pmq, - p->payload, - p->payload_len); - } -#else - ret = mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, - &det_ctx->mtc, - &det_ctx->pmq, - p->payload, - p->payload_len); -#endif - - SCReturnInt(ret); + return s; } -/** \brief Uri Pattern match -- searches for one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet to inspect - * - * \retval ret number of matches - */ -uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint16_t uri_len, uint8_t flags) +static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx, + const DetectContentData *cd, + const Signature *s, uint8_t flags, + int chop) { - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_uri_ctx_ts == NULL) - SCReturnUInt(0U); + uint16_t pat_offset = cd->offset; + uint16_t pat_depth = cd->depth; - ret = mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_uri_ctx_ts, - &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); - } else { - BUG_ON(1); + /* recompute offset/depth to cope with chop */ + if (chop && (pat_depth || pat_offset)) { + pat_offset += cd->fp_chop_offset; + if (pat_depth) { + pat_depth -= cd->content_len; + pat_depth += cd->fp_chop_offset + cd->fp_chop_len; + } } - //PrintRawDataFp(stdout, uri, uri_len); - - SCReturnUInt(ret); -} - -/** \brief Http client body pattern match -- searches for one pattern per - * signature. - * - * \param det_ctx Detection engine thread ctx. - * \param body The request body to inspect. - * \param body_len Body length. - * - * \retval ret Number of matches. - */ -uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *body, uint32_t body_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hcbd_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hcbd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcbd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); + if (cd->flags & DETECT_CONTENT_NOCASE) { + if (chop) { + MpmAddPatternCI(mpm_ctx, + cd->content + cd->fp_chop_offset, cd->fp_chop_len, + pat_offset, pat_depth, + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + } else { + MpmAddPatternCI(mpm_ctx, + cd->content, cd->content_len, + pat_offset, pat_depth, + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + } } else { - BUG_ON(1); + if (chop) { + MpmAddPatternCS(mpm_ctx, + cd->content + cd->fp_chop_offset, cd->fp_chop_len, + pat_offset, pat_depth, + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + } else { + MpmAddPatternCS(mpm_ctx, + cd->content, cd->content_len, + pat_offset, pat_depth, + cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID); + } } - SCReturnUInt(ret); + return; } -/** \brief Http server body pattern match -- searches for one pattern per - * signature. - * - * \param det_ctx Detection engine thread ctx. - * \param body The request body to inspect. - * \param body_len Body length. - * - * \retval ret Number of matches. - */ -uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *body, uint32_t body_len, uint8_t flags) +#define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1) +#define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER) +#define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT) + +static void SetMpm(Signature *s, SigMatch *mpm_sm) { - SCEnter(); + if (s == NULL || mpm_sm == NULL) + return; - uint32_t ret; - if (flags & STREAM_TOSERVER) { - BUG_ON(1); + DetectContentData *cd = (DetectContentData *)mpm_sm->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE) && + cd->content_len == cd->fp_chop_len) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } } else { - if (det_ctx->sgh->mpm_hsbd_ctx_tc == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hsbd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsbd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, body, body_len); + if (DETECT_CONTENT_IS_SINGLE(cd) && + !(cd->flags & DETECT_CONTENT_NEGATED) && + !(cd->flags & DETECT_CONTENT_REPLACE)) + { + cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; + } } - - SCReturnUInt(ret); + s->init_data->mpm_sm = mpm_sm; + return; } -/** - * \brief Http header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param headers Headers to inspect. - * \param headers_len Headers length. - * - * \retval ret Number of matches. - */ -uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *headers, uint32_t headers_len, uint8_t flags) +void RetrieveFPForSig(Signature *s) { - SCEnter(); + if (s->init_data->mpm_sm != NULL) + return; - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hhd_ctx_ts == NULL) - SCReturnUInt(0); + const int nlists = DetectBufferTypeMaxId(); - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); - } else { - if (det_ctx->sgh->mpm_hhd_ctx_tc == NULL) - SCReturnUInt(0); + SigMatch *mpm_sm = NULL, *sm = NULL; + int nn_sm_list[nlists]; + int n_sm_list[nlists]; + memset(nn_sm_list, 0, nlists * sizeof(int)); + memset(n_sm_list, 0, nlists * sizeof(int)); + int count_nn_sm_list = 0; + int count_n_sm_list = 0; + int list_id; - ret = mpm_table[det_ctx->sgh->mpm_hhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, headers, headers_len); - } + /* inspect rule to see if we have the fast_pattern reg to + * force using a sig, otherwise keep stats about the patterns */ + for (list_id = 0; list_id < nlists; list_id++) { + if (s->init_data->smlists[list_id] == NULL) + continue; - SCReturnUInt(ret); -} + if (!FastPatternSupportEnabledForSigMatchList(list_id)) + continue; -/** - * \brief Http raw header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param headers Raw headers to inspect. - * \param headers_len Raw headers length. - * - * \retval ret Number of matches. - */ -uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *raw_headers, uint32_t raw_headers_len, uint8_t flags) -{ - SCEnter(); + for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hrhd_ctx_ts == NULL) - SCReturnUInt(0); + DetectContentData *cd = (DetectContentData *)sm->ctx; - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); - } else { - if (det_ctx->sgh->mpm_hrhd_ctx_tc == NULL) - SCReturnUInt(0); + /* fast_pattern set in rule, so using this pattern */ + if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) { + SetMpm(s, sm); + return; + } - ret = mpm_table[det_ctx->sgh->mpm_hrhd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hrhd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, raw_headers, raw_headers_len); + if (cd->flags & DETECT_CONTENT_NEGATED) { + n_sm_list[list_id] = 1; + count_n_sm_list++; + } else { + nn_sm_list[list_id] = 1; + count_nn_sm_list++; + } + } } - SCReturnUInt(ret); -} - -/** - * \brief Http method match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param method Method to inspect. - * \param method_len Method length. - * - * \retval ret Number of matches. - */ -uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *raw_method, uint32_t raw_method_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hmd_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hmd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hmd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, raw_method, raw_method_len); + /* prefer normal not-negated over negated */ + int *curr_sm_list = NULL; + int skip_negated_content = 1; + if (count_nn_sm_list > 0) { + curr_sm_list = nn_sm_list; + } else if (count_n_sm_list > 0) { + curr_sm_list = n_sm_list; + skip_negated_content = 0; } else { - BUG_ON(1); + return; } - SCReturnUInt(ret); -} + int final_sm_list[nlists]; + memset(&final_sm_list, 0, (nlists * sizeof(int))); -/** - * \brief Http cookie match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param cookie Cookie to inspect. - * \param cookie_len Cookie length. - * - * \retval ret Number of matches. - */ -uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *cookie, uint32_t cookie_len, uint8_t flags) -{ - SCEnter(); + int count_final_sm_list = 0; + int priority; - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hcd_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); - } else { - if (det_ctx->sgh->mpm_hcd_ctx_tc == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hcd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hcd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, cookie, cookie_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http raw uri match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param uri Raw uri to inspect. - * \param uri_len Raw uri length. - * - * \retval ret Number of matches. - */ -uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint32_t uri_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hrud_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hrud_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrud_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, uri, uri_len); - } else { - BUG_ON(1); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http stat msg match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param stat_msg Stat msg to inspect. - * \param stat_msg_len Stat msg length. - * - * \retval ret Number of matches. - */ -uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *stat_msg, uint32_t stat_msg_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - BUG_ON(1); - } else { - if (det_ctx->sgh->mpm_hsmd_ctx_tc == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hsmd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hsmd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_msg, stat_msg_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http stat code match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param stat_code Stat code to inspect. - * \param stat_code_len Stat code length. - * - * \retval ret Number of matches. - */ -uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *stat_code, uint32_t stat_code_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - BUG_ON(1); - } else { - if (det_ctx->sgh->mpm_hscd_ctx_tc == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hscd_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_hscd_ctx_tc, &det_ctx->mtcu, - &det_ctx->pmq, stat_code, stat_code_len); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http user agent match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param cookie User-Agent to inspect. - * \param cookie_len User-Agent buffer length. - * - * \retval ret Number of matches. - */ -uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *ua, uint32_t ua_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_huad_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_huad_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_huad_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, ua, ua_len); - } else { - BUG_ON(1); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http host header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hh Host header to inspect. - * \param hh_len Host header buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *hh, uint32_t hh_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hhhd_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hh, hh_len); - } else { - BUG_ON(1); - } - - SCReturnUInt(ret); -} - -/** - * \brief Http raw host header match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hrh Raw hostname to inspect. - * \param hrh_len Raw hostname buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *hrh, uint32_t hrh_len, uint8_t flags) -{ - SCEnter(); - - uint32_t ret; - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_hrhhd_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_hrhhd_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_hrhhd_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, hrh, hrh_len); - } else { - BUG_ON(1); - } - - SCReturnUInt(ret); -} - -/** - * \brief DNS query match -- searches for one pattern per signature. - * - * \param det_ctx Detection engine thread ctx. - * \param hrh Buffer to inspect. - * \param hrh_len buffer length. - * \param flags Flags - * - * \retval ret Number of matches. - */ -uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, - uint8_t *buffer, uint32_t buffer_len, - uint8_t flags) -{ - SCEnter(); - - uint32_t ret = 0; - - if (flags & STREAM_TOSERVER) { - if (det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL) - SCReturnUInt(0); - - ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu, - &det_ctx->pmq, buffer, buffer_len); - } - - SCReturnUInt(ret); -} - -/** \brief Pattern match -- searches for only one pattern per signature. - * - * \param det_ctx detection engine thread ctx - * \param p packet - * \param smsg stream msg (reassembled stream data) - * \param flags stream flags - * - * \retval ret number of matches - */ -uint32_t StreamPatternSearch(DetectEngineThreadCtx *det_ctx, Packet *p, - StreamMsg *smsg, uint8_t flags) -{ - SCEnter(); - - uint32_t ret = 0; - uint8_t cnt = 0; - - //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); - - uint32_t r; - if (flags & STREAM_TOSERVER) { - for ( ; smsg != NULL; smsg = smsg->next) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_ts, &det_ctx->mtcs, - &det_ctx->smsg_pmq[cnt], smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - - SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt); - - /* merge results with overall pmq */ - PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq); - } - - cnt++; - } - } else { - for ( ; smsg != NULL; smsg = smsg->next) { - r = mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type]. - Search(det_ctx->sgh->mpm_stream_ctx_tc, &det_ctx->mtcs, - &det_ctx->smsg_pmq[cnt], smsg->data, smsg->data_len); - if (r > 0) { - ret += r; - - SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt); - - /* merge results with overall pmq */ - PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq); - } - - cnt++; - } - } - - SCReturnInt(ret); -} - -/** \brief cleans up the mpm instance after a match */ -void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) -{ - PmqReset(&det_ctx->pmq); - - if (det_ctx->sgh == NULL) - return; - - /* content */ - if (det_ctx->sgh->mpm_proto_tcp_ctx_ts != NULL && - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_ts->mpm_type].Cleanup(&det_ctx->mtc); - } - if (det_ctx->sgh->mpm_proto_tcp_ctx_tc != NULL && - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_tc->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_tcp_ctx_tc->mpm_type].Cleanup(&det_ctx->mtc); - } - - if (det_ctx->sgh->mpm_proto_udp_ctx_ts != NULL && - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_ts->mpm_type].Cleanup(&det_ctx->mtc); - } - if (det_ctx->sgh->mpm_proto_udp_ctx_tc != NULL && - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_tc->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_udp_ctx_tc->mpm_type].Cleanup(&det_ctx->mtc); - } - - if (det_ctx->sgh->mpm_proto_other_ctx != NULL && - mpm_table[det_ctx->sgh->mpm_proto_other_ctx->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_proto_other_ctx->mpm_type].Cleanup(&det_ctx->mtc); - } - - /* uricontent */ - if (det_ctx->sgh->mpm_uri_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_uri_ctx_ts->mpm_type].Cleanup(&det_ctx->mtcu); - } - - /* stream content */ - if (det_ctx->sgh->mpm_stream_ctx_ts != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_stream_ctx_ts->mpm_type].Cleanup(&det_ctx->mtcs); - } - if (det_ctx->sgh->mpm_stream_ctx_tc != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type].Cleanup != NULL) { - mpm_table[det_ctx->sgh->mpm_stream_ctx_tc->mpm_type].Cleanup(&det_ctx->mtcs); - } - - return; -} - -void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg) -{ - uint8_t cnt = 0; - - while (smsg != NULL) { - PmqReset(&det_ctx->smsg_pmq[cnt]); - - smsg = smsg->next; - cnt++; - } -} - -void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) -{ - SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); - mpm_table[mpm_matcher].DestroyCtx(mpm_ctx); -} - -void PatternMatchPrepare(MpmCtx *mpm_ctx, uint16_t mpm_matcher) -{ - SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher); - MpmInitCtx(mpm_ctx, mpm_matcher); -} - -void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) -{ - SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher); - //mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx); -} -void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) -{ - SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher); - mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx); -} -void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher, uint32_t max_id) -{ - SCLogDebug("mpm_thread_ctx %p, type %"PRIu16", max_id %"PRIu32"", mpm_thread_ctx, mpm_matcher, max_id); - MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher, max_id); -} - - -/* free the pattern matcher part of a SigGroupHead */ -void PatternMatchDestroyGroup(SigGroupHead *sh) -{ - /* content */ - if (!(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) { - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_tcp_ctx_ts, sh); - if (sh->mpm_proto_tcp_ctx_ts != NULL && - !sh->mpm_proto_tcp_ctx_ts->global) { - mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. - DestroyCtx(sh->mpm_proto_tcp_ctx_ts); - SCFree(sh->mpm_proto_tcp_ctx_ts); - } - /* ready for reuse */ - sh->mpm_proto_tcp_ctx_ts = NULL; - - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_tcp_ctx_tc, sh); - if (sh->mpm_proto_tcp_ctx_tc != NULL && - !sh->mpm_proto_tcp_ctx_tc->global) { - mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. - DestroyCtx(sh->mpm_proto_tcp_ctx_tc); - SCFree(sh->mpm_proto_tcp_ctx_tc); - } - /* ready for reuse */ - sh->mpm_proto_tcp_ctx_tc = NULL; - - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_udp_ctx_ts, sh); - if (sh->mpm_proto_udp_ctx_ts != NULL && - !sh->mpm_proto_udp_ctx_ts->global) { - mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. - DestroyCtx(sh->mpm_proto_udp_ctx_ts); - SCFree(sh->mpm_proto_udp_ctx_ts); - } - /* ready for reuse */ - sh->mpm_proto_udp_ctx_ts = NULL; - - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_udp_ctx_tc, sh); - if (sh->mpm_proto_udp_ctx_tc != NULL && - !sh->mpm_proto_udp_ctx_tc->global) { - mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. - DestroyCtx(sh->mpm_proto_udp_ctx_tc); - SCFree(sh->mpm_proto_udp_ctx_tc); - } - /* ready for reuse */ - sh->mpm_proto_udp_ctx_tc = NULL; - - SCLogDebug("destroying mpm_ctx %p (sh %p)", - sh->mpm_proto_other_ctx, sh); - if (sh->mpm_proto_other_ctx != NULL && - !sh->mpm_proto_other_ctx->global) { - mpm_table[sh->mpm_proto_other_ctx->mpm_type]. - DestroyCtx(sh->mpm_proto_other_ctx); - SCFree(sh->mpm_proto_other_ctx); - } - /* ready for reuse */ - sh->mpm_proto_other_ctx = NULL; - } - - /* uricontent */ - if ((sh->mpm_uri_ctx_ts != NULL) && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) { - if (sh->mpm_uri_ctx_ts != NULL) { - SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx_ts, sh); - if (!sh->mpm_uri_ctx_ts->global) { - mpm_table[sh->mpm_uri_ctx_ts->mpm_type].DestroyCtx(sh->mpm_uri_ctx_ts); - SCFree(sh->mpm_uri_ctx_ts); - } - /* ready for reuse */ - sh->mpm_uri_ctx_ts = NULL; - } - } - - /* stream content */ - if ((sh->mpm_stream_ctx_ts != NULL || sh->mpm_stream_ctx_tc != NULL) && - !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) { - if (sh->mpm_stream_ctx_ts != NULL) { - SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_ts, sh); - if (!sh->mpm_stream_ctx_ts->global) { - mpm_table[sh->mpm_stream_ctx_ts->mpm_type].DestroyCtx(sh->mpm_stream_ctx_ts); - SCFree(sh->mpm_stream_ctx_ts); - } - /* ready for reuse */ - sh->mpm_stream_ctx_ts = NULL; - } - if (sh->mpm_stream_ctx_tc != NULL) { - SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx_tc, sh); - if (!sh->mpm_stream_ctx_tc->global) { - mpm_table[sh->mpm_stream_ctx_tc->mpm_type].DestroyCtx(sh->mpm_stream_ctx_tc); - SCFree(sh->mpm_stream_ctx_tc); - } - /* ready for reuse */ - sh->mpm_stream_ctx_tc = NULL; - } - } - - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (!sh->mpm_hcbd_ctx_ts->global) { - mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hcbd_ctx_ts); - SCFree(sh->mpm_hcbd_ctx_ts); - } - sh->mpm_hcbd_ctx_ts = NULL; - } - } - - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (!sh->mpm_hsbd_ctx_tc->global) { - mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hsbd_ctx_tc); - SCFree(sh->mpm_hsbd_ctx_tc); - } - sh->mpm_hsbd_ctx_tc = NULL; - } - } - - if (sh->mpm_hhd_ctx_ts != NULL || sh->mpm_hhd_ctx_tc != NULL) { - if (sh->mpm_hhd_ctx_ts != NULL) { - if (!sh->mpm_hhd_ctx_ts->global) { - mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hhd_ctx_ts); - SCFree(sh->mpm_hhd_ctx_ts); - } - sh->mpm_hhd_ctx_ts = NULL; - } - if (sh->mpm_hhd_ctx_tc != NULL) { - if (!sh->mpm_hhd_ctx_tc->global) { - mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hhd_ctx_tc); - SCFree(sh->mpm_hhd_ctx_tc); - } - sh->mpm_hhd_ctx_tc = NULL; - } - } - - if (sh->mpm_hrhd_ctx_ts != NULL || sh->mpm_hrhd_ctx_tc != NULL) { - if (sh->mpm_hrhd_ctx_ts != NULL) { - if (!sh->mpm_hrhd_ctx_ts->global) { - mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hrhd_ctx_ts); - SCFree(sh->mpm_hrhd_ctx_ts); - } - sh->mpm_hrhd_ctx_ts = NULL; - } - if (sh->mpm_hrhd_ctx_tc != NULL) { - if (!sh->mpm_hrhd_ctx_tc->global) { - mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hrhd_ctx_tc); - SCFree(sh->mpm_hrhd_ctx_tc); - } - sh->mpm_hrhd_ctx_tc = NULL; - } - } - - if (sh->mpm_hmd_ctx_ts != NULL) { - if (sh->mpm_hmd_ctx_ts != NULL) { - if (!sh->mpm_hmd_ctx_ts->global) { - mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hmd_ctx_ts); - SCFree(sh->mpm_hmd_ctx_ts); - } - sh->mpm_hmd_ctx_ts = NULL; - } - } - - if (sh->mpm_hcd_ctx_ts != NULL || sh->mpm_hcd_ctx_tc != NULL) { - if (sh->mpm_hcd_ctx_ts != NULL) { - if (!sh->mpm_hcd_ctx_ts->global) { - mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hcd_ctx_ts); - SCFree(sh->mpm_hcd_ctx_ts); - } - sh->mpm_hcd_ctx_ts = NULL; - } - if (sh->mpm_hcd_ctx_tc != NULL) { - if (!sh->mpm_hcd_ctx_tc->global) { - mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hcd_ctx_tc); - SCFree(sh->mpm_hcd_ctx_tc); - } - sh->mpm_hcd_ctx_tc = NULL; - } - } - - if (sh->mpm_hrud_ctx_ts != NULL) { - if (sh->mpm_hrud_ctx_ts != NULL) { - if (!sh->mpm_hrud_ctx_ts->global) { - mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].DestroyCtx(sh->mpm_hrud_ctx_ts); - SCFree(sh->mpm_hrud_ctx_ts); - } - sh->mpm_hrud_ctx_ts = NULL; - } - } - - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (!sh->mpm_hsmd_ctx_tc->global) { - mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hsmd_ctx_tc); - SCFree(sh->mpm_hsmd_ctx_tc); - } - sh->mpm_hsmd_ctx_tc = NULL; - } - } - - if (sh->mpm_hscd_ctx_tc != NULL) { - if (sh->mpm_hscd_ctx_tc != NULL) { - if (!sh->mpm_hscd_ctx_tc->global) { - mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].DestroyCtx(sh->mpm_hscd_ctx_tc); - SCFree(sh->mpm_hscd_ctx_tc); - } - sh->mpm_hscd_ctx_tc = NULL; - } - } - - if (sh->mpm_huad_ctx_ts != NULL) { - if (sh->mpm_huad_ctx_ts != NULL) { - if (!sh->mpm_huad_ctx_ts->global) { - mpm_table[sh->mpm_huad_ctx_ts->mpm_type].DestroyCtx(sh->mpm_huad_ctx_ts); - SCFree(sh->mpm_huad_ctx_ts); - } - sh->mpm_huad_ctx_ts = NULL; - } - } - - /* dns query */ - if (sh->mpm_dnsquery_ctx_ts != NULL) { - if (!sh->mpm_dnsquery_ctx_ts->global) { - mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].DestroyCtx(sh->mpm_dnsquery_ctx_ts); - SCFree(sh->mpm_dnsquery_ctx_ts); - } - sh->mpm_dnsquery_ctx_ts = NULL; - } - - return; -} - -/** \brief Hash for looking up contents that are most used, - * always used, etc. */ -typedef struct ContentHash_ { - DetectContentData *ptr; - uint16_t cnt; - uint8_t use; /* use no matter what */ -} ContentHash; - -typedef struct UricontentHash_ { - DetectContentData *ptr; - uint16_t cnt; - uint8_t use; /* use no matter what */ -} UricontentHash; - -uint32_t ContentHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - ContentHash *ch = (ContentHash *)data; - DetectContentData *co = ch->ptr; - uint32_t hash = 0; - int i; - for (i = 0; i < co->content_len; i++) { - hash += co->content[i]; - } - hash = hash % ht->array_size; - SCLogDebug("hash %" PRIu32 "", hash); - return hash; -} - -uint32_t UricontentHashFunc(HashTable *ht, void *data, uint16_t datalen) -{ - UricontentHash *ch = (UricontentHash *)data; - DetectContentData *ud = ch->ptr; - uint32_t hash = 0; - int i; - for (i = 0; i < ud->content_len; i++) { - hash += ud->content[i]; - } - hash = hash % ht->array_size; - SCLogDebug("hash %" PRIu32 "", hash); - return hash; -} - -char ContentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - ContentHash *ch1 = (ContentHash *)data1; - ContentHash *ch2 = (ContentHash *)data2; - DetectContentData *co1 = ch1->ptr; - DetectContentData *co2 = ch2->ptr; - - if (co1->content_len == co2->content_len && - ((co1->flags & DETECT_CONTENT_NOCASE) == (co2->flags & DETECT_CONTENT_NOCASE)) && - SCMemcmp(co1->content, co2->content, co1->content_len) == 0) - return 1; - - return 0; -} - -char UricontentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) -{ - UricontentHash *ch1 = (UricontentHash *)data1; - UricontentHash *ch2 = (UricontentHash *)data2; - DetectContentData *ud1 = ch1->ptr; - DetectContentData *ud2 = ch2->ptr; - - if (ud1->content_len == ud2->content_len && - ((ud1->flags & DETECT_CONTENT_NOCASE) == (ud2->flags & DETECT_CONTENT_NOCASE)) && - SCMemcmp(ud1->content, ud2->content, ud1->content_len) == 0) - return 1; - - return 0; -} - -ContentHash *ContentHashAlloc(DetectContentData *ptr) -{ - ContentHash *ch = SCMalloc(sizeof(ContentHash)); - if (unlikely(ch == NULL)) - return NULL; - - ch->ptr = ptr; - ch->cnt = 1; - ch->use = 0; - - return ch; -} - -UricontentHash *UricontentHashAlloc(DetectContentData *ptr) -{ - UricontentHash *ch = SCMalloc(sizeof(UricontentHash)); - if (unlikely(ch == NULL)) - return NULL; - - ch->ptr = ptr; - ch->cnt = 1; - ch->use = 0; - - return ch; -} - -void ContentHashFree(void *ch) -{ - SCFree(ch); -} - -void UricontentHashFree(void *ch) -{ - SCFree(ch); -} - -/** \brief Predict a strength value for patterns - * - * Patterns with high character diversity score higher. - * Alpha chars score not so high - * Other printable + a few common codes a little higher - * Everything else highest. - * Longer patterns score better than short patters. - * - * \param pat pattern - * \param patlen length of the patternn - * - * \retval s pattern score - */ -uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) -{ - uint8_t a[256]; - memset(&a, 0 ,sizeof(a)); - - uint32_t s = 0; - uint16_t u = 0; - for (u = 0; u < patlen; u++) { - if (a[pat[u]] == 0) { - if (isalpha(pat[u])) - s += 3; - else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF) - s += 4; - else - s += 6; - - a[pat[u]] = 1; - } else { - s++; - } - } - - return s; -} - -static void PopulateMpmHelperAddPatternToPktCtx(MpmCtx *mpm_ctx, - DetectContentData *cd, - Signature *s, uint8_t flags, - int chop) -{ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (chop) { - MpmAddPatternCI(mpm_ctx, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } else { - MpmAddPatternCI(mpm_ctx, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (chop) { - MpmAddPatternCS(mpm_ctx, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } else { - MpmAddPatternCS(mpm_ctx, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } - - return; -} - -static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx, - SigGroupHead *sgh, Signature *s, - SigMatch *mpm_sm) -{ - s->mpm_sm = mpm_sm; - - if (mpm_sm == NULL) { - SCLogDebug("%"PRIu32" no mpm pattern selected", s->id); - return; - } - - int sm_list = SigMatchListSMBelongsTo(s, mpm_sm); - if (sm_list == -1) - BUG_ON(SigMatchListSMBelongsTo(s, mpm_sm) == -1); - - uint8_t flags = 0; - - DetectContentData *cd = NULL; - - switch (sm_list) { - case DETECT_SM_LIST_PMATCH: - { - cd = (DetectContentData *)mpm_sm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - /* add the content to the "packet" mpm */ - if (SignatureHasPacketContent(s)) { - if (s->proto.proto[6 / 8] & 1 << (6 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, - cd, s, flags, 1); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, - cd, s, flags, 1); - } - } - if (s->proto.proto[17 / 8] & 1 << (17 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, - cd, s, flags, 1); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, - cd, s, flags, 1); - } - } - int i; - for (i = 0; i < 256; i++) { - if (i == 6 || i == 17) - continue; - if (s->proto.proto[i / 8] & (1 << (i % 8))) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, - cd, s, flags, 1); - break; - } - } - /* tell matcher we are inspecting packet */ - s->flags |= SIG_FLAG_MPM_PACKET; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; - } - } - if (SignatureHasStreamContent(s)) { - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCI(sgh->mpm_stream_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCI(sgh->mpm_stream_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCS(sgh->mpm_stream_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCS(sgh->mpm_stream_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - } - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } - } - } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - if (SignatureHasPacketContent(s)) { - /* add the content to the "packet" mpm */ - if (s->proto.proto[6 / 8] & 1 << (6 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_ts, - cd, s, flags, 0); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_tcp_ctx_tc, - cd, s, flags, 0); - } - } - if (s->proto.proto[17 / 8] & 1 << (17 % 8)) { - if (s->flags & SIG_FLAG_TOSERVER) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_ts, - cd, s, flags, 0); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_udp_ctx_tc, - cd, s, flags, 0); - } - } - int i; - for (i = 0; i < 256; i++) { - if (i == 6 || i == 17) - continue; - if (s->proto.proto[i / 8] & (1 << (i % 8))) { - PopulateMpmHelperAddPatternToPktCtx(sgh->mpm_proto_other_ctx, - cd, s, flags, 0); - break; - } - } - /* tell matcher we are inspecting packet */ - s->flags |= SIG_FLAG_MPM_PACKET; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_PACKET_NEG; - } - } - if (SignatureHasStreamContent(s)) { - /* add the content to the "packet" mpm */ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCI(sgh->mpm_stream_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCI(sgh->mpm_stream_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (s->flags & SIG_FLAG_TOSERVER) { - MpmAddPatternCS(sgh->mpm_stream_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (s->flags & SIG_FLAG_TOCLIENT) { - MpmAddPatternCS(sgh->mpm_stream_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } - /* tell matcher we are inspecting stream */ - s->flags |= SIG_FLAG_MPM_STREAM; - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - if (cd->flags & DETECT_CONTENT_NEGATED) { - SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id); - s->flags |= SIG_FLAG_MPM_STREAM_NEG; - } - } - } - if (SignatureHasPacketContent(s)) { - sgh->flags |= SIG_GROUP_HEAD_MPM_PACKET; - } - if (SignatureHasStreamContent(s)) { - sgh->flags |= SIG_GROUP_HEAD_MPM_STREAM; - } - - break; - } /* case DETECT_CONTENT */ - - case DETECT_SM_LIST_UMATCH: - case DETECT_SM_LIST_HRUDMATCH: - case DETECT_SM_LIST_HCBDMATCH: - case DETECT_SM_LIST_HSBDMATCH: - case DETECT_SM_LIST_HHDMATCH: - case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HMDMATCH: - case DETECT_SM_LIST_HCDMATCH: - case DETECT_SM_LIST_HSMDMATCH: - case DETECT_SM_LIST_HSCDMATCH: - case DETECT_SM_LIST_HUADMATCH: - case DETECT_SM_LIST_HHHDMATCH: - case DETECT_SM_LIST_HRHHDMATCH: - case DETECT_SM_LIST_DNSQUERY_MATCH: - { - MpmCtx *mpm_ctx_ts = NULL; - MpmCtx *mpm_ctx_tc = NULL; - - cd = (DetectContentData *)mpm_sm->ctx; - - if (sm_list == DETECT_SM_LIST_UMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_uri_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_URI; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HCBDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hcbd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HCBD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HSBDMATCH) { - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hsbd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSBD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hhd_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hhd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HRHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hrhd_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hrhd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HRHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HMDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hmd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HMD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HCDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hcd_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hcd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HCD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HRUDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hrud_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HRUD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HSMDMATCH) { - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hsmd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSMD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HSCDMATCH) { - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = sgh->mpm_hscd_ctx_tc; - sgh->flags |= SIG_GROUP_HEAD_MPM_HSCD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HUADMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_huad_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HUAD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HHHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hhhd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HHHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_HRHHDMATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_hrhhd_ctx_ts; - sgh->flags |= SIG_GROUP_HEAD_MPM_HRHHD; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } else if (sm_list == DETECT_SM_LIST_DNSQUERY_MATCH) { - if (s->flags & SIG_FLAG_TOSERVER) - mpm_ctx_ts = sgh->mpm_dnsquery_ctx_ts; - if (s->flags & SIG_FLAG_TOCLIENT) - mpm_ctx_tc = NULL; - sgh->flags |= SIG_GROUP_HEAD_MPM_DNSQUERY; - s->flags |= SIG_FLAG_MPM_APPLAYER; - if (cd->flags & DETECT_CONTENT_NEGATED) - s->flags |= SIG_FLAG_MPM_APPLAYER_NEG; - } - - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE) && - cd->content_len == cd->fp_chop_len) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - /* add the content to the mpm */ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCI(mpm_ctx_ts, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCI(mpm_ctx_tc, - cd->content + cd->fp_chop_offset, cd->fp_chop_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCS(mpm_ctx_ts, - cd->content + cd->fp_chop_offset, - cd->fp_chop_len, - 0, 0, cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCS(mpm_ctx_tc, - cd->content + cd->fp_chop_offset, - cd->fp_chop_len, - 0, 0, cd->id, s->num, flags); - } - } - } else { - if (DETECT_CONTENT_IS_SINGLE(cd) && - !(cd->flags & DETECT_CONTENT_NEGATED) && - !(cd->flags & DETECT_CONTENT_REPLACE)) { - cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED; - } - - /* add the content to the "uri" mpm */ - if (cd->flags & DETECT_CONTENT_NOCASE) { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCI(mpm_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCI(mpm_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } else { - if (mpm_ctx_ts != NULL) { - MpmAddPatternCS(mpm_ctx_ts, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - if (mpm_ctx_tc != NULL) { - MpmAddPatternCS(mpm_ctx_tc, - cd->content, cd->content_len, - 0, 0, - cd->id, s->num, flags); - } - } - } - /* tell matcher we are inspecting uri */ - s->mpm_pattern_id_div_8 = cd->id / 8; - s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8); - - break; - } - } /* switch (mpm_sm->type) */ - - SCLogDebug("%"PRIu32" adding cd->id %"PRIu32" to the mpm phase " - "(s->num %"PRIu32")", s->id, - ((DetectContentData *)mpm_sm->ctx)->id, s->num); - - return; -} - -SigMatch *RetrieveFPForSig(Signature *s) -{ - SigMatch *mpm_sm = NULL, *sm = NULL; - uint8_t has_non_negated_non_stream_pattern = 0; - - if (s->mpm_sm != NULL) - return s->mpm_sm; - - int list_id; - for (list_id = 0 ; list_id < DETECT_SM_LIST_MAX; list_id++) { - /* we have no keywords that support fp in this Signature sm list */ - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - /* this keyword isn't registered for fp support */ - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN) - return sm; - if (!(cd->flags & DETECT_CONTENT_NEGATED) && - (list_id != DETECT_SM_LIST_PMATCH) && - (list_id != DETECT_SM_LIST_HMDMATCH) && - (list_id != DETECT_SM_LIST_HSMDMATCH) && - (list_id != DETECT_SM_LIST_HSCDMATCH)) { - has_non_negated_non_stream_pattern = 1; - } - } - } - - int max_len = 0; - int max_len_negated = 0; - int max_len_non_negated = 0; - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - if (has_non_negated_non_stream_pattern && - ((list_id == DETECT_SM_LIST_PMATCH) || - (list_id == DETECT_SM_LIST_HMDMATCH) || - (list_id == DETECT_SM_LIST_HSMDMATCH) || - (list_id == DETECT_SM_LIST_HSCDMATCH))) { - continue; - } - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_NEGATED) { - if (max_len_negated < cd->content_len) - max_len_negated = cd->content_len; - } else { - if (max_len_non_negated < cd->content_len) - max_len_non_negated = cd->content_len; - } - } - } - - int skip_negated_content = 0; - if (max_len_non_negated == 0) { - max_len = max_len_negated; - skip_negated_content = 0; - } else { - max_len = max_len_non_negated; - skip_negated_content = 1; - } - - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - if (has_non_negated_non_stream_pattern && - ((list_id == DETECT_SM_LIST_PMATCH) || - (list_id == DETECT_SM_LIST_HMDMATCH) || - (list_id == DETECT_SM_LIST_HSMDMATCH) || - (list_id == DETECT_SM_LIST_HSCDMATCH))) { - continue; - } - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content) - continue; - if (cd->content_len < max_len) - continue; - - if (mpm_sm == NULL) { - mpm_sm = sm; - } else { - DetectContentData *data1 = (DetectContentData *)sm->ctx; - DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx; - uint32_t ls = PatternStrength(data1->content, data1->content_len); - uint32_t ss = PatternStrength(data2->content, data2->content_len); - if (ls > ss) { - mpm_sm = sm; - } else if (ls == ss) { - /* if 2 patterns are of equal strength, we pick the longest */ - if (data1->content_len > data2->content_len) - mpm_sm = sm; - } else { - SCLogDebug("sticking with mpm_sm"); - } - } /* else - if (mpm == NULL) */ - } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */ - } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */ - - return mpm_sm; -} - -SigMatch *RetrieveFPForSigV2(Signature *s) -{ - if (s->mpm_sm != NULL) - return s->mpm_sm; - - - SigMatch *mpm_sm = NULL, *sm = NULL; - int nn_sm_list[DETECT_SM_LIST_MAX]; - int n_sm_list[DETECT_SM_LIST_MAX]; - memset(nn_sm_list, 0, sizeof(nn_sm_list)); - memset(n_sm_list, 0, sizeof(n_sm_list)); - int count_nn_sm_list = 0; - int count_n_sm_list = 0; - int list_id; - - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { - if (!FastPatternSupportEnabledForSigMatchList(list_id)) - continue; - - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - - DetectContentData *cd = (DetectContentData *)sm->ctx; - if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) - return sm; - if (cd->flags & DETECT_CONTENT_NEGATED) { - n_sm_list[list_id] = 1; - count_n_sm_list++; - } else { - nn_sm_list[list_id] = 1; - count_nn_sm_list++; - } - } /* for */ - } /* for */ - - int *curr_sm_list = NULL; - int skip_negated_content = 1; - if (count_nn_sm_list > 0) { - curr_sm_list = nn_sm_list; - } else if (count_n_sm_list > 0) { - curr_sm_list = n_sm_list; - skip_negated_content = 0; - } else { - return NULL; - } - - int final_sm_list[DETECT_SM_LIST_MAX]; - int count_final_sm_list = 0; - int priority; - - SCFPSupportSMList *tmp = sm_fp_support_smlist_list; - while (tmp != NULL) { - for (priority = tmp->priority; - tmp != NULL && priority == tmp->priority; - tmp = tmp->next) { - - if (curr_sm_list[tmp->list_id] == 0) - continue; - final_sm_list[count_final_sm_list++] = tmp->list_id; - } - if (count_final_sm_list != 0) - break; - } + SCFPSupportSMList *tmp = sm_fp_support_smlist_list; + while (tmp != NULL) { + for (priority = tmp->priority; + tmp != NULL && priority == tmp->priority; + tmp = tmp->next) + { + if (curr_sm_list[tmp->list_id] == 0) + continue; + final_sm_list[count_final_sm_list++] = tmp->list_id; + } + if (count_final_sm_list != 0) + break; + } BUG_ON(count_final_sm_list == 0); int max_len = 0; int i; for (i = 0; i < count_final_sm_list; i++) { - for (sm = s->sm_lists[final_sm_list[i]]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; @@ -1858,7 +640,7 @@ SigMatch *RetrieveFPForSigV2(Signature *s) } for (i = 0; i < count_final_sm_list; i++) { - for (sm = s->sm_lists[final_sm_list[i]]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) continue; @@ -1886,937 +668,613 @@ SigMatch *RetrieveFPForSigV2(Signature *s) } else { SCLogDebug("sticking with mpm_sm"); } - } /* else - if */ - } /* for */ - } /* for */ - - return mpm_sm; -} - -/** - * \internal - * \brief Setup the mpm content. - * - * \param de_ctx Pointer to the detect engine context. - * \param sgh Pointer to the signature group head against which we are - * adding patterns to the mpm ctx. - * - * \retval 0 Always. - */ -static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - uint32_t sig = 0; - for (sig = 0; sig < sgh->sig_cnt; sig++) { - Signature *s = sgh->match_array[sig]; - if (s == NULL) - continue; - PopulateMpmAddPatternToMpm(de_ctx, sgh, s, s->mpm_sm); - } /* for (sig = 0; sig < sgh->sig_cnt; sig++) */ + } + } + } - return 0; + /* assign to signature */ + SetMpm(s, mpm_sm); + return; } -/** \brief Prepare the pattern matcher ctx in a sig group head. +/** \internal + * \brief The hash function for MpmStore + * + * \param ht Pointer to the hash table. + * \param data Pointer to the MpmStore. + * \param datalen Not used in our case. * - * \todo determine if a content match can set the 'single' flag - * \todo do error checking - * \todo rewrite the COPY stuff + * \retval hash The generated hash value. */ -int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) +static uint32_t MpmStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) { - Signature *s = NULL; - uint32_t has_co_packet = 0; /**< our sgh has packet payload inspecting content */ - uint32_t has_co_stream = 0; /**< our sgh has stream inspecting content */ - uint32_t has_co_uri = 0; /**< our sgh has uri inspecting content */ - /* used to indicate if sgh has atleast one sig with http_client_body */ - uint32_t has_co_hcbd = 0; - /* used to indicate if sgh has atleast one sig with http_server_body */ - uint32_t has_co_hsbd = 0; - /* used to indicate if sgh has atleast one sig with http_header */ - uint32_t has_co_hhd = 0; - /* used to indicate if sgh has atleast one sig with http_raw_header */ - uint32_t has_co_hrhd = 0; - /* used to indicate if sgh has atleast one sig with http_method */ - uint32_t has_co_hmd = 0; - /* used to indicate if sgh has atleast one sig with http_cookie */ - uint32_t has_co_hcd = 0; - /* used to indicate if sgh has atleast one sig with http_raw_uri */ - uint32_t has_co_hrud = 0; - /* used to indicate if sgh has atleast one sig with http_stat_msg */ - uint32_t has_co_hsmd = 0; - /* used to indicate if sgh has atleast one sig with http_stat_code */ - uint32_t has_co_hscd = 0; - /* used to indicate if sgh has atleast one sig with http_user_agent */ - uint32_t has_co_huad = 0; - /* used to indicate if sgh has atleast one sig with http_host */ - uint32_t has_co_hhhd = 0; - /* used to indicate if sgh has atleast one sig with http_raw_host */ - uint32_t has_co_hrhhd = 0; - //uint32_t cnt = 0; - uint32_t sig = 0; - /* sgh has at least one sig with dns_query */ - int has_co_dnsquery = 0; - - /* see if this head has content and/or uricontent */ - for (sig = 0; sig < sh->sig_cnt; sig++) { - s = sh->match_array[sig]; - if (s == NULL) - continue; - - if (SignatureHasPacketContent(s) == 1) { - has_co_packet = 1; - } - if (SignatureHasStreamContent(s) == 1) { - has_co_stream = 1; - } - - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - has_co_uri = 1; - } - - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { - has_co_hcbd = 1; - } - - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { - has_co_hsbd = 1; - } - - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { - has_co_hhd = 1; - } - - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - has_co_hrhd = 1; - } - - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { - has_co_hmd = 1; - } + const MpmStore *ms = (MpmStore *)data; + uint32_t hash = 0; + uint32_t b = 0; - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { - has_co_hcd = 1; - } + for (b = 0; b < ms->sid_array_size; b++) + hash += ms->sid_array[b]; - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - has_co_hrud = 1; - } + return hash % ht->array_size; +} - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { - has_co_hsmd = 1; - } +/** + * \brief The Compare function for MpmStore + * + * \param data1 Pointer to the first MpmStore. + * \param len1 Not used. + * \param data2 Pointer to the second MpmStore. + * \param len2 Not used. + * + * \retval 1 If the 2 MpmStores sent as args match. + * \retval 0 If the 2 MpmStores sent as args do not match. + */ +static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + const MpmStore *ms1 = (MpmStore *)data1; + const MpmStore *ms2 = (MpmStore *)data2; - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { - has_co_hscd = 1; - } + if (ms1->sid_array_size != ms2->sid_array_size) + return 0; - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { - has_co_huad = 1; - } + if (ms1->buffer != ms2->buffer) + return 0; - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - has_co_hhhd = 1; - } + if (ms1->direction != ms2->direction) + return 0; - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { - has_co_hrhhd = 1; - } + if (ms1->sm_list != ms2->sm_list) + return 0; - if (s->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH] != NULL) { - has_co_dnsquery = 1; - } + if (SCMemcmp(ms1->sid_array, ms2->sid_array, + ms1->sid_array_size) != 0) + { + return 0; } - /* intialize contexes */ - if (has_co_packet) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); - sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); - } else { - sh->mpm_proto_tcp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_proto_tcp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_proto_tcp_ctx_ts == NULL || sh->mpm_proto_tcp_ctx_tc == NULL) { - SCLogDebug("sh->mpm_proto_tcp_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - MpmInitCtx(sh->mpm_proto_tcp_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_proto_tcp_ctx_tc, de_ctx->mpm_matcher); - - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); - sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); - } else { - sh->mpm_proto_udp_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_proto_udp_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_proto_udp_ctx_ts == NULL || sh->mpm_proto_udp_ctx_tc == NULL) { - SCLogDebug("sh->mpm_proto_udp_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - MpmInitCtx(sh->mpm_proto_udp_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_proto_udp_ctx_tc, de_ctx->mpm_matcher); + return 1; +} - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_proto_other_ctx = - MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); - } else { - sh->mpm_proto_other_ctx = - MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_proto_other_ctx == NULL) { - SCLogDebug("sh->mpm_proto_other_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); +static void MpmStoreFreeFunc(void *ptr) +{ + MpmStore *ms = ptr; + if (ms != NULL) { + if (ms->mpm_ctx != NULL && !ms->mpm_ctx->global) + { + SCLogDebug("destroying mpm_ctx %p", ms->mpm_ctx); + mpm_table[ms->mpm_ctx->mpm_type].DestroyCtx(ms->mpm_ctx); + SCFree(ms->mpm_ctx); } - MpmInitCtx(sh->mpm_proto_other_ctx, de_ctx->mpm_matcher); - } /* if (has_co_packet) */ + ms->mpm_ctx = NULL; - if (has_co_stream) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_stream_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); - sh->mpm_stream_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); - } else { - sh->mpm_stream_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_stream_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_stream_ctx_tc == NULL || sh->mpm_stream_ctx_ts == NULL) { - SCLogDebug("sh->mpm_stream_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - MpmInitCtx(sh->mpm_stream_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_stream_ctx_tc, de_ctx->mpm_matcher); + SCFree(ms->sid_array); + SCFree(ms); } +} - if (has_co_uri) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); - } else { - sh->mpm_uri_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_uri_ctx_ts == NULL) { - SCLogDebug("sh->mpm_uri_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_uri_ctx_ts, de_ctx->mpm_matcher); - } +/** + * \brief Initializes the MpmStore mpm hash table to be used by the detection + * engine context. + * + * \param de_ctx Pointer to the detection engine context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int MpmStoreInit(DetectEngineCtx *de_ctx) +{ + de_ctx->mpm_hash_table = HashListTableInit(4096, + MpmStoreHashFunc, + MpmStoreCompareFunc, + MpmStoreFreeFunc); + if (de_ctx->mpm_hash_table == NULL) + goto error; - if (has_co_hcbd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hcbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); - } else { - sh->mpm_hcbd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hcbd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hcbd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + return 0; - MpmInitCtx(sh->mpm_hcbd_ctx_ts, de_ctx->mpm_matcher); - } +error: + return -1; +} - if (has_co_hsbd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hsbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 1); - } else { - sh->mpm_hsbd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hsbd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hsbd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } +/** + * \brief Adds a MpmStore to the detection engine context MpmStore + * + * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to the MpmStore. + * + * \retval ret 0 on Successfully adding the argument sgh; -1 on failure. + */ +static int MpmStoreAdd(DetectEngineCtx *de_ctx, MpmStore *s) +{ + int ret = HashListTableAdd(de_ctx->mpm_hash_table, (void *)s, 0); + return ret; +} - MpmInitCtx(sh->mpm_hsbd_ctx_tc, de_ctx->mpm_matcher); - } +/** + * \brief Used to lookup a MpmStore from the MpmStore + * + * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to the MpmStore. + * + * \retval rsgh On success a pointer to the MpmStore if the MpmStore is + * found in the hash table; NULL on failure. + */ +static MpmStore *MpmStoreLookup(DetectEngineCtx *de_ctx, MpmStore *s) +{ + MpmStore *rs = HashListTableLookup(de_ctx->mpm_hash_table, + (void *)s, 0); + return rs; +} - if (has_co_hhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); - sh->mpm_hhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); - } else { - sh->mpm_hhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_hhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); +void MpmStoreReportStats(const DetectEngineCtx *de_ctx) +{ + HashListTableBucket *htb = NULL; + + int app_mpms_cnt = 0; + DetectMpmAppLayerKeyword *a = de_ctx->app_mpms; + while (a->reg != NULL) { + a++; + app_mpms_cnt++; + } + uint32_t stats[MPMB_MAX] = {0}; + uint32_t appstats[app_mpms_cnt + 1]; // +1 to silence scan-build + memset(&appstats, 0x00, sizeof(appstats)); + + for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table); + htb != NULL; + htb = HashListTableGetListNext(htb)) + { + const MpmStore *ms = (MpmStore *)HashListTableGetListData(htb); + if (ms == NULL) { + continue; } - if (sh->mpm_hhd_ctx_ts == NULL || sh->mpm_hhd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + if (ms->buffer < MPMB_MAX) + stats[ms->buffer]++; + else if (ms->sm_list != DETECT_SM_LIST_PMATCH) { + int i = 0; + DetectMpmAppLayerKeyword *am = de_ctx->app_mpms; + while (am->reg != NULL) { + if (ms->sm_list == am->reg->sm_list && + ms->direction == am->reg->direction) + { + SCLogDebug("%s %s: %u patterns. Min %u, Max %u. Ctx %p", + am->reg->name, + am->reg->direction == SIG_FLAG_TOSERVER ? "toserver":"toclient", + ms->mpm_ctx->pattern_cnt, + ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen, + ms->mpm_ctx); + appstats[i]++; + break; + } + i++; + am++; + } } - - MpmInitCtx(sh->mpm_hhd_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_hhd_ctx_tc, de_ctx->mpm_matcher); } - if (has_co_hrhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hrhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); - sh->mpm_hrhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); - } else { - sh->mpm_hrhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_hrhd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); + if (!(de_ctx->flags & DE_QUIET)) { + int x; + for (x = 0; x < MPMB_MAX; x++) { + SCLogPerf("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]); } - if (sh->mpm_hrhd_ctx_ts == NULL || sh->mpm_hrhd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hrhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + for (x = 0; x < app_mpms_cnt; x++) { + if (appstats[x] == 0) + continue; + const char *name = de_ctx->app_mpms[x].reg->name; + char *direction = de_ctx->app_mpms[x].reg->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient"; + SCLogPerf("AppLayer MPM \"%s %s\": %u", direction, name, appstats[x]); } - - MpmInitCtx(sh->mpm_hrhd_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_hrhd_ctx_tc, de_ctx->mpm_matcher); } +} - if (has_co_hmd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); - } else { - sh->mpm_hmd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hmd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hmd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } +/** + * \brief Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by + * MpmStoreInit() function. + * + * \param de_ctx Pointer to the detection engine context. + */ +void MpmStoreFree(DetectEngineCtx *de_ctx) +{ + if (de_ctx->mpm_hash_table == NULL) + return; - MpmInitCtx(sh->mpm_hmd_ctx_ts, de_ctx->mpm_matcher); - } + HashListTableFree(de_ctx->mpm_hash_table); + de_ctx->mpm_hash_table = NULL; + return; +} - if (has_co_hcd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hcd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); - sh->mpm_hcd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); - } else { - sh->mpm_hcd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - sh->mpm_hcd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hcd_ctx_ts == NULL || sh->mpm_hcd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hcd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } +void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms) +{ + const Signature *s = NULL; + uint32_t sig; - MpmInitCtx(sh->mpm_hcd_ctx_ts, de_ctx->mpm_matcher); - MpmInitCtx(sh->mpm_hcd_ctx_tc, de_ctx->mpm_matcher); - } + int dir = 0; - if (has_co_hrud) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hrud_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); - } else { - sh->mpm_hrud_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hrud_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hrud_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + if (ms->buffer != MPMB_MAX) { + BUG_ON(ms->sm_list != DETECT_SM_LIST_PMATCH); - MpmInitCtx(sh->mpm_hrud_ctx_ts, de_ctx->mpm_matcher); - } + switch (ms->buffer) { + /* TS is 1 */ + case MPMB_TCP_PKT_TS: + case MPMB_TCP_STREAM_TS: + case MPMB_UDP_TS: + dir = 1; + break; - if (has_co_hsmd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hsmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); - } else { - sh->mpm_hsmd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hsmd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hsmd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + /* TC is 0 */ + default: + case MPMB_UDP_TC: + case MPMB_TCP_STREAM_TC: + case MPMB_TCP_PKT_TC: + case MPMB_OTHERIP: /**< use 0 for other */ + dir = 0; + break; } + } else { + BUG_ON(ms->sm_list == DETECT_SM_LIST_PMATCH); + BUG_ON(ms->direction == 0); + BUG_ON(ms->direction == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)); - MpmInitCtx(sh->mpm_hsmd_ctx_tc, de_ctx->mpm_matcher); + if (ms->direction == SIG_FLAG_TOSERVER) + dir = 1; + else + dir = 0; } - if (has_co_hscd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hscd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); - } else { - sh->mpm_hscd_ctx_tc = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 1); - } - if (sh->mpm_hscd_ctx_tc == NULL) { - SCLogDebug("sh->mpm_hscd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir); + if (ms->mpm_ctx == NULL) + return; - MpmInitCtx(sh->mpm_hscd_ctx_tc, de_ctx->mpm_matcher); - } + MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher); - if (has_co_huad) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); - } else { - sh->mpm_huad_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_huad_ctx_ts == NULL) { - SCLogDebug("sh->mpm_huad_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } + /* add the patterns */ + for (sig = 0; sig < (ms->sid_array_size * 8); sig++) { + if (ms->sid_array[sig / 8] & (1 << (sig % 8))) { + s = de_ctx->sig_array[sig]; + if (s == NULL) + continue; + if (s->init_data->mpm_sm == NULL) + continue; + int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); + if (list < 0) + continue; + if (list != ms->sm_list) + continue; + if ((s->flags & ms->direction) == 0) + continue; - MpmInitCtx(sh->mpm_huad_ctx_ts, de_ctx->mpm_matcher); - } + SCLogDebug("adding %u", s->id); + + const DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx; + + int skip = 0; + /* negated logic: if mpm match can't be used to be sure about this + * pattern, we have to inspect the rule fully regardless of mpm + * match. So in this case there is no point of adding it at all. + * The non-mpm list entry for the sig will make sure the sig is + * inspected. */ + if ((cd->flags & DETECT_CONTENT_NEGATED) && + !(DETECT_CONTENT_MPM_IS_CONCLUSIVE(cd))) + { + skip = 1; + SCLogDebug("not adding negated mpm as it's not 'single'"); + } - if (has_co_hhhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 0); - } else { - sh->mpm_hhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hhhd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hhhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + if (!skip) { + PopulateMpmHelperAddPattern(ms->mpm_ctx, + cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP)); + } } - - MpmInitCtx(sh->mpm_hhhd_ctx_ts, de_ctx->mpm_matcher); } - if (has_co_hrhhd) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_hrhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 0); - } else { - sh->mpm_hrhhd_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_hrhhd_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hrhhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); + if (ms->mpm_ctx->pattern_cnt == 0) { + MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx); + ms->mpm_ctx = NULL; + } else { + if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { + if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) { + mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx); + } } - - MpmInitCtx(sh->mpm_hrhhd_ctx_ts, de_ctx->mpm_matcher); } +} - if (has_co_dnsquery) { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - sh->mpm_dnsquery_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_dnsquery, 0); - } else { - sh->mpm_dnsquery_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0); - } - if (sh->mpm_dnsquery_ctx_ts == NULL) { - SCLogDebug("sh->mpm_hrhhd_ctx == NULL. This should never happen"); - exit(EXIT_FAILURE); - } - - MpmInitCtx(sh->mpm_dnsquery_ctx_ts, de_ctx->mpm_matcher); - } - if (has_co_packet || - has_co_stream || - has_co_uri || - has_co_hcbd || - has_co_hsbd || - has_co_hhd || - has_co_hrhd || - has_co_hmd || - has_co_hcd || - has_co_hsmd || - has_co_hscd || - has_co_hrud || - has_co_huad || - has_co_hhhd || - has_co_hrhhd || - has_co_dnsquery) +/** \brief Get MpmStore for a built-in buffer type + * + */ +MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, + enum MpmBuiltinBuffers buf) { - - PatternMatchPreparePopulateMpm(de_ctx, sh); - - //if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (sh->mpm_proto_tcp_ctx_ts != NULL) { - if (sh->mpm_proto_tcp_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); - sh->mpm_proto_tcp_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_tcp_ctx_ts->mpm_type]. - Prepare(sh->mpm_proto_tcp_ctx_ts); - } - } - } - } - if (sh->mpm_proto_tcp_ctx_tc != NULL) { - if (sh->mpm_proto_tcp_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); - sh->mpm_proto_tcp_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_tcp_ctx_tc->mpm_type]. - Prepare(sh->mpm_proto_tcp_ctx_tc); - } - } - } - } - - if (sh->mpm_proto_udp_ctx_ts != NULL) { - if (sh->mpm_proto_udp_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); - sh->mpm_proto_udp_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_udp_ctx_ts->mpm_type]. - Prepare(sh->mpm_proto_udp_ctx_ts); - } - } - } - } - if (sh->mpm_proto_udp_ctx_tc != NULL) { - if (sh->mpm_proto_udp_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); - sh->mpm_proto_udp_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_udp_ctx_tc->mpm_type]. - Prepare(sh->mpm_proto_udp_ctx_tc); - } - } - } - } - - if (sh->mpm_proto_other_ctx != NULL) { - if (sh->mpm_proto_other_ctx->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); - sh->mpm_proto_other_ctx = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_proto_other_ctx->mpm_type].Prepare != NULL) { - mpm_table[sh->mpm_proto_other_ctx->mpm_type]. - Prepare(sh->mpm_proto_other_ctx); - } - } - } - } - - if (sh->mpm_stream_ctx_ts != NULL) { - if (sh->mpm_stream_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); - sh->mpm_stream_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_stream_ctx_ts->mpm_type].Prepare(sh->mpm_stream_ctx_ts); - } - } - } - if (sh->mpm_stream_ctx_tc != NULL) { - if (sh->mpm_stream_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); - sh->mpm_stream_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_stream_ctx_tc->mpm_type].Prepare(sh->mpm_stream_ctx_tc); - } - } - } - - if (sh->mpm_uri_ctx_ts != NULL) { - if (sh->mpm_uri_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); - sh->mpm_uri_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_uri_ctx_ts->mpm_type].Prepare(sh->mpm_uri_ctx_ts); - } - } - } - - if (sh->mpm_hcbd_ctx_ts != NULL) { - if (sh->mpm_hcbd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); - sh->mpm_hcbd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcbd_ctx_ts->mpm_type].Prepare(sh->mpm_hcbd_ctx_ts); - } - } - } - - if (sh->mpm_hsbd_ctx_tc != NULL) { - if (sh->mpm_hsbd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsbd_ctx_tc); - sh->mpm_hsbd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hsbd_ctx_tc->mpm_type].Prepare(sh->mpm_hsbd_ctx_tc); - } - } - } - - if (sh->mpm_hhd_ctx_ts != NULL) { - if (sh->mpm_hhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); - sh->mpm_hhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhd_ctx_ts); - } - } - } - if (sh->mpm_hhd_ctx_tc != NULL) { - if (sh->mpm_hhd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); - sh->mpm_hhd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhd_ctx_tc->mpm_type].Prepare(sh->mpm_hhd_ctx_tc); - } - } - } - - if (sh->mpm_hrhd_ctx_ts != NULL) { - if (sh->mpm_hrhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); - sh->mpm_hrhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhd_ctx_ts); - } - } - } - if (sh->mpm_hrhd_ctx_tc != NULL) { - if (sh->mpm_hrhd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); - sh->mpm_hrhd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhd_ctx_tc->mpm_type].Prepare(sh->mpm_hrhd_ctx_tc); - } - } - } - - if (sh->mpm_hmd_ctx_ts != NULL) { - if (sh->mpm_hmd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); - sh->mpm_hmd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hmd_ctx_ts->mpm_type].Prepare(sh->mpm_hmd_ctx_ts); - } - } - } - - if (sh->mpm_hcd_ctx_ts != NULL) { - if (sh->mpm_hcd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); - sh->mpm_hcd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcd_ctx_ts->mpm_type].Prepare(sh->mpm_hcd_ctx_ts); - } - } - } - if (sh->mpm_hcd_ctx_tc != NULL) { - if (sh->mpm_hcd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); - sh->mpm_hcd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hcd_ctx_tc->mpm_type].Prepare(sh->mpm_hcd_ctx_tc); - } - } - } - - if (sh->mpm_hrud_ctx_ts != NULL) { - if (sh->mpm_hrud_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); - sh->mpm_hrud_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrud_ctx_ts->mpm_type].Prepare(sh->mpm_hrud_ctx_ts); - } - } - } - - if (sh->mpm_hsmd_ctx_tc != NULL) { - if (sh->mpm_hsmd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); - sh->mpm_hsmd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hsmd_ctx_tc->mpm_type].Prepare(sh->mpm_hsmd_ctx_tc); - } - } - } - - if (sh->mpm_hscd_ctx_tc != NULL) { - if (sh->mpm_hscd_ctx_tc->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); - sh->mpm_hscd_ctx_tc = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hscd_ctx_tc->mpm_type].Prepare(sh->mpm_hscd_ctx_tc); - } - } - } - - if (sh->mpm_huad_ctx_ts != NULL) { - if (sh->mpm_huad_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); - sh->mpm_huad_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_huad_ctx_ts->mpm_type].Prepare(sh->mpm_huad_ctx_ts); - } - } - } - - if (sh->mpm_hhhd_ctx_ts != NULL) { - if (sh->mpm_hhhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); - sh->mpm_hhhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hhhd_ctx_ts); - } - } - } - - if (sh->mpm_hrhhd_ctx_ts != NULL) { - if (sh->mpm_hrhhd_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); - sh->mpm_hrhhd_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_hrhhd_ctx_ts->mpm_type].Prepare(sh->mpm_hrhhd_ctx_ts); - } - } - } - - if (sh->mpm_dnsquery_ctx_ts != NULL) { - if (sh->mpm_dnsquery_ctx_ts->pattern_cnt == 0) { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); - sh->mpm_dnsquery_ctx_ts = NULL; - } else { - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) { - if (mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare != NULL) - mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare(sh->mpm_dnsquery_ctx_ts); - } - } - } - //} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */ - } else { - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx); - sh->mpm_proto_other_ctx = NULL; - - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_ts); - sh->mpm_proto_tcp_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_ts); - sh->mpm_proto_udp_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_ts); - sh->mpm_stream_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_uri_ctx_ts); - sh->mpm_uri_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcbd_ctx_ts); - sh->mpm_hcbd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_ts); - sh->mpm_hhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_ts); - sh->mpm_hrhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hmd_ctx_ts); - sh->mpm_hmd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_ts); - sh->mpm_hcd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrud_ctx_ts); - sh->mpm_hrud_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_huad_ctx_ts); - sh->mpm_huad_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhhd_ctx_ts); - sh->mpm_hhhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts); - sh->mpm_hrhhd_ctx_ts = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts); - sh->mpm_dnsquery_ctx_ts = NULL; - - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc); - sh->mpm_proto_tcp_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_udp_ctx_tc); - sh->mpm_proto_udp_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_stream_ctx_tc); - sh->mpm_stream_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hhd_ctx_tc); - sh->mpm_hhd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhd_ctx_tc); - sh->mpm_hrhd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hcd_ctx_tc); - sh->mpm_hcd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hsmd_ctx_tc); - sh->mpm_hsmd_ctx_tc = NULL; - MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hscd_ctx_tc); - sh->mpm_hscd_ctx_tc = NULL; + const Signature *s = NULL; + uint32_t sig; + uint32_t cnt = 0; + int direction = 0; + uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; + uint8_t sids_array[max_sid]; + memset(sids_array, 0x00, max_sid); + int sgh_mpm_context = 0; + + switch (buf) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_PKT_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet; + break; + case MPMB_TCP_STREAM_TS: + case MPMB_TCP_STREAM_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_stream; + break; + case MPMB_UDP_TS: + case MPMB_UDP_TC: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet; + break; + case MPMB_OTHERIP: + sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet; + break; + default: + break; } - return 0; -} + switch(buf) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_STREAM_TS: + case MPMB_UDP_TS: + direction = SIG_FLAG_TOSERVER; + break; -/** \brief Pattern ID Hash for sharing pattern id's - * - * A per detection engine hash to make sure each pattern has a unique - * global id but patterns that are the same share id's. - */ -typedef struct MpmPatternIdTableElmt_ { - uint8_t *pattern; /**< ptr to the pattern */ - uint16_t pattern_len; /**< pattern len */ - PatIntId id; /**< pattern id */ - uint16_t dup_count; /**< duplicate count */ - uint8_t sm_list; /**< SigMatch list */ -} MpmPatternIdTableElmt; - -/** \brief Hash compare func for MpmPatternId api - * \retval 1 patterns are the same - * \retval 0 patterns are not the same - **/ -static char MpmPatternIdCompare(void *p1, uint16_t len1, void *p2, uint16_t len2) -{ - SCEnter(); - BUG_ON(len1 < sizeof(MpmPatternIdTableElmt)); - BUG_ON(len2 < sizeof(MpmPatternIdTableElmt)); + case MPMB_TCP_PKT_TC: + case MPMB_TCP_STREAM_TC: + case MPMB_UDP_TC: + direction = SIG_FLAG_TOCLIENT; + break; - MpmPatternIdTableElmt *e1 = (MpmPatternIdTableElmt *)p1; - MpmPatternIdTableElmt *e2 = (MpmPatternIdTableElmt *)p2; + case MPMB_OTHERIP: + direction = (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER); + break; - if (e1->pattern_len != e2->pattern_len || - e1->sm_list != e2->sm_list) { - SCReturnInt(0); + case MPMB_MAX: + BUG_ON(1); + break; } - if (SCMemcmp(e1->pattern, e2->pattern, e1->pattern_len) != 0) { - SCReturnInt(0); - } + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; - SCReturnInt(1); -} + if (s->init_data->mpm_sm == NULL) + continue; -/** \brief Hash func for MpmPatternId api - * \retval hash hash value - */ -static uint32_t MpmPatternIdHashFunc(HashTable *ht, void *p, uint16_t len) -{ - SCEnter(); - BUG_ON(len < sizeof(MpmPatternIdTableElmt)); + int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); + if (list < 0) + continue; - MpmPatternIdTableElmt *e = (MpmPatternIdTableElmt *)p; - uint32_t hash = e->pattern_len; - uint16_t u = 0; + if (list != DETECT_SM_LIST_PMATCH) + continue; - for (u = 0; u < e->pattern_len; u++) { - hash += e->pattern[u]; + switch (buf) { + case MPMB_TCP_PKT_TS: + case MPMB_TCP_PKT_TC: + if (SignatureHasPacketContent(s) == 1) + { + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + } + break; + case MPMB_TCP_STREAM_TS: + case MPMB_TCP_STREAM_TC: + if (SignatureHasStreamContent(s) == 1) + { + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + } + break; + case MPMB_UDP_TS: + case MPMB_UDP_TC: + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + break; + case MPMB_OTHERIP: + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; + break; + default: + break; + } } - SCReturnUInt(hash % ht->array_size); -} + if (cnt == 0) + return NULL; -/** \brief free a MpmPatternIdTableElmt */ -static void MpmPatternIdTableElmtFree(void *e) -{ - SCEnter(); - MpmPatternIdTableElmt *c = (MpmPatternIdTableElmt *)e; - SCFree(c->pattern); - SCFree(c); - SCReturn; + MpmStore lookup = { sids_array, max_sid, direction, buf, DETECT_SM_LIST_PMATCH, 0, NULL}; + + MpmStore *result = MpmStoreLookup(de_ctx, &lookup); + if (result == NULL) { + MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); + if (copy == NULL) + return NULL; + uint8_t *sids = SCCalloc(1, max_sid); + if (sids == NULL) { + SCFree(copy); + return NULL; + } + + memcpy(sids, sids_array, max_sid); + copy->sid_array = sids; + copy->sid_array_size = max_sid; + copy->buffer = buf; + copy->direction = direction; + copy->sm_list = DETECT_SM_LIST_PMATCH; + copy->sgh_mpm_context = sgh_mpm_context; + + MpmStoreSetup(de_ctx, copy); + MpmStoreAdd(de_ctx, copy); + return copy; + } else { + return result; + } } -/** \brief alloc initialize the MpmPatternIdHash */ -MpmPatternIdStore *MpmPatternIdTableInitHash(void) +static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, DetectMpmAppLayerKeyword *am) { - SCEnter(); + const Signature *s = NULL; + uint32_t sig; + uint32_t cnt = 0; + uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; + uint8_t sids_array[max_sid]; + memset(sids_array, 0x00, max_sid); - MpmPatternIdStore *ht = SCMalloc(sizeof(MpmPatternIdStore)); - BUG_ON(ht == NULL); - memset(ht, 0x00, sizeof(MpmPatternIdStore)); + SCLogDebug("handling %s direction %s for list %d", am->reg->name, + am->reg->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + am->reg->sm_list); - ht->hash = HashTableInit(65536, MpmPatternIdHashFunc, MpmPatternIdCompare, MpmPatternIdTableElmtFree); - BUG_ON(ht->hash == NULL); + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; - SCReturnPtr(ht, "MpmPatternIdStore"); -} + if (s->init_data->mpm_sm == NULL) + continue; -void MpmPatternIdTableFreeHash(MpmPatternIdStore *ht) -{ - SCEnter(); + int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); + if (list < 0) + continue; - if (ht == NULL) { - SCReturn; - } + if ((s->flags & am->reg->direction) == 0) + continue; + + if (list != am->reg->sm_list) + continue; - if (ht->hash != NULL) { - HashTableFree(ht->hash); + sids_array[s->num / 8] |= 1 << (s->num % 8); + cnt++; } - SCFree(ht); - SCReturn; -} + if (cnt == 0) + return NULL; -uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *ht) -{ - if (ht == NULL) { - return 0; + MpmStore lookup = { sids_array, max_sid, am->reg->direction, + MPMB_MAX, am->reg->sm_list, 0, NULL}; + SCLogDebug("am->direction %d am->sm_list %d", + am->reg->direction, am->reg->sm_list); + + MpmStore *result = MpmStoreLookup(de_ctx, &lookup); + if (result == NULL) { + SCLogDebug("new unique mpm for %s %s: %u patterns", + am->reg->name, + am->reg->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + cnt); + + MpmStore *copy = SCCalloc(1, sizeof(MpmStore)); + if (copy == NULL) + return NULL; + uint8_t *sids = SCCalloc(1, max_sid); + if (sids == NULL) { + SCFree(copy); + return NULL; + } + + memcpy(sids, sids_array, max_sid); + copy->sid_array = sids; + copy->sid_array_size = max_sid; + copy->buffer = MPMB_MAX; + copy->direction = am->reg->direction; + copy->sm_list = am->reg->sm_list; + copy->sgh_mpm_context = am->sgh_mpm_context; + + MpmStoreSetup(de_ctx, copy); + MpmStoreAdd(de_ctx, copy); + return copy; + } else { + SCLogDebug("using existing mpm %p", result); + return result; } - - return ht->max_id; + return NULL; } -/** - * \brief Get the pattern id for a content pattern - * - * \param ht mpm pattern id hash table store - * \param co content pattern data +/** \brief Prepare the pattern matcher ctx in a sig group head. * - * \retval id pattern id - * \initonly */ -uint32_t DetectContentGetId(MpmPatternIdStore *ht, DetectContentData *co) +int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh) { - SCEnter(); - - BUG_ON(ht == NULL || ht->hash == NULL); - - MpmPatternIdTableElmt *e = NULL; - MpmPatternIdTableElmt *r = NULL; - uint32_t id = 0; - - e = SCMalloc(sizeof(MpmPatternIdTableElmt)); - BUG_ON(e == NULL); - memset(e, 0, sizeof(MpmPatternIdTableElmt)); - e->pattern = SCMalloc(co->content_len); - BUG_ON(e->pattern == NULL); - memcpy(e->pattern, co->content, co->content_len); - e->pattern_len = co->content_len; - e->id = 0; - - r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt)); - if (r == NULL) { - e->id = ht->max_id; - ht->max_id++; - id = e->id; - - int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt)); - BUG_ON(ret != 0); + MpmStore *mpm_store = NULL; + if (SGH_PROTO(sh, IPPROTO_TCP)) { + if (SGH_DIRECTION_TS(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS); + if (mpm_store != NULL) { + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); + } - e = NULL; + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS); + if (mpm_store != NULL) { + PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); + } + } + if (SGH_DIRECTION_TC(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC); + if (mpm_store != NULL) { + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); + } - ht->unique_patterns++; + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC); + if (mpm_store != NULL) { + PrefilterPktStreamRegister(sh, mpm_store->mpm_ctx); + } + } + } else if (SGH_PROTO(sh, IPPROTO_UDP)) { + if (SGH_DIRECTION_TS(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS); + if (mpm_store != NULL) { + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); + } + } + if (SGH_DIRECTION_TC(sh)) { + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC); + if (mpm_store != NULL) { + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); + } + } } else { - id = r->id; + mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP); + if (mpm_store != NULL) { + PrefilterPktPayloadRegister(sh, mpm_store->mpm_ctx); + } + } - ht->shared_patterns++; + int i = 0; + DetectMpmAppLayerKeyword *a = de_ctx->app_mpms; + while (a->reg != NULL) { + i++; + a++; } + if (i == 0) + return 0; - if (e != NULL) - MpmPatternIdTableElmtFree(e); + sh->init->app_mpms = SCCalloc(i, sizeof(MpmCtx *)); + BUG_ON(sh->init->app_mpms == NULL); + + a = de_ctx->app_mpms; + while (a->reg != NULL) { + if ((a->reg->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) || + (a->reg->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh))) + { + mpm_store = MpmStorePrepareBufferAppLayer(de_ctx, sh, a); + if (mpm_store != NULL) { + sh->init->app_mpms[a->reg->id] = mpm_store->mpm_ctx; + + /* if we have just certain types of negated patterns, + * mpm_ctx can be NULL */ + if (a->reg->PrefilterRegister && mpm_store->mpm_ctx) { + BUG_ON(a->reg->PrefilterRegister(sh, mpm_store->mpm_ctx) != 0); + } + } + } + a++; + } - SCReturnUInt(id); + return 0; } typedef struct DetectFPAndItsId_ { @@ -2848,13 +1306,21 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) * true size, since duplicates are removed below, but counted here. */ for (s = de_ctx->sig_list; s != NULL; s = s->next) { - s->mpm_sm = RetrieveFPForSigV2(s); - if (s->mpm_sm != NULL) { - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + if (s->flags & SIG_FLAG_PREFILTER) + continue; + + RetrieveFPForSig(s); + if (s->init_data->mpm_sm != NULL) { + DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx; struct_total_size += sizeof(DetectFPAndItsId); content_total_size += cd->content_len; + + s->flags |= SIG_FLAG_PREFILTER; } } + /* no rules */ + if (struct_total_size + content_total_size == 0) + return 0; /* array hash buffer - i've run out of ideas to name it */ uint8_t *ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size)); @@ -2866,12 +1332,13 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) PatIntId max_id = 0; DetectFPAndItsId *struct_offset = (DetectFPAndItsId *)ahb; uint8_t *content_offset = ahb + struct_total_size; + for (s = de_ctx->sig_list; s != NULL; s = s->next) { - if (s->mpm_sm != NULL) { - int sm_list = SigMatchListSMBelongsTo(s, s->mpm_sm); + if (s->init_data->mpm_sm != NULL) { + int sm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); BUG_ON(sm_list == -1); - DetectContentData *cd = (DetectContentData *)s->mpm_sm->ctx; + DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx; DetectFPAndItsId *dup = (DetectFPAndItsId *)ahb; if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { content = cd->content + cd->fp_chop_offset; @@ -2903,8 +1370,8 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) break; } if (dup != struct_offset) { - /* Exited for-loop before the end, so found an existing match. - * Use its ID. */ + /* Exited for-loop before the end, so found an existing match. + * Use its ID. */ cd->id = dup->id; continue; } @@ -2923,14 +1390,14 @@ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx) content_offset += content_len; if (flags & DETECT_CONTENT_NOCASE) { - /* Need to store case-insensitive patterns as lower case - * because SCMemcmpLowercase() above assumes that all - * patterns are stored lower case so that it doesn't - * need to relower its first argument. - */ - memcpy_tolower(struct_offset->content, content, content_len); + /* Need to store case-insensitive patterns as lower case + * because SCMemcmpLowercase() above assumes that all + * patterns are stored lower case so that it doesn't + * need to relower its first argument. + */ + memcpy_tolower(struct_offset->content, content, content_len); } else { - memcpy(struct_offset->content, content, content_len); + memcpy(struct_offset->content, content, content_len); } struct_offset++; diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index 05178e46fc19..d3fee45229d4 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -32,32 +32,20 @@ #include "stream.h" -uint16_t PatternMatchDefaultMatcher(void); +void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx); +void DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx); +void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx); +void DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx); uint32_t PatternStrength(uint8_t *, uint16_t); -uint32_t PacketPatternSearchWithStreamCtx(DetectEngineThreadCtx *, Packet *); -uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); -uint32_t UriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint16_t, uint8_t); -uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); -uint32_t HttpClientBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpServerBodyPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpRawHeaderPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpMethodPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpCookiePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpRawUriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpStatMsgPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); -uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t); + +uint16_t PatternMatchDefaultMatcher(void); uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags); void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *); -void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg); void PatternMatchPrepare(MpmCtx *, uint16_t); -void PatternMatchThreadPrepare(MpmThreadCtx *, uint16_t type, uint32_t max_id); +void PatternMatchThreadPrepare(MpmThreadCtx *, uint16_t type); void PatternMatchDestroy(MpmCtx *, uint16_t); void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t); @@ -65,23 +53,21 @@ void PatternMatchThreadPrint(MpmThreadCtx *, uint16_t); int PatternMatchPrepareGroup(DetectEngineCtx *, SigGroupHead *); void DetectEngineThreadCtxInfo(ThreadVars *, DetectEngineThreadCtx *); -void PatternMatchDestroyGroup(SigGroupHead *); TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); void DbgPrintSearchStats(); -MpmPatternIdStore *MpmPatternIdTableInitHash(void); -void MpmPatternIdTableFreeHash(MpmPatternIdStore *); -uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *); -uint32_t DetectContentGetId(MpmPatternIdStore *, DetectContentData *); +int SignatureHasPacketContent(const Signature *); +int SignatureHasStreamContent(const Signature *); -int SignatureHasPacketContent(Signature *); -int SignatureHasStreamContent(Signature *); +void RetrieveFPForSig(Signature *s); -SigMatch *RetrieveFPForSig(Signature *s); -SigMatch *RetrieveFPForSigV2(Signature *s); +int MpmStoreInit(DetectEngineCtx *); +void MpmStoreFree(DetectEngineCtx *); +void MpmStoreReportStats(const DetectEngineCtx *de_ctx); +MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh, enum MpmBuiltinBuffers buf); /** * \brief Figured out the FP and their respective content ids for all the @@ -94,5 +80,17 @@ SigMatch *RetrieveFPForSigV2(Signature *s); */ int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx); +/** \brief register an app layer keyword for mpm + * \param name keyword name + * \param direction SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT + * \param PrefilterRegister Prefilter api registration function + * + * \note direction must be set to either toserver or toclient. + * If both are needed, register the keyword twice. + */ +void DetectAppLayerMpmRegister(const char *name, + int direction, int priority, + int (*PrefilterRegister)(SigGroupHead *sgh, MpmCtx *mpm_ctx)); + #endif /* __DETECT_ENGINE_MPM_H__ */ diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index af0d9c3e3d2f..ce65a08ba4e8 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -32,12 +32,89 @@ #include "detect-engine.h" #include "detect-parse.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" + +#include "stream.h" #include "util-debug.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" +#include "util-validate.h" + +#include "util-mpm-ac.h" + +static void PrefilterPktStream(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const StreamMsg *smsg = det_ctx->smsg; + + /* for established packets inspect any smsg we may have queued up */ + if (p->flowflags & FLOW_PKT_ESTABLISHED) { + SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); + + for ( ; smsg != NULL; smsg = smsg->next) { + if (smsg->data_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcs, &det_ctx->pmq, + smsg->data, smsg->data_len); + } + } + } else { + SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); + } + + /* packets that have not been added to the stream will be inspected + * as if they are stream chunks */ + if ((!(p->flags & PKT_NOPAYLOAD_INSPECTION)) && + !(p->flags & PKT_STREAM_ADD)) + { + if (p->payload_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); + } + } +} + +int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + return PrefilterAppendPayloadEngine(sgh, PrefilterPktStream, mpm_ctx, NULL, "stream"); +} + +static void PrefilterPktPayload(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + if (p->payload_len < mpm_ctx->minlen) + SCReturn; + +#ifdef __SC_CUDA_SUPPORT__ + if (p->cuda_pkt_vars.cuda_mpm_enabled && p->pkt_src == PKT_SRC_WIRE) { + (void)SCACCudaPacketResultsProcessing(p, mpm_ctx, &det_ctx->pmq); + } else { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); + } +#else + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtc, &det_ctx->pmq, + p->payload, p->payload_len); +#endif +} + +int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + return PrefilterAppendPayloadEngine(sgh, PrefilterPktPayload, mpm_ctx, NULL, "payload"); +} + /** * \brief Do the content inspection & validation for a signature @@ -57,7 +134,7 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, SCEnter(); int r = 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } @@ -65,13 +142,10 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; det_ctx->replist = NULL; - //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_PMATCH], f, p->payload, p->payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_PAYLOAD, p); - //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], p, f, p->payload, p->payload_len); - //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET; if (r == 1) { SCReturnInt(1); } @@ -96,27 +170,23 @@ int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, * from the current packet here. */ int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, Signature *s, Flow *f, + DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, uint8_t *payload, uint32_t payload_len) { SCEnter(); int r = 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL) { SCReturnInt(0); } det_ctx->buffer_offset = 0; det_ctx->discontinue_matching = 0; det_ctx->inspection_recursion_counter = 0; - //det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; - r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], + r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_arrays[DETECT_SM_LIST_PMATCH], f, payload, payload_len, 0, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STREAM, NULL); - - //r = DoInspectPacketPayload(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_PMATCH], NULL, f, payload, payload_len); - //det_ctx->flags &= ~DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM; if (r == 1) { SCReturnInt(1); } @@ -137,7 +207,7 @@ static int PayloadTestSig01 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; content:\"d\"; distance:0; within:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -159,7 +229,7 @@ static int PayloadTestSig02 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"abc\"; nocase; content:\"d\"; distance:0; within:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -181,7 +251,7 @@ static int PayloadTestSig03 (void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"aBc\"; nocase; content:\"abca\"; distance:-10; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -206,7 +276,7 @@ static int PayloadTestSig04(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:6; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -231,7 +301,7 @@ static int PayloadTestSig05(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"this\"; content:\"is\"; within:9; content:\"big\"; within:12; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -256,7 +326,7 @@ static int PayloadTestSig06(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"now\"; content:\"this\"; content:\"is\"; within:12; content:\"big\"; within:8; " "content:\"string\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -281,7 +351,7 @@ static int PayloadTestSig07(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"thus\"; offset:8; content:\"is\"; within:6; content:\"big\"; within:8; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -307,7 +377,7 @@ static int PayloadTestSig08(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"fix\"; content:\"this\"; within:6; content:!\"and\"; distance:0; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) != 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1) { goto end; } @@ -331,7 +401,7 @@ static int PayloadTestSig09(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/super/; content:\"nova\"; within:7; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -356,7 +426,7 @@ static int PayloadTestSig10(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_test:4,>,2,0,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -381,7 +451,7 @@ static int PayloadTestSig11(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "byte_jump:1,0,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -406,7 +476,7 @@ static int PayloadTestSig12(void) char sig[] = "alert udp any any -> any any (msg:\"crash\"; " "isdataat:10,relative; sid:11;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -446,7 +516,7 @@ static int PayloadTestSig13(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; - uint16_t mpm_type = MPM_B2G; + uint16_t mpm_type = mpm_default_matcher; char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"aa\"; content:\"aa\"; distance:0; content:\"aa\"; distance:0; " @@ -528,7 +598,7 @@ static int PayloadTestSig14(void) //char sig[] = "alert tcp any any -> any any (content:\"User-Agent: Mozilla/5.0 (Macintosh; \"; content:\"Firefox/3.\"; distance:0; content:!\"Firefox/3.6.12\"; distance:-10; content:!\"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b4) Gecko/20090423 Firefox/3.6 GTB5\"; sid:1; rev:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { goto end; } @@ -549,7 +619,7 @@ static int PayloadTestSig15(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:18,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -572,7 +642,7 @@ static int PayloadTestSig16(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; isdataat:!20,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -596,7 +666,7 @@ static int PayloadTestSig17(void) "content:\"%\"; depth:4; offset:0; " "content:\"%\"; within:2; distance:1; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -625,7 +695,7 @@ static int PayloadTestSig18(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -654,7 +724,7 @@ static int PayloadTestSig19(void) "byte_extract:1,2,one,string,hex,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -683,7 +753,7 @@ static int PayloadTestSig20(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|06 35 07 08|\"; offset:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -712,7 +782,7 @@ static int PayloadTestSig21(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|03 04 05 06|\"; depth:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -741,7 +811,7 @@ static int PayloadTestSig22(void) "byte_extract:1,2,one,string,dec,relative; " "content:\"|09 0A 0B 0C|\"; within:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -771,7 +841,7 @@ static int PayloadTestSig23(void) "byte_extract:1,3,two,string,dec,relative; " "byte_test:1,=,one,two,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -801,7 +871,7 @@ static int PayloadTestSig24(void) "byte_jump:1,one,string,dec,relative; " "content:\"|0D 0E 0F|\"; distance:0; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -833,7 +903,7 @@ static int PayloadTestSig25(void) "byte_extract:1,-4,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -865,7 +935,7 @@ static int PayloadTestSig26(void) "byte_extract:1,-3000,one,string,dec,relative; " "content:\"|0C 0D 0E 0F|\"; distance:one; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 0) { result = 0; goto end; } @@ -893,7 +963,7 @@ static int PayloadTestSig27(void) "depth:5; sid:1;)"; p->flags |= PKT_STREAM_ADD; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 1) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1) goto end; result = 1; @@ -919,7 +989,7 @@ static int PayloadTestSig28(void) "offset:4; depth:12; sid:1;)"; p->flags |= PKT_STREAM_ADD; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) != 1) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) != 1) goto end; result = 1; @@ -943,7 +1013,7 @@ static int PayloadTestSig29(void) char sig[] = "alert tcp any any -> any any (msg:\"dummy\"; " "pcre:/^.{4}/; content:\"nova\"; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, DEFAULT_MPM) == 1) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 1) { result = 0; goto end; } @@ -964,7 +1034,7 @@ static int PayloadTestSig30(void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/^two/R\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -985,7 +1055,7 @@ static int PayloadTestSig31(void) int result = 0; char sig[] = "alert tcp any any -> any any (content:\"one\"; pcre:\"/(fiv|^two)/R\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) { + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) { result = 0; goto end; } @@ -1010,7 +1080,7 @@ static int PayloadTestSig32(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_jump:2,-14,string,dec,relative; content:\"card\"; within:4; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) goto end; result = 1; @@ -1033,7 +1103,7 @@ static int PayloadTestSig33(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_test:1,=,2,-14,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) goto end; result = 1; @@ -1056,7 +1126,7 @@ static int PayloadTestSig34(void) char sig[] = "alert tcp any any -> any any (msg:\"crash\"; " "content:\"message\"; byte_extract:1,-14,boom,string,dec,relative; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, MPM_B2G) == 0) + if (UTHPacketMatchSigMpm(p, sig, mpm_default_matcher) == 0) goto end; result = 1; @@ -1071,42 +1141,42 @@ static int PayloadTestSig34(void) void PayloadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("PayloadTestSig01", PayloadTestSig01, 1); - UtRegisterTest("PayloadTestSig02", PayloadTestSig02, 1); - UtRegisterTest("PayloadTestSig03", PayloadTestSig03, 1); - UtRegisterTest("PayloadTestSig04", PayloadTestSig04, 1); - UtRegisterTest("PayloadTestSig05", PayloadTestSig05, 1); - UtRegisterTest("PayloadTestSig06", PayloadTestSig06, 1); - UtRegisterTest("PayloadTestSig07", PayloadTestSig07, 1); - UtRegisterTest("PayloadTestSig08", PayloadTestSig08, 1); - UtRegisterTest("PayloadTestSig09", PayloadTestSig09, 1); - UtRegisterTest("PayloadTestSig10", PayloadTestSig10, 1); - UtRegisterTest("PayloadTestSig11", PayloadTestSig11, 1); - UtRegisterTest("PayloadTestSig12", PayloadTestSig12, 1); - UtRegisterTest("PayloadTestSig13", PayloadTestSig13, 1); - UtRegisterTest("PayloadTestSig14", PayloadTestSig14, 1); - UtRegisterTest("PayloadTestSig15", PayloadTestSig15, 1); - UtRegisterTest("PayloadTestSig16", PayloadTestSig16, 1); - UtRegisterTest("PayloadTestSig17", PayloadTestSig17, 1); - - UtRegisterTest("PayloadTestSig18", PayloadTestSig18, 1); - UtRegisterTest("PayloadTestSig19", PayloadTestSig19, 1); - UtRegisterTest("PayloadTestSig20", PayloadTestSig20, 1); - UtRegisterTest("PayloadTestSig21", PayloadTestSig21, 1); - UtRegisterTest("PayloadTestSig22", PayloadTestSig22, 1); - UtRegisterTest("PayloadTestSig23", PayloadTestSig23, 1); - UtRegisterTest("PayloadTestSig24", PayloadTestSig24, 1); - UtRegisterTest("PayloadTestSig25", PayloadTestSig25, 1); - UtRegisterTest("PayloadTestSig26", PayloadTestSig26, 1); - UtRegisterTest("PayloadTestSig27", PayloadTestSig27, 1); - UtRegisterTest("PayloadTestSig28", PayloadTestSig28, 1); - UtRegisterTest("PayloadTestSig29", PayloadTestSig29, 1); - - UtRegisterTest("PayloadTestSig30", PayloadTestSig30, 1); - UtRegisterTest("PayloadTestSig31", PayloadTestSig31, 1); - UtRegisterTest("PayloadTestSig32", PayloadTestSig32, 1); - UtRegisterTest("PayloadTestSig33", PayloadTestSig33, 1); - UtRegisterTest("PayloadTestSig34", PayloadTestSig34, 1); + UtRegisterTest("PayloadTestSig01", PayloadTestSig01); + UtRegisterTest("PayloadTestSig02", PayloadTestSig02); + UtRegisterTest("PayloadTestSig03", PayloadTestSig03); + UtRegisterTest("PayloadTestSig04", PayloadTestSig04); + UtRegisterTest("PayloadTestSig05", PayloadTestSig05); + UtRegisterTest("PayloadTestSig06", PayloadTestSig06); + UtRegisterTest("PayloadTestSig07", PayloadTestSig07); + UtRegisterTest("PayloadTestSig08", PayloadTestSig08); + UtRegisterTest("PayloadTestSig09", PayloadTestSig09); + UtRegisterTest("PayloadTestSig10", PayloadTestSig10); + UtRegisterTest("PayloadTestSig11", PayloadTestSig11); + UtRegisterTest("PayloadTestSig12", PayloadTestSig12); + UtRegisterTest("PayloadTestSig13", PayloadTestSig13); + UtRegisterTest("PayloadTestSig14", PayloadTestSig14); + UtRegisterTest("PayloadTestSig15", PayloadTestSig15); + UtRegisterTest("PayloadTestSig16", PayloadTestSig16); + UtRegisterTest("PayloadTestSig17", PayloadTestSig17); + + UtRegisterTest("PayloadTestSig18", PayloadTestSig18); + UtRegisterTest("PayloadTestSig19", PayloadTestSig19); + UtRegisterTest("PayloadTestSig20", PayloadTestSig20); + UtRegisterTest("PayloadTestSig21", PayloadTestSig21); + UtRegisterTest("PayloadTestSig22", PayloadTestSig22); + UtRegisterTest("PayloadTestSig23", PayloadTestSig23); + UtRegisterTest("PayloadTestSig24", PayloadTestSig24); + UtRegisterTest("PayloadTestSig25", PayloadTestSig25); + UtRegisterTest("PayloadTestSig26", PayloadTestSig26); + UtRegisterTest("PayloadTestSig27", PayloadTestSig27); + UtRegisterTest("PayloadTestSig28", PayloadTestSig28); + UtRegisterTest("PayloadTestSig29", PayloadTestSig29); + + UtRegisterTest("PayloadTestSig30", PayloadTestSig30); + UtRegisterTest("PayloadTestSig31", PayloadTestSig31); + UtRegisterTest("PayloadTestSig32", PayloadTestSig32); + UtRegisterTest("PayloadTestSig33", PayloadTestSig33); + UtRegisterTest("PayloadTestSig34", PayloadTestSig34); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-payload.h b/src/detect-engine-payload.h index d6220b18a598..205f8523f494 100644 --- a/src/detect-engine-payload.h +++ b/src/detect-engine-payload.h @@ -24,10 +24,13 @@ #ifndef __DETECT_ENGINE_PAYLOAD_H__ #define __DETECT_ENGINE_PAYLOAD_H__ +int PrefilterPktPayloadRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterPktStreamRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + int DetectEngineInspectPacketPayload(DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, Packet *); + DetectEngineThreadCtx *, const Signature *, Flow *, Packet *); int DetectEngineInspectStreamPayload(DetectEngineCtx *, - DetectEngineThreadCtx *, Signature *, Flow *, + DetectEngineThreadCtx *, const Signature *, Flow *, uint8_t *, uint32_t); void PayloadRegisterTests(void); diff --git a/src/detect-engine-port.c b/src/detect-engine-port.c index 2583f018d572..661cb47686d3 100644 --- a/src/detect-engine-port.c +++ b/src/detect-engine-port.c @@ -51,6 +51,7 @@ #include "pkt-var.h" #include "host.h" #include "util-profiling.h" +#include "util-var.h" static int DetectPortCutNot(DetectPort *, DetectPort **); static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, @@ -58,11 +59,6 @@ static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *, DetectPort *PortParse(char *str); int DetectPortIsValidRange(char *); -/** Memory usage counters */ -static uint32_t detect_port_memory = 0; -static uint32_t detect_port_init_cnt = 0; -static uint32_t detect_port_free_cnt = 0; - /** * \brief Alloc a DetectPort structure and update counters * @@ -76,9 +72,6 @@ DetectPort *DetectPortInit(void) return NULL; memset(dp, 0, sizeof(DetectPort)); - detect_port_memory += sizeof(DetectPort); - detect_port_init_cnt++; - return dp; } @@ -98,33 +91,9 @@ void DetectPortFree(DetectPort *dp) } dp->sh = NULL; - if (dp->dst_ph != NULL && !(dp->flags & PORT_GROUP_PORTS_COPY)) { - DetectPortCleanupList(dp->dst_ph); - } - dp->dst_ph = NULL; - - //BUG_ON(dp->next != NULL); - - detect_port_memory -= sizeof(DetectPort); - detect_port_free_cnt++; SCFree(dp); } -/** - * \brief Prints Memory statistics of the counters at detect-engine-port.[c,h] - */ -void DetectPortPrintMemory(void) -{ - SCLogDebug(" * Port memory stats (DetectPort %" PRIuMAX "):", - (uintmax_t)sizeof(DetectPort)); - SCLogDebug(" - detect_port_memory %" PRIu32 "", detect_port_memory); - SCLogDebug(" - detect_port_init_cnt %" PRIu32 "", detect_port_init_cnt); - SCLogDebug(" - detect_port_free_cnt %" PRIu32 "", detect_port_free_cnt); - SCLogDebug(" - outstanding ports %" PRIu32 "", - detect_port_init_cnt - detect_port_free_cnt); - SCLogDebug(" * Port memory stats done"); -} - /** * \brief Used to see if the exact same portrange exists in the list * @@ -288,7 +257,6 @@ int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, /* exact overlap/match */ if (cur != new) { SigGroupHeadCopySigs(de_ctx, new->sh, &cur->sh); - cur->cnt += new->cnt; DetectPortFree(new); return 0; } @@ -420,9 +388,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadCopySigs(de_ctx,b->sh,&tmp_c->sh); /* copy old b to c */ SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); /* copy a to b */ - tmp_c->cnt += b->cnt; - b->cnt += a->cnt; - /** * We have 3 parts: [bbb[baba]aaa] * part a: b_port1 <-> a_port1 - 1 @@ -460,13 +425,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += tmp->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; - /** * We have 2 or three parts: * @@ -496,7 +454,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, /** 'b' overlaps 'a' so 'a' needs the 'b' sigs */ SigGroupHeadCopySigs(de_ctx,b->sh,&a->sh); - a->cnt += b->cnt; } else if (a_port2 == b_port2) { SCLogDebug("2"); @@ -513,12 +470,9 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, * clear a * copy tmp to a */ SigGroupHeadCopySigs(de_ctx,b->sh,&tmp->sh); /* store old a list */ - tmp->cnt = b->cnt; SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - b->cnt += a->cnt; SigGroupHeadClearSigs(a->sh); /* clean a list */ SigGroupHeadCopySigs(de_ctx,tmp->sh,&a->sh);/* merge old a with b */ - a->cnt = tmp->cnt; SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ } else { SCLogDebug("3"); @@ -550,13 +504,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadCopySigs(de_ctx,tmp->sh,&b->sh);/* merge old a with b */ SigGroupHeadClearSigs(tmp->sh); /* clean tmp list */ - - tmp->cnt += a->cnt; - a->cnt = 0; - tmp_c->cnt += b->cnt; - a->cnt += b->cnt; - b->cnt += tmp->cnt; - tmp->cnt = 0; } /** * We have 2 or three parts: @@ -593,12 +540,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadClearSigs(tmp->sh); - tmp->cnt += b->cnt; - b->cnt = 0; - b->cnt += a->cnt; - a->cnt += tmp->cnt; - tmp->cnt = 0; - } else if (a_port2 == b_port2) { SCLogDebug("2"); @@ -611,8 +552,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, /** 'a' overlaps 'b' so 'b' needs the 'a' sigs */ SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); - b->cnt += a->cnt; - } else { SCLogDebug("3"); a->port = a_port1; @@ -633,9 +572,6 @@ static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a, SigGroupHeadCopySigs(de_ctx,a->sh,&b->sh); SigGroupHeadCopySigs(de_ctx,a->sh,&tmp_c->sh); - - b->cnt += a->cnt; - tmp_c->cnt += a->cnt; } } @@ -898,7 +834,6 @@ int DetectPortJoin(DetectEngineCtx *de_ctx, DetectPort *target, if (target == NULL || source == NULL) return -1; - target->cnt += source->cnt; SigGroupHeadCopySigs(de_ctx,source->sh,&target->sh); if (source->port < target->port) @@ -1017,14 +952,15 @@ static int DetectPortParseInsertString(DetectPort **head, char *s) * that are negated. * \param s Pointer to the character string holding the port to be * parsed. - * \param negate Flag that indicates if the receieved address string is negated + * \param negate Flag that indicates if the received address string is negated * or not. 0 if it is not, 1 it it is. * * \retval 0 On successfully parsing. * \retval -1 On failure. */ -static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, - int negate) +static int DetectPortParseDo(const DetectEngineCtx *de_ctx, + DetectPort **head, DetectPort **nhead, + char *s, int negate, ResolvedVariablesList *var_list) { size_t u = 0; size_t x = 0; @@ -1064,7 +1000,7 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, SCLogDebug("Parsed port from DetectPortParseDo - %s", address); x = 0; - r = DetectPortParseDo(head, nhead, address, negate? negate: n_set); + r = DetectPortParseDo(de_ctx, head, nhead, address, negate? negate: n_set, var_list); if (r == -1) goto error; @@ -1081,7 +1017,7 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, address[x - 1] = '\0'; - rule_var_port = SCRuleVarsGetConfVar(address, + rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; @@ -1101,8 +1037,8 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, "[%s]", rule_var_port); temp_rule_var_port = alloc_rule_var_port; } - r = DetectPortParseDo(head, nhead, temp_rule_var_port, - (negate + n_set) % 2);//negate? negate: n_set); + r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, + (negate + n_set) % 2, var_list);//negate? negate: n_set); if (r == -1) goto error; @@ -1136,12 +1072,19 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, address[x] = '\0'; } SCLogDebug("%s", address); + + if (AddVariableToResolveList(var_list, address) == -1) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Found a loop in a port " + "groups declaration. This is likely a misconfiguration."); + goto error; + } + x = 0; if (d_set == 1) { char *temp_rule_var_port = NULL, *alloc_rule_var_port = NULL; - rule_var_port = SCRuleVarsGetConfVar(address, + rule_var_port = SCRuleVarsGetConfVar(de_ctx, address, SC_RULE_VARS_PORT_GROUPS); if (rule_var_port == NULL) goto error; @@ -1161,8 +1104,8 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, "[%s]", rule_var_port); temp_rule_var_port = alloc_rule_var_port; } - r = DetectPortParseDo(head, nhead, temp_rule_var_port, - (negate + n_set) % 2); + r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port, + (negate + n_set) % 2, var_list); if (r == -1) goto error; @@ -1179,6 +1122,8 @@ static int DetectPortParseDo(DetectPort **head, DetectPort **nhead, char *s, goto error; } n_set = 0; + } else if (depth == 1 && s[u] == ',') { + range = 0; } } @@ -1274,7 +1219,7 @@ int DetectPortParseMergeNotPorts(DetectPort **head, DetectPort **nhead) /** work with a copy of the ad so we can easily clean up * the ghn group later. */ - ad = DetectPortCopy(NULL, ag); + ad = DetectPortCopySingle(NULL, ag); if (ad == NULL) { goto error; } @@ -1336,6 +1281,8 @@ int DetectPortTestConfVars(void) { SCLogDebug("Testing port conf vars for any misconfigured values"); + ResolvedVariablesList var_list = TAILQ_HEAD_INITIALIZER(var_list); + ConfNode *port_vars_node = ConfGetNode("vars.port-groups"); if (port_vars_node == NULL) { return 0; @@ -1360,9 +1307,15 @@ int DetectPortTestConfVars(void) goto error; } - int r = DetectPortParseDo(&gh, &ghn, seq_node->val, /* start with negate no */0); + int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val, /* start with negate no */0, &var_list); + + CleanVariableResolveList(&var_list); + if (r < 0) { DetectPortCleanupList(gh); + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, + "failed to parse port var \"%s\" with value \"%s\". " + "Please check it's syntax", seq_node->name, seq_node->val); goto error; } @@ -1398,7 +1351,8 @@ int DetectPortTestConfVars(void) * \retval 0 on success * \retval -1 on error */ -int DetectPortParse(DetectPort **head, char *str) +int DetectPortParse(const DetectEngineCtx *de_ctx, + DetectPort **head, char *str) { int r; @@ -1407,7 +1361,7 @@ int DetectPortParse(DetectPort **head, char *str) /* negate port list */ DetectPort *nhead = NULL; - r = DetectPortParseDo(head, &nhead, str,/* start with negate no */0); + r = DetectPortParseDo(de_ctx, head, &nhead, str,/* start with negate no */0, NULL); if (r < 0) goto error; @@ -1517,195 +1471,137 @@ int DetectPortIsValidRange(char *port) } /********************** End parsing routines ********************/ - -/********************* Hash function routines *******************/ -#define PORT_HASH_SIZE 1024 +/* hash table */ /** - * \brief Generate a hash for a DetectPort group + * \brief The hash function to be the used by the hash table - + * DetectEngineCtx->dport_hash_table. * - * \param ht HashListTable - * \param data Pointer to the DetectPort - * \param datalen sizeof data (not used here atm) + * \param ht Pointer to the hash table. + * \param data Pointer to the DetectPort. + * \param datalen Not used in our case. * - * \retval uint32_t the value of the generated hash + * \retval hash The generated hash value. */ -uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen) +static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen) { DetectPort *p = (DetectPort *)data; - uint32_t hash = p->port * p->port2; + uint32_t hash = 0; - return hash % ht->array_size; + SCLogDebug("hashing sgh %p", p); + + hash = ((uint32_t)p->port << 16) | p->port2; + + hash %= ht->array_size; + SCLogDebug("hash %"PRIu32, hash); + return hash; } /** - * \brief Function that return if the two DetectPort groups are equal or not + * \brief The Compare function to be used by the DetectPort hash table - + * DetectEngineCtx->dport_hash_table. * - * \param data1 Pointer to the DetectPort 1 - * \param len1 sizeof data 1 (not used here atm) - * \param data2 Pointer to the DetectPort 2 - * \param len2 sizeof data 2 (not used here atm) + * \param data1 Pointer to the first DetectPort. + * \param len1 Not used. + * \param data2 Pointer to the second DetectPort. + * \param len2 Not used. * - * \retval 1 if the DetectPort groups are equal - * \retval 0 if not equal + * \retval 1 If the 2 DetectPort sent as args match. + * \retval 0 If the 2 DetectPort sent as args do not match. */ -char DetectPortCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) +static char DetectPortCompareFunc(void *data1, uint16_t len1, + void *data2, uint16_t len2) { - DetectPort *p1 = (DetectPort *)data1; - DetectPort *p2 = (DetectPort *)data2; + DetectPort *dp1 = (DetectPort *)data1; + DetectPort *dp2 = (DetectPort *)data2; - if (p1->port2 == p2->port2 && p1->port == p2->port && - p1->flags == p2->flags) + if (data1 == NULL || data2 == NULL) + return 0; + + if (dp1->port == dp2->port && dp1->port2 == dp2->port2) return 1; return 0; } -void DetectPortFreeFunc(void *p) +static void DetectPortHashFreeFunc(void *ptr) { - DetectPort *dp = (DetectPort *)p; - DetectPortFree(dp); + DetectPort *p = ptr; + DetectPortFree(p); } /** - * \brief Function that initialize the HashListTable of destination DetectPort + * \brief Initializes the hash table in the detection engine context to hold the + * DetectPort hash. * - * \param de_ctx Pointer to the current DetectionEngineContext + * \param de_ctx Pointer to the detection engine context. * - * \retval 0 HashListTable initialization succes - * \retval -1 Error + * \retval 0 On success. + * \retval -1 On failure. */ -int DetectPortDpHashInit(DetectEngineCtx *de_ctx) +int DetectPortHashInit(DetectEngineCtx *de_ctx) { - de_ctx->dport_hash_table = HashListTableInit(PORT_HASH_SIZE, - DetectPortHashFunc, DetectPortCompareFunc, DetectPortFreeFunc); + de_ctx->dport_hash_table = HashListTableInit(4096, DetectPortHashFunc, + DetectPortCompareFunc, + DetectPortHashFreeFunc); if (de_ctx->dport_hash_table == NULL) goto error; return 0; + error: return -1; } /** - * \brief Function that free the HashListTable of destination DetectPort + * \brief Adds a DetectPort to the detection engine context DetectPort + * hash table. * - * \param de_ctx Pointer to the current DetectionEngineCtx - */ -void DetectPortDpHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->dport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->dport_hash_table); - de_ctx->dport_hash_table = NULL; -} - -/** - * \brief Function that reset the HashListTable of destination DetectPort - * (Free and Initialize it) + * \param de_ctx Pointer to the detection engine context. + * \param dp Pointer to the DetectPort. * - * \param de_ctx Pointer to the current DetectionEngineCtx + * \retval ret 0 on Successfully adding the DetectPort; -1 on failure. */ -void DetectPortDpHashReset(DetectEngineCtx *de_ctx) +int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp) { - DetectPortDpHashFree(de_ctx); - DetectPortDpHashInit(de_ctx); + int ret = HashListTableAdd(de_ctx->dport_hash_table, (void *)dp, 0); + return ret; } /** - * \brief Function that add a destination DetectPort into the hashtable + * \brief Used to lookup a DetectPort hash from the detection engine context + * DetectPort hash table. * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to add - */ -int DetectPortDpHashAdd(DetectEngineCtx *de_ctx, DetectPort *p) -{ - return HashListTableAdd(de_ctx->dport_hash_table, (void *)p, 0); -} - -/** - * \brief Function that search a destination DetectPort in the hashtable + * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to the DetectPort. * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to search + * \retval rsgh On success a pointer to the DetectPort if the DetectPort is + * found in the hash table; NULL on failure. */ -DetectPort *DetectPortDpHashLookup(DetectEngineCtx *de_ctx, DetectPort *p) +DetectPort *DetectPortHashLookup(DetectEngineCtx *de_ctx, DetectPort *dp) { - DetectPort *rp = HashListTableLookup(de_ctx->dport_hash_table, - (void *)p, 0); - return rp; -} + SCEnter(); -/** - * \brief Function that initialize the HashListTable of source DetectPort - * - * \param de_ctx Pointer to the current DetectionEngineContext - * - * \retval 0 HashListTable initialization succes - * \retval -1 Error - */ -int DetectPortSpHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sport_hash_table = HashListTableInit(PORT_HASH_SIZE, - DetectPortHashFunc, DetectPortCompareFunc, DetectPortFreeFunc); - if (de_ctx->sport_hash_table == NULL) - goto error; + DetectPort *rdp = HashListTableLookup(de_ctx->dport_hash_table, (void *)dp, 0); - return 0; -error: - return -1; + SCReturnPtr(rdp, "DetectPort"); } /** - * \brief Function that free the HashListTable of source DetectPort + * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by + * DetectPortInit() function. * - * \param de_ctx Pointer to the current DetectionEngineCtx + * \param de_ctx Pointer to the detection engine context. */ -void DetectPortSpHashFree(DetectEngineCtx *de_ctx) +void DetectPortHashFree(DetectEngineCtx *de_ctx) { - if (de_ctx->sport_hash_table == NULL) + if (de_ctx->sgh_hash_table == NULL) return; - HashListTableFree(de_ctx->sport_hash_table); - de_ctx->sport_hash_table = NULL; -} - -/** - * \brief Function that reset the HashListTable of source DetectPort - * (Free and Initialize it) - * - * \param de_ctx Pointer to the current DetectionEngineCtx - */ -void DetectPortSpHashReset(DetectEngineCtx *de_ctx) -{ - DetectPortSpHashFree(de_ctx); - DetectPortSpHashInit(de_ctx); -} - -/** - * \brief Function that add a source DetectPort into the hashtable - * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to add - */ -int DetectPortSpHashAdd(DetectEngineCtx *de_ctx, DetectPort *p) -{ - return HashListTableAdd(de_ctx->sport_hash_table, (void *)p, 0); -} + HashListTableFree(de_ctx->dport_hash_table); + de_ctx->dport_hash_table = NULL; -/** - * \brief Function that search a source DetectPort in the hashtable - * - * \param de_ctx Pointer to the current DetectionEngineCtx - * \param p Pointer to the DetectPort to search - */ -DetectPort *DetectPortSpHashLookup(DetectEngineCtx *de_ctx, DetectPort *p) -{ - DetectPort *rp = HashListTableLookup(de_ctx->sport_hash_table, - (void *)p, 0); - return rp; + return; } /*---------------------- Unittests -------------------------*/ @@ -1719,7 +1615,7 @@ int PortTestParse01 (void) { DetectPort *dd = NULL; - int r = DetectPortParse(&dd,"80"); + int r = DetectPortParse(NULL,&dd,"80"); if (r == 0) { DetectPortFree(dd); return 1; @@ -1736,9 +1632,9 @@ int PortTestParse02 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"80"); + int r = DetectPortParse(NULL,&dd,"80"); if (r == 0) { - r = DetectPortParse(&dd,"22"); + r = DetectPortParse(NULL,&dd,"22"); if (r == 0) { result = 1; } @@ -1758,9 +1654,9 @@ int PortTestParse03 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"80:88"); + int r = DetectPortParse(NULL,&dd,"80:88"); if (r == 0) { - r = DetectPortParse(&dd,"85:100"); + r = DetectPortParse(NULL,&dd,"85:100"); if (r == 0) { result = 1; } @@ -1780,7 +1676,7 @@ int PortTestParse04 (void) { DetectPort *dd = NULL; - int r = DetectPortParse(&dd,"!80:81"); + int r = DetectPortParse(NULL,&dd,"!80:81"); if (r == 0) { DetectPortCleanupList(dd); return 1; @@ -1798,7 +1694,7 @@ int PortTestParse05 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"!80:81"); + int r = DetectPortParse(NULL,&dd,"!80:81"); if (r != 0) goto end; @@ -1825,15 +1721,15 @@ int PortTestParse06 (void) DetectPort *dd = NULL, *copy = NULL; int result = 0; - int r = DetectPortParse(&dd,"22"); + int r = DetectPortParse(NULL,&dd,"22"); if (r != 0) goto end; - r = DetectPortParse(&dd,"80"); + r = DetectPortParse(NULL,&dd,"80"); if (r != 0) goto end; - r = DetectPortParse(&dd,"143"); + r = DetectPortParse(NULL,&dd,"143"); if (r != 0) goto end; @@ -1879,7 +1775,7 @@ int PortTestParse07 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"!21:902"); + int r = DetectPortParse(NULL,&dd,"!21:902"); if (r != 0) goto end; @@ -1906,7 +1802,7 @@ int PortTestParse08 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"[80:!80]"); + int r = DetectPortParse(NULL,&dd,"[80:!80]"); if (r == 0) goto end; @@ -1924,7 +1820,7 @@ int PortTestParse09 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"1024:"); + int r = DetectPortParse(NULL,&dd,"1024:"); if (r != 0) goto end; @@ -1948,7 +1844,7 @@ int PortTestParse10 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"77777777777777777777777777777777777777777777"); + int r = DetectPortParse(NULL,&dd,"77777777777777777777777777777777777777777777"); if (r != 0) { result = 1 ; goto end; @@ -1968,7 +1864,7 @@ int PortTestParse11 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"1024:65536"); + int r = DetectPortParse(NULL,&dd,"1024:65536"); if (r != 0) { result = 1 ; goto end; @@ -1988,7 +1884,7 @@ int PortTestParse12 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"1024:65535"); + int r = DetectPortParse(NULL,&dd,"1024:65535"); if (r != 0) { goto end; } @@ -2008,7 +1904,7 @@ int PortTestParse13 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"65536:65535"); + int r = DetectPortParse(NULL,&dd,"65536:65535"); if (r != 0) { result = 1 ; goto end; @@ -2055,7 +1951,7 @@ int PortTestParse15 (void) DetectPort *dd = NULL; int result = 0; - int r = DetectPortParse(&dd,"![0:100,1000:3000]"); + int r = DetectPortParse(NULL,&dd,"![0:100,1000:3000]"); if (r != 0 || dd->next == NULL) goto end; @@ -2079,15 +1975,15 @@ int PortTestParse16 (void) DetectPort *dd = NULL, *copy = NULL; int result = 0; - int r = DetectPortParse(&dd,"22"); + int r = DetectPortParse(NULL,&dd,"22"); if (r != 0) goto end; - r = DetectPortParse(&dd,"80"); + r = DetectPortParse(NULL,&dd,"80"); if (r != 0) goto end; - r = DetectPortParse(&dd,"143"); + r = DetectPortParse(NULL,&dd,"143"); if (r != 0) goto end; @@ -2125,6 +2021,7 @@ int PortTestParse16 (void) DetectPortCleanupList(dd); return result; } + /** * \test Test general functions */ @@ -2135,7 +2032,7 @@ int PortTestFunctions01(void) int result = 0; /* Parse */ - int r = DetectPortParse(&head,"![0:100,1000:65535]"); + int r = DetectPortParse(NULL,&head,"![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; @@ -2147,7 +2044,7 @@ int PortTestFunctions01(void) if (!(head->next == NULL)) goto end; - r = DetectPortParse(&dp1,"2000:3000"); + r = DetectPortParse(NULL, &dp1,"2000:3000"); if (r != 0 || dp1->next != NULL) goto end; if (!(dp1->port == 2000)) @@ -2198,11 +2095,11 @@ int PortTestFunctions02(void) int result = 0; /* Parse */ - int r = DetectPortParse(&head, "![0:100,1000:65535]"); + int r = DetectPortParse(NULL,&head, "![0:100,1000:65535]"); if (r != 0 || head->next != NULL) goto end; - r = DetectPortParse(&dp1, "!200:300"); + r = DetectPortParse(NULL, &dp1, "!200:300"); if (r != 0 || dp1->next == NULL) goto end; @@ -2211,7 +2108,7 @@ int PortTestFunctions02(void) if (r != 0 || head->next != NULL) goto end; - r = DetectPortParse(&dp2, "!100:500"); + r = DetectPortParse(NULL, &dp2, "!100:500"); if (r != 0 || dp2->next == NULL) goto end; @@ -2247,11 +2144,11 @@ int PortTestFunctions03(void) DetectPort *dp3= NULL; int result = 0; - int r = DetectPortParse(&dp1, "200:300"); + int r = DetectPortParse(NULL, &dp1, "200:300"); if (r != 0) goto end; - r = DetectPortParse(&dp2, "250:300"); + r = DetectPortParse(NULL, &dp2, "250:300"); if (r != 0) goto end; @@ -2312,7 +2209,7 @@ int PortTestFunctions04(void) DetectPort *dp2= NULL; int result = 0; - int r = DetectPortParse(&dp1, "200:300"); + int r = DetectPortParse(NULL, &dp1, "200:300"); if (r != 0) goto end; @@ -2359,14 +2256,14 @@ static int PortTestFunctions05(void) s[0].num = 0; s[1].num = 1; - r = DetectPortParse(&dp1, "1024:65535"); + r = DetectPortParse(NULL, &dp1, "1024:65535"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp1->sh, &s[0]); - r = DetectPortParse(&dp2, "any"); + r = DetectPortParse(NULL, &dp2, "any"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; @@ -2437,14 +2334,14 @@ static int PortTestFunctions06(void) s[0].num = 0; s[1].num = 1; - r = DetectPortParse(&dp1, "1024:65535"); + r = DetectPortParse(NULL, &dp1, "1024:65535"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; } SigGroupHeadAppendSig(de_ctx, &dp1->sh, &s[0]); - r = DetectPortParse(&dp2, "any"); + r = DetectPortParse(NULL, &dp2, "any"); if (r != 0) { printf("r != 0 but %d: ", r); goto end; @@ -2497,6 +2394,34 @@ static int PortTestFunctions06(void) return result; } +/** + * \test Test general functions + */ +static int PortTestFunctions07(void) +{ + DetectPort *dd = NULL; + + // This one should fail due to negation in a range + FAIL_IF(DetectPortParse(NULL, &dd, "[80:!99]") == 0); + + // Correct: from 80 till 100 but 99 excluded + FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[80:100,!99]") == 0); + FAIL_IF_NULL(dd->next); + FAIL_IF_NOT(dd->port == 80); + FAIL_IF_NOT(dd->port2 == 98); + FAIL_IF_NOT(dd->next->port == 100); + + // Also good: from 1 till 80 except of 2 and 4 + FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[1:80,![2,4]]") == 0); + FAIL_IF_NOT(dd->port == 1); + FAIL_IF_NULL(DetectPortLookupGroup(dd, 3)); + FAIL_IF_NOT_NULL(DetectPortLookupGroup(dd, 2)); + FAIL_IF_NULL(DetectPortLookupGroup(dd, 80)); + + DetectPortCleanupList(dd); + PASS; +} + /** * \test Test packet Matches * \param raw_eth_pkt pointer to the ethernet packet @@ -2784,7 +2709,7 @@ static int PortTestMatchDoubleNegation(void) int result = 0; DetectPort *head = NULL, *nhead = NULL; - if (DetectPortParseDo(&head, &nhead, "![!80]", 0) == -1) + if (DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0, NULL) == -1) return result; result = (head != NULL); @@ -2798,49 +2723,49 @@ static int PortTestMatchDoubleNegation(void) void DetectPortTests(void) { #ifdef UNITTESTS - UtRegisterTest("PortTestParse01", PortTestParse01, 1); - UtRegisterTest("PortTestParse02", PortTestParse02, 1); - UtRegisterTest("PortTestParse03", PortTestParse03, 1); - UtRegisterTest("PortTestParse04", PortTestParse04, 1); - UtRegisterTest("PortTestParse05", PortTestParse05, 1); - UtRegisterTest("PortTestParse06", PortTestParse06, 1); - UtRegisterTest("PortTestParse07", PortTestParse07, 1); - UtRegisterTest("PortTestParse08", PortTestParse08, 1); - UtRegisterTest("PortTestParse09", PortTestParse09, 1); - UtRegisterTest("PortTestParse10", PortTestParse10, 1); - UtRegisterTest("PortTestParse11", PortTestParse11, 1); - UtRegisterTest("PortTestParse12", PortTestParse12, 1); - UtRegisterTest("PortTestParse13", PortTestParse13, 1); - UtRegisterTest("PortTestParse14", PortTestParse14, 1); - UtRegisterTest("PortTestParse15", PortTestParse15, 1); - UtRegisterTest("PortTestParse16", PortTestParse16, 1); - UtRegisterTest("PortTestFunctions01", PortTestFunctions01, 1); - UtRegisterTest("PortTestFunctions02", PortTestFunctions02, 1); - UtRegisterTest("PortTestFunctions03", PortTestFunctions03, 1); - UtRegisterTest("PortTestFunctions04", PortTestFunctions04, 1); - UtRegisterTest("PortTestFunctions05", PortTestFunctions05, 1); - UtRegisterTest("PortTestFunctions06", PortTestFunctions06, 1); - UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01, 1); - UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02, 1); - UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03, 1); - UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04, 1); - UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05, 1); - UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06, 1); - UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07, 1); - UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08, 1); - UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09, 1); - UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10, 1); - UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11, 1); - UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12, 1); - UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13, 1); - UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14, 1); - UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15, 1); - UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16, 1); - UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17, 1); - UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18, 1); - UtRegisterTest("PortTestMatchReal19", - PortTestMatchReal19, 1); - UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation, 1); + UtRegisterTest("PortTestParse01", PortTestParse01); + UtRegisterTest("PortTestParse02", PortTestParse02); + UtRegisterTest("PortTestParse03", PortTestParse03); + UtRegisterTest("PortTestParse04", PortTestParse04); + UtRegisterTest("PortTestParse05", PortTestParse05); + UtRegisterTest("PortTestParse06", PortTestParse06); + UtRegisterTest("PortTestParse07", PortTestParse07); + UtRegisterTest("PortTestParse08", PortTestParse08); + UtRegisterTest("PortTestParse09", PortTestParse09); + UtRegisterTest("PortTestParse10", PortTestParse10); + UtRegisterTest("PortTestParse11", PortTestParse11); + UtRegisterTest("PortTestParse12", PortTestParse12); + UtRegisterTest("PortTestParse13", PortTestParse13); + UtRegisterTest("PortTestParse14", PortTestParse14); + UtRegisterTest("PortTestParse15", PortTestParse15); + UtRegisterTest("PortTestParse16", PortTestParse16); + UtRegisterTest("PortTestFunctions01", PortTestFunctions01); + UtRegisterTest("PortTestFunctions02", PortTestFunctions02); + UtRegisterTest("PortTestFunctions03", PortTestFunctions03); + UtRegisterTest("PortTestFunctions04", PortTestFunctions04); + UtRegisterTest("PortTestFunctions05", PortTestFunctions05); + UtRegisterTest("PortTestFunctions06", PortTestFunctions06); + UtRegisterTest("PortTestFunctions07", PortTestFunctions07); + UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01); + UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02); + UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03); + UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04); + UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05); + UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06); + UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07); + UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08); + UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09); + UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10); + UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11); + UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12); + UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13); + UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14); + UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15); + UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16); + UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17); + UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18); + UtRegisterTest("PortTestMatchReal19", PortTestMatchReal19); + UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation); #endif /* UNITTESTS */ diff --git a/src/detect-engine-port.h b/src/detect-engine-port.h index bfba92d19a61..924f710ce85d 100644 --- a/src/detect-engine-port.h +++ b/src/detect-engine-port.h @@ -25,7 +25,7 @@ #define __DETECT_PORT_H__ /* prototypes */ -int DetectPortParse(DetectPort **head, char *str); +int DetectPortParse(const DetectEngineCtx *, DetectPort **head, char *str); DetectPort *DetectPortCopy(DetectEngineCtx *, DetectPort *); DetectPort *DetectPortCopySingle(DetectEngineCtx *, DetectPort *); @@ -33,26 +33,8 @@ int DetectPortInsertCopy(DetectEngineCtx *,DetectPort **, DetectPort *); int DetectPortInsert(DetectEngineCtx *,DetectPort **, DetectPort *); void DetectPortCleanupList (DetectPort *head); -DetectPort *DetectPortLookup(DetectPort *head, DetectPort *dp); -int DetectPortAdd(DetectPort **head, DetectPort *dp); - DetectPort *DetectPortLookupGroup(DetectPort *dp, uint16_t port); -void DetectPortPrintMemory(void); - -DetectPort *DetectPortDpHashLookup(DetectEngineCtx *, DetectPort *); -DetectPort *DetectPortDpHashGetListPtr(DetectEngineCtx *); -int DetectPortDpHashInit(DetectEngineCtx *); -void DetectPortDpHashFree(DetectEngineCtx *); -int DetectPortDpHashAdd(DetectEngineCtx *, DetectPort *); -void DetectPortDpHashReset(DetectEngineCtx *); - -DetectPort *DetectPortSpHashLookup(DetectEngineCtx *, DetectPort *); -int DetectPortSpHashInit(DetectEngineCtx *); -void DetectPortSpHashFree(DetectEngineCtx *); -int DetectPortSpHashAdd(DetectEngineCtx *, DetectPort *); -void DetectPortSpHashReset(DetectEngineCtx *); - int DetectPortJoin(DetectEngineCtx *,DetectPort *target, DetectPort *source); void DetectPortPrint(DetectPort *); @@ -62,6 +44,11 @@ void DetectPortFree(DetectPort *); int DetectPortTestConfVars(void); +DetectPort *DetectPortHashLookup(DetectEngineCtx *de_ctx, DetectPort *dp); +void DetectPortHashFree(DetectEngineCtx *de_ctx); +int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp); +int DetectPortHashInit(DetectEngineCtx *de_ctx); + void DetectPortTests(void); #endif /* __DETECT_PORT_H__ */ diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c new file mode 100644 index 000000000000..35f45e71b0a2 --- /dev/null +++ b/src/detect-engine-prefilter-common.c @@ -0,0 +1,412 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" + +typedef struct PrefilterPacketHeaderHashCtx_ { + PrefilterPacketHeaderValue v1; + + uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */ + uint16_t value; + + uint32_t cnt; +} PrefilterPacketHeaderHashCtx; + +static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + PrefilterPacketHeaderCtx *ctx = data; + uint64_t hash = ctx->v1.u64 + ctx->type + ctx->value; + hash %= ht->array_size; + return hash; +} + +static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1, + void *data2, uint16_t len2) +{ + PrefilterPacketHeaderHashCtx *ctx1 = data1; + PrefilterPacketHeaderHashCtx *ctx2 = data2; + return (ctx1->v1.u64 == ctx2->v1.u64 && + ctx1->type == ctx2->type && + ctx1->value == ctx2->value); +} + +static void PrefilterPacketHeaderFreeFunc(void *ptr) +{ + SCFree(ptr); +} + +static void PrefilterPacketHeaderFree(void *pectx) +{ + PrefilterPacketHeaderCtx *ctx = pectx; + SCFree(ctx->sigs_array); + SCFree(ctx); +} + +static void PrefilterPacketU8HashCtxFree(void *vctx) +{ + PrefilterPacketU8HashCtx *ctx = vctx; + int i; + for (i = 0; i < 256; i++) { + SigsArray *sa = ctx->array[i]; + if (sa == NULL) + continue; + SCFree(sa->sigs); + SCFree(sa); + } + SCFree(ctx); +} + +static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value) +{ + if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 && + !(s->sp->flags & PORT_FLAG_NOT)) + { + *type = PREFILTER_EXTRA_MATCH_SRCPORT; + *value = s->sp->port; + } else if (s->alproto != ALPROTO_UNKNOWN) { + *type = PREFILTER_EXTRA_MATCH_ALPROTO; + *value = s->alproto; + } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 && + !(s->dp->flags & PORT_FLAG_NOT)) + { + *type = PREFILTER_EXTRA_MATCH_DSTPORT; + *value = s->dp->port; + } +} + +/** \internal + */ +static int +SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, + PrefilterPacketHeaderHashCtx *hctx, + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) +{ + Signature *s = NULL; + uint32_t sig = 0; + uint32_t sig_offset = 0; + + PrefilterPacketHeaderCtx *ctx = SCCalloc(1, sizeof(PrefilterPacketHeaderCtx)); + if (ctx == NULL) + return -1; + + ctx->v1 = hctx->v1; + ctx->type = hctx->type; + ctx->value = hctx->value; + + ctx->sigs_cnt = hctx->cnt; + ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId)); + if (ctx->sigs_array == NULL) { + SCFree(ctx); + return -1; + } + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type) + continue; + + uint16_t type = 0; + uint16_t value = 0; + GetExtraMatch(s, &type, &value); + + if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) && + ctx->type == type && ctx->value == value) + { + SCLogDebug("appending sid %u on %u", s->id, sig_offset); + ctx->sigs_array[sig_offset] = s->num; + sig_offset++; + + s->flags |= SIG_FLAG_PREFILTER; + } + } + + SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u", + sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value, + ctx->sigs_cnt); + PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree, + sigmatch_table[sm_type].name); + return 0; +} + +/** \internal + * \brief apply signature to each value */ +static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s) +{ + switch (v.u8[0]) { + case PREFILTER_U8HASH_MODE_EQ: + { + SigsArray *sa = ctx->array[v.u8[1]]; + sa->sigs[sa->offset++] = s->num; + break; + } + case PREFILTER_U8HASH_MODE_LT: + { + uint8_t x = v.u8[1] - 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (x--); + + break; + } + case PREFILTER_U8HASH_MODE_GT: + { + int x = v.u8[1] + 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (++x < 256); + + break; + } + case PREFILTER_U8HASH_MODE_RA: + { + int x = v.u8[1] + 1; + do { + SigsArray *sa = ctx->array[x]; + sa->sigs[sa->offset++] = s->num; + } while (++x < v.u8[2]); + + break; + } + } +} + +/** \internal + * \brief turn values into a u8 hash map + * \todo improve error handling + * \todo deduplicate sigs arrays + */ +static int +SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(SigGroupHead *sgh, int sm_type, + uint32_t *counts, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) +{ + Signature *s = NULL; + uint32_t sig = 0; + uint32_t cnt = 0; + + PrefilterPacketU8HashCtx *ctx = SCCalloc(1, sizeof(PrefilterPacketU8HashCtx)); + if (ctx == NULL) + return -1; + + int i; + for (i = 0; i < 256; i++) { + if (counts[i] == 0) + continue; + ctx->array[i] = SCCalloc(1, sizeof(SigsArray)); + BUG_ON(ctx->array[i] == NULL); + + ctx->array[i]->cnt = counts[i]; + ctx->array[i]->sigs = SCCalloc(ctx->array[i]->cnt, sizeof(SigIntId)); + BUG_ON(ctx->array[i]->sigs == NULL); + } + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type) + continue; + + PrefilterPacketHeaderValue v; + memset(&v, 0, sizeof(v)); + Set(&v, s->init_data->prefilter_sm->ctx); + + ApplyToU8Hash(ctx, v, s); + s->flags |= SIG_FLAG_PREFILTER; + cnt++; + } + + if (cnt) { + PrefilterAppendEngine(sgh, Match, ctx, + PrefilterPacketU8HashCtxFree, + sigmatch_table[sm_type].name); + } else { + PrefilterPacketU8HashCtxFree(ctx); + } + return 0; +} + +/** \internal + * \brief setup a engine for each unique value + */ +static void SetupSingle(HashListTable *hash_table, + SigGroupHead *sgh, int sm_type, + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + HashListTableBucket *hb = HashListTableGetListHead(hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); + + SetupEngineForPacketHeader(sgh, sm_type, + ctx, Compare, Match); + } +} + +/** \internal + * \brief setup a single engine with a hash map for u8 values + */ +static void SetupU8Hash(HashListTable *hash_table, + SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + uint32_t counts[256]; + memset(&counts, 0, sizeof(counts)); + + HashListTableBucket *hb = HashListTableGetListHead(hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); + + switch (ctx->v1.u8[0]) { + case PREFILTER_U8HASH_MODE_EQ: + counts[ctx->v1.u8[1]] += ctx->cnt; + break; + case PREFILTER_U8HASH_MODE_LT: + { + uint8_t v = ctx->v1.u8[1] - 1; + do { + counts[v] += ctx->cnt; + } while (v--); + + break; + } + case PREFILTER_U8HASH_MODE_GT: + { + int v = ctx->v1.u8[1] + 1; + do { + counts[v] += ctx->cnt; + } while (++v < 256); + + break; + } + case PREFILTER_U8HASH_MODE_RA: + { + int v = ctx->v1.u8[1] + 1; + do { + counts[v] += ctx->cnt; + } while (++v < ctx->v1.u8[2]); + + break; + } + } + } + + SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(sgh, sm_type, + counts, Set, Compare, Match); +} + +static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx), + _Bool u8hash) +{ + Signature *s = NULL; + uint32_t sig = 0; + + if (sgh == NULL) + return 0; + + /* first count how many engines we will need */ + + HashListTable *hash_table = HashListTableInit(4096, + PrefilterPacketHeaderHashFunc, + PrefilterPacketHeaderCompareFunc, + PrefilterPacketHeaderFreeFunc); + if (hash_table == NULL) + return -1; + + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; + if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type) + continue; + + PrefilterPacketHeaderHashCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + Set(&ctx.v1, s->init_data->prefilter_sm->ctx); + + GetExtraMatch(s, &ctx.type, &ctx.value); + + PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0); + if (rctx != 0) { + rctx->cnt++; + } else { + PrefilterPacketHeaderHashCtx *actx = SCCalloc(1, sizeof(*actx)); + if (actx == NULL) + goto error; + + Set(&actx->v1, s->init_data->prefilter_sm->ctx); + actx->cnt = 1; + actx->type = ctx.type; + actx->value = ctx.value; + + int ret = HashListTableAdd(hash_table, actx, 0); + if (ret != 0) { + SCFree(actx); + goto error; + } + } + } + + if (u8hash == FALSE) { + SetupSingle(hash_table, sgh, sm_type, Compare, Match); + } else { + SetupU8Hash(hash_table, sgh, sm_type, Set, Compare, Match); + } + + HashListTableFree(hash_table); + return 0; +error: + HashListTableFree(hash_table); + return -1; +} + +int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + return PrefilterSetupPacketHeaderCommon(sgh, sm_type, + Set, Compare, Match, TRUE); +} + +int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)) +{ + return PrefilterSetupPacketHeaderCommon(sgh, sm_type, + Set, Compare, Match, FALSE); +} diff --git a/src/detect-engine-prefilter-common.h b/src/detect-engine-prefilter-common.h new file mode 100644 index 000000000000..6072b56c51fa --- /dev/null +++ b/src/detect-engine-prefilter-common.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __DETECT_ENGINE_PREFILTER_COMMON_H__ +#define __DETECT_ENGINE_PREFILTER_COMMON_H__ + +typedef union { + uint8_t u8[8]; + uint16_t u16[4]; + uint32_t u32[2]; + uint64_t u64; +} PrefilterPacketHeaderValue; + +#define PREFILTER_EXTRA_MATCH_UNUSED 0 +#define PREFILTER_EXTRA_MATCH_ALPROTO 1 +#define PREFILTER_EXTRA_MATCH_SRCPORT 2 +#define PREFILTER_EXTRA_MATCH_DSTPORT 3 + +typedef struct PrefilterPacketHeaderCtx_ { + PrefilterPacketHeaderValue v1; + + uint16_t type; + uint16_t value; + + /** rules to add when the flags are present */ + uint32_t sigs_cnt; + SigIntId *sigs_array; +} PrefilterPacketHeaderCtx; + +typedef struct SigsArray_ { + SigIntId *sigs; + uint32_t cnt; + uint32_t offset; // used to track assign pos +} SigsArray; + +typedef struct PrefilterPacketU8HashCtx_ { + SigsArray *array[256]; +} PrefilterPacketU8HashCtx; + +#define PREFILTER_U8HASH_MODE_EQ 0 +#define PREFILTER_U8HASH_MODE_LT 1 +#define PREFILTER_U8HASH_MODE_GT 2 +#define PREFILTER_U8HASH_MODE_RA 3 + +int PrefilterSetupPacketHeader(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)); + +int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type, + void (*Set)(PrefilterPacketHeaderValue *v, void *), + _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), + void (*Match)(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx)); + +static inline _Bool +PrefilterPacketHeaderExtraMatch(const PrefilterPacketHeaderCtx *ctx, + const Packet *p) +{ + switch (ctx->type) + { + case PREFILTER_EXTRA_MATCH_UNUSED: + break; + case PREFILTER_EXTRA_MATCH_ALPROTO: + if (p->flow == NULL || p->flow->alproto != ctx->value) + return FALSE; + break; + case PREFILTER_EXTRA_MATCH_SRCPORT: + if (p->sp != ctx->value) + return FALSE; + break; + case PREFILTER_EXTRA_MATCH_DSTPORT: + if (p->dp != ctx->value) + return FALSE; + break; + } + return TRUE; +} + +#endif /* __DETECT_ENGINE_PREFILTER_COMMON_H__ */ diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c new file mode 100644 index 000000000000..1bb2dc649590 --- /dev/null +++ b/src/detect-engine-prefilter.c @@ -0,0 +1,591 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Prefilter engine + * + * Prefilter engines have as purpose to check for a critical common part of + * a set of rules. If the condition is present in the traffic, the rules + * will have to be inspected individually. Otherwise, the rules can be + * skipped. + * + * The best example of this is the MPM. From each rule take a pattern and + * add it to the MPM state machine. Inspect that in one step and only + * individually inspect the rules that had a match in MPM. + * + * This prefilter API is designed to abstract this logic so that it becomes + * easier to add other types of prefilters. + * + * The prefilter engines are structured as a simple list of engines. Each + * engine checks for a condition using it's callback function and private + * data. It then adds the rule match candidates to the PrefilterRuleStore + * structure. + * + * After the engines have run the resulting list of match candidates is + * sorted by the rule id's so that the individual inspection happens in + * the correct order. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "detect-engine-prefilter.h" +#include "detect-engine-mpm.h" + +#include "app-layer-parser.h" +#include "app-layer-htp.h" + +#include "util-profiling.h" + +typedef struct PrefilterStore_ { + const char *name; + void (*FreeFunc)(void *); + uint32_t id; +} PrefilterStore; + +static int PrefilterStoreGetId(const char *name, void (*FreeFunc)(void *)); +static const PrefilterStore *PrefilterStoreGetStore(const uint32_t id); + +static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n) +{ + if (n < 2) + return; + SigIntId p = sids[n / 2]; + SigIntId *l = sids; + SigIntId *r = sids + n - 1; + while (l <= r) { + if (*l < p) + l++; + else if (*r > p) + r--; + else { + SigIntId t = *l; + *l = *r; + *r = t; + l++; + r--; + } + } + QuickSortSigIntId(sids, r - sids + 1); + QuickSortSigIntId(l, sids + n - l); +} + +static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, + const SigGroupHead *sgh, Packet *p, const uint8_t flags) +{ + SCEnter(); + + const AppProto alproto = p->flow->alproto; + const uint8_t ipproto = p->proto; + + if (!(AppLayerParserProtocolIsTxAware(ipproto, alproto))) + SCReturn; + + void *alstate = p->flow->alstate; + uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); + const uint64_t total_txs = AppLayerParserGetTxCnt(ipproto, alproto, alstate); + + /* HACK test HTTP state here instead of in each engine */ + if (alproto == ALPROTO_HTTP) { + HtpState *htp_state = (HtpState *)alstate; + if (unlikely(htp_state->connp == NULL)) { + SCLogDebug("no HTTP connp"); + SCReturn; + } + } + + /* run our engines against each tx */ + for (; idx < total_txs; idx++) { + void *tx = AppLayerParserGetTx(ipproto, alproto, alstate, idx); + if (tx == NULL) + continue; + + const int tx_progress = AppLayerParserGetStateProgress(ipproto, alproto, tx, flags); + SCLogDebug("tx %p progress %d", tx, tx_progress); + + PrefilterEngine *engine = sgh->tx_engines; + do { + if (engine->alproto != alproto) + goto next; + if (engine->tx_min_progress > tx_progress) + goto next; + + PROFILING_PREFILTER_START(p); + engine->cb.PrefilterTx(det_ctx, engine->pectx, + p, p->flow, tx, idx, flags); + PROFILING_PREFILTER_END(p, engine->gid); + next: + if (engine->is_last) + break; + engine++; + } while (1); + } +} + +void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, + Packet *p, const uint8_t flags, int has_state) +{ + SCEnter(); + + PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->prefilter_maxid); + + if (sgh->pkt_engines) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT); + /* run packet engines */ + PrefilterEngine *engine = sgh->pkt_engines; + do { + PROFILING_PREFILTER_START(p); + engine->cb.Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->gid); + + if (engine->is_last) + break; + engine++; + } while (1); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT); + } + + /* run payload inspecting engines */ + if (sgh->payload_engines && + (p->payload_len > 0 || det_ctx->smsg != NULL) && + !(p->flags & PKT_NOPAYLOAD_INSPECTION)) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); + PrefilterEngine *engine = sgh->payload_engines; + while (1) { + PROFILING_PREFILTER_START(p); + engine->cb.Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->gid); + + if (engine->is_last) + break; + engine++; + } + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD); + } + + /* run tx engines */ + if (((p->proto == IPPROTO_TCP && p->flowflags & FLOW_PKT_ESTABLISHED) || p->proto != IPPROTO_TCP) && has_state) { + if (sgh->tx_engines != NULL && p->flow != NULL && + p->flow->alproto != ALPROTO_UNKNOWN && p->flow->alstate != NULL) + { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_TX); + PrefilterTx(det_ctx, sgh, p, flags); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_TX); + } + } + + /* Sort the rule list to lets look at pmq. + * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */ + if (likely(det_ctx->pmq.rule_id_array_cnt > 1)) { + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT1); + QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT1); + } +} + +int PrefilterAppendEngine(SigGroupHead *sgh, + void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx), + const char *name) +{ + if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL) + return -1; + + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); + if (e == NULL) + return -1; + memset(e, 0x00, sizeof(*e)); + + e->Prefilter = PrefilterFunc; + e->pectx = pectx; + e->Free = FreeFunc; + + if (sgh->init->pkt_engines == NULL) { + sgh->init->pkt_engines = e; + } else { + PrefilterEngineList *t = sgh->init->pkt_engines; + while (t->next != NULL) { + t = t->next; + } + + t->next = e; + e->id = t->id + 1; + } + + e->name = name; + e->gid = PrefilterStoreGetId(e->name, e->Free); + return 0; +} + +int PrefilterAppendPayloadEngine(SigGroupHead *sgh, + void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx), + const char *name) +{ + if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL) + return -1; + + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); + if (e == NULL) + return -1; + memset(e, 0x00, sizeof(*e)); + + e->Prefilter = PrefilterFunc; + e->pectx = pectx; + e->Free = FreeFunc; + + if (sgh->init->payload_engines == NULL) { + sgh->init->payload_engines = e; + } else { + PrefilterEngineList *t = sgh->init->payload_engines; + while (t->next != NULL) { + t = t->next; + } + + t->next = e; + e->id = t->id + 1; + } + + e->name = name; + e->gid = PrefilterStoreGetId(e->name, e->Free); + return 0; +} + +int PrefilterAppendTxEngine(SigGroupHead *sgh, + void (*PrefilterTxFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags), + AppProto alproto, int tx_min_progress, + void *pectx, void (*FreeFunc)(void *pectx), + const char *name) +{ + if (sgh == NULL || PrefilterTxFunc == NULL || pectx == NULL) + return -1; + + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); + if (e == NULL) + return -1; + memset(e, 0x00, sizeof(*e)); + + e->PrefilterTx = PrefilterTxFunc; + e->pectx = pectx; + e->alproto = alproto; + e->tx_min_progress = tx_min_progress; + e->Free = FreeFunc; + + if (sgh->init->tx_engines == NULL) { + sgh->init->tx_engines = e; + } else { + PrefilterEngineList *t = sgh->init->tx_engines; + while (t->next != NULL) { + t = t->next; + } + + t->next = e; + e->id = t->id + 1; + } + + e->name = name; + e->gid = PrefilterStoreGetId(e->name, e->Free); + return 0; +} + +static void PrefilterFreeEngineList(PrefilterEngineList *e) +{ + if (e->Free && e->pectx) { + e->Free(e->pectx); + } + SCFreeAligned(e); +} + +void PrefilterFreeEnginesList(PrefilterEngineList *list) +{ + PrefilterEngineList *t = list; + + while (t != NULL) { + PrefilterEngineList *next = t->next; + PrefilterFreeEngineList(t); + t = next; + } +} + +static void PrefilterFreeEngines(PrefilterEngine *list) +{ + PrefilterEngine *t = list; + + while (1) { + const PrefilterStore *s = PrefilterStoreGetStore(t->gid); + if (s && s->FreeFunc && t->pectx) { + s->FreeFunc(t->pectx); + } + + if (t->is_last) + break; + t++; + } + SCFreeAligned(list); +} + +void PrefilterCleanupRuleGroup(SigGroupHead *sgh) +{ + if (sgh->pkt_engines) { + PrefilterFreeEngines(sgh->pkt_engines); + sgh->pkt_engines = NULL; + } + if (sgh->payload_engines) { + PrefilterFreeEngines(sgh->payload_engines); + sgh->payload_engines = NULL; + } + if (sgh->tx_engines) { + PrefilterFreeEngines(sgh->tx_engines); + sgh->tx_engines = NULL; + } +} + +void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); + + if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO) { + int i = 0; + for (i = 0; i < DETECT_TBLSIZE; i++) + { + if (sigmatch_table[i].SetupPrefilter != NULL) { + sigmatch_table[i].SetupPrefilter(sgh); + } + } + } + + /* we have lists of engines in sgh->init now. Lets setup the + * match arrays */ + PrefilterEngineList *el; + if (sgh->init->pkt_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + cnt++; + de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid); + } + sgh->pkt_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); + if (sgh->pkt_engines == NULL) { + return; + } + memset(sgh->pkt_engines, 0x00, (cnt * sizeof(PrefilterEngine))); + + PrefilterEngine *e = sgh->pkt_engines; + for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + e->id = el->id; + e->cb.Prefilter = el->Prefilter; + e->pectx = el->pectx; + el->pectx = NULL; // e now owns the ctx + e->gid = el->gid; + if (el->next == NULL) { + e->is_last = TRUE; + } + e++; + } + } + if (sgh->init->payload_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->payload_engines ; el != NULL; el = el->next) { + cnt++; + de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid); + } + sgh->payload_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); + if (sgh->payload_engines == NULL) { + return; + } + memset(sgh->payload_engines, 0x00, (cnt * sizeof(PrefilterEngine))); + + PrefilterEngine *e = sgh->payload_engines; + for (el = sgh->init->payload_engines ; el != NULL; el = el->next) { + e->id = el->id; + e->cb.Prefilter = el->Prefilter; + e->pectx = el->pectx; + el->pectx = NULL; // e now owns the ctx + e->gid = el->gid; + if (el->next == NULL) { + e->is_last = TRUE; + } + e++; + } + } + if (sgh->init->tx_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { + cnt++; + de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid); + } + sgh->tx_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS); + if (sgh->tx_engines == NULL) { + return; + } + memset(sgh->tx_engines, 0x00, (cnt * sizeof(PrefilterEngine))); + + PrefilterEngine *e = sgh->tx_engines; + for (el = sgh->init->tx_engines ; el != NULL; el = el->next) { + e->id = el->id; + e->alproto = el->alproto; + e->tx_min_progress = el->tx_min_progress; + e->cb.PrefilterTx = el->PrefilterTx; + e->pectx = el->pectx; + el->pectx = NULL; // e now owns the ctx + e->gid = el->gid; + if (el->next == NULL) { + e->is_last = TRUE; + } + e++; + } + } +} + +/* hash table for assigning a unique id to each engine type. */ + +static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + PrefilterStore *ctx = data; + + uint32_t hash = strlen(ctx->name); + uint16_t u; + + for (u = 0; u < strlen(ctx->name); u++) { + hash += ctx->name[u]; + } + + hash %= ht->array_size; + return hash; +} + +static char PrefilterStoreCompareFunc(void *data1, uint16_t len1, + void *data2, uint16_t len2) +{ + PrefilterStore *ctx1 = data1; + PrefilterStore *ctx2 = data2; + return (strcmp(ctx1->name, ctx2->name) == 0); +} + +static void PrefilterStoreFreeFunc(void *ptr) +{ + SCFree(ptr); +} + +static SCMutex g_prefilter_mutex = SCMUTEX_INITIALIZER; +static uint32_t g_prefilter_id = 0; +static HashListTable *g_prefilter_hash_table = NULL; + +static void PrefilterDeinit(void) +{ + SCMutexLock(&g_prefilter_mutex); + BUG_ON(g_prefilter_hash_table == NULL); + HashListTableFree(g_prefilter_hash_table); + SCMutexUnlock(&g_prefilter_mutex); +} + +static void PrefilterInit(void) +{ + SCMutexLock(&g_prefilter_mutex); + BUG_ON(g_prefilter_hash_table != NULL); + + g_prefilter_hash_table = HashListTableInit(256, + PrefilterStoreHashFunc, + PrefilterStoreCompareFunc, + PrefilterStoreFreeFunc); + BUG_ON(g_prefilter_hash_table == NULL); + atexit(PrefilterDeinit); + SCMutexUnlock(&g_prefilter_mutex); +} + +static int PrefilterStoreGetId(const char *name, void (*FreeFunc)(void *)) +{ + PrefilterStore ctx = { name, FreeFunc, 0 }; + + if (g_prefilter_hash_table == NULL) { + PrefilterInit(); + } + + SCLogDebug("looking up %s", name); + + SCMutexLock(&g_prefilter_mutex); + PrefilterStore *rctx = HashListTableLookup(g_prefilter_hash_table, (void *)&ctx, 0); + if (rctx != NULL) { + SCMutexUnlock(&g_prefilter_mutex); + return rctx->id; + } + + PrefilterStore *actx = SCCalloc(1, sizeof(*actx)); + if (actx == NULL) { + SCMutexUnlock(&g_prefilter_mutex); + return -1; + } + + actx->name = name; + actx->FreeFunc = FreeFunc; + actx->id = g_prefilter_id++; + SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id); + + int ret = HashListTableAdd(g_prefilter_hash_table, actx, 0); + if (ret != 0) { + SCMutexUnlock(&g_prefilter_mutex); + SCFree(actx); + return -1; + } + + int r = actx->id; + SCMutexUnlock(&g_prefilter_mutex); + return r; +} + +/** \warning slow */ +static const PrefilterStore *PrefilterStoreGetStore(const uint32_t id) +{ + const PrefilterStore *store = NULL; + SCMutexLock(&g_prefilter_mutex); + if (g_prefilter_hash_table != NULL) { + HashListTableBucket *hb = HashListTableGetListHead(g_prefilter_hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterStore *ctx = HashListTableGetListData(hb); + if (ctx->id == id) { + store = ctx; + break; + } + } + } + SCMutexUnlock(&g_prefilter_mutex); + return store; +} + +/** \warning slow */ +const char *PrefilterStoreGetName(const uint32_t id) +{ + const char *name = NULL; + SCMutexLock(&g_prefilter_mutex); + if (g_prefilter_hash_table != NULL) { + HashListTableBucket *hb = HashListTableGetListHead(g_prefilter_hash_table); + for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) { + PrefilterStore *ctx = HashListTableGetListData(hb); + if (ctx->id == id) { + name = ctx->name; + break; + } + } + } + SCMutexUnlock(&g_prefilter_mutex); + return name; +} diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h new file mode 100644 index 000000000000..b058cf738eb6 --- /dev/null +++ b/src/detect-engine-prefilter.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_ENGINE_PREFILTER_H__ +#define __DETECT_ENGINE_PREFILTER_H__ + +void Prefilter(DetectEngineThreadCtx *, const SigGroupHead *, Packet *p, + const uint8_t flags, int has_state); + +int PrefilterAppendEngine(SigGroupHead *sgh, + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx), + const char *name); +int PrefilterAppendPayloadEngine(SigGroupHead *sgh, + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), + void *pectx, void (*FreeFunc)(void *pectx), + const char *name); +int PrefilterAppendTxEngine(SigGroupHead *sgh, + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags), + const AppProto alproto, const int tx_min_progress, + void *pectx, void (*FreeFunc)(void *pectx), + const char *name); + +void PrefilterFreeEnginesList(PrefilterEngineList *list); + +void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh); +void PrefilterCleanupRuleGroup(SigGroupHead *sgh); + +#ifdef PROFILING +const char *PrefilterStoreGetName(const uint32_t id); +#endif + +#endif diff --git a/src/detect-engine-profile.c b/src/detect-engine-profile.c new file mode 100644 index 000000000000..971c222ad653 --- /dev/null +++ b/src/detect-engine-profile.c @@ -0,0 +1,141 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" +#include "output-json.h" +#include "util-buffer.h" +#include "util-print.h" + +#ifdef PROFILING +#ifdef HAVE_LIBJANSSON +#if 0 +static void DumpFp(const SigMatch *sm, char *pat_orig, uint32_t pat_orig_sz, char *pat_chop, uint32_t pat_chop_sz) +{ + int fast_pattern_chop_set = 0; + const DetectContentData *cd = (DetectContentData *)sm->ctx; + + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + fast_pattern_chop_set = 1; + } + } + + uint32_t off = 0; + PrintRawUriBuf(pat_orig, &off, pat_orig_sz, cd->content, cd->content_len); + + if (fast_pattern_chop_set) { + off = 0; + PrintRawUriBuf(pat_chop, &off, pat_chop_sz, cd->content + cd->fp_chop_offset, cd->fp_chop_len); + } +} +#endif + +SCMutex g_rule_dump_write_m = SCMUTEX_INITIALIZER; +void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p) +{ + json_t *js = CreateJSONHeader(p, 0, "inspectedrules"); + if (js == NULL) + return; + json_t *ir = json_object(); + if (ir == NULL) + return; + + json_object_set_new(ir, "rule_group_id", json_integer(det_ctx->sgh->id)); + json_object_set_new(ir, "rule_cnt", json_integer(det_ctx->match_array_cnt)); + + json_t *js_array = json_array(); + uint32_t x; + for (x = 0; x < det_ctx->match_array_cnt; x++) + { + const Signature *s = det_ctx->match_array[x]; + if (s == NULL) + continue; + + json_t *js_sig = json_object(); + if (unlikely(js == NULL)) + continue; + json_object_set_new(js_sig, "sig_id", json_integer(s->id)); +#if 0 + json_object_set_new(js_sig, "mpm", (s->mpm_sm != NULL) ? json_true() : json_false()); + + if (s->mpm_sm != NULL) { + char orig[256] = ""; + char chop[256] = ""; + + DumpFp(s->mpm_sm, orig, sizeof(orig), chop, sizeof(chop)); + + json_object_set_new(js_sig, "mpm_buffer", json_string(DetectListToHumanString(SigMatchListSMBelongsTo(s, s->mpm_sm)))); + json_object_set_new(js_sig, "mpm_pattern", json_string(orig)); + + if (strlen(chop) > 0) { + json_object_set_new(js_sig, "mpm_pattern_chop", json_string(chop)); + } + } +#endif + json_array_append_new(js_array, js_sig); + } + + json_object_set_new(ir, "rules", js_array); + json_object_set_new(js, "inspectedrules", ir); + + const char *filename = "packet_inspected_rules.json"; + const char *log_dir = ConfigGetLogDirectory(); + char log_path[PATH_MAX] = ""; + snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename); + + MemBuffer *mbuf = NULL; + mbuf = MemBufferCreateNew(4096); + BUG_ON(mbuf == NULL); + + OutputJSONMemBufferWrapper wrapper = { + .buffer = &mbuf, + .expand_by = 4096, + }; + + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + if (r != 0) { + SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object"); + } else { + MemBufferWriteString(mbuf, "\n"); + SCMutexLock(&g_rule_dump_write_m); + FILE *fp = fopen(log_path, "a"); + if (fp != NULL) { + MemBufferPrintToFPAsString(mbuf, fp); + fclose(fp); + SCMutexUnlock(&g_rule_dump_write_m); + } + } + + MemBufferFree(mbuf); + json_object_clear(js); + json_decref(js); +} +#endif /* HAVE_LIBJANSSON */ +#endif /* PROFILING */ diff --git a/src/detect-engine-profile.h b/src/detect-engine-profile.h new file mode 100644 index 000000000000..d7ed1c93ea74 --- /dev/null +++ b/src/detect-engine-profile.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef _DETECT_ENGINE_PROFILE_H +#define _DETECT_ENGINE_PROFILE_H + +void RulesDumpMatchArray(const DetectEngineThreadCtx *det_ctx, const Packet *p); + +#endif /* _DETECT_ENGINE_PROFILE_H */ diff --git a/src/detect-engine-proto.c b/src/detect-engine-proto.c index cacaeee3b72a..0d2d4193ee3d 100644 --- a/src/detect-engine-proto.c +++ b/src/detect-engine-proto.c @@ -162,7 +162,7 @@ int DetectProtoParse(DetectProto *dp, char *str) * \param proto protocol (such as IPPROTO_TCP) to look for * \retval 0 protocol not in the set * \retval 1 protocol is in the set */ -int DetectProtoContainsProto(DetectProto *dp, int proto) +int DetectProtoContainsProto(const DetectProto *dp, int proto) { if (dp->flags & DETECT_PROTO_ANY) return 1; @@ -609,19 +609,19 @@ static int DetectProtoTestSig02(void) void DetectProtoTests(void) { #ifdef UNITTESTS - UtRegisterTest("ProtoTestParse01", ProtoTestParse01, 1); - UtRegisterTest("ProtoTestParse02", ProtoTestParse02, 1); - UtRegisterTest("ProtoTestParse03", ProtoTestParse03, 1); - UtRegisterTest("ProtoTestParse04", ProtoTestParse04, 1); - UtRegisterTest("ProtoTestParse05", ProtoTestParse05, 1); - UtRegisterTest("ProtoTestParse06", ProtoTestParse06, 1); - UtRegisterTest("ProtoTestParse07", ProtoTestParse07, 1); - - UtRegisterTest("DetectProtoTestSetup01", DetectProtoTestSetup01, 1); - UtRegisterTest("DetectProtoTestSetup02", DetectProtoTestSetup02, 1); - - UtRegisterTest("DetectProtoTestSig01", DetectProtoTestSig01, 1); - UtRegisterTest("DetectProtoTestSig02", DetectProtoTestSig02, 1); + UtRegisterTest("ProtoTestParse01", ProtoTestParse01); + UtRegisterTest("ProtoTestParse02", ProtoTestParse02); + UtRegisterTest("ProtoTestParse03", ProtoTestParse03); + UtRegisterTest("ProtoTestParse04", ProtoTestParse04); + UtRegisterTest("ProtoTestParse05", ProtoTestParse05); + UtRegisterTest("ProtoTestParse06", ProtoTestParse06); + UtRegisterTest("ProtoTestParse07", ProtoTestParse07); + + UtRegisterTest("DetectProtoTestSetup01", DetectProtoTestSetup01); + UtRegisterTest("DetectProtoTestSetup02", DetectProtoTestSetup02); + + UtRegisterTest("DetectProtoTestSig01", DetectProtoTestSig01); + UtRegisterTest("DetectProtoTestSig02", DetectProtoTestSig02); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-proto.h b/src/detect-engine-proto.h index 4edfe3b5333b..05f8f4bef509 100644 --- a/src/detect-engine-proto.h +++ b/src/detect-engine-proto.h @@ -40,7 +40,7 @@ typedef struct DetectProto_ { /* prototypes */ int DetectProtoParse(DetectProto *dp, char *str); -int DetectProtoContainsProto(DetectProto *, int); +int DetectProtoContainsProto(const DetectProto *, int); void DetectProtoTests(void); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 1a6cdcb97815..28996a5e91c1 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -36,9 +36,11 @@ #include "detect-engine-address.h" #include "detect-engine-mpm.h" #include "detect-engine-siggroup.h" +#include "detect-engine-prefilter.h" #include "detect-content.h" #include "detect-uricontent.h" +#include "detect-flags.h" #include "util-hash.h" #include "util-hashlist.h" @@ -53,42 +55,21 @@ /* prototypes */ int SigGroupHeadClearSigs(SigGroupHead *); -static uint32_t detect_siggroup_head_memory = 0; -static uint32_t detect_siggroup_head_init_cnt = 0; -static uint32_t detect_siggroup_head_free_cnt = 0; -static uint32_t detect_siggroup_head_initdata_memory = 0; -static uint32_t detect_siggroup_head_initdata_init_cnt = 0; -static uint32_t detect_siggroup_head_initdata_free_cnt = 0; -static uint32_t detect_siggroup_sigarray_memory = 0; -static uint32_t detect_siggroup_sigarray_init_cnt = 0; -static uint32_t detect_siggroup_sigarray_free_cnt = 0; -static uint32_t detect_siggroup_matcharray_memory = 0; -static uint32_t detect_siggroup_matcharray_init_cnt = 0; -static uint32_t detect_siggroup_matcharray_free_cnt = 0; - void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) { - if (sghid->content_array != NULL) { - SCFree(sghid->content_array); - sghid->content_array = NULL; - sghid->content_size = 0; - } - if (sghid->uri_content_array != NULL) { - SCFree(sghid->uri_content_array); - sghid->uri_content_array = NULL; - sghid->uri_content_size = 0; - } if (sghid->sig_array != NULL) { SCFree(sghid->sig_array); sghid->sig_array = NULL; - - detect_siggroup_sigarray_free_cnt++; - detect_siggroup_sigarray_memory -= sghid->sig_size; } - SCFree(sghid); + if (sghid->app_mpms != NULL) { + SCFree(sghid->app_mpms); + } - detect_siggroup_head_initdata_free_cnt++; - detect_siggroup_head_initdata_memory -= sizeof(SigGroupHeadInitData); + PrefilterFreeEnginesList(sghid->tx_engines); + PrefilterFreeEnginesList(sghid->pkt_engines); + PrefilterFreeEnginesList(sghid->payload_engines); + + SCFree(sghid); } static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) @@ -99,9 +80,6 @@ static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) memset(sghid, 0x00, sizeof(SigGroupHeadInitData)); - detect_siggroup_head_initdata_init_cnt++; - detect_siggroup_head_initdata_memory += sizeof(SigGroupHeadInitData); - /* initialize the signature bitarray */ sghid->sig_size = size; if ( (sghid->sig_array = SCMalloc(sghid->sig_size)) == NULL) @@ -109,9 +87,6 @@ static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) memset(sghid->sig_array, 0, sghid->sig_size); - detect_siggroup_sigarray_init_cnt++; - detect_siggroup_sigarray_memory += sghid->sig_size; - return sghid; error: SigGroupHeadInitDataFree(sghid); @@ -125,8 +100,9 @@ void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) if (de_ctx->sgh_array_cnt < de_ctx->sgh_array_size) { de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } else { + int increase = 16; ptmp = SCRealloc(de_ctx->sgh_array, - sizeof(SigGroupHead *) * (16 + de_ctx->sgh_array_size)); + sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size)); if (ptmp == NULL) { SCFree(de_ctx->sgh_array); de_ctx->sgh_array = NULL; @@ -134,7 +110,7 @@ void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } de_ctx->sgh_array = ptmp; - de_ctx->sgh_array_size += 10; + de_ctx->sgh_array_size += increase; de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; } de_ctx->sgh_array_cnt++; @@ -149,7 +125,7 @@ void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) * \retval sgh Pointer to the newly init SigGroupHead on success; or NULL in * case of error. */ -static SigGroupHead *SigGroupHeadAlloc(DetectEngineCtx *de_ctx, uint32_t size) +static SigGroupHead *SigGroupHeadAlloc(const DetectEngineCtx *de_ctx, uint32_t size) { SigGroupHead *sgh = SCMalloc(sizeof(SigGroupHead)); if (unlikely(sgh == NULL)) @@ -160,9 +136,6 @@ static SigGroupHead *SigGroupHeadAlloc(DetectEngineCtx *de_ctx, uint32_t size) if (sgh->init == NULL) goto error; - detect_siggroup_head_init_cnt++; - detect_siggroup_head_memory += sizeof(SigGroupHead); - return sgh; error: @@ -182,26 +155,21 @@ void SigGroupHeadFree(SigGroupHead *sgh) SCLogDebug("sgh %p", sgh); - PatternMatchDestroyGroup(sgh); - -#if defined(__SSE3__) || defined(__tile__) - if (sgh->mask_array != NULL) { - /* mask is aligned */ - SCFreeAligned(sgh->mask_array); - sgh->mask_array = NULL; + if (sgh->match_array != NULL) { + SCFree(sgh->match_array); + sgh->match_array = NULL; } -#endif - if (sgh->head_array != NULL) { - SCFree(sgh->head_array); - sgh->head_array = NULL; + if (sgh->non_pf_other_store_array != NULL) { + SCFree(sgh->non_pf_other_store_array); + sgh->non_pf_other_store_array = NULL; + sgh->non_pf_other_store_cnt = 0; } - if (sgh->match_array != NULL) { - detect_siggroup_matcharray_free_cnt++; - detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *)); - SCFree(sgh->match_array); - sgh->match_array = NULL; + if (sgh->non_pf_syn_store_array != NULL) { + SCFree(sgh->non_pf_syn_store_array); + sgh->non_pf_syn_store_array = NULL; + sgh->non_pf_syn_store_cnt = 0; } sgh->sig_cnt = 0; @@ -211,17 +179,15 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->init = NULL; } + PrefilterCleanupRuleGroup(sgh); SCFree(sgh); - detect_siggroup_head_free_cnt++; - detect_siggroup_head_memory -= sizeof(SigGroupHead); - return; } /** - * \brief The hash function to be the used by the mpm SigGroupHead hash table - - * DetectEngineCtx->sgh_mpm_hash_table. + * \brief The hash function to be the used by the hash table - + * DetectEngineCtx->sgh_hash_table. * * \param ht Pointer to the hash table. * \param data Pointer to the SigGroupHead. @@ -229,21 +195,25 @@ void SigGroupHeadFree(SigGroupHead *sgh) * * \retval hash The generated hash value. */ -uint32_t SigGroupHeadMpmHashFunc(HashListTable *ht, void *data, uint16_t datalen) +uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen) { SigGroupHead *sgh = (SigGroupHead *)data; uint32_t hash = 0; uint32_t b = 0; - for (b = 0; b < sgh->init->content_size; b++) - hash += sgh->init->content_array[b]; + SCLogDebug("hashing sgh %p", sgh); + + for (b = 0; b < sgh->init->sig_size; b++) + hash += sgh->init->sig_array[b]; - return hash % ht->array_size; + hash %= ht->array_size; + SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size); + return hash; } /** - * \brief The Compare function to be used by the mpm SigGroupHead hash table - - * DetectEngineCtx->sgh_mpm_hash_table. + * \brief The Compare function to be used by the SigGroupHead hash table - + * DetectEngineCtx->sgh_hash_table. * * \param data1 Pointer to the first SigGroupHead. * \param len1 Not used. @@ -253,39 +223,38 @@ uint32_t SigGroupHeadMpmHashFunc(HashListTable *ht, void *data, uint16_t datalen * \retval 1 If the 2 SigGroupHeads sent as args match. * \retval 0 If the 2 SigGroupHeads sent as args do not match. */ -char SigGroupHeadMpmCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) +char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) { SigGroupHead *sgh1 = (SigGroupHead *)data1; SigGroupHead *sgh2 = (SigGroupHead *)data2; - if (sgh1->init->content_size != sgh2->init->content_size) + if (data1 == NULL || data2 == NULL) return 0; - if (SCMemcmp(sgh1->init->content_array, sgh2->init->content_array, - sgh1->init->content_size) != 0) { + if (sgh1->init->sig_size != sgh2->init->sig_size) + return 0; + + if (SCMemcmp(sgh1->init->sig_array, sgh2->init->sig_array, sgh1->init->sig_size) != 0) return 0; - } return 1; } /** - * \brief Initializes the SigGroupHead mpm hash table to be used by the detection - * engine context. + * \brief Initializes the hash table in the detection engine context to hold the + * SigGroupHeads. * * \param de_ctx Pointer to the detection engine context. * * \retval 0 On success. * \retval -1 On failure. */ -int SigGroupHeadMpmHashInit(DetectEngineCtx *de_ctx) +int SigGroupHeadHashInit(DetectEngineCtx *de_ctx) { - de_ctx->sgh_mpm_hash_table = HashListTableInit(4096, SigGroupHeadMpmHashFunc, - SigGroupHeadMpmCompareFunc, - NULL); - - if (de_ctx->sgh_mpm_hash_table == NULL) + de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, + SigGroupHeadCompareFunc, NULL); + if (de_ctx->sgh_hash_table == NULL) goto error; return 0; @@ -296,150 +265,28 @@ int SigGroupHeadMpmHashInit(DetectEngineCtx *de_ctx) /** * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * mpm hash table. + * hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. * - * \retval ret 0 on Successfully adding the argument sgh; -1 on failure. + * \retval ret 0 on Successfully adding the SigGroupHead; -1 on failure. */ -int SigGroupHeadMpmHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - int ret = HashListTableAdd(de_ctx->sgh_mpm_hash_table, (void *)sgh, 0); + int ret = HashListTableAdd(de_ctx->sgh_hash_table, (void *)sgh, 0); return ret; } -/** - * \brief Used to lookup a SigGroupHead from the detection engine context - * SigGroupHead mpm hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadMpmHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_hash_table, allocated by - * SigGroupHeadMpmHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadMpmHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_mpm_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_mpm_hash_table); - de_ctx->sgh_mpm_hash_table = NULL; - - return; -} - -/** - * \brief The hash function to be the used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param ht Pointer to the hash table. - * \param data Pointer to the SigGroupHead. - * \param datalen Not used in our case. - * - * \retval hash The generated hash value. - */ -uint32_t SigGroupHeadMpmUriHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - SigGroupHead *sgh = (SigGroupHead *)data; - uint32_t hash = 0; - uint32_t b = 0; - - for (b = 0; b < sgh->init->uri_content_size; b++) - hash += sgh->init->uri_content_array[b]; - - return hash % ht->array_size; -} - -/** - * \brief The Compare function to be used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param data1 Pointer to the first SigGroupHead. - * \param len1 Not used. - * \param data2 Pointer to the second SigGroupHead. - * \param len2 Not used. - * - * \retval 1 If the 2 SigGroupHeads sent as args match. - * \retval 0 If the 2 SigGroupHeads sent as args do not match. - */ -char SigGroupHeadMpmUriCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - SigGroupHead *sgh1 = (SigGroupHead *)data1; - SigGroupHead *sgh2 = (SigGroupHead *)data2; - - if (sgh1->init->uri_content_size != sgh2->init->uri_content_size) - return 0; - - if (SCMemcmp(sgh1->init->uri_content_array, sgh2->init->uri_content_array, - sgh1->init->uri_content_size) != 0) { - return 0; - } - - return 1; -} - -/** - * \brief Initializes the mpm uri hash table to be used by the detection engine - * context. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadMpmUriHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_mpm_uri_hash_table = HashListTableInit(4096, - SigGroupHeadMpmUriHashFunc, - SigGroupHeadMpmUriCompareFunc, - NULL); - if (de_ctx->sgh_mpm_uri_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +int SigGroupHeadHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - int ret = HashListTableAdd(de_ctx->sgh_mpm_uri_hash_table, (void *)sgh, 0); - - return ret; + return HashListTableRemove(de_ctx->sgh_hash_table, (void *)sgh, 0); } /** - * \brief Used to lookup a SigGroupHead from the detection engine context - * SigGroupHead mpm uri hash table. + * \brief Used to lookup a SigGroupHead hash from the detection engine context + * SigGroupHead hash table. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. @@ -447,1093 +294,180 @@ int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is * found in the hash table; NULL on failure. */ -SigGroupHead *SigGroupHeadMpmUriHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) +SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_uri_hash_table, + SCEnter(); + + SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, (void *)sgh, 0); - return rsgh; + SCReturnPtr(rsgh, "SigGroupHead"); } /** - * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_uri_hash_table, - * allocated by SigGroupHeadMpmUriHashInit() function. + * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by + * SigGroupHeadHashInit() function. * * \param de_ctx Pointer to the detection engine context. */ -void SigGroupHeadMpmUriHashFree(DetectEngineCtx *de_ctx) +void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) { - if (de_ctx->sgh_mpm_uri_hash_table == NULL) + if (de_ctx->sgh_hash_table == NULL) return; - HashListTableFree(de_ctx->sgh_mpm_uri_hash_table); - de_ctx->sgh_mpm_uri_hash_table = NULL; + HashListTableFree(de_ctx->sgh_hash_table); + de_ctx->sgh_hash_table = NULL; return; } /** - * \brief The hash function to be the used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param ht Pointer to the hash table. - * \param data Pointer to the SigGroupHead. - * \param datalen Not used in our case. - * - * \retval hash The generated hash value. - */ -uint32_t SigGroupHeadMpmStreamHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - SigGroupHead *sgh = (SigGroupHead *)data; - uint32_t hash = 0; - uint32_t b = 0; - - for (b = 0; b < sgh->init->stream_content_size; b++) - hash += sgh->init->stream_content_array[b]; - - return hash % ht->array_size; -} - -/** - * \brief The Compare function to be used by the mpm uri SigGroupHead hash - * table - DetectEngineCtx->sgh_mpm_uri_hash_table. - * - * \param data1 Pointer to the first SigGroupHead. - * \param len1 Not used. - * \param data2 Pointer to the second SigGroupHead. - * \param len2 Not used. - * - * \retval 1 If the 2 SigGroupHeads sent as args match. - * \retval 0 If the 2 SigGroupHeads sent as args do not match. - */ -char SigGroupHeadMpmStreamCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - SigGroupHead *sgh1 = (SigGroupHead *)data1; - SigGroupHead *sgh2 = (SigGroupHead *)data2; - - if (sgh1->init->stream_content_size != sgh2->init->stream_content_size) - return 0; - - if (SCMemcmp(sgh1->init->stream_content_array, sgh2->init->stream_content_array, - sgh1->init->stream_content_size) != 0) { - return 0; - } - - return 1; -} - -/** - * \brief Initializes the mpm uri hash table to be used by the detection engine - * context. + * \brief Add a Signature to a SigGroupHead. * * \param de_ctx Pointer to the detection engine context. + * \param sgh Pointer to a SigGroupHead. Can be NULL also. + * \param s Pointer to the Signature that has to be added to the + * SigGroupHead. * * \retval 0 On success. * \retval -1 On failure. */ -int SigGroupHeadMpmStreamHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_mpm_stream_hash_table = HashListTableInit(4096, - SigGroupHeadMpmStreamHashFunc, SigGroupHeadMpmStreamCompareFunc, NULL); - if (de_ctx->sgh_mpm_stream_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadMpmStreamHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_mpm_stream_hash_table, (void *)sgh, 0); - - return ret; -} - -/** - * \brief Used to lookup a SigGroupHead from the detection engine context - * SigGroupHead mpm uri hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadMpmStreamHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_mpm_stream_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_mpm_uri_hash_table, - * allocated by SigGroupHeadMpmUriHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadMpmStreamHashFree(DetectEngineCtx *de_ctx) +int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, + const Signature *s) { - if (de_ctx->sgh_mpm_stream_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_mpm_stream_hash_table); - de_ctx->sgh_mpm_stream_hash_table = NULL; + if (de_ctx == NULL) + return 0; - return; -} - -/** - * \brief The hash function to be the used by the hash table - - * DetectEngineCtx->sgh_hash_table. - * - * \param ht Pointer to the hash table. - * \param data Pointer to the SigGroupHead. - * \param datalen Not used in our case. - * - * \retval hash The generated hash value. - */ -uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen) -{ - SigGroupHead *sgh = (SigGroupHead *)data; - uint32_t hash = 0; - uint32_t b = 0; - - SCLogDebug("hashing sgh %p (mpm_content_maxlen %u)", sgh, sgh->mpm_content_maxlen); - - for (b = 0; b < sgh->init->sig_size; b++) - hash += sgh->init->sig_array[b]; - - hash %= ht->array_size; - SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size); - return hash; -} - -/** - * \brief The Compare function to be used by the SigGroupHead hash table - - * DetectEngineCtx->sgh_hash_table. - * - * \param data1 Pointer to the first SigGroupHead. - * \param len1 Not used. - * \param data2 Pointer to the second SigGroupHead. - * \param len2 Not used. - * - * \retval 1 If the 2 SigGroupHeads sent as args match. - * \retval 0 If the 2 SigGroupHeads sent as args do not match. - */ -char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, - uint16_t len2) -{ - SigGroupHead *sgh1 = (SigGroupHead *)data1; - SigGroupHead *sgh2 = (SigGroupHead *)data2; - - if (data1 == NULL || data2 == NULL) - return 0; - - if (sgh1->init->sig_size != sgh2->init->sig_size) - return 0; - - if (SCMemcmp(sgh1->init->sig_array, sgh2->init->sig_array, sgh1->init->sig_size) != 0) - return 0; - - return 1; -} - -/** - * \brief Initializes the hash table in the detection engine context to hold the - * SigGroupHeads. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, - SigGroupHeadCompareFunc, NULL); - if (de_ctx->sgh_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context SigGroupHead - * hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the SigGroupHead; -1 on failure. - */ -int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_hash_table, (void *)sgh, 0); - - return ret; -} - -int SigGroupHeadHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - return HashListTableRemove(de_ctx->sgh_hash_table, (void *)sgh, 0); -} - -/** - * \brief Used to lookup a SigGroupHead hash from the detection engine context - * SigGroupHead hash table. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, - (void *)sgh, 0); - - SCReturnPtr(rsgh, "SigGroupHead"); -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by - * SigGroupHeadHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_hash_table); - de_ctx->sgh_hash_table = NULL; - - return; -} - -/** - * \brief Initializes the dport based SigGroupHead hash table to hold the - * SigGroupHeads. The hash table that would be initialized is - * DetectEngineCtx->sgh_dport_hash_table. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadDPortHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_dport_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, - SigGroupHeadCompareFunc, - NULL); - if (de_ctx->sgh_dport_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context dport based - * SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadDPortHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_dport_hash_table, (void *)sgh, 0); - - return ret; -} - -/** - * \brief Used to lookup a SigGroupHead hash from the detection engine ctx dport - * based SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadDPortHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SCEnter(); - - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_dport_hash_table, - (void *)sgh, 0); - - SCReturnPtr(rsgh,"SigGroupHead"); -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_dport_hash_table, - * allocated by the SigGroupHeadDPortHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadDPortHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_dport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_dport_hash_table); - de_ctx->sgh_dport_hash_table = NULL; - - return; -} - -/** - * \brief Initializes the sport based SigGroupHead hash table to hold the - * SigGroupHeads. The hash table that would be initialized is - * DetectEngineCtx->sgh_sport_hash_table. - * - * \param de_ctx Pointer to the detection engine context. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadSPortHashInit(DetectEngineCtx *de_ctx) -{ - de_ctx->sgh_sport_hash_table = HashListTableInit(4096, - SigGroupHeadHashFunc, - SigGroupHeadCompareFunc, - NULL); - if (de_ctx->sgh_sport_hash_table == NULL) - goto error; - - return 0; - -error: - return -1; -} - -/** - * \brief Adds a SigGroupHead to the detection engine context dport based - * SigGroupHead hash table(DetectEngineCtx->sgh_sport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval ret 0 on Successfully adding the argument sgh and -1 on failure. - */ -int SigGroupHeadSPortHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - int ret = HashListTableAdd(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); - - return ret; -} - -int SigGroupHeadSPortHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - return HashListTableRemove(de_ctx->sgh_sport_hash_table, (void *)sgh, 0); -} - -/** - * \brief Used to lookup a SigGroupHead hash from the detection engine ctx sport - * based SigGroupHead hash table(DetectEngineCtx->sgh_dport_hash_table). - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is - * found in the hash table; NULL on failure. - */ -SigGroupHead *SigGroupHeadSPortHashLookup(DetectEngineCtx *de_ctx, - SigGroupHead *sgh) -{ - SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_sport_hash_table, - (void *)sgh, 0); - - return rsgh; -} - -/** - * \brief Frees the hash table - DetectEngineCtx->sgh_sport_hash_table, - * allocated by the SigGroupHeadSPortHashInit() function. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadSPortHashFree(DetectEngineCtx *de_ctx) -{ - if (de_ctx->sgh_sport_hash_table == NULL) - return; - - HashListTableFree(de_ctx->sgh_sport_hash_table); - de_ctx->sgh_sport_hash_table = NULL; - - return; -} - -/** - * \brief Used to free the signature array, content_array and uri_content_array - * members from the SigGroupHeads in the HashListTable. - * - * \param de_ctx Pointer to the detection engine context. - * \param ht Pointer to the HashListTable - */ -static void SigGroupHeadFreeSigArraysHash2(DetectEngineCtx *de_ctx, - HashListTable *ht) -{ - HashListTableBucket *htb = NULL; - SigGroupHead *sgh = NULL; - - for (htb = HashListTableGetListHead(ht); - htb != NULL; - htb = HashListTableGetListNext(htb)) - { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - if (sgh == NULL) { - continue; - } - - if (sgh->init->sig_array != NULL) { - detect_siggroup_sigarray_free_cnt++; - detect_siggroup_sigarray_memory -= sgh->init->sig_size; - - SCFree(sgh->init->sig_array); - sgh->init->sig_array = NULL; - sgh->init->sig_size = 0; - } - - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - - return; -} - -/** - * \brief Used to free the sig_array member of the SigGroupHeads present - * in the HashListTable. - * - * \param de_ctx Pointer to the detection engine context. - * \param ht Pointer to the HashListTable - */ -static void SigGroupHeadFreeSigArraysHash(DetectEngineCtx *de_ctx, - HashListTable *ht) -{ - HashListTableBucket *htb = NULL; - SigGroupHead *sgh = NULL; - - for (htb = HashListTableGetListHead(ht); - htb != NULL; - htb = HashListTableGetListNext(htb)) { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - - if (sgh->init != NULL) { - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - } - - return; -} - -/** - * \brief Free the sigarrays in the sgh's. Those are only used during the init - * stage. - * - * \param de_ctx Pointer to the detection engine context whose sigarrays have to - * be freed. - */ -void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx) -{ - SigGroupHeadFreeSigArraysHash2(de_ctx, de_ctx->sgh_hash_table); - SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_dport_hash_table); - SigGroupHeadFreeSigArraysHash(de_ctx, de_ctx->sgh_sport_hash_table); - - return; -} - -/** - * \brief Free the mpm arrays that are only used during the init stage. - * - * \param de_ctx Pointer to the detection engine context. - */ -void SigGroupHeadFreeMpmArrays(DetectEngineCtx *de_ctx) -{ - HashListTableBucket *htb = NULL; - SigGroupHead *sgh = NULL; - - for (htb = HashListTableGetListHead(de_ctx->sgh_dport_hash_table); htb != NULL; htb = HashListTableGetListNext(htb)) { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - if (sgh->init != NULL) { - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - } - - for (htb = HashListTableGetListHead(de_ctx->sgh_sport_hash_table); htb != NULL; htb = HashListTableGetListNext(htb)) { - sgh = (SigGroupHead *)HashListTableGetListData(htb); - if (sgh->init != NULL) { - SigGroupHeadInitDataFree(sgh->init); - sgh->init = NULL; - } - } - - return; -} - -/** - * \brief Add a Signature to a SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to a SigGroupHead. Can be NULL also. - * \param s Pointer to the Signature that has to be added to the - * SigGroupHead. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadAppendSig(DetectEngineCtx *de_ctx, SigGroupHead **sgh, - Signature *s) -{ - if (de_ctx == NULL) - return 0; - - /* see if we have a head already */ - if (*sgh == NULL) { - *sgh = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); - if (*sgh == NULL) - goto error; - } + /* see if we have a head already */ + if (*sgh == NULL) { + *sgh = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); + if (*sgh == NULL) + goto error; + } /* enable the sig in the bitarray */ (*sgh)->init->sig_array[s->num / 8] |= 1 << (s->num % 8); - /* update maxlen for mpm */ - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { - /* check with the precalculated values from the sig */ - if (s->mpm_content_maxlen > 0) { - if ((*sgh)->mpm_content_maxlen == 0) - (*sgh)->mpm_content_maxlen = s->mpm_content_maxlen; - - if ((*sgh)->mpm_content_maxlen > s->mpm_content_maxlen) - (*sgh)->mpm_content_maxlen = s->mpm_content_maxlen; - - SCLogDebug("(%p)->mpm_content_maxlen %u", *sgh, (*sgh)->mpm_content_maxlen); - } - } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - if (s->mpm_uricontent_maxlen > 0) { - if ((*sgh)->mpm_uricontent_maxlen == 0) - (*sgh)->mpm_uricontent_maxlen = s->mpm_uricontent_maxlen; - - if ((*sgh)->mpm_uricontent_maxlen > s->mpm_uricontent_maxlen) - (*sgh)->mpm_uricontent_maxlen = s->mpm_uricontent_maxlen; - - SCLogDebug("(%p)->mpm_uricontent_maxlen %u", *sgh, (*sgh)->mpm_uricontent_maxlen); - } - } - return 0; - -error: - return -1; -} - -/** - * \brief Clears the bitarray holding the sids for this SigGroupHead. - * - * \param sgh Pointer to the SigGroupHead. - * - * \retval 0 Always. - */ -int SigGroupHeadClearSigs(SigGroupHead *sgh) -{ - if (sgh == NULL) - return 0; - - if (sgh->init->sig_array != NULL) - memset(sgh->init->sig_array, 0, sgh->init->sig_size); - - sgh->sig_cnt = 0; - - return 0; -} - -/** - * \brief Copies the bitarray holding the sids from the source SigGroupHead to - * the destination SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param src Pointer to the source SigGroupHead. - * \param dst Pointer to the destination SigGroupHead. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst) -{ - uint32_t idx = 0; - - if (src == NULL || de_ctx == NULL) - return 0; - - if (*dst == NULL) { - *dst = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); - if (*dst == NULL) - goto error; - } - - /* do the copy */ - for (idx = 0; idx < src->init->sig_size; idx++) - (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; - - if (src->mpm_content_maxlen != 0) { - if ((*dst)->mpm_content_maxlen == 0) - (*dst)->mpm_content_maxlen = src->mpm_content_maxlen; - - if ((*dst)->mpm_content_maxlen > src->mpm_content_maxlen) - (*dst)->mpm_content_maxlen = src->mpm_content_maxlen; - - SCLogDebug("src (%p)->mpm_content_maxlen %u", src, src->mpm_content_maxlen); - SCLogDebug("dst (%p)->mpm_content_maxlen %u", (*dst), (*dst)->mpm_content_maxlen); - BUG_ON((*dst)->mpm_content_maxlen == 0); - } - if (src->mpm_uricontent_maxlen != 0) { - if ((*dst)->mpm_uricontent_maxlen == 0) - (*dst)->mpm_uricontent_maxlen = src->mpm_uricontent_maxlen; - - if ((*dst)->mpm_uricontent_maxlen > src->mpm_uricontent_maxlen) - (*dst)->mpm_uricontent_maxlen = src->mpm_uricontent_maxlen; - } - return 0; - -error: - return -1; -} - -/** - * \brief Updates the SigGroupHead->sig_cnt with the total count of all the - * Signatures present in this SigGroupHead. - * - * \param sgh Pointer to the SigGroupHead. - * \param max_idx Maximum sid of the all the Signatures present in this - * SigGroupHead. - */ -void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) -{ - uint32_t sig; - - sgh->sig_cnt = 0; - for (sig = 0; sig < max_idx + 1; sig++) { - if (sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) - sgh->sig_cnt++; - } - - return; -} - -/** - * \brief Prints the memory statistics for the detect-engine-siggroup.[ch] module. - */ -void DetectSigGroupPrintMemory(void) -{ - SCLogDebug(" * Sig group head memory stats (SigGroupHead %" PRIuMAX "):", - (uintmax_t)sizeof(SigGroupHead)); - SCLogDebug(" - detect_siggroup_head_memory %" PRIu32, - detect_siggroup_head_memory); - SCLogDebug(" - detect_siggroup_head_init_cnt %" PRIu32, - detect_siggroup_head_init_cnt); - SCLogDebug(" - detect_siggroup_head_free_cnt %" PRIu32, - detect_siggroup_head_free_cnt); - SCLogDebug(" - outstanding sig group heads %" PRIu32, - detect_siggroup_head_init_cnt - detect_siggroup_head_free_cnt); - SCLogDebug(" * Sig group head memory stats done"); - SCLogDebug(" * Sig group head initdata memory stats (SigGroupHeadInitData %" PRIuMAX "):", - (uintmax_t)sizeof(SigGroupHeadInitData)); - SCLogDebug(" - detect_siggroup_head_initdata_memory %" PRIu32, - detect_siggroup_head_initdata_memory); - SCLogDebug(" - detect_siggroup_head_initdata_init_cnt %" PRIu32, - detect_siggroup_head_initdata_init_cnt); - SCLogDebug(" - detect_siggroup_head_initdata_free_cnt %" PRIu32, - detect_siggroup_head_initdata_free_cnt); - SCLogDebug(" - outstanding sig group head initdatas %" PRIu32, - detect_siggroup_head_initdata_init_cnt - detect_siggroup_head_initdata_free_cnt); - SCLogDebug(" * Sig group head memory initdata stats done"); - SCLogDebug(" * Sig group sigarray memory stats:"); - SCLogDebug(" - detect_siggroup_sigarray_memory %" PRIu32, - detect_siggroup_sigarray_memory); - SCLogDebug(" - detect_siggroup_sigarray_init_cnt %" PRIu32, - detect_siggroup_sigarray_init_cnt); - SCLogDebug(" - detect_siggroup_sigarray_free_cnt %" PRIu32, - detect_siggroup_sigarray_free_cnt); - SCLogDebug(" - outstanding sig group sigarrays %" PRIu32, - (detect_siggroup_sigarray_init_cnt - - detect_siggroup_sigarray_free_cnt)); - SCLogDebug(" * Sig group sigarray memory stats done"); - SCLogDebug(" * Sig group matcharray memory stats:"); - SCLogDebug(" - detect_siggroup_matcharray_memory %" PRIu32, - detect_siggroup_matcharray_memory); - SCLogDebug(" - detect_siggroup_matcharray_init_cnt %" PRIu32, - detect_siggroup_matcharray_init_cnt); - SCLogDebug(" - detect_siggroup_matcharray_free_cnt %" PRIu32, - detect_siggroup_matcharray_free_cnt); - SCLogDebug(" - outstanding sig group matcharrays %" PRIu32, - (detect_siggroup_matcharray_init_cnt - - detect_siggroup_matcharray_free_cnt)); - SCLogDebug(" * Sig group sigarray memory stats done"); - SCLogDebug(" X Total %" PRIu32, - (detect_siggroup_head_memory + detect_siggroup_sigarray_memory + - detect_siggroup_matcharray_memory)); - - return; -} - -/** - * \brief Helper function used to print the list of sids for the Signatures - * present in this SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - */ -void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - if (sgh == NULL) { - SCReturn; - } - - uint32_t u; - - SCLogDebug("The Signatures present in this SigGroupHead are: "); - for (u = 0; u < (sgh->init->sig_size * 8); u++) { - if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) { - SCLogDebug("%" PRIu32, u); - printf("s->num %"PRIu16" ", u); - } - } - - SCReturn; -} - -/** - * \brief Helper function used to print the content ids of all the contents that - * have been added to the bitarray of this SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - */ -void SigGroupHeadPrintContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - uint32_t i = 0; - - SCLogDebug("Contents with the following content ids are present in this " - "SigGroupHead - "); - for (i = 0; i < DetectContentMaxId(de_ctx); i++) { - if (sgh->init->content_array[i / 8] & (1 << (i % 8))) - SCLogDebug("%" PRIu32, i); - } - - SCReturn; -} - -/** - * \brief Helper function used to print the total no of contents that have - * been added to the bitarray for this SigGroupHead. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - */ -void SigGroupHeadPrintContentCnt(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - SCEnter(); - - uint32_t i = 0; - uint32_t cnt = 0; - - for (i = 0; i < DetectContentMaxId(de_ctx); i++) { - if (sgh->init->content_array[i / 8] & (1 << (i % 8))) - cnt++; - } - - SCLogDebug("Total contents added to the SigGroupHead content bitarray: " - "%" PRIu32, cnt); - - SCReturn; -} - -/** - * \brief Loads all the content ids from all the contents belonging to all the - * Signatures in this SigGroupHead, into a bitarray. A fast and an - * efficient way of comparing pattern sets. - * - * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. - * - * \retval 0 On success, i.e. on either the detection engine context being NULL - * or on successfully allocating memory and updating it with relevant - * data. - * \retval -1 On failure. - */ -int SigGroupHeadLoadContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - Signature *s = NULL; - SigMatch *sm = NULL; - uint32_t sig = 0; - DetectContentData *co = NULL; - - if (sgh == NULL) - return 0; - - if (DetectContentMaxId(de_ctx) == 0) - return 0; - - BUG_ON(sgh->init == NULL); - - sgh->init->content_size = (DetectContentMaxId(de_ctx) / 8) + 1; - sgh->init->content_array = SCMalloc(sgh->init->content_size); - if (sgh->init->content_array == NULL) - return -1; - - memset(sgh->init->content_array,0, sgh->init->content_size); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - if (s == NULL) - continue; - - if (s->alproto != ALPROTO_UNKNOWN) - continue; - - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm == NULL) - continue; - - for ( ;sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - co = (DetectContentData *)sm->ctx; - - sgh->init->content_array[co->id / 8] |= 1 << (co->id % 8); - } - } - } - return 0; + +error: + return -1; } /** - * \brief Clears the memory allocated by SigGroupHeadLoadContent() for the - * bitarray to hold the content ids for a SigGroupHead. + * \brief Clears the bitarray holding the sids for this SigGroupHead. * - * \param Pointer to the SigGroupHead whose content_array would to be cleared. + * \param sgh Pointer to the SigGroupHead. * - * \ret 0 Always. + * \retval 0 Always. */ -int SigGroupHeadClearContent(SigGroupHead *sh) +int SigGroupHeadClearSigs(SigGroupHead *sgh) { - if (sh == NULL) + if (sgh == NULL) return 0; - if (sh->init->content_array != NULL) { - SCFree(sh->init->content_array); - sh->init->content_array = NULL; - sh->init->content_size = 0; - } + if (sgh->init->sig_array != NULL) + memset(sgh->init->sig_array, 0, sgh->init->sig_size); + + sgh->sig_cnt = 0; + return 0; } /** - * \brief Loads all the uri content ids from all the uri contents belonging to - * all the Signatures in this SigGroupHead, into a bitarray. A fast and - * an efficient way of comparing pattern sets. + * \brief Copies the bitarray holding the sids from the source SigGroupHead to + * the destination SigGroupHead. * * \param de_ctx Pointer to the detection engine context. - * \param sgh Pointer to the SigGroupHead. + * \param src Pointer to the source SigGroupHead. + * \param dst Pointer to the destination SigGroupHead. * - * \retval 0 On success, i.e. on either the detection engine context being NULL - * or on successfully allocating memory and updating it with relevant - * data. + * \retval 0 On success. * \retval -1 On failure. */ -int SigGroupHeadLoadUricontent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst) { - Signature *s = NULL; - SigMatch *sm = NULL; - uint32_t sig = 0; - DetectContentData *co = NULL; - - if (sgh == NULL) - return 0; + uint32_t idx = 0; - if (DetectUricontentMaxId(de_ctx) == 0) + if (src == NULL || de_ctx == NULL) return 0; - BUG_ON(sgh->init == NULL); - - sgh->init->uri_content_size = (DetectUricontentMaxId(de_ctx) / 8) + 1; - sgh->init->uri_content_array = SCMalloc(sgh->init->uri_content_size); - if (sgh->init->uri_content_array == NULL) - return -1; - - memset(sgh->init->uri_content_array, 0, sgh->init->uri_content_size); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - - if (s == NULL) - continue; - - sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; - if (sm == NULL) - continue; + if (*dst == NULL) { + *dst = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); + if (*dst == NULL) + goto error; + } - for ( ;sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - co = (DetectContentData *)sm->ctx; + /* do the copy */ + for (idx = 0; idx < src->init->sig_size; idx++) + (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; - sgh->init->uri_content_array[co->id / 8] |= 1 << (co->id % 8); - } - } - } + if (src->init->whitelist) + (*dst)->init->whitelist = MAX((*dst)->init->whitelist, src->init->whitelist); return 0; + +error: + return -1; } /** - * \brief Clears the memory allocated by SigGroupHeadLoadUriContent() for the - * bitarray to hold the uri content ids for a SigGroupHead. - * - * \param Pointer to the SigGroupHead whose uri_content_array would to be - * cleared. + * \brief Updates the SigGroupHead->sig_cnt with the total count of all the + * Signatures present in this SigGroupHead. * - * \retval 0 Always. + * \param sgh Pointer to the SigGroupHead. + * \param max_idx Maximum sid of the all the Signatures present in this + * SigGroupHead. */ -int SigGroupHeadClearUricontent(SigGroupHead *sh) +void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) { - if (sh == NULL) - return 0; + uint32_t sig; - if (sh->init->uri_content_array != NULL) { - SCFree(sh->init->uri_content_array); - sh->init->uri_content_array = NULL; - sh->init->uri_content_size = 0; + sgh->sig_cnt = 0; + for (sig = 0; sig < max_idx + 1; sig++) { + if (sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) + sgh->sig_cnt++; } - return 0; + return; +} + +void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, + uint8_t ipproto, int dir) +{ + if (sgh && sgh->init) { + SCLogDebug("setting proto %u and dir %d on sgh %p", ipproto, dir, sgh); + sgh->init->protos[ipproto] = 1; + sgh->init->direction |= dir; + } } /** - * \brief Loads all the content ids from all the contents belonging to all the - * Signatures in this SigGroupHead, into a bitarray. A fast and an - * efficient way of comparing pattern sets. + * \brief Helper function used to print the list of sids for the Signatures + * present in this SigGroupHead. * * \param de_ctx Pointer to the detection engine context. * \param sgh Pointer to the SigGroupHead. - * - * \retval 0 On success, i.e. on either the detection engine context being NULL - * or on successfully allocating memory and updating it with relevant - * data. - * \retval -1 On failure. */ -int SigGroupHeadLoadStreamContent(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { SCEnter(); - Signature *s = NULL; - SigMatch *sm = NULL; - uint32_t sig = 0; - DetectContentData *co = NULL; - if (sgh == NULL) { - SCReturnInt(0); - } - - if (DetectContentMaxId(de_ctx) == 0) { - SCReturnInt(0); - } - - BUG_ON(sgh->init == NULL); - - sgh->init->stream_content_size = (DetectContentMaxId(de_ctx) / 8) + 1; - sgh->init->stream_content_array = SCMalloc(sgh->init->stream_content_size); - if (sgh->init->stream_content_array == NULL) { - SCReturnInt(-1); + SCReturn; } - memset(sgh->init->stream_content_array,0, sgh->init->stream_content_size); - - for (sig = 0; sig < sgh->sig_cnt; sig++) { - s = sgh->match_array[sig]; - - SCLogDebug("s %"PRIu32, s->id); - - if (s == NULL) - continue; - - if (SignatureHasPacketContent(s)) { - SCLogDebug("Sig has packet content"); - continue; - } - - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm == NULL) - continue; - - for ( ;sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - co = (DetectContentData *)sm->ctx; + uint32_t u; - sgh->init->stream_content_array[co->id / 8] |= 1 << (co->id % 8); - } + SCLogDebug("The Signatures present in this SigGroupHead are: "); + for (u = 0; u < (sgh->init->sig_size * 8); u++) { + if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) { + SCLogDebug("%" PRIu32, u); + printf("s->num %"PRIu32" ", u); } } - SCReturnInt(0); -} - -/** - * \brief Clears the memory allocated by SigGroupHeadLoadContent() for the - * bitarray to hold the content ids for a SigGroupHead. - * - * \param Pointer to the SigGroupHead whose content_array would to be cleared. - * - * \ret 0 Always. - */ -int SigGroupHeadClearStreamContent(SigGroupHead *sh) -{ - if (sh == NULL) - return 0; - - if (sh->init->stream_content_array != NULL) { - SCFree(sh->init->stream_content_array); - sh->init->stream_content_array = NULL; - sh->init->stream_content_size = 0; - } - return 0; + SCReturn; } /** @@ -1565,9 +499,6 @@ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, memset(sgh->match_array,0, sgh->sig_cnt * sizeof(Signature *)); - detect_siggroup_matcharray_init_cnt++; - detect_siggroup_matcharray_memory += (sgh->sig_cnt * sizeof(Signature *)); - for (sig = 0; sig < max_idx + 1; sig++) { if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) ) continue; @@ -1584,13 +515,14 @@ int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, } /** - * \brief Set the need md5 flag in the sgh. + * \brief Set the need magic flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in */ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { +#ifdef HAVE_MAGIC Signature *s = NULL; uint32_t sig = 0; @@ -1607,7 +539,7 @@ void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) break; } } - +#endif return; } @@ -1640,12 +572,12 @@ void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } /** - * \brief Set the need magic flag in the sgh. + * \brief Set the need hash flag in the sgh. * * \param de_ctx detection engine ctx for the signatures * \param sgh sig group head to set the flag in */ -void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +void SigGroupHeadSetFileHashFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; uint32_t sig = 0; @@ -1663,6 +595,18 @@ void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) SCLogDebug("sgh %p has filemd5", sgh); break; } + + if (SignatureIsFileSha1Inspecting(s)) { + sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA1; + SCLogDebug("sgh %p has filesha1", sgh); + break; + } + + if (SignatureIsFileSha256Inspecting(s)) { + sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA256; + SCLogDebug("sgh %p has filesha256", sgh); + break; + } } return; @@ -1695,64 +639,79 @@ void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh) return; } -int SigGroupHeadBuildHeadArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +/** \brief build an array of rule id's for sigs with no prefilter + * Also updated de_ctx::non_pf_store_cnt_max to track the highest cnt + */ +int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { Signature *s = NULL; - uint32_t idx = 0; uint32_t sig = 0; + uint32_t non_pf = 0; + uint32_t non_pf_syn = 0; if (sgh == NULL) return 0; - BUG_ON(sgh->head_array != NULL); -#if defined(__SSE3__) || defined(__tile__) - BUG_ON(sgh->mask_array != NULL); - - /* mask array is 16 byte aligned for SIMD checking, also we always - * alloc a multiple of 32/64 bytes */ - int cnt = sgh->sig_cnt; -#if __WORDSIZE == 32 - if (cnt % 32 != 0) { - cnt += (32 - (cnt % 32)); - } -#elif __WORDSIZE == 64 - if (cnt % 64 != 0) { - cnt += (64 - (cnt % 64)); - } -#endif /* __WORDSIZE */ + BUG_ON(sgh->non_pf_other_store_array != NULL); - sgh->mask_array = (SignatureMask *)SCMallocAligned((cnt * sizeof(SignatureMask)), 16); - if (sgh->mask_array == NULL) - return -1; + for (sig = 0; sig < sgh->sig_cnt; sig++) { + s = sgh->match_array[sig]; + if (s == NULL) + continue; - memset(sgh->mask_array, 0, (cnt * sizeof(SignatureMask))); -#endif + if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) { + if (!(DetectFlagsSignatureNeedsSynPackets(s))) { + non_pf++; + } + non_pf_syn++; + } + } - sgh->head_array = SCMalloc(sgh->sig_cnt * sizeof(SignatureHeader)); - if (sgh->head_array == NULL) - return -1; + if (non_pf == 0 && non_pf_syn == 0) { + sgh->non_pf_other_store_array = NULL; + sgh->non_pf_syn_store_array = NULL; + return 0; + } - memset(sgh->head_array, 0, sgh->sig_cnt * sizeof(SignatureHeader)); + if (non_pf > 0) { + sgh->non_pf_other_store_array = SCMalloc(non_pf * sizeof(SignatureNonPrefilterStore)); + BUG_ON(sgh->non_pf_other_store_array == NULL); + memset(sgh->non_pf_other_store_array, 0, non_pf * sizeof(SignatureNonPrefilterStore)); + } - detect_siggroup_matcharray_init_cnt++; - detect_siggroup_matcharray_memory += (sgh->sig_cnt * sizeof(SignatureHeader *)); + if (non_pf_syn > 0) { + sgh->non_pf_syn_store_array = SCMalloc(non_pf_syn * sizeof(SignatureNonPrefilterStore)); + BUG_ON(sgh->non_pf_syn_store_array == NULL); + memset(sgh->non_pf_syn_store_array, 0, non_pf_syn * sizeof(SignatureNonPrefilterStore)); + } for (sig = 0; sig < sgh->sig_cnt; sig++) { s = sgh->match_array[sig]; if (s == NULL) continue; - sgh->head_array[idx].hdr_copy1 = s->hdr_copy1; - sgh->head_array[idx].hdr_copy2 = s->hdr_copy2; - sgh->head_array[idx].hdr_copy3 = s->hdr_copy3; - sgh->head_array[idx].full_sig = s; + if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) { + if (!(DetectFlagsSignatureNeedsSynPackets(s))) { + BUG_ON(sgh->non_pf_other_store_cnt >= non_pf); + BUG_ON(sgh->non_pf_other_store_array == NULL); + sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].id = s->num; + sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].mask = s->mask; + sgh->non_pf_other_store_cnt++; + } -#if defined(__SSE3__) || defined(__tile__) - sgh->mask_array[idx] = s->mask; -#endif - idx++; + BUG_ON(sgh->non_pf_syn_store_cnt >= non_pf_syn); + BUG_ON(sgh->non_pf_syn_store_array == NULL); + sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].id = s->num; + sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].mask = s->mask; + sgh->non_pf_syn_store_cnt++; + } } + /* track highest cnt for any sgh in our de_ctx */ + uint32_t max = MAX(sgh->non_pf_other_store_cnt, sgh->non_pf_syn_store_cnt); + if (max > de_ctx->non_pf_store_cnt_max) + de_ctx->non_pf_store_cnt_max = max; + return 0; } @@ -1811,50 +770,6 @@ int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int SigAddressPrepareStage1(DetectEngineCtx *); -/** - * \test Check if a SigGroupHead mpm hash table is properly allocated and - * deallocated when calling SigGroupHeadMpmHashInit() and - * SigGroupHeadMpmHashFree() respectively. - */ -static int SigGroupHeadTest01(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadMpmHashInit(&de_ctx); - - result &= (de_ctx.sgh_mpm_hash_table != NULL); - - SigGroupHeadMpmHashFree(&de_ctx); - - result &= (de_ctx.sgh_mpm_hash_table == NULL); - - return result; -} - -/** - * \test Check if a SigGroupHead mpm uri hash table is properly allocated and - * deallocated when calling SigGroupHeadMpmUriHashInit() and - * SigGroupHeadMpmUriHashFree() respectively. - */ -static int SigGroupHeadTest02(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadMpmUriHashInit(&de_ctx); - - result &= (de_ctx.sgh_mpm_uri_hash_table != NULL); - - SigGroupHeadMpmUriHashFree(&de_ctx); - - result &= (de_ctx.sgh_mpm_uri_hash_table == NULL); - - return result; -} - /** * \test Check if a SigGroupHead hash table is properly allocated and * deallocated when calling SigGroupHeadHashInit() and @@ -1877,50 +792,6 @@ static int SigGroupHeadTest03(void) return result; } -/** - * \test Check if a SigGroupHead dport hash table is properly allocated and - * deallocated when calling SigGroupHeadDPortHashInit() and - * SigGroupHeadDportHashFree() respectively. - */ -static int SigGroupHeadTest04(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadDPortHashInit(&de_ctx); - - result &= (de_ctx.sgh_dport_hash_table != NULL); - - SigGroupHeadDPortHashFree(&de_ctx); - - result &= (de_ctx.sgh_dport_hash_table == NULL); - - return result; -} - -/** - * \test Check if a SigGroupHead dport hash table is properly allocated and - * deallocated when calling SigGroupHeadSPortHashInit() and - * SigGroupHeadSportHashFree() respectively. - */ -static int SigGroupHeadTest05(void) -{ - int result = 1; - - DetectEngineCtx de_ctx; - - SigGroupHeadSPortHashInit(&de_ctx); - - result &= (de_ctx.sgh_sport_hash_table != NULL); - - SigGroupHeadSPortHashFree(&de_ctx); - - result &= (de_ctx.sgh_sport_hash_table == NULL); - - return result; -} - /** * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates @@ -2324,75 +1195,16 @@ static int SigGroupHeadTest10(void) UTHFreePackets(&p, 1); return result; } - -/** - * \test sig grouping bug. - */ -static int SigGroupHeadTest11(void) -{ - int result = 0; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - Signature *s = NULL; - Packet *p = NULL; - DetectEngineThreadCtx *det_ctx = NULL; - ThreadVars th_v; - - memset(&th_v, 0, sizeof(ThreadVars)); - - p = UTHBuildPacketReal(NULL, 0, IPPROTO_TCP, "192.168.1.1", "1.2.3.4", 60000, 80); - - if (de_ctx == NULL || p == NULL) - return 0; - - s = DetectEngineAppendSig(de_ctx, "alert tcp any 1024: -> any 1024: (content:\"abc\"; sid:1;)"); - if (s == NULL) { - goto end; - } - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"def\"; http_client_body; sid:2;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - AddressDebugPrint(&p->dst); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - goto end; - } - - /* check if hcbd flag is set in sgh */ - if (!(sgh->flags & SIG_GROUP_HEAD_MPM_HCBD)) { - printf("sgh has not SIG_GROUP_HEAD_MPM_HCBD flag set: "); - goto end; - } - - /* check if sig 2 is part of the sgh */ - - result = 1; -end: - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - UTHFreePackets(&p, 1); - return result; -} #endif void SigGroupHeadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SigGroupHeadTest01", SigGroupHeadTest01, 1); - UtRegisterTest("SigGroupHeadTest02", SigGroupHeadTest02, 1); - UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03, 1); - UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04, 1); - UtRegisterTest("SigGroupHeadTest05", SigGroupHeadTest05, 1); - UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06, 1); - UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07, 1); - UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08, 1); - UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09, 1); - UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10, 1); - UtRegisterTest("SigGroupHeadTest11", SigGroupHeadTest11, 1); + UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03); + UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06); + UtRegisterTest("SigGroupHeadTest07", SigGroupHeadTest07); + UtRegisterTest("SigGroupHeadTest08", SigGroupHeadTest08); + UtRegisterTest("SigGroupHeadTest09", SigGroupHeadTest09); + UtRegisterTest("SigGroupHeadTest10", SigGroupHeadTest10); #endif } diff --git a/src/detect-engine-siggroup.h b/src/detect-engine-siggroup.h index ff44aaf2886f..a5b24808267a 100644 --- a/src/detect-engine-siggroup.h +++ b/src/detect-engine-siggroup.h @@ -24,55 +24,36 @@ #ifndef __DETECT_ENGINE_SIGGROUP_H__ #define __DETECT_ENGINE_SIGGROUP_H__ -void DetectSigGroupPrintMemory(void); - -int SigGroupHeadAppendSig(DetectEngineCtx *, SigGroupHead **, Signature *); +int SigGroupHeadAppendSig(const DetectEngineCtx *, SigGroupHead **, const Signature *); int SigGroupHeadClearSigs(SigGroupHead *); int SigGroupHeadCopySigs(DetectEngineCtx *, SigGroupHead *, SigGroupHead **); -int SigGroupHeadLoadContent(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadLoadUricontent(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadLoadStreamContent(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadClearContent(SigGroupHead *); -int SigGroupHeadClearUricontent(SigGroupHead *); -int SigGroupHeadClearStreamContent(SigGroupHead *); - void SigGroupHeadFree(SigGroupHead *); void SigGroupHeadFreeMpmArrays(DetectEngineCtx *); SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadMpmHashLookup(DetectEngineCtx *, SigGroupHead *); -SigGroupHead *SigGroupHeadMpmUriHashLookup(DetectEngineCtx *, SigGroupHead *); -SigGroupHead *SigGroupHeadMpmStreamHashLookup(DetectEngineCtx *, SigGroupHead *); SigGroupHead *SigGroupHeadDPortHashLookup(DetectEngineCtx *, SigGroupHead *); -SigGroupHead *SigGroupHeadSPortHashLookup(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadMpmHashAdd(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadMpmUriHashAdd(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadMpmStreamHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadHashAdd(DetectEngineCtx *, SigGroupHead *); int SigGroupHeadDPortHashAdd(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadSPortHashAdd(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadHashFree(DetectEngineCtx *); void SigGroupHeadMpmHashFree(DetectEngineCtx *); -void SigGroupHeadMpmUriHashFree(DetectEngineCtx *); -void SigGroupHeadMpmStreamHashFree(DetectEngineCtx *); void SigGroupHeadDPortHashFree(DetectEngineCtx *); -void SigGroupHeadSPortHashFree(DetectEngineCtx *); int SigGroupHeadHashInit(DetectEngineCtx *); int SigGroupHeadMpmHashInit(DetectEngineCtx *); -int SigGroupHeadMpmUriHashInit(DetectEngineCtx *); int SigGroupHeadDPortHashInit(DetectEngineCtx *); -int SigGroupHeadSPortHashInit(DetectEngineCtx *); int SigGroupHeadHashRemove(DetectEngineCtx *, SigGroupHead *); -int SigGroupHeadSPortHashRemove(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid); void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx); +void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, + uint8_t ipproto, int dir); int SigGroupHeadBuildMatchArray (DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t max_idx); void SigGroupHeadFreeSigArrays(DetectEngineCtx *de_ctx); @@ -84,11 +65,13 @@ void SigGroupHeadRegisterTests(void); void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh); void SigGroupHeadStore(DetectEngineCtx *, SigGroupHead *); - -int SigGroupHeadBuildHeadArray(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilestoreCount(DetectEngineCtx *, SigGroupHead *); -void SigGroupHeadSetFileMd5Flag(DetectEngineCtx *, SigGroupHead *); +void SigGroupHeadSetFileHashFlag(DetectEngineCtx *, SigGroupHead *); void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *, SigGroupHead *); +uint16_t SigGroupHeadGetMinMpmSize(DetectEngineCtx *de_ctx, + SigGroupHead *sgh, int list); + +int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh); #endif /* __DETECT_ENGINE_SIGGROUP_H__ */ diff --git a/src/detect-engine-sigorder.c b/src/detect-engine-sigorder.c index 4a980ad66da3..737e49365353 100644 --- a/src/detect-engine-sigorder.c +++ b/src/detect-engine-sigorder.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "detect.h" +#include "detect-xbits.h" #include "detect-flowbits.h" #include "detect-flowint.h" #include "detect-parse.h" @@ -58,6 +59,11 @@ #define DETECT_FLOWINT_TYPE_SET_READ 3 #define DETECT_FLOWINT_TYPE_SET 4 +#define DETECT_XBITS_NOT_USED 1 +#define DETECT_XBITS_TYPE_READ 2 +#define DETECT_XBITS_TYPE_SET_READ 3 +#define DETECT_XBITS_TYPE_SET 4 + /** * \brief Registers a keyword-based, signature ordering function @@ -127,7 +133,7 @@ static inline int SCSigGetFlowbitsType(Signature *sig) int flowbits_user_type = DETECT_FLOWBITS_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { @@ -145,7 +151,7 @@ static inline int SCSigGetFlowbitsType(Signature *sig) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWBITS) { fb = (DetectFlowbitsData *)sm->ctx; @@ -182,7 +188,7 @@ static inline int SCSigGetFlowintType(Signature *sig) int flowint_user_type = DETECT_FLOWINT_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { @@ -193,6 +199,7 @@ static inline int SCSigGetFlowintType(Signature *sig) fi->modifier == FLOWINT_MODIFIER_NE || fi->modifier == FLOWINT_MODIFIER_GE || fi->modifier == FLOWINT_MODIFIER_GT || + fi->modifier == FLOWINT_MODIFIER_NOTSET || fi->modifier == FLOWINT_MODIFIER_ISSET) { read++; } else { @@ -205,7 +212,7 @@ static inline int SCSigGetFlowintType(Signature *sig) sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_POSTMATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; while (sm != NULL) { if (sm->type == DETECT_FLOWINT) { fi = (DetectFlowintData *)sm->ctx; @@ -256,18 +263,24 @@ static inline int SCSigGetFlowvarType(Signature *sig) int type = DETECT_FLOWVAR_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; - if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_FLOW)) { - write++; + if (sm->type == DETECT_PCRE) { + uint8_t x; + for (x = 0; x < pd->idx; x++) { + if (pd->captypes[x] == VAR_TYPE_FLOW_VAR) { + write++; + break; + } + } } sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; pd = NULL; while (sm != NULL) { if (sm->type == DETECT_FLOWVAR) { @@ -308,18 +321,24 @@ static inline int SCSigGetPktvarType(Signature *sig) int type = DETECT_PKTVAR_NOT_USED; int read = 0; int write = 0; - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { pd = (DetectPcreData *)sm->ctx; - if (sm->type == DETECT_PCRE && (pd->flags & DETECT_PCRE_CAPTURE_PKT)) { - write++; + if (sm->type == DETECT_PCRE) { + uint8_t x; + for (x = 0; x < pd->idx; x++) { + if (pd->captypes[x] == VAR_TYPE_PKT_VAR) { + write++; + break; + } + } } sm = sm->next; } - sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; pd = NULL; while (sm != NULL) { if (sm->type == DETECT_PKTVAR) { @@ -340,6 +359,79 @@ static inline int SCSigGetPktvarType(Signature *sig) return type; } +/** + * \brief Returns the xbit type set for this signature. If more than one + * xbit has been set for the same rule, we return the xbit type of + * the maximum priority/value, where priority/value is maximum for the + * ones that set the value and the lowest for ones that read the value. + * If no xbit has been set for the rule, we return 0, which indicates + * the least value amongst xbit types. + * + * \param sig Pointer to the Signature from which the xbit value has to be + * returned. + * + * \retval xbits The xbits type for this signature if it is set; if it is + * not set, return 0 + */ +static inline int SCSigGetXbitsType(Signature *sig, enum VarTypes type) +{ + DetectXbitsData *fb = NULL; + int xbits_user_type = DETECT_XBITS_NOT_USED; + int read = 0; + int write = 0; + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; + + while (sm != NULL) { + if (sm->type == DETECT_XBITS) { + fb = (DetectXbitsData *)sm->ctx; + if (fb->type == type) { + if (fb->cmd == DETECT_XBITS_CMD_ISNOTSET || + fb->cmd == DETECT_XBITS_CMD_ISSET) { + read++; + } else { +#ifdef DEBUG + BUG_ON(1); +#endif + } + } + } + + sm = sm->next; + } + + sm = sig->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; + while (sm != NULL) { + if (sm->type == DETECT_HOSTBITS) { + fb = (DetectXbitsData *)sm->ctx; + if (fb->type == type) { + if (fb->cmd == DETECT_XBITS_CMD_SET || + fb->cmd == DETECT_XBITS_CMD_UNSET || + fb->cmd == DETECT_XBITS_CMD_TOGGLE) { + write++; + } else { +#ifdef DEBUG + BUG_ON(1); +#endif + } + } + } + + sm = sm->next; + } + + if (read > 0 && write == 0) { + xbits_user_type = DETECT_XBITS_TYPE_READ; + } else if (read == 0 && write > 0) { + xbits_user_type = DETECT_XBITS_TYPE_SET; + } else if (read > 0 && write > 0) { + xbits_user_type = DETECT_XBITS_TYPE_SET_READ; + } + + SCLogDebug("Sig %s typeval %d", sig->msg, xbits_user_type); + + return xbits_user_type; +} + /** * \brief Processes the flowbits data for this signature and caches it for * future use. This is needed to optimize the sig_ordering module. @@ -381,6 +473,30 @@ static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw) sw->user[SC_RADIX_USER_DATA_PKTVAR] = SCSigGetPktvarType(sw->sig); } +/** + * \brief Processes the hostbits data for this signature and caches it for + * future use. This is needed to optimize the sig_ordering module. + * + * \param sw The sigwrapper/signature for which the hostbits data has to be + * cached + */ +static inline void SCSigProcessUserDataForHostbits(SCSigSignatureWrapper *sw) +{ + sw->user[SC_RADIX_USER_DATA_HOSTBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_HOST_BIT); +} + +/** + * \brief Processes the hostbits data for this signature and caches it for + * future use. This is needed to optimize the sig_ordering module. + * + * \param sw The sigwrapper/signature for which the hostbits data has to be + * cached + */ +static inline void SCSigProcessUserDataForIPPairbits(SCSigSignatureWrapper *sw) +{ + sw->user[SC_RADIX_USER_DATA_IPPAIRBITS] = SCSigGetXbitsType(sw->sig, VAR_TYPE_IPPAIR_BIT); +} + /* Return 1 if sw1 comes before sw2 in the final list. */ static int SCSigLessThan(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2, @@ -528,6 +644,34 @@ static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1, sw2->user[SC_RADIX_USER_DATA_FLOWINT]; } +/** + * \brief Orders an incoming Signature based on its hostbits type + * + * \param de_ctx Pointer to the detection engine context from which the + * signatures have to be ordered. + * \param sw The new signature that has to be ordered based on its hostbits + */ +static int SCSigOrderByHostbitsCompare(SCSigSignatureWrapper *sw1, + SCSigSignatureWrapper *sw2) +{ + return sw1->user[SC_RADIX_USER_DATA_HOSTBITS] - + sw2->user[SC_RADIX_USER_DATA_HOSTBITS]; +} + +/** + * \brief Orders an incoming Signature based on its ippairbits (xbits) type + * + * \param de_ctx Pointer to the detection engine context from which the + * signatures have to be ordered. + * \param sw The new signature that has to be ordered based on its bits + */ +static int SCSigOrderByIPPairbitsCompare(SCSigSignatureWrapper *sw1, + SCSigSignatureWrapper *sw2) +{ + return sw1->user[SC_RADIX_USER_DATA_IPPAIRBITS] - + sw2->user[SC_RADIX_USER_DATA_IPPAIRBITS]; +} + /** * \brief Orders an incoming Signature based on its priority type * @@ -564,6 +708,8 @@ static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig) SCSigProcessUserDataForFlowvar(sw); SCSigProcessUserDataForFlowint(sw); SCSigProcessUserDataForPktvar(sw); + SCSigProcessUserDataForHostbits(sw); + SCSigProcessUserDataForIPPairbits(sw); return sw; } @@ -643,6 +789,8 @@ void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx) SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowintCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare); + SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByHostbitsCompare); + SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByIPPairbitsCompare); SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare); } @@ -2049,18 +2197,18 @@ void SCSigRegisterSignatureOrderingTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCSigOrderingTest01", SCSigOrderingTest01, 1); - UtRegisterTest("SCSigOrderingTest02", SCSigOrderingTest02, 1); - UtRegisterTest("SCSigOrderingTest03", SCSigOrderingTest03, 1); - UtRegisterTest("SCSigOrderingTest04", SCSigOrderingTest04, 1); - UtRegisterTest("SCSigOrderingTest05", SCSigOrderingTest05, 1); - UtRegisterTest("SCSigOrderingTest06", SCSigOrderingTest06, 1); - UtRegisterTest("SCSigOrderingTest07", SCSigOrderingTest07, 1); - UtRegisterTest("SCSigOrderingTest08", SCSigOrderingTest08, 1); - UtRegisterTest("SCSigOrderingTest09", SCSigOrderingTest09, 1); - UtRegisterTest("SCSigOrderingTest10", SCSigOrderingTest10, 1); - UtRegisterTest("SCSigOrderingTest11", SCSigOrderingTest11, 1); - UtRegisterTest("SCSigOrderingTest12", SCSigOrderingTest12, 1); - UtRegisterTest("SCSigOrderingTest13", SCSigOrderingTest13, 1); + UtRegisterTest("SCSigOrderingTest01", SCSigOrderingTest01); + UtRegisterTest("SCSigOrderingTest02", SCSigOrderingTest02); + UtRegisterTest("SCSigOrderingTest03", SCSigOrderingTest03); + UtRegisterTest("SCSigOrderingTest04", SCSigOrderingTest04); + UtRegisterTest("SCSigOrderingTest05", SCSigOrderingTest05); + UtRegisterTest("SCSigOrderingTest06", SCSigOrderingTest06); + UtRegisterTest("SCSigOrderingTest07", SCSigOrderingTest07); + UtRegisterTest("SCSigOrderingTest08", SCSigOrderingTest08); + UtRegisterTest("SCSigOrderingTest09", SCSigOrderingTest09); + UtRegisterTest("SCSigOrderingTest10", SCSigOrderingTest10); + UtRegisterTest("SCSigOrderingTest11", SCSigOrderingTest11); + UtRegisterTest("SCSigOrderingTest12", SCSigOrderingTest12); + UtRegisterTest("SCSigOrderingTest13", SCSigOrderingTest13); #endif } diff --git a/src/detect-engine-sigorder.h b/src/detect-engine-sigorder.h index 1451dfc3fae3..686ce9280f4d 100644 --- a/src/detect-engine-sigorder.h +++ b/src/detect-engine-sigorder.h @@ -33,6 +33,8 @@ typedef enum{ SC_RADIX_USER_DATA_FLOWVAR, SC_RADIX_USER_DATA_PKTVAR, SC_RADIX_USER_DATA_FLOWINT, + SC_RADIX_USER_DATA_HOSTBITS, + SC_RADIX_USER_DATA_IPPAIRBITS, SC_RADIX_USER_DATA_MAX } SCRadixUserDataType; diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 2ca789afa7fd..98e1304c04bb 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -81,8 +81,42 @@ /** convert enum to string */ #define CASE_CODE(E) case E: return #E +/** The DetectEngineThreadCtx::de_state_sig_array contains 2 separate values: + * 1. the first bit tells the prefilter engine to bypass the rule (or not) + * 2. the other bits allow 'ContinueDetect' to specify an offset again the + * base tx id. This offset will then be used by 'StartDetect' to not + * inspect transactions again for the same signature. + * + * The offset in (2) has a max value due to the limited data type. If it is + * set to max the code will fall back to a slower path that validates that + * we're not adding duplicate rules to the detection state. + */ +#define MAX_STORED_TXID_OFFSET 127 + /******** static internal helpers *********/ +static inline int StateIsValid(uint16_t alproto, void *alstate) +{ + if (alstate != NULL) { + if (alproto == ALPROTO_HTTP) { + HtpState *htp_state = (HtpState *)alstate; + if (htp_state->conn != NULL) { + return 1; + } + } else { + return 1; + } + } + return 0; +} + +static inline int TxIsLast(uint64_t tx_id, uint64_t total_txs) +{ + if (total_txs - tx_id <= 1) + return 1; + return 0; +} + static DeStateStore *DeStateStoreAlloc(void) { DeStateStore *d = SCMalloc(sizeof(DeStateStore)); @@ -93,13 +127,41 @@ static DeStateStore *DeStateStoreAlloc(void) return d; } -static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, - SigMatch *sm, uint32_t inspect_flags, - uint8_t direction) +static int DeStateSearchState(DetectEngineState *state, uint8_t direction, SigIntId num) +{ + DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; + DeStateStore *tx_store = dir_state->head; + SigIntId store_cnt; + SigIntId state_cnt = 0; + + for (; tx_store != NULL; tx_store = tx_store->next) { + SCLogDebug("tx_store %p", tx_store); + for (store_cnt = 0; + store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; + store_cnt++, state_cnt++) + { + DeStateStoreItem *item = &tx_store->store[store_cnt]; + if (item->sid == num) { + SCLogDebug("sid %u already in state: %p %p %p %u %u, direction %s", + num, state, dir_state, tx_store, state_cnt, + store_cnt, direction & STREAM_TOSERVER ? "toserver" : "toclient"); + return 1; + } + } + } + return 0; +} + +static void DeStateSignatureAppend(DetectEngineState *state, + const Signature *s, uint32_t inspect_flags, uint8_t direction) { int jump = 0; int i = 0; DetectEngineStateDirection *dir_state = &state->dir_state[direction & STREAM_TOSERVER ? 0 : 1]; + +#ifdef DEBUG_VALIDATION + BUG_ON(DeStateSearchState(state, direction, s->num)); +#endif DeStateStore *store = dir_state->head; if (store == NULL) { @@ -128,15 +190,6 @@ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s, SigIntId idx = dir_state->cnt++ % DE_STATE_CHUNK_SIZE; store->store[idx].sid = s->num; store->store[idx].flags = inspect_flags; - store->store[idx].nm = sm; - - return; -} - -static void DeStateStoreStateVersion(DetectEngineState *de_state, - uint16_t alversion, uint8_t direction) -{ - de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].alversion = alversion; return; } @@ -148,7 +201,7 @@ static void DeStateStoreFileNoMatchCnt(DetectEngineState *de_state, uint16_t fil return; } -static int DeStateStoreFilestoreSigsCantMatch(SigGroupHead *sgh, DetectEngineState *de_state, uint8_t direction) +static int DeStateStoreFilestoreSigsCantMatch(const SigGroupHead *sgh, DetectEngineState *de_state, uint8_t direction) { if (de_state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].filestore_cnt == sgh->filestore_cnt) return 1; @@ -156,33 +209,6 @@ static int DeStateStoreFilestoreSigsCantMatch(SigGroupHead *sgh, DetectEngineSta return 0; } -static void DeStateResetFileInspection(Flow *f, AppProto alproto, void *alstate, uint8_t direction) -{ - if (f == NULL || alproto != ALPROTO_HTTP || alstate == NULL || f->de_state == NULL) - return; - - FLOWLOCK_WRLOCK(f); - HtpState *htp_state = (HtpState *)alstate; - - if (direction & STREAM_TOSERVER) { - if (htp_state->flags & HTP_FLAG_NEW_FILE_TX_TS) { - SCLogDebug("new file in the TS direction"); - htp_state->flags &= ~HTP_FLAG_NEW_FILE_TX_TS; - f->de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW; - } - } else { - if (htp_state->flags & HTP_FLAG_NEW_FILE_TX_TC) { - SCLogDebug("new file in the TC direction"); - htp_state->flags &= ~HTP_FLAG_NEW_FILE_TX_TC; - f->de_state->dir_state[1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW; - } - } - - FLOWLOCK_UNLOCK(f); -} - - - DetectEngineState *DetectEngineStateAlloc(void) { DetectEngineState *d = SCMalloc(sizeof(DetectEngineState)); @@ -212,615 +238,632 @@ void DetectEngineStateFree(DetectEngineState *state) return; } -/** +static int HasStoredSigs(const Flow *f, const uint8_t flags) +{ + if (AppLayerParserProtocolSupportsTxs(f->proto, f->alproto)) { + AppProto alproto = f->alproto; + void *alstate = FlowGetAppState(f); + if (!StateIsValid(f->alproto, alstate)) { + return 0; + } + + int state = AppLayerParserHasTxDetectState(f->proto, alproto, f->alstate); + if (state == -ENOSYS) { /* proto doesn't support this API call */ + /* fall through */ + } else if (state == 0) { + return 0; + } + /* if state == 1 we also fall through */ + + uint64_t inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); + + for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx != NULL) { + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, alproto, inspect_tx); + if (tx_de_state == NULL) { + continue; + } + if (tx_de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].cnt != 0) { + SCLogDebug("tx %u has sigs present", (uint)inspect_tx_id); + return 1; + } + } + } + } + return 0; +} + +/** \brief Check if we need to inspect this state + * + * State needs to be inspected if: + * 1. state has been updated + * 2. we already have de_state in progress + * * \retval 0 no inspectable state * \retval 1 inspectable state - * \retval 2 inspectable state, but no update */ -int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion, uint8_t flags) +int DeStateFlowHasInspectableState(const Flow *f, const uint8_t flags) { int r = 0; - SCMutexLock(&f->de_state_m); - if (f->de_state == NULL || f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].cnt == 0) { - if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { - FLOWLOCK_RDLOCK(f); - if (f->alparser != NULL && f->alstate != NULL) { - if (AppLayerParserGetTransactionInspectId(f->alparser, flags) >= - AppLayerParserGetTxCnt(f->proto, alproto, f->alstate)) { - r = 2; - } + if (HasStoredSigs(f, flags)) { + r = 1; + } else { + r = 0; + } + return r; +} + +static void StoreStateTxHandleFiles(DetectEngineThreadCtx *det_ctx, Flow *f, + DetectEngineState *destate, const uint8_t flags, + const uint64_t tx_id, const uint16_t file_no_match) +{ + SCLogDebug("tx %u, file_no_match %u", (uint)tx_id, file_no_match); + DeStateStoreFileNoMatchCnt(destate, file_no_match, flags); + if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, destate, flags) == 1) { + FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT | STREAM_TOSERVER), tx_id); + } +} + +static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, + Flow *f, const uint8_t flags, const uint64_t tx_id, void *tx, + const uint16_t file_no_match) +{ + if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { + DetectEngineState *destate = AppLayerParserGetTxDetectState(f->proto, f->alproto, tx); + if (destate == NULL) { + destate = DetectEngineStateAlloc(); + if (destate == NULL) + return; + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { + DetectEngineStateFree(destate); + return; } - FLOWLOCK_UNLOCK(f); + SCLogDebug("destate created for %"PRIu64, tx_id); } - } else if (!(flags & STREAM_EOF) && - f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].alversion == alversion) { - r = 2; - } else { - r = 1; + StoreStateTxHandleFiles(det_ctx, f, destate, flags, tx_id, file_no_match); } - SCMutexUnlock(&f->de_state_m); +} - return r; +/** + * \param check_before_add check for duplicates before adding the sig + */ +static void StoreStateTx(DetectEngineThreadCtx *det_ctx, + Flow *f, const uint8_t flags, + const uint64_t tx_id, void *tx, + const Signature *s, const SigMatchData *smd, + const uint32_t inspect_flags, const uint16_t file_no_match, int check_before_add) +{ + if (AppLayerParserSupportsTxDetectState(f->proto, f->alproto)) { + DetectEngineState *destate = AppLayerParserGetTxDetectState(f->proto, f->alproto, tx); + if (destate == NULL) { + destate = DetectEngineStateAlloc(); + if (destate == NULL) + return; + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { + DetectEngineStateFree(destate); + return; + } + SCLogDebug("destate created for %"PRIu64, tx_id); + } + + SCLogDebug("file_no_match %u", file_no_match); + + if (check_before_add == 0 || DeStateSearchState(destate, flags, s->num) == 0) + DeStateSignatureAppend(destate, s, inspect_flags, flags); + + StoreStateTxHandleFiles(det_ctx, f, destate, flags, tx_id, file_no_match); + } + SCLogDebug("Stored for TX %"PRIu64, tx_id); } int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion) + const Signature *s, Packet *p, Flow *f, uint8_t flags, + AppProto alproto) { - DetectEngineAppInspectionEngine *engine = NULL; - SigMatch *sm = NULL; + SigMatchData *smd = NULL; uint16_t file_no_match = 0; uint32_t inspect_flags = 0; - - void *alstate = NULL; - HtpState *htp_state = NULL; - SMBState *smb_state = NULL; - - void *tx = NULL; - uint64_t tx_id = 0; - uint64_t total_txs = 0; - int match = 0; - int store_de_state = 0; - uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; - /* this was introduced later to allow protocols that had both app - * keywords with transaction keywords. Without this we would - * assume that we have an alert if engine == NULL */ - int total_matches = 0; - int alert_cnt = 0; + SCLogDebug("rule %u", s->id); + + /* TX based matches (inspect engines) */ if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); + uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; + int check_before_add = 0; + uint64_t tx_id = 0; + uint64_t total_txs = 0; + + void *alstate = FlowGetAppState(f); + if (!StateIsValid(alproto, alstate)) { goto end; } - if (alproto == ALPROTO_HTTP) { - htp_state = (HtpState *)alstate; - if (htp_state->conn == NULL) { - FLOWLOCK_UNLOCK(f); - goto end; - } - } + + /* if continue detection already inspected this rule for this tx, + * continue with the first not-inspected tx */ + uint8_t offset = det_ctx->de_state_sig_array[s->num] & 0xef; tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); - SCLogDebug("tx_id %"PRIu64, tx_id); + if (offset > 0) { + SCLogDebug("using stored_tx_id %u instead of %u", (uint)tx_id+offset, (uint)tx_id); + tx_id += offset; + } + if (offset == MAX_STORED_TXID_OFFSET) { + check_before_add = 1; + } + total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); SCLogDebug("total_txs %"PRIu64, total_txs); + SCLogDebug("starting: start tx %u, packet %u", (uint)tx_id, (uint)p->pcap_cnt); + for (; tx_id < total_txs; tx_id++) { - total_matches = 0; - tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); + int total_matches = 0; + void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); + SCLogDebug("tx %p", tx); if (tx == NULL) continue; det_ctx->tx_id = tx_id; det_ctx->tx_id_set = 1; - engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][direction]; + + DetectEngineAppInspectionEngine *engine = s->app_inspect; + SCLogDebug("engine %p", engine); inspect_flags = 0; while (engine != NULL) { - if (s->sm_lists[engine->sm_list] != NULL) { + SCLogDebug("engine %p", engine); + SCLogDebug("inspect_flags %x", inspect_flags); + if (direction == engine->dir) { KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - match = engine->Callback(tv, de_ctx, det_ctx, s, f, - flags, alstate, - tx, tx_id); - if (match == 1) { - inspect_flags |= engine->inspect_flags; + int match = engine->Callback(tv, de_ctx, det_ctx, + s, engine->smd, f, flags, alstate, tx, tx_id); + SCLogDebug("engine %p match %d", engine, match); + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { + inspect_flags |= BIT_U32(engine->id); engine = engine->next; total_matches++; continue; - } else if (match == 2) { + } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { + /* if the file engine matched, but indicated more + * files are still in progress, we don't set inspect + * flags as these would end inspection for this tx */ + engine = engine->next; + total_matches++; + continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - } else if (match == 3) { + inspect_flags |= BIT_U32(engine->id);; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; + inspect_flags |= BIT_U32(engine->id); file_no_match++; } break; } engine = engine->next; } + SCLogDebug("inspect_flags %x", inspect_flags); /* all the engines seem to be exhausted at this point. If we * didn't have a match in one of the engines we would have * broken off and engine wouldn't be NULL. Hence the alert. */ if (engine == NULL && total_matches > 0) { - if (!(s->flags & SIG_FLAG_NOALERT)) { PacketAlertAppend(det_ctx, s, p, tx_id, PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); } else { - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } - alert_cnt = 1; + SCLogDebug("MATCH: tx %u packet %u", (uint)tx_id, (uint)p->pcap_cnt); } - if (tx_id == (total_txs - 1)) { - void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id); - if (tx == NULL) - continue; - if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) < - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { - store_de_state = 1; - if (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + /* if this is the last tx in our list, and it's incomplete: then + * we store the state so that ContinueDetection knows about it */ + int tx_is_done = (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) >= + AppLayerParserGetStateProgressCompletionStatus(alproto, flags)); + /* see if we need to consider the next tx in our decision to add + * a sig to the 'no inspect array'. */ + int next_tx_no_progress = 0; + if (!TxIsLast(tx_id, total_txs)) { + void *next_tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id+1); + if (next_tx != NULL) { + int c = AppLayerParserGetStateProgress(f->proto, alproto, next_tx, flags); + if (c == 0) { + next_tx_no_progress = 1; + } } } - } /* for */ - FLOWLOCK_UNLOCK(f); + SCLogDebug("tx %u, packet %u, rule %u, alert_cnt %u, last tx %d, tx_is_done %d, next_tx_no_progress %d", + (uint)tx_id, (uint)p->pcap_cnt, s->num, alert_cnt, + TxIsLast(tx_id, total_txs), tx_is_done, next_tx_no_progress); - } else if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL && - (alproto == ALPROTO_DCERPC || alproto == ALPROTO_SMB || - alproto == ALPROTO_SMB2)) - { - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); - goto end; - } + /* if we have something to store (partial match or file store info), + * then we do it now. */ + if (inspect_flags != 0) { + if (!(TxIsLast(tx_id, total_txs)) || !tx_is_done) { + if (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; + } - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_DMATCH); - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present && - DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, &smb_state->dcerpc) == 1) { - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); + /* store */ + StoreStateTx(det_ctx, f, flags, tx_id, tx, + s, smd, inspect_flags, file_no_match, check_before_add); } else { - PACKET_UPDATE_ACTION(p, s->action); + StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match); } + } else { + SCLogDebug("no state to store"); + } + if (next_tx_no_progress) + break; + } /* for */ + } + end: + det_ctx->tx_id = 0; + det_ctx->tx_id_set = 0; + return alert_cnt ? 1:0; +} - alert_cnt = 1; +static int DoInspectItem(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + DeStateStoreItem *item, const uint8_t dir_state_flags, + Packet *p, Flow *f, AppProto alproto, uint8_t flags, + const uint64_t inspect_tx_id, const uint64_t total_txs, + + uint16_t *file_no_match, int inprogress, // is current tx in progress? + const int next_tx_no_progress) // tx after current is still dormant +{ + Signature *s = de_ctx->sig_array[item->sid]; + + SCLogDebug("file_no_match %u, sid %u", *file_no_match, s->id); + + /* check if a sig in state 'full inspect' needs to be reconsidered + * as the result of a new file in the existing tx */ + if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { + if (item->flags & (DE_STATE_FLAG_FILE_TC_INSPECT|DE_STATE_FLAG_FILE_TS_INSPECT)) { + if ((flags & STREAM_TOCLIENT) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) + { + SCLogDebug("~DE_STATE_FLAG_FILE_TC_INSPECT"); + item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; + item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; } - } else { - if (DetectEngineInspectDcePayload(de_ctx, det_ctx, s, f, - flags, alstate) == 1) { - alert_cnt = 1; - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - PACKET_UPDATE_ACTION(p, s->action); - } + if ((flags & STREAM_TOSERVER) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) + { + SCLogDebug("~DE_STATE_FLAG_FILE_TS_INSPECT"); + item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; + item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; + } + } + if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { + if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + SCLogDebug("skip and bypass %u: tx %u packet %u", s->id, (uint)inspect_tx_id, (uint)p->pcap_cnt); + } else { + SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + + /* make sure that if we reinspect this right now from + * start detection, we skip this tx we just matched on */ + uint64_t base_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t offset = (inspect_tx_id + 1) - base_tx_id; + if (offset > MAX_STORED_TXID_OFFSET) + offset = MAX_STORED_TXID_OFFSET; + det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; +#ifdef DEBUG_VALIDATION + BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit +#endif + SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } + return 0; } - FLOWLOCK_UNLOCK(f); } - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); - sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; - if (sm != NULL) { - /* RDLOCK would be nicer, but at least tlsstore needs - * write lock currently. */ - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); - goto end; - } + /* check if a sig in state 'cant match' needs to be reconsidered + * as the result of a new file in the existing tx */ + SCLogDebug("item->flags %x", item->flags); + if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { + SCLogDebug("DE_STATE_FLAG_SIG_CANT_MATCH"); - for (match = 0; sm != NULL; sm = sm->next) { - match = 0; - if (sigmatch_table[sm->type].AppLayerMatch != NULL) { - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present) { - KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); - } - } else { - KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); - } + if ((flags & STREAM_TOSERVER) && + (item->flags & DE_STATE_FLAG_FILE_TS_INSPECT) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) + { + SCLogDebug("unset ~DE_STATE_FLAG_FILE_TS_INSPECT ~DE_STATE_FLAG_SIG_CANT_MATCH"); + item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; - if (match == 0) - break; - if (match == 2) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - break; - } + } else if ((flags & STREAM_TOCLIENT) && + (item->flags & DE_STATE_FLAG_FILE_TC_INSPECT) && + (dir_state_flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) + { + SCLogDebug("unset ~DE_STATE_FLAG_FILE_TC_INSPECT ~DE_STATE_FLAG_SIG_CANT_MATCH"); + item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; + item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; + } else { + if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + SCLogDebug("skip and bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + } else { + SCLogDebug("just skip: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + + /* make sure that if we reinspect this right now from + * start detection, we skip this tx we just matched on */ + uint64_t base_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t offset = (inspect_tx_id + 1) - base_tx_id; + if (offset > MAX_STORED_TXID_OFFSET) + offset = MAX_STORED_TXID_OFFSET; + det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; +#ifdef DEBUG_VALIDATION + BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit +#endif + SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } + return 0; } - FLOWLOCK_UNLOCK(f); + } - store_de_state = 1; - if (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) { - if (match == 1) { - if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - PACKET_UPDATE_ACTION(p, s->action); - } - alert_cnt = 1; - } - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } + uint8_t alert = 0; + uint32_t inspect_flags = 0; + int total_matches = 0; + + RULE_PROFILING_START(p); + + void *alstate = FlowGetAppState(f); + if (!StateIsValid(alproto, alstate)) { + RULE_PROFILING_END(det_ctx, s, 0, p); + return -1; } - if (!store_de_state && file_no_match == 0) - goto end; + det_ctx->tx_id = inspect_tx_id; + det_ctx->tx_id_set = 1; + SCLogDebug("inspecting: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); - SCMutexLock(&f->de_state_m); - if (f->de_state == NULL) { - f->de_state = DetectEngineStateAlloc(); - if (f->de_state == NULL) { - SCMutexUnlock(&f->de_state_m); - goto end; + uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; + DetectEngineAppInspectionEngine *engine = s->app_inspect; + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx == NULL) { + RULE_PROFILING_END(det_ctx, s, 0, p); + return -1; + } + + while (engine != NULL) { + if (!(item->flags & BIT_U32(engine->id)) && + direction == engine->dir) + { + SCLogDebug("inspect_flags %x", inspect_flags); + KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); + int match = engine->Callback(tv, de_ctx, det_ctx, + s, engine->smd, + f, flags, alstate, inspect_tx, inspect_tx_id); + if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) { + inspect_flags |= BIT_U32(engine->id); + engine = engine->next; + total_matches++; + continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) { + /* if the file engine matched, but indicated more + * files are still in progress, we don't set inspect + * flags as these would end inspection for this tx */ + engine = engine->next; + total_matches++; + continue; + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) { + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + inspect_flags |= BIT_U32(engine->id); + } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) { + inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; + inspect_flags |= BIT_U32(engine->id); + (*file_no_match)++; + } + break; } + engine = engine->next; } - if (store_de_state) { - DeStateSignatureAppend(f->de_state, s, sm, inspect_flags, flags); - DeStateStoreStateVersion(f->de_state, alversion, flags); + SCLogDebug("inspect_flags %x", inspect_flags); + if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { + if (engine == NULL) + alert = 1; + inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } - DeStateStoreFileNoMatchCnt(f->de_state, file_no_match, flags); - if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, f->de_state, flags) == 1) { - FLOWLOCK_WRLOCK(f); - FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT | STREAM_TOSERVER), - det_ctx->tx_id); - FLOWLOCK_UNLOCK(f); - f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1].flags |= DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED; + + item->flags |= inspect_flags; + /* flag this sig to don't inspect again from the detection loop it if + * there is no need for it */ + if (TxIsLast(inspect_tx_id, total_txs) || inprogress || next_tx_no_progress) { + det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + SCLogDebug("inspected, now bypass: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + } else { + /* make sure that if we reinspect this right now from + * start detection, we skip this tx we just matched on */ + uint64_t base_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + uint64_t offset = (inspect_tx_id + 1) - base_tx_id; + if (offset > MAX_STORED_TXID_OFFSET) + offset = MAX_STORED_TXID_OFFSET; + det_ctx->de_state_sig_array[item->sid] = (uint8_t)offset; +#ifdef DEBUG_VALIDATION + BUG_ON(det_ctx->de_state_sig_array[item->sid] & DE_STATE_MATCH_NO_NEW_STATE); // check that we don't set the bit +#endif + SCLogDebug("storing tx_id %u for this sid", (uint)inspect_tx_id + 1); } - SCMutexUnlock(&f->de_state_m); + RULE_PROFILING_END(det_ctx, s, (alert == 1), p); - end: - det_ctx->tx_id = 0; - det_ctx->tx_id_set = 0; - return alert_cnt ? 1:0; + if (alert) { + SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); + + if (!(s->flags & SIG_FLAG_NOALERT)) { + PacketAlertAppend(det_ctx, s, p, inspect_tx_id, + PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); + } else { + PACKET_UPDATE_ACTION(p, s->action); + } + SCLogDebug("MATCH: tx %u packet %u", (uint)inspect_tx_id, (uint)p->pcap_cnt); + } + + DetectVarProcessList(det_ctx, f, p); + return 1; } void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion) + AppProto alproto) { - SCMutexLock(&f->de_state_m); - - DetectEngineAppInspectionEngine *engine = NULL; - SigMatch *sm = NULL; uint16_t file_no_match = 0; - uint32_t inspect_flags = 0; - - void *alstate = NULL; - HtpState *htp_state = NULL; - SMBState *smb_state = NULL; - SigIntId store_cnt = 0; SigIntId state_cnt = 0; - int match = 0; - uint8_t alert = 0; - - DetectEngineStateDirection *dir_state = &f->de_state->dir_state[flags & STREAM_TOSERVER ? 0 : 1]; - DeStateStore *store = dir_state->head; - void *inspect_tx = NULL; uint64_t inspect_tx_id = 0; uint64_t total_txs = 0; - uint8_t alproto_supports_txs = 0; - uint8_t reset_de_state = 0; - /* this was introduced later to allow protocols that had both app - * keywords with transaction keywords. Without this we would - * assume that we have an alert if engine == NULL */ - uint8_t total_matches = 0; + uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1; - DeStateResetFileInspection(f, alproto, alstate, flags); + SCLogDebug("starting continue detection for packet %"PRIu64, p->pcap_cnt); if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) { - FLOWLOCK_RDLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); - SCMutexUnlock(&f->de_state_m); + void *alstate = FlowGetAppState(f); + if (!StateIsValid(alproto, alstate)) { return; } inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); - inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); - if (inspect_tx != NULL) { - if (AppLayerParserGetStateProgress(f->proto, alproto, inspect_tx, flags) >= - AppLayerParserGetStateProgressCompletionStatus(f->proto, alproto, flags)) { - reset_de_state = 1; - } - } - FLOWLOCK_UNLOCK(f); - alproto_supports_txs = 1; - } - - for (; store != NULL; store = store->next) { - for (store_cnt = 0; - store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < dir_state->cnt; - store_cnt++, state_cnt++) - { - total_matches = 0; - DeStateStoreItem *item = &store->store[store_cnt]; - Signature *s = de_ctx->sig_array[item->sid]; - - if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - if (item->flags & (DE_STATE_FLAG_FILE_TC_INSPECT | - DE_STATE_FLAG_FILE_TS_INSPECT)) { - if ((flags & STREAM_TOCLIENT) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; - item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; - } - if ((flags & STREAM_TOSERVER) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; - item->flags &= ~DE_STATE_FLAG_FULL_INSPECT; - } + for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + int inspect_tx_inprogress = 0; + int next_tx_no_progress = 0; + void *inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); + if (inspect_tx != NULL) { + int a = AppLayerParserGetStateProgress(f->proto, alproto, inspect_tx, flags); + int b = AppLayerParserGetStateProgressCompletionStatus(alproto, flags); + if (a < b) { + inspect_tx_inprogress = 1; } + SCLogDebug("tx %"PRIu64" (%"PRIu64") => %s", inspect_tx_id, total_txs, + inspect_tx_inprogress ? "in progress" : "done"); - if (item->flags & DE_STATE_FLAG_FULL_INSPECT) { - if (alproto_supports_txs) { - if ((total_txs - inspect_tx_id) <= 1) - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } else { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, alproto, inspect_tx); + if (tx_de_state == NULL) { + SCLogDebug("NO STATE tx %"PRIu64" (%"PRIu64")", inspect_tx_id, total_txs); continue; } - } - - if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { - if ((flags & STREAM_TOSERVER) && - (item->flags & DE_STATE_FLAG_FILE_TS_INSPECT) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TS_INSPECT; - item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; - } else if ((flags & STREAM_TOCLIENT) && - (item->flags & DE_STATE_FLAG_FILE_TC_INSPECT) && - (dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW)) - { - item->flags &= ~DE_STATE_FLAG_FILE_TC_INSPECT; - item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH; - } else { - if (alproto_supports_txs) { - if ((total_txs - inspect_tx_id) <= 1) - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } else { - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - } - continue; - } - } - - alert = 0; - inspect_flags = 0; - match = 0; - - RULE_PROFILING_START(p); - - if (alproto_supports_txs) { - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match, p); - goto end; - } - - if (alproto == ALPROTO_HTTP) { - htp_state = (HtpState *)alstate; - if (htp_state->conn == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match, p); - goto end; - } - } - - det_ctx->tx_id = inspect_tx_id; - det_ctx->tx_id_set = 1; - engine = app_inspection_engine[FlowGetProtoMapping(f->proto)][alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; - inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id); - if (inspect_tx == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match, p); - goto end; - } - while (engine != NULL) { - if (!(item->flags & engine->inspect_flags) && - s->sm_lists[engine->sm_list] != NULL) - { - KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list); - match = engine->Callback(tv, de_ctx, det_ctx, s, f, - flags, alstate, inspect_tx, inspect_tx_id); - if (match == 1) { - inspect_flags |= engine->inspect_flags; - engine = engine->next; - total_matches++; - continue; - } else if (match == 2) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - } else if (match == 3) { - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - inspect_flags |= engine->inspect_flags; - file_no_match++; + DetectEngineStateDirection *tx_dir_state = &tx_de_state->dir_state[direction]; + DeStateStore *tx_store = tx_dir_state->head; + + SCLogDebug("tx_dir_state->filestore_cnt %u", tx_dir_state->filestore_cnt); + + /* see if we need to consider the next tx in our decision to add + * a sig to the 'no inspect array'. */ + if (!TxIsLast(inspect_tx_id, total_txs)) { + void *next_inspect_tx = AppLayerParserGetTx(f->proto, alproto, alstate, inspect_tx_id+1); + if (next_inspect_tx != NULL) { + int c = AppLayerParserGetStateProgress(f->proto, alproto, next_inspect_tx, flags); + if (c == 0) { + next_tx_no_progress = 1; } - break; } - engine = engine->next; - } - if (total_matches > 0 && (engine == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { - if (engine == NULL) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; } - FLOWLOCK_UNLOCK(f); - } - - /* count AMATCH matches */ - total_matches = 0; - - KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_AMATCH); - if (item->nm != NULL) { - /* RDLOCK would be nicer, but at least tlsstore needs - * write lock currently. */ - FLOWLOCK_WRLOCK(f); - alstate = FlowGetAppState(f); - if (alstate == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, 0 /* no match */, p); - goto end; - } - - for (sm = item->nm; sm != NULL; sm = sm->next) { - if (sigmatch_table[sm->type].AppLayerMatch != NULL) + /* Loop through stored 'items' (stateful rules) and inspect them */ + state_cnt = 0; + for (; tx_store != NULL; tx_store = tx_store->next) { + SCLogDebug("tx_store %p", tx_store); + for (store_cnt = 0; + store_cnt < DE_STATE_CHUNK_SIZE && state_cnt < tx_dir_state->cnt; + store_cnt++, state_cnt++) { - if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) { - smb_state = (SMBState *)alstate; - if (smb_state->dcerpc_present) { - KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, &smb_state->dcerpc, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); - } - } else { - KEYWORD_PROFILING_START; - match = sigmatch_table[sm->type]. - AppLayerMatch(tv, det_ctx, f, flags, alstate, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, (match > 0)); + DeStateStoreItem *item = &tx_store->store[store_cnt]; + int r = DoInspectItem(tv, de_ctx, det_ctx, + item, tx_dir_state->flags, + p, f, alproto, flags, + inspect_tx_id, total_txs, + &file_no_match, inspect_tx_inprogress, next_tx_no_progress); + if (r < 0) { + SCLogDebug("failed"); + goto end; } - - if (match == 0) - break; - else if (match == 2) - inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH; - else if (match == 1) - total_matches++; } } - FLOWLOCK_UNLOCK(f); - } - RULE_PROFILING_END(det_ctx, s, match, p); - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { - if (total_matches > 0 && (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH)) { - if (sm == NULL) - alert = 1; - inspect_flags |= DE_STATE_FLAG_FULL_INSPECT; - } - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; + tx_dir_state->flags &= + ~(DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW|DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW); } - - item->flags |= inspect_flags; - item->nm = sm; - if ((total_txs - inspect_tx_id) <= 1) - det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NO_NEW_STATE; - - if (alert) { - SigMatchSignaturesRunPostMatch(tv, de_ctx, det_ctx, p, s); - - if (!(s->flags & SIG_FLAG_NOALERT)) { - if (alproto_supports_txs) - PacketAlertAppend(det_ctx, s, p, inspect_tx_id, - PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX); - else - PacketAlertAppend(det_ctx, s, p, 0, - PACKET_ALERT_FLAG_STATE_MATCH); - } else { - PACKET_UPDATE_ACTION(p, s->action); - } + /* if the current tx is in progress, we won't advance to any newer + * tx' just yet. */ + if (inspect_tx_inprogress) { + SCLogDebug("break out"); + break; } - - DetectFlowvarProcessList(det_ctx, f); - } - } - - DeStateStoreStateVersion(f->de_state, alversion, flags); - DeStateStoreFileNoMatchCnt(f->de_state, file_no_match, flags); - - if (!(dir_state->flags & DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED)) { - if (DeStateStoreFilestoreSigsCantMatch(det_ctx->sgh, f->de_state, flags) == 1) { - SCLogDebug("disabling file storage for transaction"); - - FLOWLOCK_WRLOCK(f); - FileDisableStoringForTransaction(f, flags & (STREAM_TOCLIENT|STREAM_TOSERVER), - det_ctx->tx_id); - FLOWLOCK_UNLOCK(f); - - dir_state->flags |= DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED; } } end: - if (f->de_state != NULL) - dir_state->flags &= ~DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW; - - if (reset_de_state) - DetectEngineStateReset(f->de_state, flags); - - SCMutexUnlock(&f->de_state_m); det_ctx->tx_id = 0; det_ctx->tx_id_set = 0; return; } - /** \brief update flow's inspection id's + * + * \param f unlocked flow + * \param flags direction and disruption flags * * \note it is possible that f->alstate, f->alparser are NULL */ -void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction) +void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags) { - FLOWLOCK_WRLOCK(f); if (f->alparser && f->alstate) { - AppLayerParserSetTransactionInspectId(f->alparser, f->proto, f->alproto, f->alstate, direction); + AppLayerParserSetTransactionInspectId(f->alparser, f->proto, + f->alproto, f->alstate, flags); } - FLOWLOCK_UNLOCK(f); - return; } - -void DetectEngineStateReset(DetectEngineState *state, uint8_t direction) +/** \brief Reset de state for active tx' + * To be used on detect engine reload. + * \param f write LOCKED flow + */ +void DetectEngineStateResetTxs(Flow *f) { - if (state != NULL) { - if (direction & STREAM_TOSERVER) { - state->dir_state[0].cnt = 0; - state->dir_state[0].filestore_cnt = 0; - state->dir_state[0].flags = 0; - } - if (direction & STREAM_TOCLIENT) { - state->dir_state[1].cnt = 0; - state->dir_state[1].filestore_cnt = 0; - state->dir_state[1].flags = 0; + if (AppLayerParserProtocolSupportsTxs(f->proto, f->alproto)) { + void *alstate = FlowGetAppState(f); + if (!StateIsValid(f->alproto, alstate)) { + return; } - } - return; -} + uint64_t inspect_ts = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOCLIENT); + uint64_t inspect_tc = AppLayerParserGetTransactionInspectId(f->alparser, STREAM_TOSERVER); -/** \brief get string for match enum */ -const char *DeStateMatchResultToString(DeStateMatchResult res) -{ - switch (res) { - CASE_CODE (DE_STATE_MATCH_NO_NEW_STATE); - CASE_CODE (DE_STATE_MATCH_HAS_NEW_STATE); - } + uint64_t inspect_tx_id = MIN(inspect_ts, inspect_tc); - return NULL; + uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, alstate); + + for ( ; inspect_tx_id < total_txs; inspect_tx_id++) { + void *inspect_tx = AppLayerParserGetTx(f->proto, f->alproto, alstate, inspect_tx_id); + if (inspect_tx != NULL) { + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(f->proto, f->alproto, inspect_tx); + if (tx_de_state == NULL) { + continue; + } + + tx_de_state->dir_state[0].cnt = 0; + tx_de_state->dir_state[0].filestore_cnt = 0; + tx_de_state->dir_state[0].flags = 0; + + tx_de_state->dir_state[1].cnt = 0; + tx_de_state->dir_state[1].filestore_cnt = 0; + tx_de_state->dir_state[1].flags = 0; + } + } + } } /*********Unittests*********/ #ifdef UNITTESTS -#include "flow-util.h" static int DeStateTest01(void) { @@ -850,39 +893,39 @@ static int DeStateTest02(void) uint8_t direction = STREAM_TOSERVER; s.num = 0; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 11; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 22; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 33; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 44; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 55; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 66; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 77; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 88; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 99; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 100; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 111; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 122; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 133; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 144; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 155; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 166; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL) { goto end; @@ -918,13 +961,8 @@ static int DeStateTest02(void) static int DeStateTest03(void) { - int result = 0; - DetectEngineState *state = DetectEngineStateAlloc(); - if (state == NULL) { - printf("d == NULL: "); - goto end; - } + FAIL_IF_NULL(state); Signature s; memset(&s, 0x00, sizeof(s)); @@ -932,36 +970,22 @@ static int DeStateTest03(void) uint8_t direction = STREAM_TOSERVER; s.num = 11; - DeStateSignatureAppend(state, &s, NULL, 0, direction); + DeStateSignatureAppend(state, &s, 0, direction); s.num = 22; - DeStateSignatureAppend(state, &s, NULL, DE_STATE_FLAG_URI_INSPECT, direction); + DeStateSignatureAppend(state, &s, BIT_U32(DE_STATE_FLAG_BASE), direction); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head == NULL); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].sid != 11); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & DE_STATE_FLAG_URI_INSPECT) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[0].flags & BIT_U32(DE_STATE_FLAG_BASE)); - if (state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22) { - goto end; - } + FAIL_IF(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].sid != 22); - if (!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & DE_STATE_FLAG_URI_INSPECT)) { - goto end; - } + FAIL_IF(!(state->dir_state[direction & STREAM_TOSERVER ? 0 : 1].head->store[1].flags & BIT_U32(DE_STATE_FLAG_BASE))); - result = 1; -end: - if (state != NULL) { - DetectEngineStateFree(state); - } - return result; + DetectEngineStateFree(state); + PASS; } static int DeStateSigTest01(void) @@ -1019,14 +1043,15 @@ static int DeStateSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1035,14 +1060,15 @@ static int DeStateSigTest01(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1051,14 +1077,15 @@ static int DeStateSigTest01(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (!(PacketAlertCheck(p, 1))) { @@ -1067,15 +1094,16 @@ static int DeStateSigTest01(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1108,7 +1136,6 @@ static int DeStateSigTest01(void) /** \test multiple pipelined http transactions */ static int DeStateSigTest02(void) { - int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; @@ -1151,157 +1178,111 @@ static int DeStateSigTest02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"/\"; http_uri; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"body\"; nocase; http_client_body; sid:1; rev:1;)"); + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; sid:2; rev:1;)"); - if (s == NULL) { - printf("sig2 parse failed: "); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (2): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + void *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, f.alstate, 0); + FAIL_IF_NULL(tx); + + DetectEngineState *tx_de_state = AppLayerParserGetTxDetectState(IPPROTO_TCP, ALPROTO_HTTP, tx); + FAIL_IF_NULL(tx_de_state); + FAIL_IF(tx_de_state->dir_state[0].cnt != 1); + FAIL_IF(tx_de_state->dir_state[0].head->store[0].flags != BIT_U32(DE_STATE_FLAG_BASE)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("signature matched, but shouldn't have: "); - goto end; - } - p->alerts.cnt = 0; + FAIL_IF(!(PacketAlertCheck(p, 1))); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (5): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { - printf("sig 1 alerted (request 2, chunk 6): "); - goto end; - } + FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 2))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - } - + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } static int DeStateSigTest03(void) @@ -1320,7 +1301,6 @@ static int DeStateSigTest03(void) uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ ThreadVars th_v; TcpSession ssn; - int result = 0; Flow *f = NULL; Packet *p = NULL; HtpState *http_state = NULL; @@ -1331,31 +1311,24 @@ static int DeStateSigTest03(void) DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"POST\"; http_method; content:\"upload.cgi\"; http_uri; filestore; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80); - if (f == NULL) - goto end; + FAIL_IF_NULL(f); f->protoctx = &ssn; f->proto = IPPROTO_TCP; f->alproto = ALPROTO_HTTP; p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); - if (p == NULL) - goto end; + FAIL_IF_NULL(p); p->flow = f; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; @@ -1364,71 +1337,41 @@ static int DeStateSigTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f->m); - goto end; - } - SCMutexUnlock(&f->m); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); + FLOWLOCK_UNLOCK(f); - /* do detect */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(r != 0); http_state = f->alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF_NULL(http_state); + FAIL_IF_NULL(http_state->files_ts); - if (http_state->files_ts == NULL) { - printf("no files in state: "); - goto end; - } + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!(PacketAlertCheck(p, 1))); - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); - if (files == NULL) { - printf("no stored files: "); - SCMutexUnlock(&f->m); - goto end; - } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); + FAIL_IF_NULL(files); File *file = files->head; - if (file == NULL) { - printf("no file: "); - goto end; - } + FAIL_IF_NULL(file); - if (!(file->flags & FILE_STORE)) { - printf("file is set to store, but sig didn't match: "); - goto end; - } + FAIL_IF(!(file->flags & FILE_STORE)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); UTHFreeFlow(f); - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); - } + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); - return result; + PASS; } static int DeStateSigTest04(void) @@ -1491,15 +1434,18 @@ static int DeStateSigTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1520,15 +1466,15 @@ static int DeStateSigTest04(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -1618,15 +1564,18 @@ static int DeStateSigTest05(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1647,15 +1596,15 @@ static int DeStateSigTest05(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -1745,15 +1694,18 @@ static int DeStateSigTest06(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1774,15 +1726,15 @@ static int DeStateSigTest06(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -1875,15 +1827,17 @@ static int DeStateSigTest07(void) StreamTcpInitConfig(TRUE); SCLogDebug("\n>>>> processing chunk 1 <<<<\n"); - SCMutexLock(&f->m); - int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(f); + int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1893,15 +1847,16 @@ static int DeStateSigTest07(void) } SCLogDebug("\n>>>> processing chunk 2 size %u <<<<\n", httplen2); - SCMutexLock(&f->m); - r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_EOF, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(f); + r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_EOF, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { @@ -1921,15 +1876,15 @@ static int DeStateSigTest07(void) goto end; } - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); FileContainer *files = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, STREAM_TOSERVER); if (files == NULL) { printf("no stored files: "); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); goto end; } - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); File *file = files->head; if (file == NULL) { @@ -1964,16 +1919,16 @@ static int DeStateSigTest07(void) void DeStateRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DeStateTest01", DeStateTest01, 1); - UtRegisterTest("DeStateTest02", DeStateTest02, 1); - UtRegisterTest("DeStateTest03", DeStateTest03, 1); - UtRegisterTest("DeStateSigTest01", DeStateSigTest01, 1); - UtRegisterTest("DeStateSigTest02", DeStateSigTest02, 1); - UtRegisterTest("DeStateSigTest03", DeStateSigTest03, 1); - UtRegisterTest("DeStateSigTest04", DeStateSigTest04, 1); - UtRegisterTest("DeStateSigTest05", DeStateSigTest05, 1); - UtRegisterTest("DeStateSigTest06", DeStateSigTest06, 1); - UtRegisterTest("DeStateSigTest07", DeStateSigTest07, 1); + UtRegisterTest("DeStateTest01", DeStateTest01); + UtRegisterTest("DeStateTest02", DeStateTest02); + UtRegisterTest("DeStateTest03", DeStateTest03); + UtRegisterTest("DeStateSigTest01", DeStateSigTest01); + UtRegisterTest("DeStateSigTest02", DeStateSigTest02); + UtRegisterTest("DeStateSigTest03", DeStateSigTest03); + UtRegisterTest("DeStateSigTest04", DeStateSigTest04); + UtRegisterTest("DeStateSigTest05", DeStateSigTest05); + UtRegisterTest("DeStateSigTest06", DeStateSigTest06); + UtRegisterTest("DeStateSigTest07", DeStateSigTest07); #endif return; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index cd3e63ea4c35..224160caf92c 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -31,19 +31,6 @@ * \author Anoop Saldanha */ -/* On DeState and locking. - * - * The DeState is part of a flow, but it can't be protected by the flow lock. - * Reason is we need to lock the DeState data for an entire detection run, - * as we're looping through on "continued" detection and rely on only a single - * detection instance setting it up on first run. We can't keep the entire flow - * locked during detection for performance reasons, it would slow us down too - * much. - * - * So a new lock was introduced. The only part of the process where we need - * the flow lock is obviously when we're getting/setting the de_state ptr from - * to the flow. - */ #ifndef __DETECT_ENGINE_STATE_H__ #define __DETECT_ENGINE_STATE_H__ @@ -52,35 +39,33 @@ #define DETECT_ENGINE_INSPECT_SIG_MATCH 1 #define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH 2 #define DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE 3 +/** hack to work around a file inspection limitation. Since there can be + * multiple files in a TX and the detection engine really don't know + * about that, we have to give the file inspection engine a way to + * indicate that one of the files matched, but that there are still + * more files that have ongoing inspection. */ +#define DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES 4 /** number of DeStateStoreItem's in one DeStateStore object */ #define DE_STATE_CHUNK_SIZE 15 /* per sig flags */ -#define DE_STATE_FLAG_URI_INSPECT (1) -#define DE_STATE_FLAG_HRUD_INSPECT (1 << 1) -#define DE_STATE_FLAG_HCBD_INSPECT (1 << 2) -#define DE_STATE_FLAG_HSBD_INSPECT (1 << 3) -#define DE_STATE_FLAG_HHD_INSPECT (1 << 4) -#define DE_STATE_FLAG_HRHD_INSPECT (1 << 5) -#define DE_STATE_FLAG_HHHD_INSPECT (1 << 6) -#define DE_STATE_FLAG_HRHHD_INSPECT (1 << 7) -#define DE_STATE_FLAG_HUAD_INSPECT (1 << 8) -#define DE_STATE_FLAG_HMD_INSPECT (1 << 9) -#define DE_STATE_FLAG_HCD_INSPECT (1 << 10) -#define DE_STATE_FLAG_HSMD_INSPECT (1 << 11) -#define DE_STATE_FLAG_HSCD_INSPECT (1 << 12) -#define DE_STATE_FLAG_FILE_TC_INSPECT (1 << 13) -#define DE_STATE_FLAG_FILE_TS_INSPECT (1 << 14) -#define DE_STATE_FLAG_FULL_INSPECT (1 << 15) -#define DE_STATE_FLAG_SIG_CANT_MATCH (1 << 16) -#define DE_STATE_FLAG_DNSQUERY_INSPECT (1 << 17) -#define DE_STATE_FLAG_APP_EVENT_INSPECT (1 << 18) - -/* state flags */ -#define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 -#define DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW 0x0002 -#define DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW 0x0004 +#define DE_STATE_FLAG_FULL_INSPECT BIT_U32(0) +#define DE_STATE_FLAG_SIG_CANT_MATCH BIT_U32(1) + +#define DE_STATE_FLAG_FILE_TC_INSPECT BIT_U32(2) +#define DE_STATE_FLAG_FILE_TS_INSPECT BIT_U32(3) + +/* first bit position after the built-ins */ +#define DE_STATE_FLAG_BASE 4UL + +/* state flags + * + * Used by app-layer-parsers to notify us that new files + * are available in the tx. + */ +#define DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW BIT_U8(0) +#define DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW BIT_U8(1) /* We have 2 possible state values to be used by ContinueDetection() while * trying to figure if we have fresh state to install or not. @@ -97,13 +82,10 @@ * the HAS_NEW_STATE flag, while if we don't have a new tx, we set * NO_NEW_STATE, to avoid getting the sig reinspected for the already * inspected tx. */ -typedef enum { - DE_STATE_MATCH_HAS_NEW_STATE = 0, - DE_STATE_MATCH_NO_NEW_STATE, -} DeStateMatchResult; +#define DE_STATE_MATCH_HAS_NEW_STATE 0x00 +#define DE_STATE_MATCH_NO_NEW_STATE 0x80 typedef struct DeStateStoreItem_ { - SigMatch *nm; uint32_t flags; SigIntId sid; } DeStateStoreItem; @@ -118,7 +100,6 @@ typedef struct DetectEngineStateDirection_ { DeStateStore *tail; SigIntId cnt; uint16_t filestore_cnt; - uint8_t alversion; uint8_t flags; } DetectEngineStateDirection; @@ -144,13 +125,12 @@ void DetectEngineStateFree(DetectEngineState *state); * \brief Check if a flow already contains(newly updated as well) de state. * * \param f Pointer to the flow. - * \param alversino The alversion to check against de_state's. - * \param direction Direction to check. 0 - ts, 1 - tc. + * \param flags direction * * \retval 1 Has state. * \retval 0 Has no state. */ -int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion, uint8_t flags); +int DeStateFlowHasInspectableState(const Flow *f, const uint8_t flags); /** * \brief Match app layer sig list against app state and store relevant match @@ -163,14 +143,13 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion * \param f Pointer to the flow. * \param flags Flags. * \param alproto App protocol. - * \param alversion Current app layer version. * * \retval >= 0 An integer value indicating the no of matches. */ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *s, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion); + const Signature *s, Packet *p, Flow *f, + uint8_t flags, AppProto alproto); /** * \brief Continue DeState detection of the signatures stored in the state. @@ -181,28 +160,21 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, * \param f Pointer to the flow. * \param flags Flags. * \param alproto App protocol. - * \param alversion Current app layer version. */ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, Flow *f, uint8_t flags, - AppProto alproto, uint16_t alversion); + AppProto alproto); /** * \brief Update the inspect id. * - * \param f Flow(unlocked). - * \param direction 0 for to server, 1 for toclient. + * \param f unlocked flow + * \param flags direction and disruption flags */ -void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction); +void DeStateUpdateInspectTransactionId(Flow *f, const uint8_t flags); -/** - * \brief Reset a DetectEngineState state. - * - * \param state Pointer to the state(LOCKED). - * \param direction Direction flags - STREAM_TOSERVER or STREAM_TOCLIENT. - */ -void DetectEngineStateReset(DetectEngineState *state, uint8_t direction); +void DetectEngineStateResetTxs(Flow *f); void DeStateRegisterTests(void); diff --git a/src/detect-engine-tag.c b/src/detect-engine-tag.c index 7c8caabba082..3716d982e19a 100644 --- a/src/detect-engine-tag.c +++ b/src/detect-engine-tag.c @@ -132,7 +132,6 @@ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) if (p->flow == NULL) return 1; - FLOWLOCK_WRLOCK(p->flow); iter = FlowGetStorageById(p->flow, flow_tag_id); if (iter != NULL) { /* First iterate installed entries searching a duplicated sid/gid */ @@ -169,7 +168,6 @@ int TagFlowAdd(Packet *p, DetectTagDataEntry *tde) SCLogDebug("Max tags for sessions reached (%"PRIu16")", tag_cnt); } - FLOWLOCK_UNLOCK(p->flow); return updated; } @@ -516,9 +514,7 @@ void TagHandlePacket(DetectEngineCtx *de_ctx, /* First update and get session tags */ if (p->flow != NULL) { - FLOWLOCK_WRLOCK(p->flow); TagHandlePacketFlow(p->flow, p); - FLOWLOCK_UNLOCK(p->flow); } Host *src = HostLookupHostFromHash(&p->src); @@ -1507,13 +1503,13 @@ static int DetectTagTestPacket07 (void) void DetectEngineTagRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTagTestPacket01", DetectTagTestPacket01, 1); - UtRegisterTest("DetectTagTestPacket02", DetectTagTestPacket02, 1); - UtRegisterTest("DetectTagTestPacket03", DetectTagTestPacket03, 1); - UtRegisterTest("DetectTagTestPacket04", DetectTagTestPacket04, 1); - UtRegisterTest("DetectTagTestPacket05", DetectTagTestPacket05, 1); - UtRegisterTest("DetectTagTestPacket06", DetectTagTestPacket06, 1); - UtRegisterTest("DetectTagTestPacket07", DetectTagTestPacket07, 1); + UtRegisterTest("DetectTagTestPacket01", DetectTagTestPacket01); + UtRegisterTest("DetectTagTestPacket02", DetectTagTestPacket02); + UtRegisterTest("DetectTagTestPacket03", DetectTagTestPacket03); + UtRegisterTest("DetectTagTestPacket04", DetectTagTestPacket04); + UtRegisterTest("DetectTagTestPacket05", DetectTagTestPacket05); + UtRegisterTest("DetectTagTestPacket06", DetectTagTestPacket06); + UtRegisterTest("DetectTagTestPacket07", DetectTagTestPacket07); #endif /* UNITTESTS */ } diff --git a/src/detect-engine-template.c b/src/detect-engine-template.c new file mode 100644 index 000000000000..c7d751a15154 --- /dev/null +++ b/src/detect-engine-template.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * TODO: Update your name below and in detect-engine-template.h. + * TODO: Update description in the \file section below. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Implement buffer inspection on the decoded application layer + * content buffers. + */ + +#include "suricata-common.h" +#include "stream.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer-template.h" + +int DetectEngineInspectTemplateBuffer(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + TemplateTransaction *tx = (TemplateTransaction *)txv; + int ret = 0; + + if (flags & STREAM_TOSERVER && tx->request_buffer != NULL) { + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, tx->request_buffer, tx->request_buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + } + else if (flags & STREAM_TOCLIENT && tx->response_buffer != NULL) { + ret = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, tx->response_buffer, tx->response_buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + } + + SCLogNotice("Returning %d.", ret); + return ret; +} diff --git a/src/detect-engine-template.h b/src/detect-engine-template.h new file mode 100644 index 000000000000..fb836f0702cb --- /dev/null +++ b/src/detect-engine-template.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author FirstName LastName + */ + +#ifndef __DETECT_TEMPLATE_ENGINE_H__ +#define __DETECT_TEMPLATE_ENGINE_H__ + +int DetectEngineInspectTemplateBuffer(ThreadVars *, + DetectEngineCtx *, DetectEngineThreadCtx *, + const Signature *, const SigMatchData *, + Flow *, uint8_t, void *, void *tx, uint64_t tx_id); + +#endif /* __DETECT_TEMPLATE_ENGINE_H__ */ diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 1ebc3e404384..27e84d8e9065 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2015 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -98,35 +98,45 @@ int ThresholdHostHasThreshold(Host *host) * * */ -DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch **psm, int list) +const DetectThresholdData *SigGetThresholdTypeIter(const Signature *sig, + Packet *p, const SigMatchData **psm, int list) { - SigMatch *sm = NULL; - DetectThresholdData *tsh = NULL; + const SigMatchData *smd = NULL; + const DetectThresholdData *tsh = NULL; if (sig == NULL) return NULL; if (*psm == NULL) { - sm = sig->sm_lists_tail[list]; + smd = sig->sm_arrays[list]; } else { /* Iteration in progress, using provided value */ - sm = *psm; + smd = *psm; } if (p == NULL) return NULL; - while (sm != NULL) { - if (sm->type == DETECT_THRESHOLD || sm->type == DETECT_DETECTION_FILTER) { - tsh = (DetectThresholdData *)sm->ctx; - *psm = sm->prev; + while (1) { + if (smd->type == DETECT_THRESHOLD || + smd->type == DETECT_DETECTION_FILTER) + { + tsh = (DetectThresholdData *)smd->ctx; + + if (smd->is_last) { + *psm = NULL; + } else { + *psm = smd + 1; + } return tsh; } - sm = sm->prev; + if (smd->is_last) { + break; + } + smd++; } *psm = NULL; - return NULL; } @@ -178,7 +188,9 @@ int ThresholdTimeoutCheck(Host *host, struct timeval *tv) return retval; } -static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) +static inline DetectThresholdEntry * +DetectThresholdEntryAlloc(const DetectThresholdData *td, Packet *p, + uint32_t sid, uint32_t gid) { SCEnter(); @@ -209,12 +221,73 @@ static DetectThresholdEntry *ThresholdHostLookupEntry(Host *h, uint32_t sid, uin return e; } +int ThresholdHandlePacketSuppress(Packet *p, const DetectThresholdData *td, uint32_t sid, uint32_t gid) +{ + int ret = 0; + DetectAddress *m = NULL; + switch (td->track) { + case TRACK_DST: + m = DetectAddressLookupInHead(&td->addrs, &p->dst); + SCLogDebug("TRACK_DST"); + break; + case TRACK_SRC: + m = DetectAddressLookupInHead(&td->addrs, &p->src); + SCLogDebug("TRACK_SRC"); + break; + /* suppress if either src or dst is a match on the suppress + * address list */ + case TRACK_EITHER: + m = DetectAddressLookupInHead(&td->addrs, &p->src); + if (m == NULL) { + m = DetectAddressLookupInHead(&td->addrs, &p->dst); + } + break; + case TRACK_RULE: + default: + SCLogError(SC_ERR_INVALID_VALUE, + "track mode %d is not supported", td->track); + break; + } + if (m == NULL) + ret = 1; + else + ret = 2; /* suppressed but still need actions */ + + return ret; +} + +static inline void RateFilterSetAction(Packet *p, PacketAlert *pa, uint8_t new_action) +{ + switch (new_action) { + case TH_ACTION_ALERT: + PACKET_ALERT(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + case TH_ACTION_DROP: + PACKET_DROP(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + case TH_ACTION_REJECT: + PACKET_REJECT(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + case TH_ACTION_PASS: + PACKET_PASS(p); + pa->flags |= PACKET_ALERT_RATE_FILTER_MODIFIED; + break; + default: + /* Weird, leave the default action */ + break; + } +} + /** * \retval 2 silent match (no alert but apply actions) * \retval 1 normal match * \retval 0 no match */ -int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) +int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdData *td, + uint32_t sid, uint32_t gid, PacketAlert *pa) { int ret = 0; @@ -391,23 +464,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 } else { /* Already matching */ /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */ @@ -420,23 +477,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } } else { @@ -463,28 +504,7 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 } break; } - case TYPE_SUPPRESS: - { - int res = 0; - switch (td->track) { - case TRACK_DST: - res = DetectAddressMatch(td->addr, &p->dst); - break; - case TRACK_SRC: - res = DetectAddressMatch(td->addr, &p->src); - break; - case TRACK_RULE: - default: - SCLogError(SC_ERR_INVALID_VALUE, - "track mode %d is not supported", td->track); - break; - } - if (res == 0) - ret = 1; - else - ret = 2; /* suppressed but still need actions */ - break; - } + /* case TYPE_SUPPRESS: is not handled here */ default: SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type); } @@ -492,7 +512,8 @@ int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint3 return ret; } -static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectThresholdData *td, Signature *s) +static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, + const DetectThresholdData *td, const Signature *s, PacketAlert *pa) { int ret = 0; @@ -505,27 +526,11 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectT * we still matching (and enabling the new_action) */ if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { /* Ok, we are done, timeout reached */ - td->timeout = 0; + lookup_tsh->tv_timeout = 0; } else { /* Already matching */ /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } @@ -537,23 +542,7 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectT * timeout */ lookup_tsh->tv_timeout = p->ts.tv_sec; /* Take the action to perform */ - switch (td->new_action) { - case TH_ACTION_ALERT: - PACKET_ALERT(p); - break; - case TH_ACTION_DROP: - PACKET_DROP(p); - break; - case TH_ACTION_REJECT: - PACKET_REJECT(p); - break; - case TH_ACTION_PASS: - PACKET_PASS(p); - break; - default: - /* Weird, leave the default action */ - break; - } + RateFilterSetAction(p, pa, td->new_action); ret = 1; } } else { @@ -591,7 +580,7 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p, DetectT * \retval 0 do not alert on this event */ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - DetectThresholdData *td, Packet *p, Signature *s) + const DetectThresholdData *td, Packet *p, const Signature *s, PacketAlert *pa) { SCEnter(); @@ -600,21 +589,23 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx SCReturnInt(0); } - if (td->track == TRACK_SRC) { + if (td->type == TYPE_SUPPRESS) { + ret = ThresholdHandlePacketSuppress(p,td,s->id,s->gid); + } else if (td->track == TRACK_SRC) { Host *src = HostGetHostFromHash(&p->src); if (src) { - ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid); + ret = ThresholdHandlePacketHost(src,p,td,s->id,s->gid,pa); HostRelease(src); } } else if (td->track == TRACK_DST) { Host *dst = HostGetHostFromHash(&p->dst); if (dst) { - ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid); + ret = ThresholdHandlePacketHost(dst,p,td,s->id,s->gid,pa); HostRelease(dst); } } else if (td->track == TRACK_RULE) { SCMutexLock(&de_ctx->ths_ctx.threshold_table_lock); - ret = ThresholdHandlePacketRule(de_ctx,p,td,s); + ret = ThresholdHandlePacketRule(de_ctx,p,td,s,pa); SCMutexUnlock(&de_ctx->ths_ctx.threshold_table_lock); } diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index b874ecb2fa15..76a0759d3549 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -33,9 +33,11 @@ void ThresholdInit(void); int ThresholdHostStorageId(void); int ThresholdHostHasThreshold(Host *); -DetectThresholdData *SigGetThresholdTypeIter(Signature *, Packet *, SigMatch **, int list); +const DetectThresholdData *SigGetThresholdTypeIter(const Signature *, + Packet *, const SigMatchData **, int list); int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, - DetectThresholdData *, Packet *, Signature *); + const DetectThresholdData *, Packet *, + const Signature *, PacketAlert *); void ThresholdHashInit(DetectEngineCtx *); void ThresholdContextDestroy(DetectEngineCtx *); diff --git a/src/detect-engine-tls.c b/src/detect-engine-tls.c new file mode 100644 index 000000000000..4912da776cee --- /dev/null +++ b/src/detect-engine-tls.c @@ -0,0 +1,358 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-protos.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-validate.h" + +/** \brief TLS SNI Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxTlsSni(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->client_connp.sni == NULL) + return; + + const uint8_t *buffer = (uint8_t *)ssl_state->client_connp.sni; + const uint32_t buffer_len = strlen(ssl_state->client_connp.sni); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSni, + ALPROTO_TLS, 0, // TODO a special 'cert ready' state might be good to add + mpm_ctx, NULL, "tls_sni"); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsSni(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint8_t *buffer; + uint16_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->client_connp.sni == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->client_connp.sni; + buffer_len = strlen(ssl_state->client_connp.sni); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + + return cnt; +} + +/** \brief TLS Issuer Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxTlsIssuer(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->server_connp.cert0_issuerdn == NULL) + return; + + const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_issuerdn; + const uint32_t buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsIssuer, + ALPROTO_TLS, TLS_STATE_CERT_READY, + mpm_ctx, NULL, "tls_cert_issuer"); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsIssuer(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint8_t *buffer; + uint32_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->server_connp.cert0_issuerdn == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_issuerdn; + buffer_len = strlen(ssl_state->server_connp.cert0_issuerdn); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + + return cnt; +} + +/** \brief TLS Subject Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxTlsSubject(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->server_connp.cert0_subject == NULL) + return; + + const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_subject; + const uint32_t buffer_len = strlen(ssl_state->server_connp.cert0_subject); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSubject, + ALPROTO_TLS, TLS_STATE_CERT_READY, + mpm_ctx, NULL, "tls_cert_subject"); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsSubject(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + uint8_t *buffer; + uint32_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->server_connp.cert0_subject == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_subject; + buffer_len = strlen(ssl_state->server_connp.cert0_subject); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + + return cnt; +} + +/** \brief TLS Serial Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxTlsSerial(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, const uint64_t idx, + const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + SSLState *ssl_state = f->alstate; + + if (ssl_state->server_connp.cert0_serial == NULL) + return; + + const uint8_t *buffer = (const uint8_t *)ssl_state->server_connp.cert0_serial; + const uint32_t buffer_len = strlen(ssl_state->server_connp.cert0_serial); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, &det_ctx->mtcu, + &det_ctx->pmq, buffer, buffer_len); + } +} + +int PrefilterTxTlsSerialRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxTlsSerial, ALPROTO_TLS, + TLS_STATE_CERT_READY, mpm_ctx, NULL, + "tls_cert_serial"); +} + +/** \brief Do the content inspection and validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags App layer flags + * \param state App layer state + * + * \retval 0 No match + * \retval 1 Match + */ +int DetectEngineInspectTlsSerial(ThreadVars *tv, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Signature *s, + const SigMatchData *smd, Flow *f, + uint8_t flags, void *alstate, void *txv, + uint64_t tx_id) +{ + uint8_t *buffer; + uint32_t buffer_len; + int cnt = 0; + + SSLState *ssl_state = (SSLState *)alstate; + + if (ssl_state->server_connp.cert0_serial == NULL) + return 0; + + buffer = (uint8_t *)ssl_state->server_connp.cert0_serial; + buffer_len = strlen(ssl_state->server_connp.cert0_serial); + + cnt = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + + return cnt; +} + +int DetectEngineInspectTlsValidity(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} diff --git a/src/detect-engine-tls.h b/src/detect-engine-tls.h new file mode 100644 index 000000000000..4415ad76af20 --- /dev/null +++ b/src/detect-engine-tls.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_ENGINE_TLS_H__ +#define __DETECT_ENGINE_TLS_H__ + +int PrefilterTxTlsSniRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxTlsIssuerRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxTlsSubjectRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +int PrefilterTxTlsSerialRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + +int DetectEngineInspectTlsSni(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsIssuer(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsSubject(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsSerial(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id); + +int DetectEngineInspectTlsValidity(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +#endif /* __DETECT_ENGINE_TLS_H__ */ diff --git a/src/detect-engine-uri.c b/src/detect-engine-uri.c index e0df1e0b9e9d..084f9dde3165 100644 --- a/src/detect-engine-uri.c +++ b/src/detect-engine-uri.c @@ -32,6 +32,7 @@ #include "detect-parse.h" #include "detect-engine-state.h" #include "detect-engine-content-inspection.h" +#include "detect-engine-prefilter.h" #include "flow-util.h" #include "util-debug.h" @@ -47,6 +48,46 @@ #include "app-layer.h" #include "app-layer-htp.h" #include "app-layer-protos.h" +#include "util-validate.h" + +/** \brief HTTP URI Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxUri(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); + + if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) + return; + + const uint32_t uri_len = bstr_len(tx_ud->request_uri_normalized); + const uint8_t *uri = bstr_ptr(tx_ud->request_uri_normalized); + + if (uri_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, uri, uri_len); + } +} + +int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxUri, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, "http_uri"); +} /** * \brief Do the content inspection & validation for a signature @@ -63,17 +104,15 @@ * \retval 1 match. * \retval 2 Sig can't match. */ -int DetectEngineInspectPacketUris(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *txv, uint64_t tx_id) +int DetectEngineInspectHttpUri(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) { HtpTxUserData *tx_ud = htp_tx_get_user_data(txv); if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) { - if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_LINE) + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE) return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; else return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; @@ -90,12 +129,12 @@ int DetectEngineInspectPacketUris(ThreadVars *tv, /* Inspect all the uricontents fetched on each * transaction at the app layer */ - int r = DetectEngineContentInspection(de_ctx, det_ctx, s, s->sm_lists[DETECT_SM_LIST_UMATCH], + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, f, bstr_ptr(tx_ud->request_uri_normalized), bstr_len(tx_ud->request_uri_normalized), 0, - DETECT_ENGINE_CONTENT_INSPECTION_MODE_URI, NULL); + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); if (r == 1) { return DETECT_ENGINE_INSPECT_SIG_MATCH; } else { @@ -150,7 +189,6 @@ static int UriTestSig01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -163,14 +201,15 @@ static int UriTestSig01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -186,16 +225,15 @@ static int UriTestSig01(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -273,7 +311,6 @@ static int UriTestSig02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -286,14 +323,15 @@ static int UriTestSig02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -309,16 +347,15 @@ static int UriTestSig02(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -396,7 +433,6 @@ static int UriTestSig03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -409,14 +445,15 @@ static int UriTestSig03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -432,16 +469,15 @@ static int UriTestSig03(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -519,7 +555,6 @@ static int UriTestSig04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -532,14 +567,15 @@ static int UriTestSig04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -555,16 +591,15 @@ static int UriTestSig04(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -642,7 +677,6 @@ static int UriTestSig05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -655,14 +689,15 @@ static int UriTestSig05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -678,16 +713,15 @@ static int UriTestSig05(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -765,7 +799,6 @@ static int UriTestSig06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -778,14 +811,15 @@ static int UriTestSig06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -801,16 +835,15 @@ static int UriTestSig06(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -888,7 +921,6 @@ static int UriTestSig07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -901,14 +933,15 @@ static int UriTestSig07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -924,16 +957,15 @@ static int UriTestSig07(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1011,7 +1043,6 @@ static int UriTestSig08(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1024,14 +1055,15 @@ static int UriTestSig08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1047,16 +1079,15 @@ static int UriTestSig08(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1134,7 +1165,6 @@ static int UriTestSig09(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1147,14 +1177,15 @@ static int UriTestSig09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1170,16 +1201,15 @@ static int UriTestSig09(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1257,7 +1287,6 @@ static int UriTestSig10(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1270,14 +1299,15 @@ static int UriTestSig10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1293,16 +1323,15 @@ static int UriTestSig10(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1380,7 +1409,6 @@ static int UriTestSig11(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1394,14 +1422,15 @@ static int UriTestSig11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1417,16 +1446,15 @@ static int UriTestSig11(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1504,7 +1532,6 @@ static int UriTestSig12(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1518,14 +1545,15 @@ static int UriTestSig12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1541,16 +1569,15 @@ static int UriTestSig12(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1628,7 +1655,6 @@ static int UriTestSig13(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1641,14 +1667,15 @@ static int UriTestSig13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1664,16 +1691,15 @@ static int UriTestSig13(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1752,7 +1778,6 @@ static int UriTestSig14(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1765,14 +1790,15 @@ static int UriTestSig14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1788,16 +1814,15 @@ static int UriTestSig14(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1876,7 +1901,6 @@ static int UriTestSig15(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1889,14 +1913,15 @@ static int UriTestSig15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1912,16 +1937,15 @@ static int UriTestSig15(void) goto end; } - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2000,7 +2024,6 @@ static int UriTestSig16(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)"); @@ -2011,14 +2034,15 @@ static int UriTestSig16(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2035,18 +2059,18 @@ static int UriTestSig16(void) } p->alerts.cnt = 0; - DetectEngineStateReset(f.de_state, STREAM_TOSERVER | STREAM_TOCLIENT); p->payload = http_buf2; p->payload_len = http_buf2_len; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2120,7 +2144,6 @@ static int UriTestSig17(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2135,14 +2158,15 @@ static int UriTestSig17(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2216,7 +2240,6 @@ static int UriTestSig18(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2231,14 +2254,15 @@ static int UriTestSig18(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2312,7 +2336,6 @@ static int UriTestSig19(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2328,14 +2351,15 @@ static int UriTestSig19(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2409,7 +2433,6 @@ static int UriTestSig20(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2424,14 +2447,15 @@ static int UriTestSig20(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2505,7 +2529,6 @@ static int UriTestSig21(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2519,14 +2542,15 @@ static int UriTestSig21(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2601,7 +2625,6 @@ static int UriTestSig22(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2614,14 +2637,15 @@ static int UriTestSig22(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2695,7 +2719,6 @@ static int UriTestSig23(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2708,14 +2731,15 @@ static int UriTestSig23(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2789,7 +2813,6 @@ static int UriTestSig24(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2802,14 +2825,15 @@ static int UriTestSig24(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2883,7 +2907,6 @@ static int UriTestSig25(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2896,14 +2919,15 @@ static int UriTestSig25(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2977,7 +3001,6 @@ static int UriTestSig26(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -2990,14 +3013,15 @@ static int UriTestSig26(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3071,7 +3095,6 @@ static int UriTestSig27(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3084,14 +3107,15 @@ static int UriTestSig27(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3197,7 +3221,6 @@ static int UriTestSig28(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3212,14 +3235,15 @@ static int UriTestSig28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3290,7 +3314,6 @@ static int UriTestSig29(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3305,14 +3328,15 @@ static int UriTestSig29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3383,7 +3407,6 @@ static int UriTestSig30(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3398,14 +3421,15 @@ static int UriTestSig30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3476,7 +3500,6 @@ static int UriTestSig31(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3491,14 +3514,15 @@ static int UriTestSig31(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3569,7 +3593,6 @@ static int UriTestSig32(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -3584,14 +3607,15 @@ static int UriTestSig32(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3662,7 +3686,6 @@ static int UriTestSig33(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3675,14 +3698,15 @@ static int UriTestSig33(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3753,7 +3777,6 @@ static int UriTestSig34(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3766,14 +3789,15 @@ static int UriTestSig34(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3844,7 +3868,6 @@ static int UriTestSig35(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3857,14 +3880,15 @@ static int UriTestSig35(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3935,7 +3959,6 @@ static int UriTestSig36(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -3948,14 +3971,15 @@ static int UriTestSig36(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4026,7 +4050,6 @@ static int UriTestSig37(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -4039,14 +4062,15 @@ static int UriTestSig37(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4117,7 +4141,6 @@ static int UriTestSig38(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -4130,14 +4153,15 @@ static int UriTestSig38(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_buf_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_buf_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -4177,45 +4201,45 @@ void UriRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UriTestSig01", UriTestSig01, 1); - UtRegisterTest("UriTestSig02", UriTestSig02, 1); - UtRegisterTest("UriTestSig03", UriTestSig03, 1); - UtRegisterTest("UriTestSig04", UriTestSig04, 1); - UtRegisterTest("UriTestSig05", UriTestSig05, 1); - UtRegisterTest("UriTestSig06", UriTestSig06, 1); - UtRegisterTest("UriTestSig07", UriTestSig07, 1); - UtRegisterTest("UriTestSig08", UriTestSig08, 1); - UtRegisterTest("UriTestSig09", UriTestSig09, 1); - UtRegisterTest("UriTestSig10", UriTestSig10, 1); - UtRegisterTest("UriTestSig11", UriTestSig11, 1); - UtRegisterTest("UriTestSig12", UriTestSig12, 1); - UtRegisterTest("UriTestSig13", UriTestSig13, 1); - UtRegisterTest("UriTestSig14", UriTestSig14, 1); - UtRegisterTest("UriTestSig15", UriTestSig15, 1); - UtRegisterTest("UriTestSig16", UriTestSig16, 1); - UtRegisterTest("UriTestSig17", UriTestSig17, 1); - UtRegisterTest("UriTestSig18", UriTestSig18, 1); - UtRegisterTest("UriTestSig19", UriTestSig19, 1); - UtRegisterTest("UriTestSig20", UriTestSig20, 1); - UtRegisterTest("UriTestSig21", UriTestSig21, 1); - UtRegisterTest("UriTestSig22", UriTestSig22, 1); - UtRegisterTest("UriTestSig23", UriTestSig23, 1); - UtRegisterTest("UriTestSig24", UriTestSig24, 1); - UtRegisterTest("UriTestSig25", UriTestSig25, 1); - UtRegisterTest("UriTestSig26", UriTestSig26, 1); - UtRegisterTest("UriTestSig27", UriTestSig27, 1); - - UtRegisterTest("UriTestSig28", UriTestSig28, 1); - UtRegisterTest("UriTestSig29", UriTestSig29, 1); - UtRegisterTest("UriTestSig30", UriTestSig30, 1); - UtRegisterTest("UriTestSig31", UriTestSig31, 1); - UtRegisterTest("UriTestSig32", UriTestSig32, 1); - UtRegisterTest("UriTestSig33", UriTestSig33, 1); - UtRegisterTest("UriTestSig34", UriTestSig34, 1); - UtRegisterTest("UriTestSig35", UriTestSig35, 1); - UtRegisterTest("UriTestSig36", UriTestSig36, 1); - UtRegisterTest("UriTestSig37", UriTestSig37, 1); - UtRegisterTest("UriTestSig38", UriTestSig38, 1); + UtRegisterTest("UriTestSig01", UriTestSig01); + UtRegisterTest("UriTestSig02", UriTestSig02); + UtRegisterTest("UriTestSig03", UriTestSig03); + UtRegisterTest("UriTestSig04", UriTestSig04); + UtRegisterTest("UriTestSig05", UriTestSig05); + UtRegisterTest("UriTestSig06", UriTestSig06); + UtRegisterTest("UriTestSig07", UriTestSig07); + UtRegisterTest("UriTestSig08", UriTestSig08); + UtRegisterTest("UriTestSig09", UriTestSig09); + UtRegisterTest("UriTestSig10", UriTestSig10); + UtRegisterTest("UriTestSig11", UriTestSig11); + UtRegisterTest("UriTestSig12", UriTestSig12); + UtRegisterTest("UriTestSig13", UriTestSig13); + UtRegisterTest("UriTestSig14", UriTestSig14); + UtRegisterTest("UriTestSig15", UriTestSig15); + UtRegisterTest("UriTestSig16", UriTestSig16); + UtRegisterTest("UriTestSig17", UriTestSig17); + UtRegisterTest("UriTestSig18", UriTestSig18); + UtRegisterTest("UriTestSig19", UriTestSig19); + UtRegisterTest("UriTestSig20", UriTestSig20); + UtRegisterTest("UriTestSig21", UriTestSig21); + UtRegisterTest("UriTestSig22", UriTestSig22); + UtRegisterTest("UriTestSig23", UriTestSig23); + UtRegisterTest("UriTestSig24", UriTestSig24); + UtRegisterTest("UriTestSig25", UriTestSig25); + UtRegisterTest("UriTestSig26", UriTestSig26); + UtRegisterTest("UriTestSig27", UriTestSig27); + + UtRegisterTest("UriTestSig28", UriTestSig28); + UtRegisterTest("UriTestSig29", UriTestSig29); + UtRegisterTest("UriTestSig30", UriTestSig30); + UtRegisterTest("UriTestSig31", UriTestSig31); + UtRegisterTest("UriTestSig32", UriTestSig32); + UtRegisterTest("UriTestSig33", UriTestSig33); + UtRegisterTest("UriTestSig34", UriTestSig34); + UtRegisterTest("UriTestSig35", UriTestSig35); + UtRegisterTest("UriTestSig36", UriTestSig36); + UtRegisterTest("UriTestSig37", UriTestSig37); + UtRegisterTest("UriTestSig38", UriTestSig38); #endif /* UNITTESTS */ return; diff --git a/src/detect-engine-uri.h b/src/detect-engine-uri.h index 92b22cd35dbb..fa18960bdbdc 100644 --- a/src/detect-engine-uri.h +++ b/src/detect-engine-uri.h @@ -24,12 +24,13 @@ #ifndef __DETECT_ENGINE_URICONTENT_H__ #define __DETECT_ENGINE_URICONTENT_H__ -int DetectEngineInspectPacketUris(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); +int PrefilterTxUriRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); + +int DetectEngineInspectHttpUri(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id); + void UriRegisterTests(void); #endif /* __DETECT_ENGINE_URICONTENT_H__ */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 6c60a8540f62..0df068c52107 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -28,6 +28,7 @@ #include "flow.h" #include "flow-private.h" #include "flow-util.h" +#include "flow-worker.h" #include "conf.h" #include "conf-yaml-loader.h" @@ -40,25 +41,12 @@ #include "detect-engine-address.h" #include "detect-engine-port.h" #include "detect-engine-mpm.h" -#include "detect-engine-hcbd.h" #include "detect-engine-iponly.h" #include "detect-engine-tag.h" #include "detect-engine-uri.h" -#include "detect-engine-hcbd.h" -#include "detect-engine-hsbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" -#include "detect-engine-hmd.h" -#include "detect-engine-hcd.h" -#include "detect-engine-hrud.h" -#include "detect-engine-hsmd.h" -#include "detect-engine-hscd.h" -#include "detect-engine-hua.h" -#include "detect-engine-hhhd.h" -#include "detect-engine-hrhhd.h" #include "detect-engine-file.h" -#include "detect-engine-dns.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -68,6 +56,8 @@ #include "detect-uricontent.h" #include "detect-engine-threshold.h" +#include "detect-engine-loader.h" + #include "util-classification-config.h" #include "util-reference-config.h" #include "util-threshold-config.h" @@ -79,6 +69,7 @@ #include "util-action.h" #include "util-magic.h" #include "util-signal.h" +#include "util-spm.h" #include "util-var-name.h" @@ -93,304 +84,43 @@ #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000 -static uint32_t detect_engine_ctx_id = 1; - -static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *, void *, void **); - -static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *); - -/* 2 - for each direction */ -DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - -#if 0 - -static void DetectEnginePrintAppInspectionEngines(DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]) -{ - printf("\n"); - - AppProto alproto = ALPROTO_UNKNOWN + 1; - for ( ; alproto < ALPROTO_MAX; alproto++) { - printf("alproto - %d\n", alproto); - int dir = 0; - for ( ; dir < 2; dir++) { - printf(" direction - %d\n", dir); - DetectEngineAppInspectionEngine *engine = list[alproto][dir]; - while (engine != NULL) { - printf(" engine->alproto - %"PRIu16"\n", engine->alproto); - printf(" engine->dir - %"PRIu16"\n", engine->dir); - printf(" engine->sm_list - %d\n", engine->sm_list); - printf(" engine->inspect_flags - %"PRIu32"\n", engine->inspect_flags); - printf(" engine->match_flags - %"PRIu32"\n", engine->match_flags); - printf("\n"); - - engine = engine->next; - } - } /* for ( ; dir < 2; dir++) */ - } /* for ( ; alproto < ALPROTO_MAX; alproto++) */ - - return; -} - -#endif +static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( + ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt); -void DetectEngineRegisterAppInspectionEngines(void) -{ - struct tmp_t { - uint8_t ipproto; - AppProto alproto; - int32_t sm_list; - uint32_t inspect_flags; - uint32_t match_flags; - uint16_t dir; - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); - - }; - - struct tmp_t data_toserver[] = { - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, - 0, - DetectEngineInspectPacketUris }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HCBDMATCH, - DE_STATE_FLAG_HCBD_INSPECT, - DE_STATE_FLAG_HCBD_INSPECT, - 0, - DetectEngineInspectHttpClientBody }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, - DE_STATE_FLAG_HHD_INSPECT, - 0, - DetectEngineInspectHttpHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, - DE_STATE_FLAG_HRHD_INSPECT, - 0, - DetectEngineInspectHttpRawHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HMDMATCH, - DE_STATE_FLAG_HMD_INSPECT, - DE_STATE_FLAG_HMD_INSPECT, - 0, - DetectEngineInspectHttpMethod }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, - DE_STATE_FLAG_HCD_INSPECT, - 0, - DetectEngineInspectHttpCookie }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HRUDMATCH, - DE_STATE_FLAG_HRUD_INSPECT, - DE_STATE_FLAG_HRUD_INSPECT, - 0, - DetectEngineInspectHttpRawUri }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TS_INSPECT, - DE_STATE_FLAG_FILE_TS_INSPECT, - 0, - DetectFileInspectHttp }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HUADMATCH, - DE_STATE_FLAG_HUAD_INSPECT, - DE_STATE_FLAG_HUAD_INSPECT, - 0, - DetectEngineInspectHttpUA }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HHHDMATCH, - DE_STATE_FLAG_HHHD_INSPECT, - DE_STATE_FLAG_HHHD_INSPECT, - 0, - DetectEngineInspectHttpHH }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HRHHDMATCH, - DE_STATE_FLAG_HRHHD_INSPECT, - DE_STATE_FLAG_HRHHD_INSPECT, - 0, - DetectEngineInspectHttpHRH }, - /* DNS */ - { IPPROTO_TCP, - ALPROTO_DNS, - DETECT_SM_LIST_DNSQUERY_MATCH, - DE_STATE_FLAG_DNSQUERY_INSPECT, - DE_STATE_FLAG_DNSQUERY_INSPECT, - 0, - DetectEngineInspectDnsQueryName }, - /* specifically for UDP, register again - * allows us to use the alproto w/o translation - * in the detection engine */ - { IPPROTO_UDP, - ALPROTO_DNS, - DETECT_SM_LIST_DNSQUERY_MATCH, - DE_STATE_FLAG_DNSQUERY_INSPECT, - DE_STATE_FLAG_DNSQUERY_INSPECT, - 0, - DetectEngineInspectDnsQueryName }, - }; - - struct tmp_t data_toclient[] = { - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HSBDMATCH, - DE_STATE_FLAG_HSBD_INSPECT, - DE_STATE_FLAG_HSBD_INSPECT, - 1, - DetectEngineInspectHttpServerBody }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, - DE_STATE_FLAG_HHD_INSPECT, - 1, - DetectEngineInspectHttpHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, - DE_STATE_FLAG_HRHD_INSPECT, - 1, - DetectEngineInspectHttpRawHeader }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, - DE_STATE_FLAG_HCD_INSPECT, - 1, - DetectEngineInspectHttpCookie }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TC_INSPECT, - DE_STATE_FLAG_FILE_TC_INSPECT, - 1, - DetectFileInspectHttp }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HSMDMATCH, - DE_STATE_FLAG_HSMD_INSPECT, - DE_STATE_FLAG_HSMD_INSPECT, - 1, - DetectEngineInspectHttpStatMsg }, - { IPPROTO_TCP, - ALPROTO_HTTP, - DETECT_SM_LIST_HSCDMATCH, - DE_STATE_FLAG_HSCD_INSPECT, - DE_STATE_FLAG_HSCD_INSPECT, - 1, - DetectEngineInspectHttpStatCode } - }; - - size_t i; - for (i = 0 ; i < sizeof(data_toserver) / sizeof(struct tmp_t); i++) { - DetectEngineRegisterAppInspectionEngine(data_toserver[i].ipproto, - data_toserver[i].alproto, - data_toserver[i].dir, - data_toserver[i].sm_list, - data_toserver[i].inspect_flags, - data_toserver[i].match_flags, - data_toserver[i].Callback, - app_inspection_engine); - } - - for (i = 0 ; i < sizeof(data_toclient) / sizeof(struct tmp_t); i++) { - DetectEngineRegisterAppInspectionEngine(data_toclient[i].ipproto, - data_toclient[i].alproto, - data_toclient[i].dir, - data_toclient[i].sm_list, - data_toclient[i].inspect_flags, - data_toclient[i].match_flags, - data_toclient[i].Callback, - app_inspection_engine); - } +static int DetectEngineCtxLoadConf(DetectEngineCtx *); -#if 0 - DetectEnginePrintAppInspectionEngines(app_inspection_engine); -#endif +static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, + 0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0}; - return; -} +static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len); +static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len); +static void TenantIdFree(void *d); +static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p); +static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p); -static void AppendAppInspectionEngine(DetectEngineAppInspectionEngine *engine, - DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]) -{ - /* append to the list */ - DetectEngineAppInspectionEngine *tmp = list[FlowGetProtoMapping(engine->ipproto)][engine->alproto][engine->dir]; - DetectEngineAppInspectionEngine *insert = NULL; - while (tmp != NULL) { - if (tmp->dir == engine->dir && - (tmp->sm_list == engine->sm_list || - tmp->inspect_flags == engine->inspect_flags || - tmp->match_flags == engine->match_flags)) { - SCLogError(SC_ERR_DETECT_PREPARE, "App Inspection Engine already " - "registered for this direction(%"PRIu16") ||" - "sm_list(%d) || " - "[match(%"PRIu32")|inspect(%"PRIu32")]_flags", - tmp->dir, tmp->sm_list, tmp->inspect_flags, - tmp->match_flags); - exit(EXIT_FAILURE); - } - insert = tmp; - tmp = tmp->next; - } - if (insert == NULL) - list[FlowGetProtoMapping(engine->ipproto)][engine->alproto][engine->dir] = engine; - else - insert->next = engine; +static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL; - return; -} +void DetectAppLayerInspectEngineRegister(const char *name, + AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback) +{ + DetectBufferTypeRegister(name); + int sm_list = DetectBufferTypeGetByName(name); + BUG_ON(sm_list == -1); -void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, - AppProto alproto, - uint16_t dir, - int32_t sm_list, - uint32_t inspect_flags, - uint32_t match_flags, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id), - DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]) -{ - if ((list == NULL) || - (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) || - (dir > 1) || - (sm_list < DETECT_SM_LIST_MATCH || sm_list >= DETECT_SM_LIST_MAX) || + if ((alproto >= ALPROTO_FAILED) || + (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || + (sm_list < DETECT_SM_LIST_MATCH) || (Callback == NULL)) { SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments"); exit(EXIT_FAILURE); } - DetectEngineAppInspectionEngine *tmp = list[FlowGetProtoMapping(ipproto)][alproto][dir]; - while (tmp != NULL) { - if (tmp->sm_list == sm_list && tmp->Callback == Callback) { - return; - } - tmp = tmp->next; + int direction; + if (dir == SIG_FLAG_TOSERVER) { + direction = 0; + } else { + direction = 1; } DetectEngineAppInspectionEngine *new_engine = SCMalloc(sizeof(DetectEngineAppInspectionEngine)); @@ -398,231 +128,708 @@ void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, exit(EXIT_FAILURE); } memset(new_engine, 0, sizeof(*new_engine)); - new_engine->ipproto = ipproto; new_engine->alproto = alproto; - new_engine->dir = dir; + new_engine->dir = direction; new_engine->sm_list = sm_list; - new_engine->inspect_flags = inspect_flags; - new_engine->match_flags = match_flags; new_engine->Callback = Callback; - AppendAppInspectionEngine(new_engine, list); + if (g_app_inspect_engines == NULL) { + g_app_inspect_engines = new_engine; + } else { + DetectEngineAppInspectionEngine *t = g_app_inspect_engines; + while (t->next != NULL) { + t = t->next; + } - return; + t->next = new_engine; + } } -static void *DetectEngineLiveRuleSwap(void *arg) +int DetectEngineAppInspectionEngine2Signature(Signature *s) { - SCEnter(); + const int nlists = DetectBufferTypeMaxId(); + SigMatchData *ptrs[nlists]; + memset(&ptrs, 0, (nlists * sizeof(SigMatchData *))); + /* convert lists to SigMatchData arrays */ int i = 0; - int no_of_detect_tvs = 0; - DetectEngineCtx *old_de_ctx = NULL; - ThreadVars *tv = NULL; + for (i = DETECT_SM_LIST_DYNAMIC_START; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; - if (SCSetThreadName("LiveRuleSwap") < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); + ptrs[i] = SigMatchList2DataArray(s->init_data->smlists[i]); } - SCLogNotice("rule reload starting"); - - ThreadVars *tv_local = (ThreadVars *)arg; + DetectEngineAppInspectionEngine *t = g_app_inspect_engines; + while (t != NULL) { + if (ptrs[t->sm_list] == NULL) + goto next; + if (t->alproto == ALPROTO_UNKNOWN) { + /* special case, inspect engine applies to all protocols */ + } else if (s->alproto != ALPROTO_UNKNOWN && s->alproto != t->alproto) + goto next; + + if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) { + if (t->dir == 1) + goto next; + } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) { + if (t->dir == 0) + goto next; + } - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); + DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine)); + if (unlikely(new_engine == NULL)) { + exit(EXIT_FAILURE); + } + new_engine->alproto = t->alproto; + new_engine->dir = t->dir; + new_engine->sm_list = t->sm_list; + new_engine->smd = ptrs[new_engine->sm_list]; + new_engine->Callback = t->Callback; + + if (s->app_inspect == NULL) { + s->app_inspect = new_engine; + new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */ + } else { + DetectEngineAppInspectionEngine *a = s->app_inspect; + while (a->next != NULL) { + a = a->next; + } - if (tv_local->thread_setup_flags != 0) - TmThreadSetupOptions(tv_local); + a->next = new_engine; + new_engine->id = a->id + 1; + } + SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id); - /* release TmThreadSpawn */ - TmThreadsSetFlag(tv_local, THV_INIT_DONE); + s->flags |= SIG_FLAG_STATE_MATCH; +next: + t = t->next; + } - ConfDeInit(); - ConfInit(); + return 0; +} - /* re-load the yaml file */ - if (conf_filename != NULL) { - if (ConfYamlLoadFile(conf_filename) != 0) { - /* Error already displayed. */ - exit(EXIT_FAILURE); - } +/** \brief free app inspect engines for a signature + * + * For lists that are registered multiple times, like http_header and + * http_cookie, making the engines owner of the lists is complicated. + * Multiple engines in a sig may be pointing to the same list. To + * address this the 'free' code needs to be extra careful about not + * double freeing, so it takes an approach to first fill an array + * of the to-free pointers before freeing them. + */ +void DetectEngineAppInspectionEngineSignatureFree(Signature *s) +{ + const int nlists = DetectBufferTypeMaxId(); + SigMatchData *ptrs[nlists]; + memset(&ptrs, 0, (nlists * sizeof(SigMatchData *))); + + /* free engines and put smd in the array */ + DetectEngineAppInspectionEngine *ie = s->app_inspect; + while (ie) { + DetectEngineAppInspectionEngine *next = ie->next; + BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->smd); + ptrs[ie->sm_list] = ie->smd; + SCFree(ie); + ie = next; + } - ConfNode *file; - ConfNode *includes = ConfGetNode("include"); - if (includes != NULL) { - TAILQ_FOREACH(file, &includes->head, next) { - char *ifile = ConfLoadCompleteIncludePath(file->val); - SCLogInfo("Live Rule Swap: Including: %s", ifile); + /* free the smds */ + int i; + for (i = 0; i < nlists; i++) + { + if (ptrs[i] == NULL) + continue; - if (ConfYamlLoadFile(ifile) != 0) { - /* Error already displayed. */ - exit(EXIT_FAILURE); - } + SigMatchData *smd = ptrs[i]; + while(1) { + if (sigmatch_table[smd->type].Free != NULL) { + sigmatch_table[smd->type].Free(smd->ctx); } + if (smd->is_last) + break; + smd++; } - } /* if (conf_filename != NULL) */ + SCFree(ptrs[i]); + } +} -#if 0 - ConfDump(); -#endif +/* code for registering buffers */ - SCMutexLock(&tv_root_lock); +#include "util-hash-lookup3.h" - tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); +static HashListTable *g_buffer_type_hash = NULL; +static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START; +static int g_buffer_type_reg_closed = 0; - if (suricata_ctl_flags != 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); +typedef struct DetectBufferType_ { + const char *string; + const char *description; + int id; + _Bool mpm; + _Bool packet; /**< compat to packet matches */ + void (*SetupCallback)(Signature *); + _Bool (*ValidateCallback)(const Signature *); +} DetectBufferType; - SCLogInfo("rule reload interupted by engine shutdown"); +static DetectBufferType **g_buffer_type_map = NULL; - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCMutexUnlock(&tv_root_lock); - pthread_exit(NULL); - } +int DetectBufferTypeMaxId(void) +{ + return g_buffer_type_id; +} - if (!(tm->flags & TM_FLAG_DETECT_TM)) { - slots = slots->slot_next; - continue; - } - no_of_detect_tvs++; - break; - } +static uint32_t DetectBufferTypeHashFunc(HashListTable *ht, void *data, uint16_t datalen) +{ + const DetectBufferType *map = (DetectBufferType *)data; + uint32_t hash = 0; - tv = tv->next; + hash = hashlittle_safe(map->string, strlen(map->string), 0); + hash %= ht->array_size; + + return hash; +} + +static char DetectBufferTypeCompareFunc(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + DetectBufferType *map1 = (DetectBufferType *)data1; + DetectBufferType *map2 = (DetectBufferType *)data2; + + int r = (strcmp(map1->string, map2->string) == 0); + return r; +} + +static void DetectBufferTypeFreeFunc(void *data) +{ + DetectBufferType *map = (DetectBufferType *)data; + if (map != NULL) { + SCFree(map); } +} - if (no_of_detect_tvs == 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCLogInfo("===== Live rule swap FAILURE ====="); - pthread_exit(NULL); +int DetectBufferTypeInit(void) +{ + BUG_ON(g_buffer_type_hash); + g_buffer_type_hash = HashListTableInit(256, + DetectBufferTypeHashFunc, + DetectBufferTypeCompareFunc, + DetectBufferTypeFreeFunc); + if (g_buffer_type_hash == NULL) + return -1; + + return 0; +} + +void DetectBufferTypeFree(void) +{ + if (g_buffer_type_hash == NULL) + return; + + HashListTableFree(g_buffer_type_hash); + g_buffer_type_hash = NULL; + return; +} + +int DetectBufferTypeAdd(const char *string) +{ + DetectBufferType *map = SCCalloc(1, sizeof(*map)); + if (map == NULL) + return -1; + + map->string = string; + map->id = g_buffer_type_id++; + + BUG_ON(HashListTableAdd(g_buffer_type_hash, (void *)map, 0) != 0); + SCLogDebug("buffer %s registered with id %d", map->string, map->id); + return map->id; +} + +DetectBufferType *DetectBufferTypeLookupByName(const char *string) +{ + DetectBufferType map = { (char *)string, NULL, 0, 0, 0, NULL, NULL }; + + DetectBufferType *res = HashListTableLookup(g_buffer_type_hash, &map, 0); + return res; +} + +int DetectBufferTypeRegister(const char *name) +{ + BUG_ON(g_buffer_type_reg_closed); + if (g_buffer_type_hash == NULL) + DetectBufferTypeInit(); + + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return DetectBufferTypeAdd(name); + } else { + return exists->id; } +} - DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; - DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; - ThreadVars *detect_tvs[no_of_detect_tvs]; - memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); - memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); - memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *))); +void DetectBufferTypeSupportsPacket(const char *name) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->packet = TRUE; + SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id); +} - SCMutexUnlock(&tv_root_lock); +void DetectBufferTypeSupportsMpm(const char *name) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->mpm = TRUE; + SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id); +} - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - SCLogError(SC_ERR_LIVE_RULE_SWAP, "Allocation failure in live " - "swap. Let's get out of here."); - goto error; +int DetectBufferTypeGetByName(const char *name) +{ + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return -1; } + return exists->id; +} - SCClassConfLoadClassficationConfigFile(de_ctx); - SCRConfLoadReferenceConfigFile(de_ctx); +const char *DetectBufferTypeGetNameById(const int id) +{ + BUG_ON(id < 0 || id >= g_buffer_type_id); + BUG_ON(g_buffer_type_map == NULL); - if (ActionInitConfig() < 0) { - exit(EXIT_FAILURE); + if (g_buffer_type_map[id] == NULL) + return NULL; + + return g_buffer_type_map[id]->string; +} + +const DetectBufferType *DetectBufferTypeGetById(const int id) +{ + BUG_ON(id < 0 || id >= g_buffer_type_id); + BUG_ON(g_buffer_type_map == NULL); + + return g_buffer_type_map[id]; +} + +void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc) +{ + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return; } + exists->description = desc; +} - if (SigLoadSignatures(de_ctx, NULL, FALSE) < 0) { - SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); - if (de_ctx->failure_fatal) - exit(EXIT_FAILURE); - DetectEngineCtxFree(de_ctx); - SCLogError(SC_ERR_LIVE_RULE_SWAP, "Failure encountered while " - "loading new ruleset with live swap."); - SCLogError(SC_ERR_LIVE_RULE_SWAP, "rule reload failed"); - TmThreadsSetFlag(tv_local, THV_CLOSED); - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - pthread_exit(NULL); +const char *DetectBufferTypeGetDescriptionById(const int id) +{ + const DetectBufferType *exists = DetectBufferTypeGetById(id); + if (!exists) { + return NULL; } + return exists->description; +} - SCThresholdConfInitContext(de_ctx, NULL); +const char *DetectBufferTypeGetDescriptionByName(const char *name) +{ + const DetectBufferType *exists = DetectBufferTypeLookupByName(name); + if (!exists) { + return NULL; + } + return exists->description; +} - /* start the process of swapping detect threads ctxs */ +_Bool DetectBufferTypeSupportsPacketGetById(const int id) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map == NULL) + return FALSE; + SCLogDebug("map %p id %d packet? %d", map, id, map->packet); + return map->packet; +} - SCMutexLock(&tv_root_lock); +_Bool DetectBufferTypeSupportsMpmGetById(const int id) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map == NULL) + return FALSE; + SCLogDebug("map %p id %d mpm? %d", map, id, map->mpm); + return map->mpm; +} - /* all receive threads are part of packet processing threads */ - tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); +void DetectBufferTypeRegisterSetupCallback(const char *name, + void (*SetupCallback)(Signature *)) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->SetupCallback = SetupCallback; +} - if (suricata_ctl_flags != 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); +void DetectBufferRunSetupCallback(const int id, Signature *s) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map && map->SetupCallback) { + map->SetupCallback(s); + } +} - SCLogInfo("rule reload interupted by engine shutdown"); +void DetectBufferTypeRegisterValidateCallback(const char *name, + _Bool (*ValidateCallback)(const Signature *)) +{ + BUG_ON(g_buffer_type_reg_closed); + DetectBufferTypeRegister(name); + DetectBufferType *exists = DetectBufferTypeLookupByName(name); + BUG_ON(!exists); + exists->ValidateCallback = ValidateCallback; +} - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCMutexUnlock(&tv_root_lock); - pthread_exit(NULL); - } +_Bool DetectBufferRunValidateCallback(const int id, const Signature *s) +{ + const DetectBufferType *map = DetectBufferTypeGetById(id); + if (map && map->ValidateCallback) { + return map->ValidateCallback(s); + } + return TRUE; +} - if (!(tm->flags & TM_FLAG_DETECT_TM)) { - slots = slots->slot_next; - continue; - } +void DetectBufferTypeFinalizeRegistration(void) +{ + BUG_ON(g_buffer_type_hash == NULL); + + const int size = g_buffer_type_id; + BUG_ON(!(size > 0)); + + g_buffer_type_map = SCCalloc(size, sizeof(DetectBufferType *)); + BUG_ON(!g_buffer_type_map); + + SCLogDebug("DETECT_SM_LIST_DYNAMIC_START %u", DETECT_SM_LIST_DYNAMIC_START); + HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash); + while (b) { + DetectBufferType *map = HashListTableGetListData(b); + g_buffer_type_map[map->id] = map; + SCLogDebug("name %s id %d mpm %s packet %s -- %s. " + "Callbacks: Setup %p Validate %p", map->string, map->id, + map->mpm ? "true" : "false", map->packet ? "true" : "false", + map->description, map->SetupCallback, map->ValidateCallback); + b = HashListTableGetListNext(b); + } + g_buffer_type_reg_closed = 1; +} - old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data); - detect_tvs[i] = tv; - TmEcode r = DetectEngineThreadCtxInitForLiveRuleSwap(tv, (void *)de_ctx, - (void **)&new_det_ctx[i]); - i++; - if (r == TM_ECODE_FAILED) { - SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " - "failure in live rule swap. Let's get out of here"); - SCMutexUnlock(&tv_root_lock); - goto error; +/* code to control the main thread to do a reload */ + +enum DetectEngineSyncState { + IDLE, /**< ready to start a reload */ + RELOAD, /**< command main thread to do the reload */ + DONE, /**< main thread telling us reload is done */ +}; + + +typedef struct DetectEngineSyncer_ { + SCMutex m; + enum DetectEngineSyncState state; +} DetectEngineSyncer; + +static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE }; + +/* tell main to start reloading */ +int DetectEngineReloadStart(void) +{ + int r = 0; + SCMutexLock(&detect_sync.m); + if (detect_sync.state == IDLE) { + detect_sync.state = RELOAD; + } else { + r = -1; + } + SCMutexUnlock(&detect_sync.m); + return r; +} + +/* main thread checks this to see if it should start */ +int DetectEngineReloadIsStart(void) +{ + int r = 0; + SCMutexLock(&detect_sync.m); + if (detect_sync.state == RELOAD) { + r = 1; + } + SCMutexUnlock(&detect_sync.m); + return r; +} + +/* main thread sets done when it's done */ +void DetectEngineReloadSetDone(void) +{ + SCMutexLock(&detect_sync.m); + detect_sync.state = DONE; + SCMutexUnlock(&detect_sync.m); +} + +/* caller loops this until it returns 1 */ +int DetectEngineReloadIsDone(void) +{ + int r = 0; + SCMutexLock(&detect_sync.m); + if (detect_sync.state == DONE) { + r = 1; + detect_sync.state = IDLE; + } + SCMutexUnlock(&detect_sync.m); + return r; +} + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match + * \retval 1 match + */ +int DetectEngineInspectGenericList(ThreadVars *tv, + const DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, const uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + SCLogDebug("running match functions, sm %p", smd); + if (smd != NULL) { + while (1) { + int match = 0; +#ifdef PROFILING + KEYWORD_PROFILING_START; +#endif + match = sigmatch_table[smd->type]. + AppLayerTxMatch(tv, det_ctx, f, flags, alstate, txv, s, smd->ctx); +#ifdef PROFILING + KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1)); +#endif + if (match == 0) + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + if (match == 2) { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; } - SCLogDebug("live rule swap created new det_ctx - %p and de_ctx " - "- %p\n", new_det_ctx, de_ctx); - break; - } - tv = tv->next; + if (smd->is_last) + break; + smd++; + } } - i = 0; - tv = tv_root[TVT_PPT]; + return DETECT_ENGINE_INSPECT_SIG_MATCH; +} + +/* nudge capture loops to wake up */ +static void BreakCapture(void) +{ + SCMutexLock(&tv_root_lock); + ThreadVars *tv = tv_root[TVT_PPT]; while (tv) { + /* find the correct slot */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { if (suricata_ctl_flags != 0) { - TmThreadsSetFlag(tv_local, THV_CLOSED); - - SCLogInfo("rule reload interupted by engine shutdown"); - - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); SCMutexUnlock(&tv_root_lock); - pthread_exit(NULL); + return; } TmModule *tm = TmModuleGetById(slots->tm_id); - if (!(tm->flags & TM_FLAG_DETECT_TM)) { + if (!(tm->flags & TM_FLAG_RECEIVE_TM)) { slots = slots->slot_next; continue; } - SCLogDebug("swapping new det_ctx - %p with older one - %p", - new_det_ctx[i], SC_ATOMIC_GET(slots->slot_data)); - (void)SC_ATOMIC_SET(slots->slot_data, new_det_ctx[i++]); + + /* signal capture method that we need a packet. */ + TmThreadsSetFlag(tv, THV_CAPTURE_INJECT_PKT); + /* if the method supports it, BreakLoop. Otherwise we rely on + * the capture method's recv timeout */ + if (tm->PktAcqLoop && tm->PktAcqBreakLoop) { + tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(slots->slot_data)); + } + break; } tv = tv->next; } - SCMutexUnlock(&tv_root_lock); +} - SCLogInfo("Live rule swap has swapped %d old det_ctx's with new ones, " - "along with the new de_ctx", no_of_detect_tvs); - - for (i = 0; i < no_of_detect_tvs; i++) { - int break_out = 0; - int pseudo_pkt_inserted = 0; +/** \internal + * \brief inject a pseudo packet into each detect thread that doesn't use the + * new det_ctx yet + */ +static void InjectPackets(ThreadVars **detect_tvs, + DetectEngineThreadCtx **new_det_ctx, + int no_of_detect_tvs) +{ + int i; + /* inject a fake packet if the detect thread isn't using the new ctx yet, + * this speeds up the process */ + for (i = 0; i < no_of_detect_tvs; i++) { + if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { + if (detect_tvs[i]->inq != NULL) { + Packet *p = PacketGetFromAlloc(); + if (p != NULL) { + p->flags |= PKT_PSEUDO_STREAM_END; + PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; + SCMutexLock(&q->mutex_q); + PacketEnqueue(q, p); + SCCondSignal(&q->cond_q); + SCMutexUnlock(&q->mutex_q); + } + } + } + } +} + +/** \internal + * \brief Update detect threads with new detect engine + * + * Atomically update each detect thread with a new thread context + * that is associated to the new detection engine(s). + * + * If called in unix socket mode, it's possible that we don't have + * detect threads yet. + * + * \retval -1 error + * \retval 0 no detection threads + * \retval 1 successful reload + */ +static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx) +{ + SCEnter(); + int i = 0; + int no_of_detect_tvs = 0; + ThreadVars *tv = NULL; + + /* count detect threads in use */ + SCMutexLock(&tv_root_lock); + tv = tv_root[TVT_PPT]; + while (tv) { + /* obtain the slots for this TV */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + TmModule *tm = TmModuleGetById(slots->tm_id); + + if (suricata_ctl_flags != 0) { + SCLogInfo("rule reload interupted by engine shutdown"); + SCMutexUnlock(&tv_root_lock); + return -1; + } + + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + no_of_detect_tvs++; + break; + } + + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); + + /* can be zero in unix socket mode */ + if (no_of_detect_tvs == 0) { + return 0; + } + + /* prepare swap structures */ + DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs]; + DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs]; + ThreadVars *detect_tvs[no_of_detect_tvs]; + memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); + memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *))); + memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *))); + + /* start the process of swapping detect threads ctxs */ + + /* get reference to tv's and setup new_det_ctx array */ + SCMutexLock(&tv_root_lock); + tv = tv_root[TVT_PPT]; + while (tv) { + /* obtain the slots for this TV */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + TmModule *tm = TmModuleGetById(slots->tm_id); + + if (suricata_ctl_flags != 0) { + SCMutexUnlock(&tv_root_lock); + goto error; + } + + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + + old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(slots->slot_data)); + detect_tvs[i] = tv; + + new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1); + if (new_det_ctx[i] == NULL) { + SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init " + "failure in live rule swap. Let's get out of here"); + SCMutexUnlock(&tv_root_lock); + goto error; + } + SCLogDebug("live rule swap created new det_ctx - %p and de_ctx " + "- %p\n", new_det_ctx[i], new_de_ctx); + i++; + break; + } + + tv = tv->next; + } + BUG_ON(i != no_of_detect_tvs); + + /* atomicly replace the det_ctx data */ + i = 0; + tv = tv_root[TVT_PPT]; + while (tv) { + /* find the correct slot */ + TmSlot *slots = tv->tm_slots; + while (slots != NULL) { + if (suricata_ctl_flags != 0) { + return -1; + } + + TmModule *tm = TmModuleGetById(slots->tm_id); + if (!(tm->flags & TM_FLAG_DETECT_TM)) { + slots = slots->slot_next; + continue; + } + SCLogDebug("swapping new det_ctx - %p with older one - %p", + new_det_ctx[i], SC_ATOMIC_GET(slots->slot_data)); + FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(slots->slot_data), new_det_ctx[i++]); + break; + } + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); + + /* threads now all have new data, however they may not have started using + * it and may still use the old data */ + + SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, " + "along with the new de_ctx", no_of_detect_tvs); + + InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs); + + for (i = 0; i < no_of_detect_tvs; i++) { + int break_out = 0; usleep(1000); while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) { if (suricata_ctl_flags != 0) { @@ -630,21 +837,7 @@ static void *DetectEngineLiveRuleSwap(void *arg) break; } - if (pseudo_pkt_inserted == 0) { - pseudo_pkt_inserted = 1; - if (detect_tvs[i]->inq != NULL) { - Packet *p = PacketGetFromAlloc(); - if (p != NULL) { - p->flags |= PKT_PSEUDO_STREAM_END; - PacketQueue *q = &trans_q[detect_tvs[i]->inq->id]; - SCMutexLock(&q->mutex_q); - - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - } - } - } + BreakCapture(); usleep(1000); } if (break_out) @@ -657,14 +850,13 @@ static void *DetectEngineLiveRuleSwap(void *arg) * de_ctx, till all detect threads have stopped working and sitting * silently after setting RUNNING_DONE flag and while waiting for * THV_DEINIT flag */ - if (i != no_of_detect_tvs) { - ThreadVars *tv = tv_root[TVT_PPT]; + if (i != no_of_detect_tvs) { // not all threads we swapped + tv = tv_root[TVT_PPT]; while (tv) { /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { TmModule *tm = TmModuleGetById(slots->tm_id); - if (!(tm->flags & TM_FLAG_DETECT_TM)) { slots = slots->slot_next; continue; @@ -682,174 +874,116 @@ static void *DetectEngineLiveRuleSwap(void *arg) } /* free all the ctxs */ - old_de_ctx = old_det_ctx[0]->de_ctx; for (i = 0; i < no_of_detect_tvs; i++) { SCLogDebug("Freeing old_det_ctx - %p used by detect", old_det_ctx[i]); DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]); } - DetectEngineCtxFree(old_de_ctx); SRepReloadComplete(); - /* reset the handler */ - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - - TmThreadsSetFlag(tv_local, THV_CLOSED); - - SCLogNotice("rule reload complete"); - - pthread_exit(NULL); + return 1; error: for (i = 0; i < no_of_detect_tvs; i++) { if (new_det_ctx[i] != NULL) DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]); } - DetectEngineCtxFree(de_ctx); - TmThreadsSetFlag(tv_local, THV_CLOSED); - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - SCLogInfo("===== Live rule swap FAILURE ====="); - pthread_exit(NULL); + return -1; } -void DetectEngineSpawnLiveRuleSwapMgmtThread(void) -{ - SCEnter(); - - SCLogDebug("Spawning mgmt thread for live rule swap"); - - ThreadVars *tv = TmThreadCreateMgmtThread("DetectEngineLiveRuleSwap", - DetectEngineLiveRuleSwap, 0); - if (tv == NULL) { - SCLogError(SC_ERR_THREAD_CREATE, "Live rule swap thread spawn failed"); - exit(EXIT_FAILURE); - } - - TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); - - if (TmThreadSpawn(tv) != 0) { - SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed for " - "DetectEngineLiveRuleSwap"); - exit(EXIT_FAILURE); - } - - SCReturn; -} - -DetectEngineCtx *DetectEngineGetGlobalDeCtx(void) -{ - DetectEngineCtx *de_ctx = NULL; - - SCMutexLock(&tv_root_lock); - - ThreadVars *tv = tv_root[TVT_PPT]; - while (tv) { - /* obtain the slots for this TV */ - TmSlot *slots = tv->tm_slots; - while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); - - if (tm->flags & TM_FLAG_DETECT_TM) { - DetectEngineThreadCtx *det_ctx = SC_ATOMIC_GET(slots->slot_data); - de_ctx = det_ctx->de_ctx; - SCMutexUnlock(&tv_root_lock); - return de_ctx; - } - - slots = slots->slot_next; - } - - tv = tv->next; - } - - SCMutexUnlock(&tv_root_lock); - return NULL; -} - -DetectEngineCtx *DetectEngineCtxInit(void) +static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix) { DetectEngineCtx *de_ctx; - ConfNode *seq_node = NULL; - ConfNode *insp_recursion_limit_node = NULL; - ConfNode *de_engine_node = NULL; - char *insp_recursion_limit = NULL; - de_ctx = SCMalloc(sizeof(DetectEngineCtx)); if (unlikely(de_ctx == NULL)) goto error; memset(de_ctx,0,sizeof(DetectEngineCtx)); - if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) { - SCLogDebug("ConfGetBool could not load the value."); + if (minimal) { + de_ctx->minimal = 1; + de_ctx->version = DetectEngineGetVersion(); + SCLogDebug("minimal with version %u", de_ctx->version); + return de_ctx; } - de_engine_node = ConfGetNode("detect-engine"); - if (de_engine_node != NULL) { - TAILQ_FOREACH(seq_node, &de_engine_node->head, next) { - if (strcmp(seq_node->val, "inspection-recursion-limit") != 0) - continue; - - insp_recursion_limit_node = ConfNodeLookupChild(seq_node, seq_node->val); - if (insp_recursion_limit_node == NULL) { - SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf " - "entry for detect-engine:inspection-recursion-limit"); - break; - } - insp_recursion_limit = insp_recursion_limit_node->val; - SCLogDebug("Found detect-engine:inspection-recursion-limit - %s:%s", - insp_recursion_limit_node->name, insp_recursion_limit_node->val); - - break; - } + if (prefix != NULL) { + strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix)); } - if (insp_recursion_limit != NULL) { - de_ctx->inspection_recursion_limit = atoi(insp_recursion_limit); - } else { - de_ctx->inspection_recursion_limit = - DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; + if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) { + SCLogDebug("ConfGetBool could not load the value."); } - if (de_ctx->inspection_recursion_limit == 0) - de_ctx->inspection_recursion_limit = -1; - - SCLogDebug("de_ctx->inspection_recursion_limit: %d", - de_ctx->inspection_recursion_limit); - de_ctx->mpm_matcher = PatternMatchDefaultMatcher(); + de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher(); + SCLogConfig("pattern matchers: MPM: %s, SPM: %s", + mpm_table[de_ctx->mpm_matcher].name, + spm_table[de_ctx->spm_matcher].name); + + de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher); + if (de_ctx->spm_global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmGlobalThreadCtx."); + goto error; + } + DetectEngineCtxLoadConf(de_ctx); SigGroupHeadHashInit(de_ctx); - SigGroupHeadMpmHashInit(de_ctx); - SigGroupHeadMpmUriHashInit(de_ctx); - SigGroupHeadSPortHashInit(de_ctx); - SigGroupHeadDPortHashInit(de_ctx); - DetectPortSpHashInit(de_ctx); - DetectPortDpHashInit(de_ctx); + MpmStoreInit(de_ctx); ThresholdHashInit(de_ctx); - VariableNameInitHash(de_ctx); DetectParseDupSigHashInit(de_ctx); - - de_ctx->mpm_pattern_id_store = MpmPatternIdTableInitHash(); - if (de_ctx->mpm_pattern_id_store == NULL) { - goto error; - } - - de_ctx->id = detect_engine_ctx_id++; + DetectAddressMapInit(de_ctx); /* init iprep... ignore errors for now */ (void)SRepInit(de_ctx); #ifdef PROFILING SCProfilingKeywordInitCounters(de_ctx); + de_ctx->profile_match_logging_threshold = UINT_MAX; // disabled + + intmax_t v = 0; + if (ConfGetInt("detect.profiling.inspect-logging-threshold", &v) == 1) + de_ctx->profile_match_logging_threshold = (uint32_t)v; #endif + SCClassConfLoadClassficationConfigFile(de_ctx, NULL); + SCRConfLoadReferenceConfigFile(de_ctx, NULL); + + if (ActionInitConfig() < 0) { + goto error; + } + + de_ctx->version = DetectEngineGetVersion(); + VarNameStoreSetupStaging(de_ctx->version); + SCLogDebug("dectx with version %u", de_ctx->version); return de_ctx; error: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } return NULL; + +} + +DetectEngineCtx *DetectEngineCtxInitMinimal(void) +{ + return DetectEngineCtxInitReal(1, NULL); +} + +DetectEngineCtx *DetectEngineCtxInit(void) +{ + return DetectEngineCtxInitReal(0, NULL); +} + +DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix) +{ + if (prefix == NULL || strlen(prefix) == 0) + return DetectEngineCtxInit(); + else + return DetectEngineCtxInitReal(0, prefix); } static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx) @@ -883,26 +1017,22 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx); // de_ctx->profile_keyword_ctx = NULL; } + if (de_ctx->profile_sgh_ctx != NULL) { + SCProfilingSghDestroyCtx(de_ctx); + } #endif /* Normally the hashes are freed elsewhere, but * to be sure look at them again here. */ - MpmPatternIdTableFreeHash(de_ctx->mpm_pattern_id_store); /* normally cleaned up in SigGroupBuild */ - SigGroupHeadHashFree(de_ctx); - SigGroupHeadMpmHashFree(de_ctx); - SigGroupHeadMpmUriHashFree(de_ctx); - SigGroupHeadSPortHashFree(de_ctx); - SigGroupHeadDPortHashFree(de_ctx); + MpmStoreFree(de_ctx); DetectParseDupSigHashFree(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); - DetectPortSpHashFree(de_ctx); - DetectPortDpHashFree(de_ctx); ThresholdContextDestroy(de_ctx); SigCleanSignatures(de_ctx); - - VariableNameFreeHash(de_ctx); + SCFree(de_ctx->app_mpms); + de_ctx->app_mpms = NULL; if (de_ctx->sig_array) SCFree(de_ctx->sig_array); @@ -911,11 +1041,33 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SigGroupCleanup(de_ctx); - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); - } + SpmDestroyGlobalThreadCtx(de_ctx->spm_global_thread_ctx); + + MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); DetectEngineCtxFreeThreadKeywordData(de_ctx); + SRepDestroy(de_ctx); + + DetectAddressMapFree(de_ctx); + + /* if we have a config prefix, remove the config from the tree */ + if (strlen(de_ctx->config_prefix) > 0) { + /* remove config */ + ConfNode *node = ConfGetNode(de_ctx->config_prefix); + if (node != NULL) { + ConfNodeRemove(node); /* frees node */ + } +#if 0 + ConfDump(); +#endif + } + + DetectPortCleanupList(de_ctx->tcp_whitelist); + DetectPortCleanupList(de_ctx->udp_whitelist); + + /* freed our var name hash */ + VarNameStoreFree(de_ctx->version); + SCFree(de_ctx); //DetectAddressGroupPrintMemory(); //DetectSigGroupPrintMemory(); @@ -927,32 +1079,32 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) * \retval 0 if no config provided, 1 if config was provided * and loaded successfuly */ -static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) +static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) { uint8_t profile = ENGINE_PROFILE_UNKNOWN; + char *max_uniq_toclient_groups_str = NULL; + char *max_uniq_toserver_groups_str = NULL; + char *sgh_mpm_context = NULL; char *de_ctx_profile = NULL; - const char *max_uniq_toclient_src_groups_str = NULL; - const char *max_uniq_toclient_dst_groups_str = NULL; - const char *max_uniq_toclient_sp_groups_str = NULL; - const char *max_uniq_toclient_dp_groups_str = NULL; - - const char *max_uniq_toserver_src_groups_str = NULL; - const char *max_uniq_toserver_dst_groups_str = NULL; - const char *max_uniq_toserver_sp_groups_str = NULL; - const char *max_uniq_toserver_dp_groups_str = NULL; - - char *sgh_mpm_context = NULL; + (void)ConfGet("detect.profile", &de_ctx_profile); + (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context); ConfNode *de_ctx_custom = ConfGetNode("detect-engine"); ConfNode *opt = NULL; if (de_ctx_custom != NULL) { TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { - if (strcmp(opt->val, "profile") == 0) { - de_ctx_profile = opt->head.tqh_first->val; - } else if (strcmp(opt->val, "sgh-mpm-context") == 0) { - sgh_mpm_context = opt->head.tqh_first->val; + if (de_ctx_profile == NULL) { + if (strcmp(opt->val, "profile") == 0) { + de_ctx_profile = opt->head.tqh_first->val; + } + } + + if (sgh_mpm_context == NULL) { + if (strcmp(opt->val, "sgh-mpm-context") == 0) { + sgh_mpm_context = opt->head.tqh_first->val; + } } } } @@ -978,7 +1130,10 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) { /* for now, since we still haven't implemented any intelligence into * understanding the patterns and distributing mpm_ctx across sgh */ - if (de_ctx->mpm_matcher == DEFAULT_MPM || de_ctx->mpm_matcher == MPM_AC_GFBS || + if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_TILE || +#ifdef BUILD_HYPERSCAN + de_ctx->mpm_matcher == MPM_HS || +#endif #ifdef __SC_CUDA_SUPPORT__ de_ctx->mpm_matcher == MPM_AC_BS || de_ctx->mpm_matcher == MPM_AC_CUDA) { #else @@ -1014,176 +1169,210 @@ static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) de_ctx->sgh_mpm_context = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL; } + /* parse profile custom-values */ opt = NULL; switch (profile) { case ENGINE_PROFILE_LOW: - de_ctx->max_uniq_toclient_src_groups = 2; - de_ctx->max_uniq_toclient_dst_groups = 2; - de_ctx->max_uniq_toclient_sp_groups = 2; - de_ctx->max_uniq_toclient_dp_groups = 3; - de_ctx->max_uniq_toserver_src_groups = 2; - de_ctx->max_uniq_toserver_dst_groups = 2; - de_ctx->max_uniq_toserver_sp_groups = 2; - de_ctx->max_uniq_toserver_dp_groups = 3; + de_ctx->max_uniq_toclient_groups = 15; + de_ctx->max_uniq_toserver_groups = 25; break; case ENGINE_PROFILE_HIGH: - de_ctx->max_uniq_toclient_src_groups = 15; - de_ctx->max_uniq_toclient_dst_groups = 15; - de_ctx->max_uniq_toclient_sp_groups = 15; - de_ctx->max_uniq_toclient_dp_groups = 20; - de_ctx->max_uniq_toserver_src_groups = 15; - de_ctx->max_uniq_toserver_dst_groups = 15; - de_ctx->max_uniq_toserver_sp_groups = 15; - de_ctx->max_uniq_toserver_dp_groups = 40; + de_ctx->max_uniq_toclient_groups = 75; + de_ctx->max_uniq_toserver_groups = 75; break; case ENGINE_PROFILE_CUSTOM: - TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { - if (strcmp(opt->val, "custom-values") == 0) { - max_uniq_toclient_src_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-src-groups"); - max_uniq_toclient_dst_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-dst-groups"); - max_uniq_toclient_sp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-sp-groups"); - max_uniq_toclient_dp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toclient-dp-groups"); - max_uniq_toserver_src_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-src-groups"); - max_uniq_toserver_dst_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-dst-groups"); - max_uniq_toserver_sp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-sp-groups"); - max_uniq_toserver_dp_groups_str = ConfNodeLookupChildValue - (opt->head.tqh_first, "toserver-dp-groups"); - } - } - if (max_uniq_toclient_src_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_src_groups, 10, - strlen(max_uniq_toclient_src_groups_str), - (const char *)max_uniq_toclient_src_groups_str) <= 0) { - de_ctx->max_uniq_toclient_src_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-src-groups failed, using %u", - max_uniq_toclient_src_groups_str, - de_ctx->max_uniq_toclient_src_groups); - } - } else { - de_ctx->max_uniq_toclient_src_groups = 4; - } - if (max_uniq_toclient_dst_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dst_groups, 10, - strlen(max_uniq_toclient_dst_groups_str), - (const char *)max_uniq_toclient_dst_groups_str) <= 0) { - de_ctx->max_uniq_toclient_dst_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-dst-groups failed, using %u", - max_uniq_toclient_dst_groups_str, - de_ctx->max_uniq_toclient_dst_groups); - } - } else { - de_ctx->max_uniq_toclient_dst_groups = 4; - } - if (max_uniq_toclient_sp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_sp_groups, 10, - strlen(max_uniq_toclient_sp_groups_str), - (const char *)max_uniq_toclient_sp_groups_str) <= 0) { - de_ctx->max_uniq_toclient_sp_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-sp-groups failed, using %u", - max_uniq_toclient_sp_groups_str, - de_ctx->max_uniq_toclient_sp_groups); - } - } else { - de_ctx->max_uniq_toclient_sp_groups = 4; - } - if (max_uniq_toclient_dp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dp_groups, 10, - strlen(max_uniq_toclient_dp_groups_str), - (const char *)max_uniq_toclient_dp_groups_str) <= 0) { - de_ctx->max_uniq_toclient_dp_groups = 6; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toclient-dp-groups failed, using %u", - max_uniq_toclient_dp_groups_str, - de_ctx->max_uniq_toclient_dp_groups); + (void)ConfGet("detect.custom-values.toclient-groups", + &max_uniq_toclient_groups_str); + (void)ConfGet("detect.custom-values.toserver-groups", + &max_uniq_toserver_groups_str); + + if (de_ctx_custom != NULL) { + TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + if (strcmp(opt->val, "custom-values") == 0) { + if (max_uniq_toclient_groups_str == NULL) { + max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toclient-sp-groups"); + } + if (max_uniq_toclient_groups_str == NULL) { + max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toclient-groups"); + } + if (max_uniq_toserver_groups_str == NULL) { + max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toserver-dp-groups"); + } + if (max_uniq_toserver_groups_str == NULL) { + max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue + (opt->head.tqh_first, "toserver-groups"); + } + } } - } else { - de_ctx->max_uniq_toclient_dp_groups = 6; } - if (max_uniq_toserver_src_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_src_groups, 10, - strlen(max_uniq_toserver_src_groups_str), - (const char *)max_uniq_toserver_src_groups_str) <= 0) { - de_ctx->max_uniq_toserver_src_groups = 4; + if (max_uniq_toclient_groups_str != NULL) { + if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_groups, 10, + strlen(max_uniq_toclient_groups_str), + (const char *)max_uniq_toclient_groups_str) <= 0) + { + de_ctx->max_uniq_toclient_groups = 20; + SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-src-groups failed, using %u", - max_uniq_toserver_src_groups_str, - de_ctx->max_uniq_toserver_src_groups); + "toclient-groups failed, using %u", + max_uniq_toclient_groups_str, + de_ctx->max_uniq_toclient_groups); } } else { - de_ctx->max_uniq_toserver_src_groups = 4; + de_ctx->max_uniq_toclient_groups = 20; } - if (max_uniq_toserver_dst_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dst_groups, 10, - strlen(max_uniq_toserver_dst_groups_str), - (const char *)max_uniq_toserver_dst_groups_str) <= 0) { - de_ctx->max_uniq_toserver_dst_groups = 8; + SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups); + + if (max_uniq_toserver_groups_str != NULL) { + if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_groups, 10, + strlen(max_uniq_toserver_groups_str), + (const char *)max_uniq_toserver_groups_str) <= 0) + { + de_ctx->max_uniq_toserver_groups = 40; + SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-dst-groups failed, using %u", - max_uniq_toserver_dst_groups_str, - de_ctx->max_uniq_toserver_dst_groups); + "toserver-groups failed, using %u", + max_uniq_toserver_groups_str, + de_ctx->max_uniq_toserver_groups); } } else { - de_ctx->max_uniq_toserver_dst_groups = 8; - } - if (max_uniq_toserver_sp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_sp_groups, 10, - strlen(max_uniq_toserver_sp_groups_str), - (const char *)max_uniq_toserver_sp_groups_str) <= 0) { - de_ctx->max_uniq_toserver_sp_groups = 4; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-sp-groups failed, using %u", - max_uniq_toserver_sp_groups_str, - de_ctx->max_uniq_toserver_sp_groups); - } - } else { - de_ctx->max_uniq_toserver_sp_groups = 4; - } - if (max_uniq_toserver_dp_groups_str != NULL) { - if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dp_groups, 10, - strlen(max_uniq_toserver_dp_groups_str), - (const char *)max_uniq_toserver_dp_groups_str) <= 0) { - de_ctx->max_uniq_toserver_dp_groups = 30; - SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for " - "toserver-dp-groups failed, using %u", - max_uniq_toserver_dp_groups_str, - de_ctx->max_uniq_toserver_dp_groups); - } - } else { - de_ctx->max_uniq_toserver_dp_groups = 30; + de_ctx->max_uniq_toserver_groups = 40; } + SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups); break; /* Default (or no config provided) is profile medium */ case ENGINE_PROFILE_MEDIUM: case ENGINE_PROFILE_UNKNOWN: default: - de_ctx->max_uniq_toclient_src_groups = 4; - de_ctx->max_uniq_toclient_dst_groups = 4; - de_ctx->max_uniq_toclient_sp_groups = 4; - de_ctx->max_uniq_toclient_dp_groups = 6; - - de_ctx->max_uniq_toserver_src_groups = 4; - de_ctx->max_uniq_toserver_dst_groups = 8; - de_ctx->max_uniq_toserver_sp_groups = 4; - de_ctx->max_uniq_toserver_dp_groups = 30; + de_ctx->max_uniq_toclient_groups = 20; + de_ctx->max_uniq_toserver_groups = 40; break; } - if (profile == ENGINE_PROFILE_UNKNOWN) - return 0; - return 1; + if (profile == ENGINE_PROFILE_UNKNOWN) { + goto error; + } + + intmax_t value = 0; + if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1) + { + if (value >= 0 && value <= INT_MAX) { + de_ctx->inspection_recursion_limit = (int)value; + } + + /* fall back to old config parsing */ + } else { + ConfNode *insp_recursion_limit_node = NULL; + char *insp_recursion_limit = NULL; + + if (de_ctx_custom != NULL) { + opt = NULL; + TAILQ_FOREACH(opt, &de_ctx_custom->head, next) { + if (strcmp(opt->val, "inspection-recursion-limit") != 0) + continue; + + insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val); + if (insp_recursion_limit_node == NULL) { + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf " + "entry for detect-engine:inspection-recursion-limit"); + break; + } + insp_recursion_limit = insp_recursion_limit_node->val; + SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s", + insp_recursion_limit_node->name, insp_recursion_limit_node->val); + break; + } + + if (insp_recursion_limit != NULL) { + de_ctx->inspection_recursion_limit = atoi(insp_recursion_limit); + } else { + de_ctx->inspection_recursion_limit = + DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT; + } + } + } + + if (de_ctx->inspection_recursion_limit == 0) + de_ctx->inspection_recursion_limit = -1; + + SCLogDebug("de_ctx->inspection_recursion_limit: %d", + de_ctx->inspection_recursion_limit); + + /* parse port grouping whitelisting settings */ + + char *ports = NULL; + (void)ConfGet("detect.grouping.tcp-whitelist", &ports); + if (ports) { + SCLogConfig("grouping: tcp-whitelist %s", ports); + } else { + ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080"; + SCLogConfig("grouping: tcp-whitelist (default) %s", ports); + + } + if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "for detect.grouping.tcp-whitelist", ports); + } + DetectPort *x = de_ctx->tcp_whitelist; + for ( ; x != NULL; x = x->next) { + if (x->port != x->port2) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "for detect.grouping.tcp-whitelist: only single ports allowed", ports); + DetectPortCleanupList(de_ctx->tcp_whitelist); + de_ctx->tcp_whitelist = NULL; + break; + } + } + + ports = NULL; + (void)ConfGet("detect.grouping.udp-whitelist", &ports); + if (ports) { + SCLogConfig("grouping: udp-whitelist %s", ports); + } else { + ports = "53, 135, 5060"; + SCLogConfig("grouping: udp-whitelist (default) %s", ports); + + } + if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "forr detect.grouping.udp-whitelist", ports); + } + for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) { + if (x->port != x->port2) { + SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value " + "for detect.grouping.udp-whitelist: only single ports allowed", ports); + DetectPortCleanupList(de_ctx->udp_whitelist); + de_ctx->udp_whitelist = NULL; + break; + } + } + + de_ctx->prefilter_setting = DETECT_PREFILTER_MPM; + char *pf_setting = NULL; + if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) { + if (strcasecmp(pf_setting, "mpm") == 0) { + de_ctx->prefilter_setting = DETECT_PREFILTER_MPM; + } else if (strcasecmp(pf_setting, "auto") == 0) { + de_ctx->prefilter_setting = DETECT_PREFILTER_AUTO; + } + } + switch (de_ctx->prefilter_setting) { + case DETECT_PREFILTER_MPM: + SCLogConfig("prefilter engines: MPM"); + break; + case DETECT_PREFILTER_AUTO: + SCLogConfig("prefilter engines: MPM and keywords"); + break; + } + + return 0; +error: + return -1; } /* @@ -1200,6 +1389,62 @@ void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx) de_ctx->signum = 0; } +static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->keyword_id > 0) { + det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *)); + if (det_ctx->global_keyword_ctxs_array == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx"); + goto error; + } + det_ctx->global_keyword_ctxs_size = master->keyword_id; + + DetectEngineThreadKeywordCtxItem *item = master->keyword_list; + while (item) { + det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data); + if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx " + "for keyword \"%s\" failed", item->name); + goto error; + } + item = item->next; + } + } + SCMutexUnlock(&master->lock); + return TM_ECODE_OK; +error: + SCMutexUnlock(&master->lock); + return TM_ECODE_FAILED; +} + +static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->global_keyword_ctxs_array == NULL || + det_ctx->global_keyword_ctxs_size == 0) { + return; + } + + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->keyword_id > 0) { + DetectEngineThreadKeywordCtxItem *item = master->keyword_list; + while (item) { + if (det_ctx->global_keyword_ctxs_array[item->id] != NULL) + item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]); + + item = item->next; + } + det_ctx->global_keyword_ctxs_size = 0; + SCFree(det_ctx->global_keyword_ctxs_array); + det_ctx->global_keyword_ctxs_array = NULL; + } + SCMutexUnlock(&master->lock); +} + static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { if (de_ctx->keyword_id > 0) { @@ -1243,26 +1488,139 @@ static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectE } } +/** NOTE: master MUST be locked before calling this */ +static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + DetectEngineTenantMapping *map_array = NULL; + uint32_t map_array_size = 0; + uint32_t map_cnt = 0; + int max_tenant_id = 0; + DetectEngineCtx *list = master->list; + HashTable *mt_det_ctxs_hash = NULL; + + if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { + SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: " + "set using multi-detect.selector"); + return TM_ECODE_FAILED; + } + + uint32_t tcnt = 0; + while (list) { + if (list->tenant_id > max_tenant_id) + max_tenant_id = list->tenant_id; + + list = list->next; + tcnt++; + } + + mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree); + if (mt_det_ctxs_hash == NULL) { + goto error; + } + + if (max_tenant_id == 0) { + SCLogInfo("no tenants left, or none registered yet"); + } else { + max_tenant_id++; + + DetectEngineTenantMapping *map = master->tenant_mapping_list; + while (map) { + map_cnt++; + map = map->next; + } + + if (map_cnt > 0) { + map_array_size = map_cnt + 1; + + map_array = SCCalloc(map_array_size, sizeof(*map_array)); + if (map_array == NULL) + goto error; + + /* fill the array */ + map_cnt = 0; + map = master->tenant_mapping_list; + while (map) { + if (map_cnt >= map_array_size) { + goto error; + } + map_array[map_cnt].traffic_id = map->traffic_id; + map_array[map_cnt].tenant_id = map->tenant_id; + map_cnt++; + map = map->next; + } + + } + + /* set up hash for tenant lookup */ + list = master->list; + while (list) { + SCLogDebug("tenant-id %u", list->tenant_id); + if (list->tenant_id != 0) { + DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0); + if (mt_det_ctx == NULL) + goto error; + if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) { + goto error; + } + } + list = list->next; + } + } + + det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash; + mt_det_ctxs_hash = NULL; + + det_ctx->mt_det_ctxs_cnt = max_tenant_id; + + det_ctx->tenant_array = map_array; + det_ctx->tenant_array_size = map_array_size; + + switch (master->tenant_selector) { + case TENANT_SELECTOR_UNKNOWN: + SCLogDebug("TENANT_SELECTOR_UNKNOWN"); + break; + case TENANT_SELECTOR_VLAN: + det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId; + SCLogDebug("TENANT_SELECTOR_VLAN"); + break; + case TENANT_SELECTOR_DIRECT: + det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap; + SCLogDebug("TENANT_SELECTOR_DIRECT"); + break; + } + + return TM_ECODE_OK; +error: + if (map_array != NULL) + SCFree(map_array); + if (mt_det_ctxs_hash != NULL) + HashTableFree(mt_det_ctxs_hash); + + return TM_ECODE_FAILED; +} + /** \internal * \brief Helper for DetectThread setup functions */ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx) { - int i; + PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher); + PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher); + PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher); - /** \todo we still depend on the global mpm_ctx here - * - * Initialize the thread pattern match ctx with the max size - * of the content and uricontent id's so our match lookup - * table is always big enough - */ - PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); - PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); - PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx)); + PmqSetup(&det_ctx->pmq); - PmqSetup(&det_ctx->pmq, de_ctx->max_fp_id); - for (i = 0; i < DETECT_SMSG_PMQ_NUM; i++) { - PmqSetup(&det_ctx->smsg_pmq[i], de_ctx->max_fp_id); + det_ctx->spm_thread_ctx = SpmMakeThreadCtx(de_ctx->spm_global_thread_ctx); + if (det_ctx->spm_thread_ctx == NULL) { + return TM_ECODE_FAILED; + } + + /* sized to the max of our sgh settings. A max setting of 0 implies that all + * sgh's have: sgh->non_pf_store_cnt == 0 */ + if (de_ctx->non_pf_store_cnt_max > 0) { + det_ctx->non_pf_id_array = SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId)); + BUG_ON(det_ctx->non_pf_id_array == NULL); } /* IP-ONLY */ @@ -1294,10 +1652,22 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * return TM_ECODE_FAILED; } + /* Allocate space for base64 decoded data. */ + if (de_ctx->base64_decode_max_len) { + det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len); + if (det_ctx->base64_decoded == NULL) { + return TM_ECODE_FAILED; + } + det_ctx->base64_decoded_len_max = de_ctx->base64_decode_max_len; + det_ctx->base64_decoded_len = 0; + } + DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx); + DetectEngineThreadCtxInitGlobalKeywords(det_ctx); #ifdef PROFILING SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx); SCProfilingKeywordThreadSetup(de_ctx->profile_keyword_ctx, det_ctx); + SCProfilingSghThreadSetup(de_ctx->profile_sgh_ctx, det_ctx); #endif SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect); @@ -1323,219 +1693,1235 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * */ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { - DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata; - if (de_ctx == NULL) - return TM_ECODE_FAILED; - /* first register the counter. In delayed detect mode we exit right after if the * rules haven't been loaded yet. */ - uint16_t counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, - SC_PERF_TYPE_UINT64, "NULL"); - if (de_ctx->delayed_detect == 1 && de_ctx->delayed_detect_initialized == 0) { - *data = NULL; - return TM_ECODE_OK; + uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv); +#ifdef PROFILING + uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv); + uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv); + uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv); + uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv); +#endif + DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); + if (unlikely(det_ctx == NULL)) + return TM_ECODE_FAILED; + memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); + + det_ctx->tv = tv; + det_ctx->de_ctx = DetectEngineGetCurrent(); + if (det_ctx->de_ctx == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) { + det_ctx->de_ctx = (DetectEngineCtx *)initdata; + } else { + DetectEngineThreadCtxDeinit(tv, det_ctx); + return TM_ECODE_FAILED; + } +#else + DetectEngineThreadCtxDeinit(tv, det_ctx); + return TM_ECODE_FAILED; +#endif + } + + if (det_ctx->de_ctx->minimal == 0) { + if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { + DetectEngineThreadCtxDeinit(tv, det_ctx); + return TM_ECODE_FAILED; + } + } + + /** alert counter setup */ + det_ctx->counter_alerts = counter_alerts; +#ifdef PROFILING + det_ctx->counter_mpm_list = counter_mpm_list; + det_ctx->counter_nonmpm_list = counter_nonmpm_list; + det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; + det_ctx->counter_match_list = counter_match_list; +#endif + + /* pass thread data back to caller */ + *data = (void *)det_ctx; + + if (DetectEngineMultiTenantEnabled()) { + if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) + return TM_ECODE_FAILED; } + return TM_ECODE_OK; +} + +/** + * \internal + * \brief initialize a det_ctx for reload cases + * \param new_de_ctx the new detection engine + * \param mt flag to indicate if MT should be set up for this det_ctx + * this should only be done for the 'root' det_ctx + * + * \retval det_ctx detection engine thread ctx or NULL in case of error + */ +static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload( + ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt) +{ DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); if (unlikely(det_ctx == NULL)) - return TM_ECODE_FAILED; + return NULL; memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); + det_ctx->tenant_id = new_de_ctx->tenant_id; det_ctx->tv = tv; - det_ctx->de_ctx = de_ctx; + det_ctx->de_ctx = DetectEngineReference(new_de_ctx); + if (det_ctx->de_ctx == NULL) { + SCFree(det_ctx); + return NULL; + } - if (ThreadCtxDoInit(de_ctx, det_ctx) != TM_ECODE_OK) - return TM_ECODE_FAILED; + /* most of the init happens here */ + if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) { + DetectEngineDeReference(&det_ctx->de_ctx); + SCFree(det_ctx); + return NULL; + } + + /** alert counter setup */ + det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv); +#ifdef PROFILING + uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv); + uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv); + uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv); + uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv); + det_ctx->counter_mpm_list = counter_mpm_list; + det_ctx->counter_nonmpm_list = counter_nonmpm_list; + det_ctx->counter_fnonmpm_list = counter_fnonmpm_list; + det_ctx->counter_match_list = counter_match_list; +#endif + + if (mt && DetectEngineMultiTenantEnabled()) { + if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) { + DetectEngineDeReference(&det_ctx->de_ctx); + SCFree(det_ctx); + return NULL; + } + } + + return det_ctx; +} + +void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx->tenant_array != NULL) { + SCFree(det_ctx->tenant_array); + det_ctx->tenant_array = NULL; + } + +#ifdef PROFILING + SCProfilingRuleThreadCleanup(det_ctx); + SCProfilingKeywordThreadCleanup(det_ctx); + SCProfilingSghThreadCleanup(det_ctx); +#endif + + DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx); + + /** \todo get rid of this static */ + if (det_ctx->de_ctx != NULL) { + PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); + PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher); + PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); + } + + PmqFree(&det_ctx->pmq); + + if (det_ctx->spm_thread_ctx != NULL) { + SpmDestroyThreadCtx(det_ctx->spm_thread_ctx); + } + + if (det_ctx->non_pf_id_array != NULL) + SCFree(det_ctx->non_pf_id_array); + + if (det_ctx->de_state_sig_array != NULL) + SCFree(det_ctx->de_state_sig_array); + if (det_ctx->match_array != NULL) + SCFree(det_ctx->match_array); + + if (det_ctx->bj_values != NULL) + SCFree(det_ctx->bj_values); + + /* HSBD */ + if (det_ctx->hsbd != NULL) { + SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_size); + SCFree(det_ctx->hsbd); + } + + /* HSCB */ + if (det_ctx->hcbd != NULL) { + SCLogDebug("det_ctx hcbd %u", det_ctx->hcbd_buffers_size); + SCFree(det_ctx->hcbd); + } + + /* SMTP */ + if (det_ctx->smtp != NULL) { + SCLogDebug("det_ctx smtp %u", det_ctx->smtp_buffers_size); + SCFree(det_ctx->smtp); + } + + /* Decoded base64 data. */ + if (det_ctx->base64_decoded != NULL) { + SCFree(det_ctx->base64_decoded); + } + + DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx); + if (det_ctx->de_ctx != NULL) { + DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); +#ifdef UNITTESTS + if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0) + DetectEngineDeReference(&det_ctx->de_ctx); +#else + DetectEngineDeReference(&det_ctx->de_ctx); +#endif + } + SCFree(det_ctx); +} + +TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) +{ + DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; + + if (det_ctx == NULL) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL"); + return TM_ECODE_OK; + } + + if (det_ctx->mt_det_ctxs_hash != NULL) { + HashTableFree(det_ctx->mt_det_ctxs_hash); + det_ctx->mt_det_ctxs_hash = NULL; + } + DetectEngineThreadCtxFree(det_ctx); + + return TM_ECODE_OK; +} + +void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx) +{ + /* XXX */ + PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); + PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); +} + +/** \brief Register Thread keyword context Funcs + * + * \param de_ctx detection engine to register in + * \param name keyword name for error printing + * \param InitFunc function ptr + * \param data keyword init data to pass to Func + * \param FreeFunc function ptr + * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct) + * + * \retval id for retrieval of ctx at runtime + * \retval -1 on error + * + * \note make sure "data" remains valid and it free'd elsewhere. It's + * recommended to store it in the keywords global ctx so that + * it's freed when the de_ctx is freed. + */ +int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode) +{ + BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL || data == NULL); + + if (mode) { + DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list; + while (item != NULL) { + if (strcmp(name, item->name) == 0) { + return item->id; + } + + item = item->next; + } + } + + DetectEngineThreadKeywordCtxItem *item = SCMalloc(sizeof(DetectEngineThreadKeywordCtxItem)); + if (unlikely(item == NULL)) + return -1; + memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem)); + + item->InitFunc = InitFunc; + item->FreeFunc = FreeFunc; + item->data = data; + item->name = name; + + item->next = de_ctx->keyword_list; + de_ctx->keyword_list = item; + item->id = de_ctx->keyword_id++; + + return item->id; +} + +/** \brief Retrieve thread local keyword ctx by id + * + * \param det_ctx detection engine thread ctx to retrieve the ctx from + * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at + * keyword init. + * + * \retval ctx or NULL on error + */ +void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) +{ + if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL) + return NULL; + + return det_ctx->keyword_ctxs_array[id]; +} + + +/** \brief Register Thread keyword context Funcs (Global) + * + * IDs stay static over reloads and between tenants + * + * \param name keyword name for error printing + * \param InitFunc function ptr + * \param FreeFunc function ptr + * + * \retval id for retrieval of ctx at runtime + * \retval -1 on error + */ +int DetectRegisterThreadCtxGlobalFuncs(const char *name, + void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)) +{ + int id; + BUG_ON(InitFunc == NULL || FreeFunc == NULL); + + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + /* if already registered, return existing id */ + DetectEngineThreadKeywordCtxItem *item = master->keyword_list; + while (item != NULL) { + if (strcmp(name, item->name) == 0) { + id = item->id; + SCMutexUnlock(&master->lock); + return id; + } + + item = item->next; + } + + item = SCCalloc(1, sizeof(*item)); + if (unlikely(item == NULL)) { + SCMutexUnlock(&master->lock); + return -1; + } + item->InitFunc = InitFunc; + item->FreeFunc = FreeFunc; + item->name = name; + item->data = data; + + item->next = master->keyword_list; + master->keyword_list = item; + item->id = master->keyword_id++; + + id = item->id; + SCMutexUnlock(&master->lock); + return id; +} + +/** \brief Retrieve thread local keyword ctx by id + * + * \param det_ctx detection engine thread ctx to retrieve the ctx from + * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at + * keyword init. + * + * \retval ctx or NULL on error + */ +void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) +{ + if (id < 0 || id > det_ctx->global_keyword_ctxs_size || + det_ctx->global_keyword_ctxs_array == NULL) { + return NULL; + } + + return det_ctx->global_keyword_ctxs_array[id]; +} + +/** \brief Check if detection is enabled + * \retval bool true or false */ +int DetectEngineEnabled(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->list == NULL) { + SCMutexUnlock(&master->lock); + return 0; + } + + SCMutexUnlock(&master->lock); + return 1; +} + +uint32_t DetectEngineGetVersion(void) +{ + uint32_t version; + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + version = master->version; + SCMutexUnlock(&master->lock); + return version; +} + +void DetectEngineBumpVersion(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + master->version++; + SCLogDebug("master version now %u", master->version); + SCMutexUnlock(&master->lock); +} + +DetectEngineCtx *DetectEngineGetCurrent(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->list == NULL) { + SCMutexUnlock(&master->lock); + return NULL; + } + + master->list->ref_cnt++; + SCLogDebug("master->list %p ref_cnt %u", master->list, master->list->ref_cnt); + SCMutexUnlock(&master->lock); + return master->list; +} + +DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx) +{ + if (de_ctx == NULL) + return NULL; + de_ctx->ref_cnt++; + return de_ctx; +} + +/** TODO locking? Not needed if this is a one time setting at startup */ +int DetectEngineMultiTenantEnabled(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + return (master->multi_tenant_enabled); +} + +/** \internal + * \brief load a tenant from a yaml file + * + * \param tenant_id the tenant id by which the config is known + * \param filename full path of a yaml file + * \param loader_id id of loader thread or -1 + * + * \retval 0 ok + * \retval -1 failed + */ +static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id) +{ + DetectEngineCtx *de_ctx = NULL; + char prefix[64]; + + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + +#ifdef OS_WIN32 + struct _stat st; + if(_stat(filename, &st) != 0) { +#else + struct stat st; + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename); + goto error; + } + + de_ctx = DetectEngineGetByTenantId(tenant_id); + if (de_ctx != NULL) { + SCLogError(SC_ERR_MT_DUPLICATE_TENANT, "tenant %u already registered", + tenant_id); + DetectEngineDeReference(&de_ctx); + goto error; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + goto error; + } + + de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + goto error; + } + SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix); + + de_ctx->tenant_id = tenant_id; + de_ctx->loader_id = loader_id; + + if (SigLoadSignatures(de_ctx, NULL, 0) < 0) { + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); + goto error; + } + + DetectEngineAddToMaster(de_ctx); + + return 0; + +error: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + return -1; +} + +static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt) +{ + DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); + if (old_de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "tenant detect engine not found"); + return -1; + } + + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt); + reload_cnt++; + SCLogDebug("prefix %s", prefix); + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml"); + goto error; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename); + goto error; + } + + DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (new_de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + goto error; + } + SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix); + + new_de_ctx->tenant_id = tenant_id; + new_de_ctx->loader_id = old_de_ctx->loader_id; + + if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) { + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); + goto error; + } + + DetectEngineAddToMaster(new_de_ctx); + + /* move to free list */ + DetectEngineMoveToFreeList(old_de_ctx); + DetectEngineDeReference(&old_de_ctx); + return 0; + +error: + DetectEngineDeReference(&old_de_ctx); + return -1; +} + + +typedef struct TenantLoaderCtx_ { + uint32_t tenant_id; + int reload_cnt; /**< used by reload */ + const char *yaml; +} TenantLoaderCtx; + +static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id) +{ + TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx; + + SCLogDebug("loader %d", loader_id); + if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) { + return -1; + } + return 0; +} + +int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml) +{ + TenantLoaderCtx *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->tenant_id = tenant_id; + t->yaml = yaml; + + return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t); +} + +static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id) +{ + TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx; + + SCLogDebug("loader_id %d", loader_id); + + if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) { + return -1; + } + return 0; +} + +int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt) +{ + DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id); + if (old_de_ctx == NULL) + return -ENOENT; + int loader_id = old_de_ctx->loader_id; + DetectEngineDeReference(&old_de_ctx); + + TenantLoaderCtx *t = SCCalloc(1, sizeof(*t)); + if (t == NULL) + return -ENOMEM; + + t->tenant_id = tenant_id; + t->yaml = yaml; + t->reload_cnt = reload_cnt; + + SCLogDebug("loader_id %d", loader_id); + + return DetectLoaderQueueTask(loader_id, DetectLoaderFuncReloadTenant, t); +} + +/** \brief Load a tenant and wait for loading to complete + */ +int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml) +{ + int r = DetectLoaderSetupLoadTenant(tenant_id, yaml); + if (r < 0) + return r; + + if (DetectLoadersSync() != 0) + return -1; + + return 0; +} + +/** \brief Reload a tenant and wait for loading to complete + */ +int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt) +{ + int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt); + if (r < 0) + return r; + + if (DetectLoadersSync() != 0) + return -1; + + return 0; +} + +/** + * \brief setup multi-detect / multi-tenancy + * + * See if MT is enabled. If so, setup the selector, tenants and mappings. + * Tenants and mappings are optional, and can also dynamically be added + * and removed from the unix socket. + */ +int DetectEngineMultiTenantSetup(void) +{ + enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN; + DetectEngineMasterCtx *master = &g_master_de_ctx; + + int unix_socket = ConfUnixSocketIsEnable(); + + int failure_fatal = 0; + (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal); + + int enabled = 0; + (void)ConfGetBool("multi-detect.enabled", &enabled); + if (enabled == 1) { + DetectLoadersInit(); + TmModuleDetectLoaderRegister(); + DetectLoaderThreadSpawn(); + TmThreadContinueDetectLoaderThreads(); + + SCMutexLock(&master->lock); + master->multi_tenant_enabled = 1; + + char *handler = NULL; + if (ConfGet("multi-detect.selector", &handler) == 1) { + SCLogConfig("multi-tenant selector type %s", handler); + + if (strcmp(handler, "vlan") == 0) { + tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN; + + int vlanbool = 0; + if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, " + "can't use multi-detect selector 'vlan'"); + SCMutexUnlock(&master->lock); + goto error; + } + + } else if (strcmp(handler, "direct") == 0) { + tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT; + } else { + SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s " + "multi-detect.selector", handler); + SCMutexUnlock(&master->lock); + goto error; + } + } + SCMutexUnlock(&master->lock); + SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler); + + /* traffic -- tenant mappings */ + ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings"); + ConfNode *mapping_node = NULL; + + int mapping_cnt = 0; + if (mappings_root_node != NULL) { + TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) { + ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id"); + if (tenant_id_node == NULL) + goto bad_mapping; + ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id"); + if (vlan_id_node == NULL) + goto bad_mapping; + + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val), + tenant_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id " + "of %s is invalid", tenant_id_node->val); + goto bad_mapping; + } + + uint16_t vlan_id = 0; + if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val), + vlan_id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid", vlan_id_node->val); + goto bad_mapping; + } + if (vlan_id == 0 || vlan_id >= 4095) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id " + "of %s is invalid. Valid range 1-4094.", vlan_id_node->val); + goto bad_mapping; + } + + if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) { + goto error; + } + SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id); + mapping_cnt++; + continue; + + bad_mapping: + if (failure_fatal) + goto error; + } + } + + if (tenant_selector == TENANT_SELECTOR_VLAN && mapping_cnt == 0) { + /* no mappings are valid when we're in unix socket mode, + * they can be added on the fly. Otherwise warn/error + * depending on failure_fatal */ + + if (unix_socket) { + SCLogNotice("no tenant traffic mappings defined, " + "tenants won't be used until mappings are added"); + } else { + if (failure_fatal) { + SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); + goto error; + } else { + SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined"); + } + } + } + + /* tenants */ + ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants"); + ConfNode *tenant_node = NULL; + + if (tenants_root_node != NULL) { + TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) { + ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id"); + if (id_node == NULL) { + goto bad_tenant; + } + ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml"); + if (yaml_node == NULL) { + goto bad_tenant; + } + + uint32_t tenant_id = 0; + if (ByteExtractStringUint32(&tenant_id, 10, strlen(id_node->val), + id_node->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id " + "of %s is invalid", id_node->val); + goto bad_tenant; + } + SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val); + + /* setup the yaml in this loop so that it's not done by the loader + * threads. ConfYamlLoadFileWithPrefix is not thread safe. */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + if (ConfYamlLoadFileWithPrefix(yaml_node->val, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", yaml_node->val); + goto bad_tenant; + } + + int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val); + if (r < 0) { + /* error logged already */ + goto bad_tenant; + } + continue; + + bad_tenant: + if (failure_fatal) + goto error; + } + } + + /* wait for our loaders to complete their tasks */ + if (DetectLoadersSync() != 0) { + goto error; + } + + VarNameStoreActivateStaging(); + + } else { + SCLogDebug("multi-detect not enabled (multi tenancy)"); + } + return 0; +error: + return -1; +} + +static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p) +{ + const DetectEngineThreadCtx *det_ctx = ctx; + uint32_t x = 0; + uint32_t vlan_id = 0; + + if (p->vlan_idx == 0) + return 0; + + vlan_id = p->vlan_id[0]; + + if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0) + return 0; + + /* not very efficient, but for now we're targeting only limited amounts. + * Can use hash/tree approach later. */ + for (x = 0; x < det_ctx->tenant_array_size; x++) { + if (det_ctx->tenant_array[x].traffic_id == vlan_id) + return det_ctx->tenant_array[x].tenant_id; + } + + return 0; +} + +static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector, + uint32_t tenant_id, uint32_t traffic_id) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) { + SCLogInfo("conflicting selector already set"); + SCMutexUnlock(&master->lock); + return -1; + } + + DetectEngineTenantMapping *m = master->tenant_mapping_list; + while (m) { + if (m->traffic_id == traffic_id) { + SCLogInfo("traffic id already registered"); + SCMutexUnlock(&master->lock); + return -1; + } + m = m->next; + } + + DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map)); + if (map == NULL) { + SCLogInfo("memory fail"); + SCMutexUnlock(&master->lock); + return -1; + } + map->traffic_id = traffic_id; + map->tenant_id = tenant_id; + + map->next = master->tenant_mapping_list; + master->tenant_mapping_list = map; + + master->tenant_selector = selector; + + SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id); + SCMutexUnlock(&master->lock); + return 0; +} + +static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelectors selector, + uint32_t tenant_id, uint32_t traffic_id) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->tenant_mapping_list == NULL) { + SCMutexUnlock(&master->lock); + return -1; + } + + DetectEngineTenantMapping *prev = NULL; + DetectEngineTenantMapping *map = master->tenant_mapping_list; + while (map) { + if (map->traffic_id == traffic_id && + map->tenant_id == tenant_id) + { + if (prev != NULL) + prev->next = map->next; + else + master->tenant_mapping_list = map->next; + + map->next = NULL; + SCFree(map); + SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id); + SCMutexUnlock(&master->lock); + return 0; + } + prev = map; + map = map->next; + } + + SCMutexUnlock(&master->lock); + return -1; +} - /** alert counter setup */ - det_ctx->counter_alerts = counter_alerts; +int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id) +{ + return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); +} - /* pass thread data back to caller */ - *data = (void *)det_ctx; +int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id) +{ + return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id); +} - return TM_ECODE_OK; +int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id) +{ + SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); + return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); } -/** - * \internal - * \brief This thread is an exact duplicate of DetectEngineThreadCtxInit(), - * except that the counters API 2 calls doesn't let us use the same - * init function. Once we have the new counters API it should let - * us use the same init function. - */ -static TmEcode DetectEngineThreadCtxInitForLiveRuleSwap(ThreadVars *tv, void *initdata, void **data) +int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id) { - *data = NULL; + SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id); + return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0); +} - DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata; - if (de_ctx == NULL) - return TM_ECODE_FAILED; +static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p) +{ + return p->pcap_v.tenant_id; +} - DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx)); - if (unlikely(det_ctx == NULL)) - return TM_ECODE_FAILED; - memset(det_ctx, 0, sizeof(DetectEngineThreadCtx)); +DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); - det_ctx->tv = tv; - det_ctx->de_ctx = de_ctx; + if (master->list == NULL) { + SCMutexUnlock(&master->lock); + return NULL; + } - if (ThreadCtxDoInit(de_ctx, det_ctx) != TM_ECODE_OK) - return TM_ECODE_FAILED; + DetectEngineCtx *de_ctx = master->list; + while (de_ctx) { + if (de_ctx->tenant_id == tenant_id) { + de_ctx->ref_cnt++; + break; + } - /** alert counter setup */ - det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv, - SC_PERF_TYPE_UINT64, "NULL"); - /* no counter creation here */ + de_ctx = de_ctx->next; + } - /* pass thread data back to caller */ - *data = (void *)det_ctx; + SCMutexUnlock(&master->lock); + return de_ctx; +} - return TM_ECODE_OK; +void DetectEngineDeReference(DetectEngineCtx **de_ctx) +{ + BUG_ON((*de_ctx)->ref_cnt == 0); + (*de_ctx)->ref_cnt--; + *de_ctx = NULL; } -TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) +static int DetectEngineAddToList(DetectEngineCtx *instance) { - DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; + DetectEngineMasterCtx *master = &g_master_de_ctx; - if (det_ctx == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL"); - return TM_ECODE_OK; + if (instance == NULL) + return -1; + + if (master->list == NULL) { + master->list = instance; + } else { + instance->next = master->list; + master->list = instance; } -#ifdef PROFILING - SCProfilingRuleThreadCleanup(det_ctx); - SCProfilingKeywordThreadCleanup(det_ctx); -#endif + return 0; +} - DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx); +int DetectEngineAddToMaster(DetectEngineCtx *de_ctx) +{ + int r; - /** \todo get rid of this static */ - PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); - PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher); - PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); + if (de_ctx == NULL) + return -1; - PmqFree(&det_ctx->pmq); - int i; - for (i = 0; i < DETECT_SMSG_PMQ_NUM; i++) { - PmqFree(&det_ctx->smsg_pmq[i]); - } + SCLogDebug("adding de_ctx %p to master", de_ctx); - if (det_ctx->de_state_sig_array != NULL) - SCFree(det_ctx->de_state_sig_array); - if (det_ctx->match_array != NULL) - SCFree(det_ctx->match_array); + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + r = DetectEngineAddToList(de_ctx); + SCMutexUnlock(&master->lock); + return r; +} - if (det_ctx->bj_values != NULL) - SCFree(det_ctx->bj_values); +int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; - /* HHD temp storage */ - for (i = 0; i < det_ctx->hhd_buffers_size; i++) { - if (det_ctx->hhd_buffers[i] != NULL) - SCFree(det_ctx->hhd_buffers[i]); + SCMutexLock(&master->lock); + DetectEngineCtx *instance = master->list; + if (instance == NULL) { + SCMutexUnlock(&master->lock); + return -1; } - if (det_ctx->hhd_buffers) - SCFree(det_ctx->hhd_buffers); - det_ctx->hhd_buffers = NULL; - if (det_ctx->hhd_buffers_len) - SCFree(det_ctx->hhd_buffers_len); - det_ctx->hhd_buffers_len = NULL; - /* HSBD */ - if (det_ctx->hsbd != NULL) { - SCLogDebug("det_ctx hsbd %u", det_ctx->hsbd_buffers_size); - for (i = 0; i < det_ctx->hsbd_buffers_size; i++) { - if (det_ctx->hsbd[i].buffer != NULL) - SCFree(det_ctx->hsbd[i].buffer); - } - SCFree(det_ctx->hsbd); - } + /* remove from active list */ + if (instance == de_ctx) { + master->list = instance->next; + } else { + DetectEngineCtx *prev = instance; + instance = instance->next; /* already checked first element */ - /* HSCB */ - if (det_ctx->hcbd != NULL) { - SCLogDebug("det_ctx hcbd %u", det_ctx->hcbd_buffers_size); - for (i = 0; i < det_ctx->hcbd_buffers_size; i++) { - if (det_ctx->hcbd[i].buffer != NULL) - SCFree(det_ctx->hcbd[i].buffer); - SCLogDebug("det_ctx->hcbd[i].buffer_size %u", det_ctx->hcbd[i].buffer_size); + while (instance) { + DetectEngineCtx *next = instance->next; + + if (instance == de_ctx) { + prev->next = instance->next; + break; + } + + prev = instance; + instance = next; + } + if (instance == NULL) { + SCMutexUnlock(&master->lock); + return -1; } - SCFree(det_ctx->hcbd); } - DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx); - SCFree(det_ctx); + /* instance is now detached from list */ + instance->next = NULL; - return TM_ECODE_OK; + /* add to free list */ + if (master->free_list == NULL) { + master->free_list = instance; + } else { + instance->next = master->free_list; + master->free_list = instance; + } + SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt); + + SCMutexUnlock(&master->lock); + return 0; } -void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx) +void DetectEnginePruneFreeList(void) { - /* XXX */ - PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher); - PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher); + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + DetectEngineCtx *prev = NULL; + DetectEngineCtx *instance = master->free_list; + while (instance) { + DetectEngineCtx *next = instance->next; + + SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt); + + if (instance->ref_cnt == 0) { + if (prev == NULL) { + master->free_list = next; + } else { + prev->next = next; + } + + SCLogDebug("freeing detect engine %p", instance); + DetectEngineCtxFree(instance); + instance = NULL; + } + + prev = instance; + instance = next; + } + SCMutexUnlock(&master->lock); } -/** \brief Register Thread keyword context Funcs - * - * \param de_ctx detection engine to register in - * \param name keyword name for error printing - * \param InitFunc function ptr - * \param data keyword init data to pass to Func - * \param FreeFunc function ptr - * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct) +static int reloads = 0; + +/** \brief Reload the detection engine * - * \retval id for retrieval of ctx at runtime - * \retval -1 on error + * \param filename YAML file to load for the detect config * - * \note make sure "data" remains valid and it free'd elsewhere. It's - * recommended to store it in the keywords global ctx so that - * it's freed when the de_ctx is freed. + * \retval -1 error + * \retval 0 ok */ -int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode) +int DetectEngineReload(SCInstance *suri) { - BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL || data == NULL); + DetectEngineCtx *new_de_ctx = NULL; + DetectEngineCtx *old_de_ctx = NULL; - if (mode) { - DetectEngineThreadKeywordCtxItem *item = de_ctx->keyword_list; - while (item != NULL) { - if (strcmp(name, item->name) == 0) { - return item->id; - } + char prefix[128]; + memset(prefix, 0, sizeof(prefix)); - item = item->next; + SCLogNotice("rule reload starting"); + + if (suri->conf_filename != NULL) { + snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++); + if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", + suri->conf_filename); + return -1; + } + + ConfNode *node = ConfGetNode(prefix); + if (node == NULL) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", + suri->conf_filename); + return -1; } +#if 0 + ConfDump(); +#endif } - DetectEngineThreadKeywordCtxItem *item = SCMalloc(sizeof(DetectEngineThreadKeywordCtxItem)); - if (unlikely(item == NULL)) + /* get a reference to the current de_ctx */ + old_de_ctx = DetectEngineGetCurrent(); + if (old_de_ctx == NULL) return -1; - memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem)); + SCLogDebug("get ref to old_de_ctx %p", old_de_ctx); + + /* get new detection engine */ + new_de_ctx = DetectEngineCtxInitWithPrefix(prefix); + if (new_de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + DetectEngineDeReference(&old_de_ctx); + return -1; + } + if (SigLoadSignatures(new_de_ctx, + suri->sig_file, suri->sig_file_exclusive) != 0) { + DetectEngineCtxFree(new_de_ctx); + DetectEngineDeReference(&old_de_ctx); + return -1; + } + SCLogDebug("set up new_de_ctx %p", new_de_ctx); - item->InitFunc = InitFunc; - item->FreeFunc = FreeFunc; - item->data = data; - item->name = name; + /* add to master */ + DetectEngineAddToMaster(new_de_ctx); - item->next = de_ctx->keyword_list; - de_ctx->keyword_list = item; - item->id = de_ctx->keyword_id++; + /* move to old free list */ + DetectEngineMoveToFreeList(old_de_ctx); + DetectEngineDeReference(&old_de_ctx); - return item->id; + SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx); + /* update the threads */ + DetectEngineReloadThreads(new_de_ctx); + SCLogDebug("threads now run new_de_ctx %p", new_de_ctx); + + /* walk free list, freeing the old_de_ctx */ + DetectEnginePruneFreeList(); + + DetectEngineBumpVersion(); + + SCLogDebug("old_de_ctx should have been freed"); + + SCLogNotice("rule reload complete"); + return 0; } -/** \brief Retrieve thread local keyword ctx by id - * - * \param det_ctx detection engine thread ctx to retrieve the ctx from - * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at - * keyword init. - * - * \retval ctx or NULL on error - */ -void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id) +static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len) { - if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL) - return NULL; + DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; + return det_ctx->tenant_id % h->array_size; +} - return det_ctx->keyword_ctxs_array[id]; +static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len) +{ + DetectEngineThreadCtx *det1 = (DetectEngineThreadCtx *)d1; + DetectEngineThreadCtx *det2 = (DetectEngineThreadCtx *)d2; + return (det1->tenant_id == det2->tenant_id); +} + +static void TenantIdFree(void *d) +{ + DetectEngineThreadCtxFree(d); +} + +int DetectEngineMTApply(void) +{ + DetectEngineMasterCtx *master = &g_master_de_ctx; + SCMutexLock(&master->lock); + + if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) { + SCLogInfo("error, no tenant selector"); + SCMutexUnlock(&master->lock); + return -1; + } + + DetectEngineCtx *minimal_de_ctx = NULL; + /* if we have no tenants, we need a minimal one */ + if (master->list == NULL) { + minimal_de_ctx = master->list = DetectEngineCtxInitMinimal(); + SCLogDebug("no tenants, using minimal %p", minimal_de_ctx); + } else if (master->list->next == NULL && master->list->tenant_id == 0) { + minimal_de_ctx = master->list; + SCLogDebug("no tenants, using original %p", minimal_de_ctx); + + /* the default de_ctx should be in the list with tenant_id 0 */ + } else { + DetectEngineCtx *list = master->list; + for ( ; list != NULL; list = list->next) { + SCLogDebug("list %p tenant %u", list, list->tenant_id); + + if (list->tenant_id == 0) { + minimal_de_ctx = list; + break; + } + } + } + + /* update the threads */ + SCLogDebug("MT reload starting"); + DetectEngineReloadThreads(minimal_de_ctx); + SCLogDebug("MT reload done"); + + SCMutexUnlock(&master->lock); + + /* walk free list, freeing the old_de_ctx */ + DetectEnginePruneFreeList(); + + SCLogDebug("old_de_ctx should have been freed"); + return 0; } const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) @@ -1546,47 +2932,11 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_PMATCH: return "packet/stream payload"; - case DETECT_SM_LIST_UMATCH: - return "http uri"; - case DETECT_SM_LIST_HRUDMATCH: - return "http raw uri"; - case DETECT_SM_LIST_HCBDMATCH: - return "http client body"; - case DETECT_SM_LIST_HSBDMATCH: - return "http server body"; - case DETECT_SM_LIST_HHDMATCH: - return "http headers"; - case DETECT_SM_LIST_HRHDMATCH: - return "http raw headers"; - case DETECT_SM_LIST_HSMDMATCH: - return "http stat msg"; - case DETECT_SM_LIST_HSCDMATCH: - return "http stat code"; - case DETECT_SM_LIST_HHHDMATCH: - return "http host"; - case DETECT_SM_LIST_HRHHDMATCH: - return "http raw host header"; - case DETECT_SM_LIST_HMDMATCH: - return "http method"; - case DETECT_SM_LIST_HCDMATCH: - return "http cookie"; - case DETECT_SM_LIST_HUADMATCH: - return "http user-agent"; - case DETECT_SM_LIST_APP_EVENT: - return "app layer events"; - - case DETECT_SM_LIST_AMATCH: - return "generic app layer"; - case DETECT_SM_LIST_DMATCH: - return "dcerpc"; case DETECT_SM_LIST_TMATCH: return "tag"; - case DETECT_SM_LIST_FILEMATCH: - return "file"; - - case DETECT_SM_LIST_DNSQUERY_MATCH: - return "dns query"; + case DETECT_SM_LIST_BASE64_DATA: + return "base64_data"; case DETECT_SM_LIST_POSTMATCH: return "post-match"; @@ -1598,8 +2948,6 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type) case DETECT_SM_LIST_MAX: return "max (internal)"; - case DETECT_SM_LIST_NOTSET: - return "not set (internal)"; } return "error"; } @@ -1776,322 +3124,6 @@ static int DetectEngineTest04(void) return result; } -int DummyTestAppInspectionEngine01(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, - Flow *f, - uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - return 0; -} - -int DummyTestAppInspectionEngine02(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, - Flow *f, - uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id) -{ - return 0; -} - -int DetectEngineTest05(void) -{ - int result = 0; - int ip = 0; - - DetectEngineAppInspectionEngine *engine_list[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - memset(engine_list, 0, sizeof(engine_list)); - - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - 0 /* STREAM_TOSERVER */, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, - DummyTestAppInspectionEngine01, - engine_list); - - int alproto = ALPROTO_UNKNOWN + 1; - for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for ( ; alproto < ALPROTO_FAILED; alproto++) { - int dir = 0; - for ( ; dir < 2; dir++) { - if (alproto == ALPROTO_HTTP && dir == 0) { - if (engine_list[ip][alproto][dir]->next != NULL) { - printf("more than one entry found\n"); - goto end; - } - - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - if (engine->alproto != alproto || - engine->dir != dir || - engine->sm_list != DETECT_SM_LIST_UMATCH || - engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->match_flags != DE_STATE_FLAG_URI_INSPECT || - engine->Callback != DummyTestAppInspectionEngine01) { - printf("failed for http and dir(0-toserver)\n"); - goto end; - } - } /* if (alproto == ALPROTO_HTTP && dir == 0) */ - - if (alproto == ALPROTO_HTTP && dir == 1) { - if (engine_list[ip][alproto][dir] != NULL) { - printf("failed for http and dir(1-toclient)\n"); - goto end; - } - } - - if (alproto != ALPROTO_HTTP && - engine_list[ip][alproto][0] != NULL && - engine_list[ip][alproto][1] != NULL) { - printf("failed for protocol %d\n", alproto); - goto end; - } - } /* for ( ; dir < 2 ..)*/ - } /* for ( ; alproto < ALPROTO_FAILED; ..) */ - } - - result = 1; - end: - return result; -} - -int DetectEngineTest06(void) -{ - int result = 0; - int ip = 0; - - DetectEngineAppInspectionEngine *engine_list[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - memset(engine_list, 0, sizeof(engine_list)); - - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - 0 /* STREAM_TOSERVER */, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, - DummyTestAppInspectionEngine01, - engine_list); - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - 1 /* STREAM_TOCLIENT */, - DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, - DummyTestAppInspectionEngine02, - engine_list); - - int alproto = ALPROTO_UNKNOWN + 1; - for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for ( ; alproto < ALPROTO_FAILED; alproto++) { - int dir = 0; - for ( ; dir < 2; dir++) { - if (alproto == ALPROTO_HTTP && dir == 0) { - if (engine_list[ip][alproto][dir]->next != NULL) { - printf("more than one entry found\n"); - goto end; - } - - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - if (engine->alproto != alproto || - engine->dir != dir || - engine->sm_list != DETECT_SM_LIST_UMATCH || - engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->match_flags != DE_STATE_FLAG_URI_INSPECT || - engine->Callback != DummyTestAppInspectionEngine01) { - printf("failed for http and dir(0-toserver)\n"); - goto end; - } - } /* if (alproto == ALPROTO_HTTP && dir == 0) */ - - if (alproto == ALPROTO_HTTP && dir == 1) { - if (engine_list[ip][alproto][dir]->next != NULL) { - printf("more than one entry found\n"); - goto end; - } - - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - if (engine->alproto != alproto || - engine->dir != dir || - engine->sm_list != DETECT_SM_LIST_UMATCH || - engine->inspect_flags != DE_STATE_FLAG_URI_INSPECT || - engine->match_flags != DE_STATE_FLAG_URI_INSPECT || - engine->Callback != DummyTestAppInspectionEngine02) { - printf("failed for http and dir(0-toclient)\n"); - goto end; - } - } /* if (alproto == ALPROTO_HTTP && dir == 1) */ - - if (alproto != ALPROTO_HTTP && - engine_list[ip][alproto][0] != NULL && - engine_list[ip][alproto][1] != NULL) { - printf("failed for protocol %d\n", alproto); - goto end; - } - } /* for ( ; dir < 2 ..)*/ - } /* for ( ; alproto < ALPROTO_FAILED; ..) */ - } - - result = 1; - end: - return result; -} - -int DetectEngineTest07(void) -{ - int result = 0; - int ip = 0; - - DetectEngineAppInspectionEngine *engine_list[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; - memset(engine_list, 0, sizeof(engine_list)); - - struct test_data_t { - int32_t sm_list; - uint32_t inspect_flags; - uint32_t match_flags; - uint16_t dir; - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); - - }; - - struct test_data_t data[] = { - { DETECT_SM_LIST_UMATCH, - DE_STATE_FLAG_URI_INSPECT, - DE_STATE_FLAG_URI_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HCBDMATCH, - DE_STATE_FLAG_HCBD_INSPECT, - DE_STATE_FLAG_HCBD_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HSBDMATCH, - DE_STATE_FLAG_HSBD_INSPECT, - DE_STATE_FLAG_HSBD_INSPECT, - 1, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HHDMATCH, - DE_STATE_FLAG_HHD_INSPECT, - DE_STATE_FLAG_HHD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HRHDMATCH, - DE_STATE_FLAG_HRHD_INSPECT, - DE_STATE_FLAG_HRHD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HMDMATCH, - DE_STATE_FLAG_HMD_INSPECT, - DE_STATE_FLAG_HMD_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HCDMATCH, - DE_STATE_FLAG_HCD_INSPECT, - DE_STATE_FLAG_HCD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HRUDMATCH, - DE_STATE_FLAG_HRUD_INSPECT, - DE_STATE_FLAG_HRUD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TS_INSPECT, - DE_STATE_FLAG_FILE_TS_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_FILEMATCH, - DE_STATE_FLAG_FILE_TC_INSPECT, - DE_STATE_FLAG_FILE_TC_INSPECT, - 1, - DummyTestAppInspectionEngine02 }, - { DETECT_SM_LIST_HSMDMATCH, - DE_STATE_FLAG_HSMD_INSPECT, - DE_STATE_FLAG_HSMD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HSCDMATCH, - DE_STATE_FLAG_HSCD_INSPECT, - DE_STATE_FLAG_HSCD_INSPECT, - 0, - DummyTestAppInspectionEngine01 }, - { DETECT_SM_LIST_HUADMATCH, - DE_STATE_FLAG_HUAD_INSPECT, - DE_STATE_FLAG_HUAD_INSPECT, - 0, - DummyTestAppInspectionEngine02 }, - }; - - size_t i = 0; - for ( ; i < sizeof(data) / sizeof(struct test_data_t); i++) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - ALPROTO_HTTP, - data[i].dir /* STREAM_TOCLIENT */, - data[i].sm_list, - data[i].inspect_flags, - data[i].match_flags, - data[i].Callback, - engine_list); - } - -#if 0 - DetectEnginePrintAppInspectionEngines(engine_list); -#endif - - int alproto = ALPROTO_UNKNOWN + 1; - for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for ( ; alproto < ALPROTO_FAILED; alproto++) { - int dir = 0; - for ( ; dir < 2; dir++) { - if (alproto == ALPROTO_HTTP) { - DetectEngineAppInspectionEngine *engine = engine_list[ip][alproto][dir]; - - size_t i = 0; - for ( ; i < (sizeof(data) / sizeof(struct test_data_t)); i++) { - if (data[i].dir != dir) - continue; - - if (engine->alproto != ALPROTO_HTTP || - engine->dir != data[i].dir || - engine->sm_list != data[i].sm_list || - engine->inspect_flags != data[i].inspect_flags || - engine->match_flags != data[i].match_flags || - engine->Callback != data[i].Callback) { - printf("failed for http\n"); - goto end; - } - engine = engine->next; - } - } else { - if (engine_list[ip][alproto][0] != NULL && - engine_list[ip][alproto][1] != NULL) { - printf("failed for protocol %d\n", alproto); - goto end; - } - } /* else */ - } /* for ( ; dir < 2; dir++) */ - } /* for ( ; alproto < ALPROTO_FAILED; ..) */ - } - - result = 1; - end: - return result; -} - static int DetectEngineTest08(void) { char *conf = @@ -2100,14 +3132,8 @@ static int DetectEngineTest08(void) "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" - " toclient-src-groups: 20\n" - " toclient-dst-groups: 21\n" - " toclient-sp-groups: 22\n" - " toclient-dp-groups: 23\n" - " toserver-src-groups: 24\n" - " toserver-dst-groups: 25\n" - " toserver-sp-groups: 26\n" - " toserver-dp-groups: 27\n"; + " toclient-groups: 23\n" + " toserver-groups: 27\n"; DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -2118,14 +3144,8 @@ static int DetectEngineTest08(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_src_groups == 20 && - de_ctx->max_uniq_toclient_dst_groups == 21 && - de_ctx->max_uniq_toclient_sp_groups == 22 && - de_ctx->max_uniq_toclient_dp_groups == 23 && - de_ctx->max_uniq_toserver_src_groups == 24 && - de_ctx->max_uniq_toserver_dst_groups == 25 && - de_ctx->max_uniq_toserver_sp_groups == 26 && - de_ctx->max_uniq_toserver_dp_groups == 27) + if (de_ctx->max_uniq_toclient_groups == 23 && + de_ctx->max_uniq_toserver_groups == 27) result = 1; end: @@ -2146,14 +3166,8 @@ static int DetectEngineTest09(void) "detect-engine:\n" " - profile: custom\n" " - custom-values:\n" - " toclient-src-groups: BA\n" - " toclient-dst-groups: BA\n" - " toclient-sp-groups: BA\n" - " toclient-dp-groups: BA\n" - " toserver-src-groups: BA\n" - " toserver-dst-groups: BA\n" - " toserver-sp-groups: BA\n" - " toserver-dp-groups: BA\n" + " toclient-groups: BA\n" + " toserver-groups: BA\n" " - inspection-recursion-limit: 10\n"; DetectEngineCtx *de_ctx = NULL; @@ -2165,14 +3179,8 @@ static int DetectEngineTest09(void) if (de_ctx == NULL) goto end; - if (de_ctx->max_uniq_toclient_src_groups == 4 && - de_ctx->max_uniq_toclient_dst_groups == 4 && - de_ctx->max_uniq_toclient_sp_groups == 4 && - de_ctx->max_uniq_toclient_dp_groups == 6 && - de_ctx->max_uniq_toserver_src_groups == 4 && - de_ctx->max_uniq_toserver_dst_groups == 8 && - de_ctx->max_uniq_toserver_sp_groups == 4 && - de_ctx->max_uniq_toserver_dp_groups == 30) + if (de_ctx->max_uniq_toclient_groups == 20 && + de_ctx->max_uniq_toserver_groups == 40) result = 1; end: @@ -2190,15 +3198,12 @@ void DetectEngineRegisterTests() { #ifdef UNITTESTS - UtRegisterTest("DetectEngineTest01", DetectEngineTest01, 1); - UtRegisterTest("DetectEngineTest02", DetectEngineTest02, 1); - UtRegisterTest("DetectEngineTest03", DetectEngineTest03, 1); - UtRegisterTest("DetectEngineTest04", DetectEngineTest04, 1); - UtRegisterTest("DetectEngineTest05", DetectEngineTest05, 1); - UtRegisterTest("DetectEngineTest06", DetectEngineTest06, 1); - UtRegisterTest("DetectEngineTest07", DetectEngineTest07, 1); - UtRegisterTest("DetectEngineTest08", DetectEngineTest08, 1); - UtRegisterTest("DetectEngineTest09", DetectEngineTest09, 1); + UtRegisterTest("DetectEngineTest01", DetectEngineTest01); + UtRegisterTest("DetectEngineTest02", DetectEngineTest02); + UtRegisterTest("DetectEngineTest03", DetectEngineTest03); + UtRegisterTest("DetectEngineTest04", DetectEngineTest04); + UtRegisterTest("DetectEngineTest08", DetectEngineTest08); + UtRegisterTest("DetectEngineTest09", DetectEngineTest09); #endif return; diff --git a/src/detect-engine.h b/src/detect-engine.h index 73b3554f20ff..590d4db6bfe8 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -28,38 +28,35 @@ #include "tm-threads.h" #include "flow-private.h" -typedef struct DetectEngineAppInspectionEngine_ { - uint8_t ipproto; - AppProto alproto; - uint16_t dir; - - int32_t sm_list; - uint32_t inspect_flags; - uint32_t match_flags; - - /* \retval 0 No match. Don't discontinue matching yet. We need more data. - * 1 Match. - * 2 Sig can't match. - * 3 Special value used by filestore sigs to indicate disabling - * filestore for the tx. - */ - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, uint8_t flags, void *alstate, - void *tx, uint64_t tx_id); - - struct DetectEngineAppInspectionEngine_ *next; -} DetectEngineAppInspectionEngine; - -extern DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2]; +int DetectBufferTypeRegister(const char *name); +int DetectBufferTypeGetByName(const char *name); +const char *DetectBufferTypeGetNameById(const int id); +void DetectBufferTypeSupportsMpm(const char *name); +void DetectBufferTypeSupportsPacket(const char *name); +_Bool DetectBufferTypeSupportsMpmGetById(const int id); +_Bool DetectBufferTypeSupportsPacketGetById(const int id); +int DetectBufferTypeMaxId(void); +void DetectBufferTypeFinalizeRegistration(void); +void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc); +const char *DetectBufferTypeGetDescriptionById(const int id); +const char *DetectBufferTypeGetDescriptionByName(const char *name); +void DetectBufferTypeRegisterSetupCallback(const char *name, + void (*Callback)(Signature *)); +void DetectBufferRunSetupCallback(const int id, Signature *s); +void DetectBufferTypeRegisterValidateCallback(const char *name, + _Bool (*ValidateCallback)(const Signature *)); +_Bool DetectBufferRunValidateCallback(const int id, const Signature *s); /* prototypes */ -void DetectEngineRegisterAppInspectionEngines(void); -void DetectEngineSpawnLiveRuleSwapMgmtThread(void); +DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix); DetectEngineCtx *DetectEngineCtxInit(void); -DetectEngineCtx *DetectEngineGetGlobalDeCtx(void); +DetectEngineCtx *DetectEngineCtxInitMinimal(void); void DetectEngineCtxFree(DetectEngineCtx *); +int DetectRegisterThreadCtxGlobalFuncs(const char *name, + void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *)); +void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id); + TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *); @@ -69,29 +66,53 @@ void DetectEngineResetMaxSigId(DetectEngineCtx *); void DetectEngineRegisterTests(void); const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type); +uint32_t DetectEngineGetVersion(void); +void DetectEngineBumpVersion(void); +int DetectEngineAddToMaster(DetectEngineCtx *de_ctx); +DetectEngineCtx *DetectEngineGetCurrent(void); +DetectEngineCtx *DetectEngineGetByTenantId(int tenant_id); +void DetectEnginePruneFreeList(void); +int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx); +DetectEngineCtx *DetectEngineReference(DetectEngineCtx *); +void DetectEngineDeReference(DetectEngineCtx **de_ctx); +int DetectEngineReload(SCInstance *suri); +int DetectEngineEnabled(void); +int DetectEngineMTApply(void); +int DetectEngineMultiTenantEnabled(void); +int DetectEngineMultiTenantSetup(void); + +int DetectEngineReloadStart(void); +int DetectEngineReloadIsStart(void); +void DetectEngineReloadSetDone(void); +int DetectEngineReloadIsDone(void); + +int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml); +int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt); + +int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id); +int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id); +int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id); +int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id); + +int DetectEngineInspectGenericList(ThreadVars *, const DetectEngineCtx *, + DetectEngineThreadCtx *, + const Signature *, const SigMatchData *, + Flow *, const uint8_t, void *, void *, + uint64_t); + /** * \brief Registers an app inspection engine. * + * \param name Name of the detection list * \param alproto App layer protocol for which we will register the engine. - * \param direction The direction for the engine. 0 - toserver; 1- toclient. - * \param sm_list The SigMatch list against which the engine works. - * \param inspect_flags The inspection flags to be used by de_state - * against the engine. - * \param match_flags The match flags to be used by de_state in tandem with - * the inpsect_flags. + * \param direction The direction for the engine: SIG_FLAG_TOSERVER or + * SIG_FLAG_TOCLIENT * \param Callback The engine callback. */ -void DetectEngineRegisterAppInspectionEngine(uint8_t ipproto, - AppProto alproto, - uint16_t direction, - int32_t sm_list, - uint32_t inspect_flags, - uint32_t match_flags, - int (*Callback)(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *sig, Flow *f, - uint8_t flags, void *alstate, - void *tx, uint64_t tx_id), - DetectEngineAppInspectionEngine *list[][ALPROTO_MAX][2]); +void DetectAppLayerInspectEngineRegister(const char *name, + AppProto alproto, uint32_t dir, InspectEngineFuncPtr Callback); + +int DetectEngineAppInspectionEngine2Signature(Signature *s); +void DetectEngineAppInspectionEngineSignatureFree(Signature *s); + #endif /* __DETECT_ENGINE_H__ */ diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index a54103e65e71..ce492cb45507 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -37,7 +37,7 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -#define DETECT_FAST_PATTERN_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" +#define PARSE_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" static pcre *parse_regex = NULL; static pcre_extra *parse_regex_study = NULL; @@ -56,8 +56,22 @@ SCFPSupportSMList *sm_fp_support_smlist_list = NULL; * \param list_id SM list id. * \param priority Priority for this list. */ -static void SupportFastPatternForSigMatchList(int list_id, int priority) +void SupportFastPatternForSigMatchList(int list_id, int priority) { + SCFPSupportSMList *ip = NULL; + /* insertion point - ip */ + for (SCFPSupportSMList *tmp = sm_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) { + if (list_id == tmp->list_id) { + SCLogDebug("SM list already registered."); + return; + } + + if (priority <= tmp->priority) + break; + + ip = tmp; + } + if (sm_fp_support_smlist_list == NULL) { SCFPSupportSMList *new = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new == NULL)) @@ -71,20 +85,6 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) return; } - /* insertion point - ip */ - SCFPSupportSMList *ip = NULL; - for (SCFPSupportSMList *tmp = sm_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) { - if (list_id == tmp->list_id) { - SCLogError(SC_ERR_FATAL, "SM list already registered."); - exit(EXIT_FAILURE); - } - - if (priority <= tmp->priority) - break; - - ip = tmp; - } - SCFPSupportSMList *new = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new == NULL)) exit(EXIT_FAILURE); @@ -99,13 +99,6 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) ip->next = new; } - for (SCFPSupportSMList *tmp = new->next; tmp != NULL; tmp = tmp->next) { - if (list_id == tmp->list_id) { - SCLogError(SC_ERR_FATAL, "SM list already registered."); - exit(EXIT_FAILURE); - } - } - return; } @@ -114,27 +107,9 @@ static void SupportFastPatternForSigMatchList(int list_id, int priority) */ void SupportFastPatternForSigMatchTypes(void) { - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSBDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_UMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRUDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHHDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHHDMATCH, 2); - - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCDMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HUADMATCH, 2); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HMDMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH, 3); - SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERY_MATCH, 2); + /* other types are handled by DetectMpmAppLayerRegister() */ #if 0 SCFPSupportSMList *tmp = sm_fp_support_smlist_list; @@ -155,39 +130,15 @@ void DetectFastPatternRegister(void) { sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern"; sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher"; - sigmatch_table[DETECT_FAST_PATTERN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#fast_pattern"; + sigmatch_table[DETECT_FAST_PATTERN].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#fast-pattern"; sigmatch_table[DETECT_FAST_PATTERN].Match = NULL; sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup; sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_PAYLOAD; - - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(DETECT_FAST_PATTERN_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", DETECT_FAST_PATTERN_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - error: - /* get some way to return an error code! */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } //static int DetectFastPatternParseArg( @@ -208,59 +159,32 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - const char *arg_substr = NULL; + char arg_substr[128] = ""; DetectContentData *cd = NULL; + const int nlists = DetectBufferTypeMaxId(); - if (s->sm_lists_tail[DETECT_SM_LIST_PMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL && - s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH] == NULL) { - SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " - "rule, without a preceding content based keyword. " - "Currently we provide fast_pattern support for content, " - "uricontent, http_client_body, http_server_body, http_header, " - "http_raw_header, http_method, http_cookie, " - "http_raw_uri, http_stat_msg, http_stat_code, " - "http_user_agent, http_host, http_raw_host or " - "dns_query option"); + SigMatch *pm1 = DetectGetLastSMFromMpmLists(s); + SigMatch *pm2 = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); + if (pm1 == NULL && pm2 == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " + "the rule, without a content context. Please use a " + "content based keyword before using fast_pattern"); return -1; } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]); - if (pm == NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " - "the rule, without a content context. Please use a " - "content based keyword before using fast_pattern"); - return -1; + SigMatch *pm = NULL; + if (pm1 && pm2) { + if (pm1->idx > pm2->idx) + pm = pm1; + else + pm = pm2; + } else if (pm1 && !pm2) { + pm = pm1; + } else { + pm = pm2; } - cd = pm->ctx; + cd = (DetectContentData *)pm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || @@ -281,11 +205,11 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a } else { /*allow only one content to have fast_pattern modifier*/ int list_id = 0; - for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { + for (list_id = 0; list_id < nlists; list_id++) { SigMatch *sm = NULL; - for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { - DetectContentData *tmp_cd = sm->ctx; + DetectContentData *tmp_cd = (DetectContentData *)sm->ctx; if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern " "can be used on only one content in a rule"); @@ -320,8 +244,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a /* fast pattern chop */ } else if (ret == 4) { - res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, - 2, &arg_substr); + res = pcre_copy_substring((char *)arg, ov, MAX_SUBSTRINGS, + 2, arg_substr, sizeof(arg_substr)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for fast_pattern offset"); @@ -334,8 +258,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a goto error; } - res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, - 3, &arg_substr); + res = pcre_copy_substring((char *)arg, ov, MAX_SUBSTRINGS, + 3, arg_substr, sizeof(arg_substr)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " "for fast_pattern offset"); @@ -396,6 +320,19 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS +static int g_file_data_buffer_id = 0; +static int g_http_method_buffer_id = 0; +static int g_http_uri_buffer_id = 0; +static int g_http_ua_buffer_id = 0; +static int g_http_cookie_buffer_id = 0; +static int g_http_host_buffer_id = 0; +static int g_http_raw_host_buffer_id = 0; +static int g_http_stat_code_buffer_id = 0; +static int g_http_stat_msg_buffer_id = 0; +static int g_http_raw_header_buffer_id = 0; +static int g_http_header_buffer_id = 0; +static int g_http_client_body_buffer_id = 0; +static int g_http_raw_uri_buffer_id = 0; /** * \test Checks if a fast_pattern is registered in a Signature @@ -410,7 +347,7 @@ int DetectFastPatternTest01(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; tcpv4-csum:valid; fast_pattern; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -450,7 +387,7 @@ int DetectFastPatternTest02(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern; " "content:\"boo\"; fast_pattern; " "msg:\"Testing fast_pattern\"; sid:1;)"); @@ -475,540 +412,58 @@ int DetectFastPatternTest03(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " - "(content:\"/one/\"; " - "msg:\"Testing fast_pattern\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; - while (sm != NULL) { - if (sm->type == DETECT_CONTENT) { - if ( !(((DetectContentData *)sm->ctx)->flags & - DETECT_CONTENT_FAST_PATTERN)) { - result = 1; - } else { - result = 0; - break; - } - } - sm = sm->next; - } - - end: - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is not registered in a Signature, when we - * supply a fast_pattern with an argument - */ -int DetectFastPatternTest04(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " - "(content:\"/one/\"; fast_pattern:boo; " - "msg:\"Testing fast_pattern\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - result = 1; - - end: - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase. - */ -int DetectFastPatternTest05(void) -{ - uint8_t *buf = (uint8_t *) "Oh strin1. But what " - "strin2. This is strings3. We strins_str4. we " - "have strins_string5"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) != 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase. - */ -int DetectFastPatternTest06(void) -{ - uint8_t *buf = (uint8_t *) "Oh this is a string1. But what is this with " - "string2. This is strings3. We have strings_str4. We also have " - "strings_string5"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) != 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase, when the payload - * doesn't contain the fast_pattern string within it. - */ -int DetectFastPatternTest07(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. now here comes our " - "dark knight strings_string5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a fast_pattern is used in the mpm phase and that we get - * exactly 1 match for the mpm phase. - */ -int DetectFastPatternTest08(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. now here comes our " - "dark knight strings3. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx init: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; fast_pattern; " - "content:\"strings_str4\"; content:\"strings_string5\"; " - "sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); - if (r != 1) { - printf("expected 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; -end: - UTHFreePackets(&p, 1); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} -/** - * \test Checks that a fast_pattern is used in the mpm phase, when the payload - * doesn't contain the fast_pattern string within it. - */ -int DetectFastPatternTest09(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. no_strings4 _imp now here " - "comes our dark knight strings3. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; fast_pattern; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a the SigInit chooses the fast_pattern with better pattern - * strength, when we have multiple fast_patterns in the Signature. Also - * checks that we get a match for the fast_pattern from the mpm phase. - */ -int DetectFastPatternTest10(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings4_imp now here " - "comes our dark knight strings5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx init: "); - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; fast_pattern; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); - if (r != 1) { - printf("expected 1, got %"PRIu32": ", r); - goto end; - } - - result = 1; -end: - UTHFreePackets(&p, 1); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - return result; -} - -/** - * \test Checks that a the SigInit chooses the fast_pattern with better pattern - * strength, when we have multiple fast_patterns in the Signature. Also - * checks that we get no matches for the fast_pattern from the mpm phase. - */ -int DetectFastPatternTest11(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings5_imp now here " - "comes our dark knight strings5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; fast_pattern; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; - - -end: - UTHFreePackets(&p, 1); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - return result; -} - -/** - * \test Checks that we don't get a match for the mpm phase. - */ -int DetectFastPatternTest12(void) -{ - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings5_imp now here " - "comes our dark knight strings5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) + if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; " - "content:\"strings_string5\"; sid:1;)"); + "(content:\"/one/\"; " + "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (PacketPatternSearchWithStreamCtx(det_ctx, p) == 0) - result = 1; + result = 0; + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; + while (sm != NULL) { + if (sm->type == DETECT_CONTENT) { + if ( !(((DetectContentData *)sm->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN)) { + result = 1; + } else { + result = 0; + break; + } + } + sm = sm->next; + } - SigGroupCleanup(de_ctx); + end: SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -end: - UTHFreePackets(&p, 1); DetectEngineCtxFree(de_ctx); return result; } /** - * \test Checks that a the SigInit chooses the fast_pattern with a better - * strength from the available patterns, when we don't specify a - * fast_pattern. We also check that we get a match from the mpm - * phase. + * \test Checks that a fast_pattern is not registered in a Signature, when we + * supply a fast_pattern with an argument */ -int DetectFastPatternTest13(void) +int DetectFastPatternTest04(void) { - uint8_t *buf = (uint8_t *) "Dummy is our name. Oh yes. From right here " - "right now, all the way to hangover. right. strings5_imp now here " - "comes our dark knight strings_string5. Yes here is our dark knight"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; int result = 0; - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf,buflen,IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx init: "); + if ( (de_ctx = DetectEngineCtxInit()) == NULL) goto end; - } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"fast_pattern test\"; content:\"string1\"; " - "content:\"string2\"; content:\"strings3\"; " - "content:\"strings4_imp\"; " - "content:\"strings_string5\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - /* start the search phase */ - det_ctx->sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - uint32_t r = PacketPatternSearchWithStreamCtx(det_ctx, p); - if (r != 1) { - printf("expected 1 result, got %"PRIu32": ", r); - goto end; - } + "(content:\"/one/\"; fast_pattern:boo; " + "msg:\"Testing fast_pattern\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + result = 1; - result = 1; -end: - UTHFreePackets(&p, 1); - SigGroupCleanup(de_ctx); + end: SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); return result; } @@ -1038,7 +493,6 @@ int DetectFastPatternTest14(void) FlowInitConfig(FLOW_QUIET); - de_ctx->mpm_matcher = MPM_B3G; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1091,7 +545,7 @@ int DetectFastPatternTest15(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -1132,7 +586,7 @@ int DetectFastPatternTest16(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) @@ -1170,14 +624,14 @@ int DetectFastPatternTest17(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; - DetectContentData *cd = sm->ctx; + DetectContentData *cd = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -1206,14 +660,14 @@ int DetectFastPatternTest18(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]; - DetectContentData *cd = sm->ctx; + DetectContentData *cd = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -1241,7 +695,7 @@ int DetectFastPatternTest19(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1263,7 +717,7 @@ int DetectFastPatternTest20(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1285,7 +739,7 @@ int DetectFastPatternTest21(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1307,7 +761,7 @@ int DetectFastPatternTest22(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1329,7 +783,7 @@ int DetectFastPatternTest23(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1351,7 +805,7 @@ int DetectFastPatternTest24(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1373,7 +827,7 @@ int DetectFastPatternTest25(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1395,7 +849,7 @@ int DetectFastPatternTest26(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1417,7 +871,7 @@ int DetectFastPatternTest27(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1439,12 +893,12 @@ int DetectFastPatternTest28(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; content:\"two\"; distance:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1470,11 +924,11 @@ int DetectFastPatternTest29(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; within:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1500,11 +954,11 @@ int DetectFastPatternTest30(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; offset:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1530,11 +984,11 @@ int DetectFastPatternTest31(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; depth:30; content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -1560,11 +1014,11 @@ int DetectFastPatternTest32(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_NEGATED && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -1591,7 +1045,7 @@ int DetectFastPatternTest33(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1613,7 +1067,7 @@ int DetectFastPatternTest34(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1635,7 +1089,7 @@ int DetectFastPatternTest35(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1657,7 +1111,7 @@ int DetectFastPatternTest36(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1679,11 +1133,11 @@ int DetectFastPatternTest37(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; content:\"oneonetwo\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1709,11 +1163,11 @@ int DetectFastPatternTest38(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1739,11 +1193,11 @@ int DetectFastPatternTest39(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1769,11 +1223,11 @@ int DetectFastPatternTest40(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1799,11 +1253,11 @@ int DetectFastPatternTest41(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twotwotwo\"; fast_pattern:3,4; content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1829,11 +1283,11 @@ int DetectFastPatternTest42(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; distance:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1859,11 +1313,11 @@ int DetectFastPatternTest43(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; within:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1889,11 +1343,11 @@ int DetectFastPatternTest44(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; offset:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1919,11 +1373,11 @@ int DetectFastPatternTest45(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; depth:10; content:\"threethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -1949,7 +1403,7 @@ int DetectFastPatternTest46(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:65977,4; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1971,7 +1425,7 @@ int DetectFastPatternTest47(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"twooneone\"; fast_pattern:3,65977; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -1993,7 +1447,7 @@ int DetectFastPatternTest48(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; fast_pattern:65534,4; content:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2015,11 +1469,11 @@ int DetectFastPatternTest49(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; if (cd->flags & DETECT_CONTENT_FAST_PATTERN && cd->flags & DETECT_CONTENT_NEGATED && !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2046,7 +1500,7 @@ int DetectFastPatternTest50(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; distance:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2068,7 +1522,7 @@ int DetectFastPatternTest51(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; within:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2090,7 +1544,7 @@ int DetectFastPatternTest52(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; offset:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2112,7 +1566,7 @@ int DetectFastPatternTest53(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; depth:10; content:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2143,14 +1597,14 @@ int DetectFastPatternTest54(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"/one/\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -2184,14 +1638,14 @@ int DetectFastPatternTest55(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -2222,14 +1676,14 @@ int DetectFastPatternTest56(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -2258,14 +1712,14 @@ int DetectFastPatternTest57(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2293,7 +1747,7 @@ int DetectFastPatternTest58(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2315,7 +1769,7 @@ int DetectFastPatternTest59(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2337,7 +1791,7 @@ int DetectFastPatternTest60(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2359,7 +1813,7 @@ int DetectFastPatternTest61(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2381,7 +1835,7 @@ int DetectFastPatternTest62(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2403,7 +1857,7 @@ int DetectFastPatternTest63(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2425,7 +1879,7 @@ int DetectFastPatternTest64(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2447,7 +1901,7 @@ int DetectFastPatternTest65(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2469,7 +1923,7 @@ int DetectFastPatternTest66(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2491,12 +1945,12 @@ int DetectFastPatternTest67(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent: \"one\"; uricontent:\"two\"; distance:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2522,11 +1976,11 @@ int DetectFastPatternTest68(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2552,11 +2006,11 @@ int DetectFastPatternTest69(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2582,11 +2036,11 @@ int DetectFastPatternTest70(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:30; uricontent:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -2612,11 +2066,11 @@ int DetectFastPatternTest71(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:!\"one\"; fast_pattern; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -2643,7 +2097,7 @@ int DetectFastPatternTest72(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2665,7 +2119,7 @@ int DetectFastPatternTest73(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2687,7 +2141,7 @@ int DetectFastPatternTest74(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2709,7 +2163,7 @@ int DetectFastPatternTest75(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; uricontent:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -2731,11 +2185,11 @@ int DetectFastPatternTest76(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2761,11 +2215,11 @@ int DetectFastPatternTest77(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2791,11 +2245,11 @@ int DetectFastPatternTest78(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2821,11 +2275,11 @@ int DetectFastPatternTest79(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2851,11 +2305,11 @@ int DetectFastPatternTest80(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2881,11 +2335,11 @@ int DetectFastPatternTest81(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2911,11 +2365,11 @@ int DetectFastPatternTest82(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2941,11 +2395,11 @@ int DetectFastPatternTest83(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -2971,11 +2425,11 @@ int DetectFastPatternTest84(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; uricontent:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3004,7 +2458,7 @@ int DetectFastPatternTest85(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:65977,4; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3026,7 +2480,7 @@ int DetectFastPatternTest86(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"oneonetwo\"; fast_pattern:3,65977; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3048,7 +2502,7 @@ int DetectFastPatternTest87(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; fast_pattern:65534,4; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3070,11 +2524,11 @@ int DetectFastPatternTest88(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3101,7 +2555,7 @@ int DetectFastPatternTest89(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; distance:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3123,7 +2577,7 @@ int DetectFastPatternTest90(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; within:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3145,7 +2599,7 @@ int DetectFastPatternTest91(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; offset:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3167,7 +2621,7 @@ int DetectFastPatternTest92(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:!\"oneonetwo\"; fast_pattern:3,4; depth:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3194,11 +2648,11 @@ int DetectFastPatternTest93(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3229,14 +2683,14 @@ int DetectFastPatternTest94(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -3270,14 +2724,14 @@ int DetectFastPatternTest95(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; while (sm != NULL) { if (sm->type == DETECT_CONTENT) { if ( ((DetectContentData *)sm->ctx)->flags & @@ -3308,14 +2762,14 @@ int DetectFastPatternTest96(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -3344,14 +2798,14 @@ int DetectFastPatternTest97(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (sm->type == DETECT_CONTENT) { if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3379,7 +2833,7 @@ int DetectFastPatternTest98(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3401,7 +2855,7 @@ int DetectFastPatternTest99(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; distance:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3423,7 +2877,7 @@ int DetectFastPatternTest100(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3445,7 +2899,7 @@ int DetectFastPatternTest101(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; within:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3467,7 +2921,7 @@ int DetectFastPatternTest102(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3489,7 +2943,7 @@ int DetectFastPatternTest103(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; offset:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3511,7 +2965,7 @@ int DetectFastPatternTest104(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:only; http_uri; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3533,7 +2987,7 @@ int DetectFastPatternTest105(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; depth:10; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3555,7 +3009,7 @@ int DetectFastPatternTest106(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3577,12 +3031,12 @@ int DetectFastPatternTest107(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent: \"one\"; uricontent:\"two\"; distance:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3608,11 +3062,11 @@ int DetectFastPatternTest108(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3638,11 +3092,11 @@ int DetectFastPatternTest109(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3668,11 +3122,11 @@ int DetectFastPatternTest110(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:30; content:\"two\"; fast_pattern:only; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -3698,11 +3152,11 @@ int DetectFastPatternTest111(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_uri; uricontent:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -3729,7 +3183,7 @@ int DetectFastPatternTest112(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3751,7 +3205,7 @@ int DetectFastPatternTest113(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3773,7 +3227,7 @@ int DetectFastPatternTest114(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3795,7 +3249,7 @@ int DetectFastPatternTest115(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"two\"; content:!\"one\"; fast_pattern; http_uri; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -3817,11 +3271,11 @@ int DetectFastPatternTest116(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3847,11 +3301,11 @@ int DetectFastPatternTest117(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3877,11 +3331,11 @@ int DetectFastPatternTest118(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3907,11 +3361,11 @@ int DetectFastPatternTest119(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3937,11 +3391,11 @@ int DetectFastPatternTest120(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3967,11 +3421,11 @@ int DetectFastPatternTest121(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -3997,11 +3451,11 @@ int DetectFastPatternTest122(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4027,11 +3481,11 @@ int DetectFastPatternTest123(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4057,11 +3511,11 @@ int DetectFastPatternTest124(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; uricontent:\"two\"; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4090,7 +3544,7 @@ int DetectFastPatternTest125(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:65977,4; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4112,7 +3566,7 @@ int DetectFastPatternTest126(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"oneonetwo\"; fast_pattern:3,65977; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4134,7 +3588,7 @@ int DetectFastPatternTest127(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:\"two\"; fast_pattern:65534,4; http_uri; uricontent:\"three\"; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4156,11 +3610,11 @@ int DetectFastPatternTest128(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4187,7 +3641,7 @@ int DetectFastPatternTest129(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; distance:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4209,7 +3663,7 @@ int DetectFastPatternTest130(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; within:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4231,7 +3685,7 @@ int DetectFastPatternTest131(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"twooneone\"; fast_pattern:3,4; http_uri; offset:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4253,7 +3707,7 @@ int DetectFastPatternTest132(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; depth:10; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4275,11 +3729,11 @@ int DetectFastPatternTest133(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(uricontent:\"one\"; content:!\"oneonetwo\"; fast_pattern:3,4; http_uri; uricontent:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4311,11 +3765,11 @@ int DetectFastPatternTest134(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4346,14 +3800,14 @@ int DetectFastPatternTest135(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_client_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -4383,14 +3837,14 @@ int DetectFastPatternTest136(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_client_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -4416,14 +3870,14 @@ int DetectFastPatternTest137(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4450,14 +3904,14 @@ int DetectFastPatternTest138(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4483,7 +3937,7 @@ int DetectFastPatternTest139(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4505,7 +3959,7 @@ int DetectFastPatternTest140(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; distance:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4527,7 +3981,7 @@ int DetectFastPatternTest141(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4549,7 +4003,7 @@ int DetectFastPatternTest142(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; within:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4571,7 +4025,7 @@ int DetectFastPatternTest143(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4593,7 +4047,7 @@ int DetectFastPatternTest144(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; offset:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4615,7 +4069,7 @@ int DetectFastPatternTest145(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:only; http_client_body; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4637,7 +4091,7 @@ int DetectFastPatternTest146(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; depth:10; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4659,7 +4113,7 @@ int DetectFastPatternTest147(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4681,12 +4135,12 @@ int DetectFastPatternTest148(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_client_body; content:\"two\"; http_client_body; distance:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4712,11 +4166,11 @@ int DetectFastPatternTest149(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4742,11 +4196,11 @@ int DetectFastPatternTest150(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4772,11 +4226,11 @@ int DetectFastPatternTest151(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:30; content:\"two\"; fast_pattern:only; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -4802,11 +4256,11 @@ int DetectFastPatternTest152(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_client_body; content:\"two\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -4833,7 +4287,7 @@ int DetectFastPatternTest153(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4855,7 +4309,7 @@ int DetectFastPatternTest154(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4877,7 +4331,7 @@ int DetectFastPatternTest155(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4899,7 +4353,7 @@ int DetectFastPatternTest156(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_client_body; content:!\"one\"; fast_pattern; http_client_body; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -4921,11 +4375,11 @@ int DetectFastPatternTest157(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4951,11 +4405,11 @@ int DetectFastPatternTest158(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -4981,11 +4435,11 @@ int DetectFastPatternTest159(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5011,11 +4465,11 @@ int DetectFastPatternTest160(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5041,11 +4495,11 @@ int DetectFastPatternTest161(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5071,11 +4525,11 @@ int DetectFastPatternTest162(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5101,11 +4555,11 @@ int DetectFastPatternTest163(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5131,11 +4585,11 @@ int DetectFastPatternTest164(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5161,11 +4615,11 @@ int DetectFastPatternTest165(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; http_client_body; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5194,7 +4648,7 @@ int DetectFastPatternTest166(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:65977,4; http_client_body; content:\"three\"; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5216,7 +4670,7 @@ int DetectFastPatternTest167(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"oneonetwo\"; fast_pattern:3,65977; http_client_body; content:\"three\"; distance:10; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5238,7 +4692,7 @@ int DetectFastPatternTest168(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:\"two\"; fast_pattern:65534,4; http_client_body; content:\"three\"; http_client_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5260,11 +4714,11 @@ int DetectFastPatternTest169(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5291,7 +4745,7 @@ int DetectFastPatternTest170(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; distance:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5313,7 +4767,7 @@ int DetectFastPatternTest171(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; within:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5335,7 +4789,7 @@ int DetectFastPatternTest172(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"twooneone\"; fast_pattern:3,4; http_client_body; offset:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5357,7 +4811,7 @@ int DetectFastPatternTest173(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; depth:10; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5379,11 +4833,11 @@ int DetectFastPatternTest174(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_client_body; content:!\"oneonetwo\"; fast_pattern:3,4; http_client_body; content:\"three\"; http_client_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5415,7 +4869,7 @@ int DetectFastPatternTest175(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; distance:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5437,7 +4891,7 @@ int DetectFastPatternTest176(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; within:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5459,7 +4913,7 @@ int DetectFastPatternTest177(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; offset:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5481,7 +4935,7 @@ int DetectFastPatternTest178(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; content:!\"one\"; depth:20; fast_pattern; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5507,13 +4961,13 @@ int DetectFastPatternTest179(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_header; " "content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -5544,14 +4998,14 @@ int DetectFastPatternTest180(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -5581,14 +5035,14 @@ int DetectFastPatternTest181(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_header; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -5614,14 +5068,14 @@ int DetectFastPatternTest182(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5648,14 +5102,14 @@ int DetectFastPatternTest183(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -5681,7 +5135,7 @@ int DetectFastPatternTest184(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5703,7 +5157,7 @@ int DetectFastPatternTest185(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; distance:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5725,7 +5179,7 @@ int DetectFastPatternTest186(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5747,7 +5201,7 @@ int DetectFastPatternTest187(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; within:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5769,7 +5223,7 @@ int DetectFastPatternTest188(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5791,7 +5245,7 @@ int DetectFastPatternTest189(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; offset:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5813,7 +5267,7 @@ int DetectFastPatternTest190(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:only; http_header; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5835,7 +5289,7 @@ int DetectFastPatternTest191(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; depth:10; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5857,7 +5311,7 @@ int DetectFastPatternTest192(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -5879,12 +5333,12 @@ int DetectFastPatternTest193(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_header; content:\"two\"; http_header; distance:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5910,11 +5364,11 @@ int DetectFastPatternTest194(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; within:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5940,11 +5394,11 @@ int DetectFastPatternTest195(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; offset:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -5970,11 +5424,11 @@ int DetectFastPatternTest196(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; depth:30; content:\"two\"; fast_pattern:only; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6000,11 +5454,11 @@ int DetectFastPatternTest197(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_header; content:\"two\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6031,7 +5485,7 @@ int DetectFastPatternTest198(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6053,7 +5507,7 @@ int DetectFastPatternTest199(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6075,7 +5529,7 @@ int DetectFastPatternTest200(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6097,7 +5551,7 @@ int DetectFastPatternTest201(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_header; content:!\"one\"; fast_pattern; http_header; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6119,11 +5573,11 @@ int DetectFastPatternTest202(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6149,11 +5603,11 @@ int DetectFastPatternTest203(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6179,11 +5633,11 @@ int DetectFastPatternTest204(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6209,11 +5663,11 @@ int DetectFastPatternTest205(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6239,11 +5693,11 @@ int DetectFastPatternTest206(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6269,11 +5723,11 @@ int DetectFastPatternTest207(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6299,11 +5753,11 @@ int DetectFastPatternTest208(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6329,11 +5783,11 @@ int DetectFastPatternTest209(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6359,11 +5813,11 @@ int DetectFastPatternTest210(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; http_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6392,7 +5846,7 @@ int DetectFastPatternTest211(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:65977,4; http_header; content:\"three\"; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6414,7 +5868,7 @@ int DetectFastPatternTest212(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"oneonetwo\"; fast_pattern:3,65977; http_header; content:\"three\"; distance:10; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6436,7 +5890,7 @@ int DetectFastPatternTest213(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:\"two\"; fast_pattern:65534,4; http_header; content:\"three\"; http_header; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6458,11 +5912,11 @@ int DetectFastPatternTest214(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6489,7 +5943,7 @@ int DetectFastPatternTest215(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; distance:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6511,7 +5965,7 @@ int DetectFastPatternTest216(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; within:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6533,7 +5987,7 @@ int DetectFastPatternTest217(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; offset:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6555,7 +6009,7 @@ int DetectFastPatternTest218(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; depth:10; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -6577,11 +6031,11 @@ int DetectFastPatternTest219(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_header; content:\"three\"; http_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6619,7 +6073,7 @@ int DetectFastPatternTest220(void) "content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -6657,7 +6111,7 @@ int DetectFastPatternTest221(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -6694,7 +6148,7 @@ int DetectFastPatternTest222(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -6726,8 +6180,8 @@ int DetectFastPatternTest223(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -6760,8 +6214,8 @@ int DetectFastPatternTest224(void) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -6990,7 +6444,7 @@ int DetectFastPatternTest234(void) if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7020,7 +6474,7 @@ int DetectFastPatternTest235(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7050,7 +6504,7 @@ int DetectFastPatternTest236(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7080,7 +6534,7 @@ int DetectFastPatternTest237(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:30; content:\"two\"; fast_pattern:only; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7110,7 +6564,7 @@ int DetectFastPatternTest238(void) "(flow:to_server; content:!\"one\"; fast_pattern; http_raw_header; content:\"two\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7229,7 +6683,7 @@ int DetectFastPatternTest243(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7259,7 +6713,7 @@ int DetectFastPatternTest244(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7289,7 +6743,7 @@ int DetectFastPatternTest245(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7319,7 +6773,7 @@ int DetectFastPatternTest246(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7349,7 +6803,7 @@ int DetectFastPatternTest247(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7379,7 +6833,7 @@ int DetectFastPatternTest248(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7409,7 +6863,7 @@ int DetectFastPatternTest249(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7439,7 +6893,7 @@ int DetectFastPatternTest250(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7469,7 +6923,7 @@ int DetectFastPatternTest251(void) "(flow:to_server; content:\"one\"; http_raw_header; content:\"two\"; http_raw_header; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7568,7 +7022,7 @@ int DetectFastPatternTest255(void) "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7687,7 +7141,7 @@ int DetectFastPatternTest260(void) "(flow:to_server; content:\"one\"; http_raw_header; content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_header; content:\"three\"; http_raw_header; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7719,13 +7173,13 @@ int DetectFastPatternTest261(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_method; " "content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -7756,14 +7210,14 @@ int DetectFastPatternTest262(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_method; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -7793,14 +7247,14 @@ int DetectFastPatternTest263(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_method; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -7826,14 +7280,14 @@ int DetectFastPatternTest264(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -7860,14 +7314,14 @@ int DetectFastPatternTest265(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_method_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -7893,7 +7347,7 @@ int DetectFastPatternTest266(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7915,7 +7369,7 @@ int DetectFastPatternTest267(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; distance:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7937,7 +7391,7 @@ int DetectFastPatternTest268(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7959,7 +7413,7 @@ int DetectFastPatternTest269(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; within:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -7981,7 +7435,7 @@ int DetectFastPatternTest270(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8003,7 +7457,7 @@ int DetectFastPatternTest271(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; offset:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8025,7 +7479,7 @@ int DetectFastPatternTest272(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:only; http_method; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8047,7 +7501,7 @@ int DetectFastPatternTest273(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; depth:10; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8069,7 +7523,7 @@ int DetectFastPatternTest274(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8091,12 +7545,12 @@ int DetectFastPatternTest275(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_method; content:\"two\"; http_method; distance:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8122,11 +7576,11 @@ int DetectFastPatternTest276(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; within:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8152,11 +7606,11 @@ int DetectFastPatternTest277(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; offset:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8182,11 +7636,11 @@ int DetectFastPatternTest278(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; depth:30; content:\"two\"; fast_pattern:only; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8212,11 +7666,11 @@ int DetectFastPatternTest279(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_method; content:\"two\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8243,7 +7697,7 @@ int DetectFastPatternTest280(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8265,7 +7719,7 @@ int DetectFastPatternTest281(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8287,7 +7741,7 @@ int DetectFastPatternTest282(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8309,7 +7763,7 @@ int DetectFastPatternTest283(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_method; content:!\"one\"; fast_pattern; http_method; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8331,11 +7785,11 @@ int DetectFastPatternTest284(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8361,11 +7815,11 @@ int DetectFastPatternTest285(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8391,11 +7845,11 @@ int DetectFastPatternTest286(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8421,11 +7875,11 @@ int DetectFastPatternTest287(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8451,11 +7905,11 @@ int DetectFastPatternTest288(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8481,11 +7935,11 @@ int DetectFastPatternTest289(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8511,11 +7965,11 @@ int DetectFastPatternTest290(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8541,11 +7995,11 @@ int DetectFastPatternTest291(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8571,11 +8025,11 @@ int DetectFastPatternTest292(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; http_method; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8604,7 +8058,7 @@ int DetectFastPatternTest293(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:65977,4; http_method; content:\"three\"; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8626,7 +8080,7 @@ int DetectFastPatternTest294(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"oneonetwo\"; fast_pattern:3,65977; http_method; content:\"three\"; distance:10; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8648,7 +8102,7 @@ int DetectFastPatternTest295(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:\"two\"; fast_pattern:65534,4; http_method; content:\"three\"; http_method; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8670,11 +8124,11 @@ int DetectFastPatternTest296(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8701,7 +8155,7 @@ int DetectFastPatternTest297(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; distance:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8723,7 +8177,7 @@ int DetectFastPatternTest298(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; within:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8745,7 +8199,7 @@ int DetectFastPatternTest299(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; offset:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8767,7 +8221,7 @@ int DetectFastPatternTest300(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; depth:10; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -8789,11 +8243,11 @@ int DetectFastPatternTest301(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_method; content:!\"oneonetwo\"; fast_pattern:3,4; http_method; content:\"three\"; http_method; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8825,13 +8279,13 @@ int DetectFastPatternTest302(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; " "content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -8862,14 +8316,14 @@ int DetectFastPatternTest303(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_cookie; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -8899,14 +8353,14 @@ int DetectFastPatternTest304(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_cookie; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -8932,14 +8386,14 @@ int DetectFastPatternTest305(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -8966,14 +8420,14 @@ int DetectFastPatternTest306(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -8999,7 +8453,7 @@ int DetectFastPatternTest307(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9021,7 +8475,7 @@ int DetectFastPatternTest308(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; distance:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9043,7 +8497,7 @@ int DetectFastPatternTest309(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9065,7 +8519,7 @@ int DetectFastPatternTest310(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; within:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9087,7 +8541,7 @@ int DetectFastPatternTest311(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9109,7 +8563,7 @@ int DetectFastPatternTest312(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; offset:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9131,7 +8585,7 @@ int DetectFastPatternTest313(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:only; http_cookie; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9153,7 +8607,7 @@ int DetectFastPatternTest314(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; depth:10; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9175,7 +8629,7 @@ int DetectFastPatternTest315(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9197,12 +8651,12 @@ int DetectFastPatternTest316(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_cookie; content:\"two\"; http_cookie; distance:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9228,11 +8682,11 @@ int DetectFastPatternTest317(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9258,11 +8712,11 @@ int DetectFastPatternTest318(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9288,11 +8742,11 @@ int DetectFastPatternTest319(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:30; content:\"two\"; fast_pattern:only; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -9318,11 +8772,11 @@ int DetectFastPatternTest320(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_cookie; content:\"two\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9349,7 +8803,7 @@ int DetectFastPatternTest321(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9371,7 +8825,7 @@ int DetectFastPatternTest322(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9393,7 +8847,7 @@ int DetectFastPatternTest323(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9415,7 +8869,7 @@ int DetectFastPatternTest324(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_cookie; content:!\"one\"; fast_pattern; http_cookie; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9437,11 +8891,11 @@ int DetectFastPatternTest325(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9467,11 +8921,11 @@ int DetectFastPatternTest326(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9497,11 +8951,11 @@ int DetectFastPatternTest327(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9527,11 +8981,11 @@ int DetectFastPatternTest328(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9557,11 +9011,11 @@ int DetectFastPatternTest329(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9587,11 +9041,11 @@ int DetectFastPatternTest330(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; distance:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9617,11 +9071,11 @@ int DetectFastPatternTest331(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; within:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9647,11 +9101,11 @@ int DetectFastPatternTest332(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; offset:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9677,11 +9131,11 @@ int DetectFastPatternTest333(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; http_cookie; depth:10; content:\"oneonethree\"; fast_pattern:3,4; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -9710,7 +9164,7 @@ int DetectFastPatternTest334(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:65977,4; http_cookie; content:\"three\"; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9732,7 +9186,7 @@ int DetectFastPatternTest335(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"oneonetwo\"; fast_pattern:3,65977; http_cookie; content:\"three\"; distance:10; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9754,7 +9208,7 @@ int DetectFastPatternTest336(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:\"two\"; fast_pattern:65534,4; http_cookie; content:\"three\"; http_cookie; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9776,11 +9230,11 @@ int DetectFastPatternTest337(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9807,7 +9261,7 @@ int DetectFastPatternTest338(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; distance:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9829,7 +9283,7 @@ int DetectFastPatternTest339(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; within:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9851,7 +9305,7 @@ int DetectFastPatternTest340(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; offset:10; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9873,7 +9327,7 @@ int DetectFastPatternTest341(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; depth:10; content:\"three2\"; http_cookie; sid:1;)"); if (de_ctx->sig_list != NULL) goto end; @@ -9895,11 +9349,11 @@ int DetectFastPatternTest342(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_cookie; content:!\"oneonetwo\"; fast_pattern:3,4; http_cookie; content:\"three\"; http_cookie; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_cookie_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9931,13 +9385,13 @@ int DetectFastPatternTest343(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -9968,14 +9422,14 @@ int DetectFastPatternTest344(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"/one/\"; fast_pattern:only; http_raw_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -10005,14 +9459,14 @@ int DetectFastPatternTest345(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_uri; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -10038,14 +9492,14 @@ int DetectFastPatternTest346(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10072,14 +9526,14 @@ int DetectFastPatternTest347(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; - DetectContentData *ud = sm->ctx; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10105,7 +9559,7 @@ int DetectFastPatternTest348(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10128,7 +9582,7 @@ int DetectFastPatternTest349(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; distance:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10151,7 +9605,7 @@ int DetectFastPatternTest350(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10174,7 +9628,7 @@ int DetectFastPatternTest351(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; within:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10197,7 +9651,7 @@ int DetectFastPatternTest352(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10220,7 +9674,7 @@ int DetectFastPatternTest353(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; offset:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10243,7 +9697,7 @@ int DetectFastPatternTest354(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:only; http_raw_uri; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10266,7 +9720,7 @@ int DetectFastPatternTest355(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; depth:10; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10289,7 +9743,7 @@ int DetectFastPatternTest356(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10312,14 +9766,14 @@ int DetectFastPatternTest357(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content: \"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; distance:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10345,13 +9799,13 @@ int DetectFastPatternTest358(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; within:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10377,13 +9831,13 @@ int DetectFastPatternTest359(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; offset:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10409,13 +9863,13 @@ int DetectFastPatternTest360(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; depth:30; " "content:\"two\"; fast_pattern:only; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -10441,12 +9895,12 @@ int DetectFastPatternTest361(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_raw_uri; " "content:\"two\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10473,7 +9927,7 @@ int DetectFastPatternTest362(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10496,7 +9950,7 @@ int DetectFastPatternTest363(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10519,7 +9973,7 @@ int DetectFastPatternTest364(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10542,7 +9996,7 @@ int DetectFastPatternTest365(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_uri; " "content:!\"one\"; fast_pattern; http_raw_uri; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -10565,13 +10019,13 @@ int DetectFastPatternTest366(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10597,13 +10051,13 @@ int DetectFastPatternTest367(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10629,13 +10083,13 @@ int DetectFastPatternTest368(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10661,13 +10115,13 @@ int DetectFastPatternTest369(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10693,13 +10147,13 @@ int DetectFastPatternTest370(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10725,13 +10179,13 @@ int DetectFastPatternTest371(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10757,13 +10211,13 @@ int DetectFastPatternTest372(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10789,13 +10243,13 @@ int DetectFastPatternTest373(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10821,13 +10275,13 @@ int DetectFastPatternTest374(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; http_raw_uri; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -10856,7 +10310,7 @@ int DetectFastPatternTest375(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:65977,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:10; sid:1;)"); @@ -10880,7 +10334,7 @@ int DetectFastPatternTest376(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_uri; " "content:\"three\"; distance:10; http_raw_uri; sid:1;)"); @@ -10904,7 +10358,7 @@ int DetectFastPatternTest377(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:\"two\"; fast_pattern:65534,4; http_raw_uri; " "content:\"three\"; http_raw_uri; distance:10; sid:1;)"); @@ -10928,13 +10382,13 @@ int DetectFastPatternTest378(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -10961,7 +10415,7 @@ int DetectFastPatternTest379(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; distance:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -10985,7 +10439,7 @@ int DetectFastPatternTest380(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; within:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -11009,7 +10463,7 @@ int DetectFastPatternTest381(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; offset:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -11033,7 +10487,7 @@ int DetectFastPatternTest382(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; depth:10; " "content:\"three\"; http_raw_uri; sid:1;)"); @@ -11057,13 +10511,13 @@ int DetectFastPatternTest383(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_uri; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_uri; " "content:\"three\"; http_raw_uri; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11095,13 +10549,13 @@ int DetectFastPatternTest384(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11132,14 +10586,14 @@ int DetectFastPatternTest385(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_msg; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -11169,14 +10623,14 @@ int DetectFastPatternTest386(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_msg; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -11202,16 +10656,16 @@ int DetectFastPatternTest387(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11238,17 +10692,17 @@ int DetectFastPatternTest388(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11274,7 +10728,7 @@ int DetectFastPatternTest389(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11297,7 +10751,7 @@ int DetectFastPatternTest390(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; distance:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11320,7 +10774,7 @@ int DetectFastPatternTest391(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11343,7 +10797,7 @@ int DetectFastPatternTest392(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; within:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11366,7 +10820,7 @@ int DetectFastPatternTest393(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11389,7 +10843,7 @@ int DetectFastPatternTest394(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; offset:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11412,7 +10866,7 @@ int DetectFastPatternTest395(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:only; http_stat_msg; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11435,7 +10889,7 @@ int DetectFastPatternTest396(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; depth:10; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11458,7 +10912,7 @@ int DetectFastPatternTest397(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11481,14 +10935,14 @@ int DetectFastPatternTest398(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; distance:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11514,13 +10968,13 @@ int DetectFastPatternTest399(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; within:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11546,13 +11000,13 @@ int DetectFastPatternTest400(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; offset:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11578,13 +11032,13 @@ int DetectFastPatternTest401(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; depth:30; " "content:\"two\"; fast_pattern:only; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -11610,12 +11064,12 @@ int DetectFastPatternTest402(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_stat_msg; " "content:\"two\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -11642,7 +11096,7 @@ int DetectFastPatternTest403(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11665,7 +11119,7 @@ int DetectFastPatternTest404(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11688,7 +11142,7 @@ int DetectFastPatternTest405(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11711,7 +11165,7 @@ int DetectFastPatternTest406(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_msg; " "content:!\"one\"; fast_pattern; http_stat_msg; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -11734,13 +11188,13 @@ int DetectFastPatternTest407(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11766,13 +11220,13 @@ int DetectFastPatternTest408(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11798,13 +11252,13 @@ int DetectFastPatternTest409(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11830,13 +11284,13 @@ int DetectFastPatternTest410(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11862,13 +11316,13 @@ int DetectFastPatternTest411(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11894,13 +11348,13 @@ int DetectFastPatternTest412(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11926,13 +11380,13 @@ int DetectFastPatternTest413(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11958,13 +11412,13 @@ int DetectFastPatternTest414(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -11990,13 +11444,13 @@ int DetectFastPatternTest415(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; http_stat_msg; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12025,7 +11479,7 @@ int DetectFastPatternTest416(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:65977,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); @@ -12049,7 +11503,7 @@ int DetectFastPatternTest417(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_msg; " "content:\"three\"; distance:10; http_stat_msg; sid:1;)"); @@ -12073,7 +11527,7 @@ int DetectFastPatternTest418(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:\"two\"; fast_pattern:65534,4; http_stat_msg; " "content:\"three\"; http_stat_msg; distance:10; sid:1;)"); @@ -12097,13 +11551,13 @@ int DetectFastPatternTest419(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12130,7 +11584,7 @@ int DetectFastPatternTest420(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; distance:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -12154,7 +11608,7 @@ int DetectFastPatternTest421(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; within:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -12178,7 +11632,7 @@ int DetectFastPatternTest422(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; offset:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -12202,7 +11656,7 @@ int DetectFastPatternTest423(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; depth:10; " "content:\"three\"; http_stat_msg; sid:1;)"); @@ -12226,13 +11680,13 @@ int DetectFastPatternTest424(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_msg; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_msg; " "content:\"three\"; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_msg_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12264,13 +11718,13 @@ int DetectFastPatternTest425(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12301,14 +11755,14 @@ int DetectFastPatternTest426(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_code; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -12338,14 +11792,14 @@ int DetectFastPatternTest427(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_code; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -12371,17 +11825,17 @@ int DetectFastPatternTest428(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12408,17 +11862,17 @@ int DetectFastPatternTest429(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12444,7 +11898,7 @@ int DetectFastPatternTest430(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12467,7 +11921,7 @@ int DetectFastPatternTest431(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; distance:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12490,7 +11944,7 @@ int DetectFastPatternTest432(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12513,7 +11967,7 @@ int DetectFastPatternTest433(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; within:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12536,7 +11990,7 @@ int DetectFastPatternTest434(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12559,7 +12013,7 @@ int DetectFastPatternTest435(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; offset:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12582,7 +12036,7 @@ int DetectFastPatternTest436(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:only; http_stat_code; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12605,7 +12059,7 @@ int DetectFastPatternTest437(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; depth:10; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12628,7 +12082,7 @@ int DetectFastPatternTest438(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12651,14 +12105,14 @@ int DetectFastPatternTest439(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_stat_code; " "content:\"two\"; http_stat_code; distance:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12684,13 +12138,13 @@ int DetectFastPatternTest440(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; within:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12716,13 +12170,13 @@ int DetectFastPatternTest441(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; offset:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12748,13 +12202,13 @@ int DetectFastPatternTest442(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; depth:30; " "content:\"two\"; fast_pattern:only; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -12780,12 +12234,12 @@ int DetectFastPatternTest443(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_stat_code; " "content:\"two\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -12812,7 +12266,7 @@ int DetectFastPatternTest444(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12835,7 +12289,7 @@ int DetectFastPatternTest445(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12858,7 +12312,7 @@ int DetectFastPatternTest446(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12881,7 +12335,7 @@ int DetectFastPatternTest447(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_stat_code; " "content:!\"one\"; fast_pattern; http_stat_code; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -12904,13 +12358,13 @@ int DetectFastPatternTest448(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12936,13 +12390,13 @@ int DetectFastPatternTest449(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -12968,13 +12422,13 @@ int DetectFastPatternTest450(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13000,13 +12454,13 @@ int DetectFastPatternTest451(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13032,13 +12486,13 @@ int DetectFastPatternTest452(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13064,13 +12518,13 @@ int DetectFastPatternTest453(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13096,13 +12550,13 @@ int DetectFastPatternTest454(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13128,13 +12582,13 @@ int DetectFastPatternTest455(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13160,13 +12614,13 @@ int DetectFastPatternTest456(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; http_stat_code; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13195,7 +12649,7 @@ int DetectFastPatternTest457(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:65977,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:10; sid:1;)"); @@ -13219,7 +12673,7 @@ int DetectFastPatternTest458(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_stat_code; " "content:\"three\"; distance:10; http_stat_code; sid:1;)"); @@ -13243,7 +12697,7 @@ int DetectFastPatternTest459(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:\"two\"; fast_pattern:65534,4; http_stat_code; " "content:\"three\"; http_stat_code; distance:10; sid:1;)"); @@ -13267,13 +12721,13 @@ int DetectFastPatternTest460(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13300,7 +12754,7 @@ int DetectFastPatternTest461(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; distance:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -13324,7 +12778,7 @@ int DetectFastPatternTest462(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; within:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -13348,7 +12802,7 @@ int DetectFastPatternTest463(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; offset:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -13372,7 +12826,7 @@ int DetectFastPatternTest464(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; depth:10; " "content:\"three\"; http_stat_code; sid:1;)"); @@ -13396,13 +12850,13 @@ int DetectFastPatternTest465(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_stat_code; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_stat_code; " "content:\"three\"; http_stat_code; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_stat_code_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13434,13 +12888,14 @@ int DetectFastPatternTest466(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13471,14 +12926,14 @@ int DetectFastPatternTest467(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_server_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -13508,14 +12963,14 @@ int DetectFastPatternTest468(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_server_body; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -13541,16 +12996,16 @@ int DetectFastPatternTest469(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13577,17 +13032,17 @@ int DetectFastPatternTest470(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -13613,7 +13068,7 @@ int DetectFastPatternTest471(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13636,7 +13091,7 @@ int DetectFastPatternTest472(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; distance:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13659,7 +13114,7 @@ int DetectFastPatternTest473(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13682,7 +13137,7 @@ int DetectFastPatternTest474(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; within:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13705,7 +13160,7 @@ int DetectFastPatternTest475(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13728,7 +13183,7 @@ int DetectFastPatternTest476(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; offset:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13751,7 +13206,7 @@ int DetectFastPatternTest477(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:only; http_server_body; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13774,7 +13229,7 @@ int DetectFastPatternTest478(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; depth:10; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13797,7 +13252,7 @@ int DetectFastPatternTest479(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -13820,14 +13275,14 @@ int DetectFastPatternTest480(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_server_body; " "content:\"two\"; http_server_body; distance:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13853,13 +13308,14 @@ int DetectFastPatternTest481(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; within:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13885,13 +13341,14 @@ int DetectFastPatternTest482(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; offset:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13917,13 +13374,14 @@ int DetectFastPatternTest483(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; depth:30; " "content:\"two\"; fast_pattern:only; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -13949,12 +13407,13 @@ int DetectFastPatternTest484(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_server_body; " "content:\"two\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -13981,7 +13440,7 @@ int DetectFastPatternTest485(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14004,7 +13463,7 @@ int DetectFastPatternTest486(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14027,7 +13486,7 @@ int DetectFastPatternTest487(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14050,7 +13509,7 @@ int DetectFastPatternTest488(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "content:!\"one\"; fast_pattern; http_server_body; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14073,13 +13532,14 @@ int DetectFastPatternTest489(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14105,13 +13565,14 @@ int DetectFastPatternTest490(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14137,13 +13598,14 @@ int DetectFastPatternTest491(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14169,13 +13631,14 @@ int DetectFastPatternTest492(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14201,13 +13664,14 @@ int DetectFastPatternTest493(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14233,13 +13697,14 @@ int DetectFastPatternTest494(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14265,13 +13730,14 @@ int DetectFastPatternTest495(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14297,13 +13763,14 @@ int DetectFastPatternTest496(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14329,13 +13796,14 @@ int DetectFastPatternTest497(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; http_server_body; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14364,7 +13832,7 @@ int DetectFastPatternTest498(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:65977,4; http_server_body; " "content:\"three\"; http_server_body; distance:10; sid:1;)"); @@ -14388,7 +13856,7 @@ int DetectFastPatternTest499(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_server_body; " "content:\"three\"; distance:10; http_server_body; sid:1;)"); @@ -14412,7 +13880,7 @@ int DetectFastPatternTest500(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; fast_pattern:65534,4; http_server_body; " "content:\"three\"; http_server_body; distance:10; sid:1;)"); @@ -14436,13 +13904,14 @@ int DetectFastPatternTest501(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14469,7 +13938,7 @@ int DetectFastPatternTest502(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; distance:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14493,7 +13962,7 @@ int DetectFastPatternTest503(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; within:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14517,7 +13986,7 @@ int DetectFastPatternTest504(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; offset:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14541,7 +14010,7 @@ int DetectFastPatternTest505(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; depth:10; " "content:\"three\"; http_server_body; sid:1;)"); @@ -14565,13 +14034,14 @@ int DetectFastPatternTest506(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_server_body; " "content:\"three\"; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -14593,38 +14063,22 @@ int DetectFastPatternTest506(void) /* http_server_body fast_pattern tests ^ */ /* file_data fast_pattern tests v */ - -int DetectFastPatternTest507(void) +/** \test file_data and icmp don't mix */ +static int DetectFastPatternTest507(void) { - DetectEngineCtx *de_ctx = NULL; - int result = 0; - - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; - + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " - "(file_data; content:\"one\"; " - "content:!\"oneonetwo\"; fast_pattern:3,4; " - "content:\"three\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - if (ud->flags & DETECT_CONTENT_FAST_PATTERN && - ud->flags & DETECT_CONTENT_NEGATED && - !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && - ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && - ud->fp_chop_offset == 3 && - ud->fp_chop_len == 4) { - result = 1; - } else { - result = 0; - } - end: - SigCleanSignatures(de_ctx); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert icmp any any -> any any " + "(file_data; content:\"one\"; " + "content:!\"oneonetwo\"; fast_pattern:3,4; " + "content:\"three\"; sid:1;)"); + FAIL_IF_NOT_NULL(s); + DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -14640,14 +14094,14 @@ int DetectFastPatternTest508(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; fast_pattern:only; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -14677,14 +14131,14 @@ int DetectFastPatternTest509(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"oneoneone\"; fast_pattern:3,4; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -14710,16 +14164,16 @@ int DetectFastPatternTest510(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -14746,17 +14200,17 @@ int DetectFastPatternTest511(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"oneoneone\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -14782,7 +14236,7 @@ int DetectFastPatternTest512(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14805,7 +14259,7 @@ int DetectFastPatternTest513(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; distance:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14828,7 +14282,7 @@ int DetectFastPatternTest514(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14851,7 +14305,7 @@ int DetectFastPatternTest515(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14874,7 +14328,7 @@ int DetectFastPatternTest516(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14897,7 +14351,7 @@ int DetectFastPatternTest517(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14920,7 +14374,7 @@ int DetectFastPatternTest518(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:only; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14943,7 +14397,7 @@ int DetectFastPatternTest519(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:10; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14966,7 +14420,7 @@ int DetectFastPatternTest520(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -14989,14 +14443,14 @@ int DetectFastPatternTest521(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\" one\"; " "content:\"two\"; distance:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15022,13 +14476,14 @@ int DetectFastPatternTest522(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15054,13 +14509,14 @@ int DetectFastPatternTest523(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15086,13 +14542,14 @@ int DetectFastPatternTest524(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:30; " "content:\"two\"; fast_pattern:only; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15118,12 +14575,13 @@ int DetectFastPatternTest525(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:!\"one\"; fast_pattern; " "content:\"two\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15150,7 +14608,7 @@ int DetectFastPatternTest526(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15173,7 +14631,7 @@ int DetectFastPatternTest527(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15196,7 +14654,7 @@ int DetectFastPatternTest528(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15219,7 +14677,7 @@ int DetectFastPatternTest529(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"two\"; " "content:!\"one\"; fast_pattern; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15242,13 +14700,14 @@ int DetectFastPatternTest530(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15274,13 +14733,14 @@ int DetectFastPatternTest531(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15306,13 +14766,14 @@ int DetectFastPatternTest532(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15338,13 +14799,14 @@ int DetectFastPatternTest533(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15370,13 +14832,14 @@ int DetectFastPatternTest534(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15402,13 +14865,14 @@ int DetectFastPatternTest535(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15434,13 +14898,14 @@ int DetectFastPatternTest536(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15466,13 +14931,14 @@ int DetectFastPatternTest537(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15498,13 +14964,14 @@ int DetectFastPatternTest538(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15533,7 +15000,7 @@ int DetectFastPatternTest539(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:65977,4; " "content:\"three\"; distance:10; sid:1;)"); @@ -15557,7 +15024,7 @@ int DetectFastPatternTest540(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"oneonetwo\"; fast_pattern:3,65977; " "content:\"three\"; distance:10; sid:1;)"); @@ -15581,7 +15048,7 @@ int DetectFastPatternTest541(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:\"two\"; fast_pattern:65534,4; " "content:\"three\"; distance:10; sid:1;)"); @@ -15605,13 +15072,14 @@ int DetectFastPatternTest542(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15638,7 +15106,7 @@ int DetectFastPatternTest543(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; distance:10; " "content:\"three\"; sid:1;)"); @@ -15662,7 +15130,7 @@ int DetectFastPatternTest544(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; within:10; " "content:\"three\"; sid:1;)"); @@ -15686,7 +15154,7 @@ int DetectFastPatternTest545(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; offset:10; " "content:\"three\"; sid:1;)"); @@ -15710,7 +15178,7 @@ int DetectFastPatternTest546(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; depth:10; " "content:\"three\"; sid:1;)"); @@ -15734,13 +15202,14 @@ int DetectFastPatternTest547(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"one\"; " "content:!\"oneonetwo\"; fast_pattern:3,4; " "content:\"three\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; + + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15772,13 +15241,13 @@ int DetectFastPatternTest548(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -15810,14 +15279,14 @@ int DetectFastPatternTest549(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_user_agent; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -15847,14 +15316,14 @@ int DetectFastPatternTest550(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm != NULL) { if ( ((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) { @@ -15880,16 +15349,16 @@ int DetectFastPatternTest551(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -15916,17 +15385,17 @@ int DetectFastPatternTest552(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_ua_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -15952,7 +15421,7 @@ int DetectFastPatternTest553(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15975,7 +15444,7 @@ int DetectFastPatternTest554(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; distance:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -15998,7 +15467,7 @@ int DetectFastPatternTest555(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16021,7 +15490,7 @@ int DetectFastPatternTest556(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; within:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16044,7 +15513,7 @@ int DetectFastPatternTest557(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16067,7 +15536,7 @@ int DetectFastPatternTest558(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; offset:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16090,7 +15559,7 @@ int DetectFastPatternTest559(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:only; http_user_agent; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16113,7 +15582,7 @@ int DetectFastPatternTest560(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; depth:10; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16136,7 +15605,7 @@ int DetectFastPatternTest561(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16159,14 +15628,14 @@ int DetectFastPatternTest562(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_user_agent; " "content:\"two\"; http_user_agent; distance:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16192,13 +15661,13 @@ int DetectFastPatternTest563(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; within:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16224,13 +15693,13 @@ int DetectFastPatternTest564(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; offset:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16256,13 +15725,13 @@ int DetectFastPatternTest565(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; depth:30; " "content:\"two\"; fast_pattern:only; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -16288,12 +15757,12 @@ int DetectFastPatternTest566(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_user_agent; " "content:\"two\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16320,7 +15789,7 @@ int DetectFastPatternTest567(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16343,7 +15812,7 @@ int DetectFastPatternTest568(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16366,7 +15835,7 @@ int DetectFastPatternTest569(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16389,7 +15858,7 @@ int DetectFastPatternTest570(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_user_agent; " "content:!\"one\"; fast_pattern; http_user_agent; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -16412,13 +15881,13 @@ int DetectFastPatternTest571(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16444,13 +15913,13 @@ int DetectFastPatternTest572(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16476,13 +15945,13 @@ int DetectFastPatternTest573(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16508,13 +15977,13 @@ int DetectFastPatternTest574(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16540,13 +16009,13 @@ int DetectFastPatternTest575(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16572,13 +16041,13 @@ int DetectFastPatternTest576(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16604,13 +16073,13 @@ int DetectFastPatternTest577(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16636,13 +16105,13 @@ int DetectFastPatternTest578(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16668,13 +16137,13 @@ int DetectFastPatternTest579(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; http_user_agent; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -16703,7 +16172,7 @@ int DetectFastPatternTest580(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:65977,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:10; sid:1;)"); @@ -16727,7 +16196,7 @@ int DetectFastPatternTest581(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_user_agent; " "content:\"three\"; distance:10; http_user_agent; sid:1;)"); @@ -16751,7 +16220,7 @@ int DetectFastPatternTest582(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:\"two\"; fast_pattern:65534,4; http_user_agent; " "content:\"three\"; http_user_agent; distance:10; sid:1;)"); @@ -16775,13 +16244,13 @@ int DetectFastPatternTest583(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16808,7 +16277,7 @@ int DetectFastPatternTest584(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; distance:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16832,7 +16301,7 @@ int DetectFastPatternTest585(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; within:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16856,7 +16325,7 @@ int DetectFastPatternTest586(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; offset:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16880,7 +16349,7 @@ int DetectFastPatternTest587(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; depth:10; " "content:\"three\"; http_user_agent; sid:1;)"); @@ -16904,13 +16373,13 @@ int DetectFastPatternTest588(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_user_agent; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_user_agent; " "content:\"three\"; http_user_agent; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16942,13 +16411,13 @@ int DetectFastPatternTest589(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -16979,14 +16448,14 @@ int DetectFastPatternTest590(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_host; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { @@ -17016,14 +16485,14 @@ int DetectFastPatternTest591(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_host; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { @@ -17049,16 +16518,16 @@ int DetectFastPatternTest592(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17085,17 +16554,17 @@ int DetectFastPatternTest593(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_host_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17121,7 +16590,7 @@ int DetectFastPatternTest594(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; distance:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17144,7 +16613,7 @@ int DetectFastPatternTest595(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; distance:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17167,7 +16636,7 @@ int DetectFastPatternTest596(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; within:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17190,7 +16659,7 @@ int DetectFastPatternTest597(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; within:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17213,7 +16682,7 @@ int DetectFastPatternTest598(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; offset:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17236,7 +16705,7 @@ int DetectFastPatternTest599(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; offset:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17259,7 +16728,7 @@ int DetectFastPatternTest600(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:only; http_host; depth:10; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17282,7 +16751,7 @@ int DetectFastPatternTest601(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; depth:10; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17305,7 +16774,7 @@ int DetectFastPatternTest602(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17328,14 +16797,14 @@ int DetectFastPatternTest603(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_host; " "content:\"two\"; http_host; distance:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17361,13 +16830,13 @@ int DetectFastPatternTest604(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; within:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17393,13 +16862,13 @@ int DetectFastPatternTest605(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; offset:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17425,13 +16894,13 @@ int DetectFastPatternTest606(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; depth:30; " "content:\"two\"; fast_pattern:only; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && @@ -17457,12 +16926,12 @@ int DetectFastPatternTest607(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_host; " "content:\"two\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -17489,7 +16958,7 @@ int DetectFastPatternTest608(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; distance:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17512,7 +16981,7 @@ int DetectFastPatternTest609(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; within:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17535,7 +17004,7 @@ int DetectFastPatternTest610(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; offset:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17558,7 +17027,7 @@ int DetectFastPatternTest611(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_host; " "content:!\"one\"; fast_pattern; http_host; depth:20; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -17581,13 +17050,13 @@ int DetectFastPatternTest612(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17613,13 +17082,13 @@ int DetectFastPatternTest613(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; distance:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17645,13 +17114,13 @@ int DetectFastPatternTest614(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; within:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17677,13 +17146,13 @@ int DetectFastPatternTest615(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; offset:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17709,13 +17178,13 @@ int DetectFastPatternTest616(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; depth:30; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17741,13 +17210,13 @@ int DetectFastPatternTest617(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; distance:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17773,13 +17242,13 @@ int DetectFastPatternTest618(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; within:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17805,13 +17274,13 @@ int DetectFastPatternTest619(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; offset:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17837,13 +17306,13 @@ int DetectFastPatternTest620(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; http_host; depth:10; " "content:\"oneonethree\"; fast_pattern:3,4; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && @@ -17872,7 +17341,7 @@ int DetectFastPatternTest621(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:65977,4; http_host; " "content:\"three\"; http_host; distance:10; sid:1;)"); @@ -17896,7 +17365,7 @@ int DetectFastPatternTest622(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_host; " "content:\"three\"; distance:10; http_host; sid:1;)"); @@ -17920,7 +17389,7 @@ int DetectFastPatternTest623(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:\"two\"; fast_pattern:65534,4; http_host; " "content:\"three\"; http_host; distance:10; sid:1;)"); @@ -17944,13 +17413,13 @@ int DetectFastPatternTest624(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -17977,7 +17446,7 @@ int DetectFastPatternTest625(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; distance:10; " "content:\"three\"; http_host; sid:1;)"); @@ -18001,7 +17470,7 @@ int DetectFastPatternTest626(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; within:10; " "content:\"three\"; http_host; sid:1;)"); @@ -18025,7 +17494,7 @@ int DetectFastPatternTest627(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; offset:10; " "content:\"three\"; http_host; sid:1;)"); @@ -18049,7 +17518,7 @@ int DetectFastPatternTest628(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; depth:10; " "content:\"three\"; http_host; sid:1;)"); @@ -18073,13 +17542,13 @@ int DetectFastPatternTest629(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_host; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_host; " "content:\"three\"; http_host; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18111,13 +17580,13 @@ int DetectFastPatternTest630(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NEGATED && ud->flags & DETECT_CONTENT_NOCASE && @@ -18149,14 +17618,14 @@ int DetectFastPatternTest631(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_host; nocase; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) && @@ -18188,14 +17657,14 @@ int DetectFastPatternTest632(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_host; nocase; " "msg:\"Testing fast_pattern\"; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm != NULL) { if ( (((DetectContentData *)sm->ctx)->flags & DETECT_CONTENT_FAST_PATTERN) && @@ -18223,16 +17692,16 @@ int DetectFastPatternTest633(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18260,17 +17729,17 @@ int DetectFastPatternTest634(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"oneoneone\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id]; if (sm == NULL) { goto end; } - DetectContentData *ud = sm->ctx; + DetectContentData *ud = (DetectContentData *)sm->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18297,7 +17766,7 @@ int DetectFastPatternTest635(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; distance:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18320,7 +17789,7 @@ int DetectFastPatternTest636(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; distance:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18343,7 +17812,7 @@ int DetectFastPatternTest637(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; within:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18366,7 +17835,7 @@ int DetectFastPatternTest638(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; within:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18389,7 +17858,7 @@ int DetectFastPatternTest639(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; offset:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18412,7 +17881,7 @@ int DetectFastPatternTest640(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; offset:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18435,7 +17904,7 @@ int DetectFastPatternTest641(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; depth:10; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18458,7 +17927,7 @@ int DetectFastPatternTest642(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; depth:10; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18481,7 +17950,7 @@ int DetectFastPatternTest643(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18504,14 +17973,14 @@ int DetectFastPatternTest644(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\" one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; distance:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18538,13 +18007,13 @@ int DetectFastPatternTest645(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; within:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18571,13 +18040,13 @@ int DetectFastPatternTest646(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; offset:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18604,13 +18073,13 @@ int DetectFastPatternTest647(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; depth:30; nocase; " "content:\"two\"; fast_pattern:only; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && @@ -18637,12 +18106,12 @@ int DetectFastPatternTest648(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:!\"one\"; fast_pattern; http_raw_host; nocase; " "content:\"two\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -18670,7 +18139,7 @@ int DetectFastPatternTest649(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; distance:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18693,7 +18162,7 @@ int DetectFastPatternTest650(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; within:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18716,7 +18185,7 @@ int DetectFastPatternTest651(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; offset:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18739,7 +18208,7 @@ int DetectFastPatternTest652(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_raw_host; nocase; " "content:!\"one\"; fast_pattern; http_raw_host; depth:20; nocase; sid:1;)"); if (de_ctx->sig_list != NULL) @@ -18762,13 +18231,13 @@ int DetectFastPatternTest653(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18795,13 +18264,13 @@ int DetectFastPatternTest654(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18828,13 +18297,13 @@ int DetectFastPatternTest655(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; within:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18861,13 +18330,13 @@ int DetectFastPatternTest656(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; offset:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18894,13 +18363,13 @@ int DetectFastPatternTest657(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; depth:30; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18927,13 +18396,13 @@ int DetectFastPatternTest658(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; distance:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18960,13 +18429,13 @@ int DetectFastPatternTest659(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; within:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -18993,13 +18462,13 @@ int DetectFastPatternTest660(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; offset:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -19026,13 +18495,13 @@ int DetectFastPatternTest661(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; http_raw_host; depth:10; nocase; " "content:\"oneonethree\"; fast_pattern:3,4; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && !(ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && @@ -19062,7 +18531,7 @@ int DetectFastPatternTest662(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:65977,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:10; nocase; sid:1;)"); @@ -19086,7 +18555,7 @@ int DetectFastPatternTest663(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"oneonetwo\"; fast_pattern:3,65977; http_raw_host; nocase; " "content:\"three\"; distance:10; http_raw_host; nocase; sid:1;)"); @@ -19110,7 +18579,7 @@ int DetectFastPatternTest664(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:\"two\"; fast_pattern:65534,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; distance:10; nocase; sid:1;)"); @@ -19134,13 +18603,13 @@ int DetectFastPatternTest665(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -19168,7 +18637,7 @@ int DetectFastPatternTest666(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; distance:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -19192,7 +18661,7 @@ int DetectFastPatternTest667(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; within:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -19216,7 +18685,7 @@ int DetectFastPatternTest668(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; offset:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -19240,7 +18709,7 @@ int DetectFastPatternTest669(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; depth:10; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); @@ -19264,13 +18733,13 @@ int DetectFastPatternTest670(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_raw_host; nocase; " "content:!\"oneonetwo\"; fast_pattern:3,4; http_raw_host; nocase; " "content:\"three\"; http_raw_host; nocase; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - DetectContentData *ud = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; + DetectContentData *ud = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; if (ud->flags & DETECT_CONTENT_FAST_PATTERN && ud->flags & DETECT_CONTENT_NOCASE && ud->flags & DETECT_CONTENT_NEGATED && @@ -19300,13 +18769,11 @@ int DetectFastPatternTest670(void) int DetectFastPatternTest671(void) { int no_of_sigs = 6; - int result = 0; char *sigs[no_of_sigs]; Signature *s[no_of_sigs]; - Signature *sig = NULL; DetectEngineCtx *de_ctx = NULL; DetectContentData *cd = NULL; - SigMatch *sm = NULL; + SigMatchData *smd = NULL; int i = 0; sigs[0] = "alert tcp any any -> any any " @@ -19323,793 +18790,756 @@ int DetectFastPatternTest671(void) "(content:\"onetwothreefour\"; fast_pattern:0,15; sid:6;)"; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("DetectEngineCtxInit() failure\n"); - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - i = 0; - s[i] = SigInit(de_ctx, sigs[i]); - de_ctx->sig_list = sig = s[i]; - if (sig == NULL) { - printf("SigInit(de_ctx, sig1) failure\n"); - goto end; - } - i++; - for ( ; i < no_of_sigs; i++) { - s[i] = SigInit(de_ctx, sigs[i]); - sig->next = s[i]; - sig = sig->next; - if (sig == NULL) { - printf("SigInit(de_ctx, sig[%d]) failure\n", i); - goto end; - } + for (i = 0; i < no_of_sigs; i++) { + s[i] = DetectEngineAppendSig(de_ctx, sigs[i]); + FAIL_IF_NULL(s[i]); } SigGroupBuild(de_ctx); - sm = s[0]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; - if (cd->id != 0) { - printf("sm = s[0]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } - - sm = s[1]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; - if (cd->id != 0) { - printf("sm = s[1]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[0]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 0); - sm = s[2]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; - if (cd->id != 1) { - printf("sm = s[2]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[1]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 0); - sm = s[3]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; - if (cd->id != 2) { - printf("sm = s[3]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[2]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 2); - sm = s[4]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; - if (cd->id != 2) { - printf("sm = s[4]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[3]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 1); - sm = s[5]->sm_lists[DETECT_SM_LIST_PMATCH]; - cd = sm->ctx; - if (cd->id != 0) { - printf("sm = s[5]->sm_lists[DETECT_SM_LIST_PMATCH] failure\n"); - goto end; - } + smd = s[4]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 1); - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - } + smd = s[5]->sm_arrays[DETECT_SM_LIST_PMATCH]; + cd = (DetectContentData *)smd->ctx; + FAIL_IF(cd->id != 0); - return result; + DetectEngineCtxFree(de_ctx); + PASS; } #endif void DetectFastPatternRegisterTests(void) { - #ifdef UNITTESTS - UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01, 1); - UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02, 1); - UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03, 1); - UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04, 1); - UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05, 1); - UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06, 1); - UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07, 1); - UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08, 1); - UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09, 1); - UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10, 1); - UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11, 1); - UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12, 1); - UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13, 1); - UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14, 1); - UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15, 1); - UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16, 1); - UtRegisterTest("DetectFastPatternTest17", DetectFastPatternTest17, 1); - UtRegisterTest("DetectFastPatternTest18", DetectFastPatternTest18, 1); - UtRegisterTest("DetectFastPatternTest19", DetectFastPatternTest19, 1); - UtRegisterTest("DetectFastPatternTest20", DetectFastPatternTest20, 1); - UtRegisterTest("DetectFastPatternTest21", DetectFastPatternTest21, 1); - UtRegisterTest("DetectFastPatternTest22", DetectFastPatternTest22, 1); - UtRegisterTest("DetectFastPatternTest23", DetectFastPatternTest23, 1); - UtRegisterTest("DetectFastPatternTest24", DetectFastPatternTest24, 1); - UtRegisterTest("DetectFastPatternTest25", DetectFastPatternTest25, 1); - UtRegisterTest("DetectFastPatternTest26", DetectFastPatternTest26, 1); - UtRegisterTest("DetectFastPatternTest27", DetectFastPatternTest27, 1); - UtRegisterTest("DetectFastPatternTest28", DetectFastPatternTest28, 1); - UtRegisterTest("DetectFastPatternTest29", DetectFastPatternTest29, 1); - UtRegisterTest("DetectFastPatternTest30", DetectFastPatternTest30, 1); - UtRegisterTest("DetectFastPatternTest31", DetectFastPatternTest31, 1); - UtRegisterTest("DetectFastPatternTest32", DetectFastPatternTest32, 1); - UtRegisterTest("DetectFastPatternTest33", DetectFastPatternTest33, 1); - UtRegisterTest("DetectFastPatternTest34", DetectFastPatternTest34, 1); - UtRegisterTest("DetectFastPatternTest35", DetectFastPatternTest35, 1); - UtRegisterTest("DetectFastPatternTest36", DetectFastPatternTest36, 1); - UtRegisterTest("DetectFastPatternTest37", DetectFastPatternTest37, 1); - UtRegisterTest("DetectFastPatternTest38", DetectFastPatternTest38, 1); - UtRegisterTest("DetectFastPatternTest39", DetectFastPatternTest39, 1); - UtRegisterTest("DetectFastPatternTest40", DetectFastPatternTest40, 1); - UtRegisterTest("DetectFastPatternTest41", DetectFastPatternTest41, 1); - UtRegisterTest("DetectFastPatternTest42", DetectFastPatternTest42, 1); - UtRegisterTest("DetectFastPatternTest43", DetectFastPatternTest43, 1); - UtRegisterTest("DetectFastPatternTest44", DetectFastPatternTest44, 1); - UtRegisterTest("DetectFastPatternTest45", DetectFastPatternTest45, 1); - UtRegisterTest("DetectFastPatternTest46", DetectFastPatternTest46, 1); - UtRegisterTest("DetectFastPatternTest47", DetectFastPatternTest47, 1); - UtRegisterTest("DetectFastPatternTest48", DetectFastPatternTest48, 1); - UtRegisterTest("DetectFastPatternTest49", DetectFastPatternTest49, 1); - UtRegisterTest("DetectFastPatternTest50", DetectFastPatternTest50, 1); - UtRegisterTest("DetectFastPatternTest51", DetectFastPatternTest51, 1); - UtRegisterTest("DetectFastPatternTest52", DetectFastPatternTest52, 1); - UtRegisterTest("DetectFastPatternTest53", DetectFastPatternTest53, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); + g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); + g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); + g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); + g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); + g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); + g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); + g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); + g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); + + UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); + UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02); + UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03); + UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04); + UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14); + UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15); + UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16); + UtRegisterTest("DetectFastPatternTest17", DetectFastPatternTest17); + UtRegisterTest("DetectFastPatternTest18", DetectFastPatternTest18); + UtRegisterTest("DetectFastPatternTest19", DetectFastPatternTest19); + UtRegisterTest("DetectFastPatternTest20", DetectFastPatternTest20); + UtRegisterTest("DetectFastPatternTest21", DetectFastPatternTest21); + UtRegisterTest("DetectFastPatternTest22", DetectFastPatternTest22); + UtRegisterTest("DetectFastPatternTest23", DetectFastPatternTest23); + UtRegisterTest("DetectFastPatternTest24", DetectFastPatternTest24); + UtRegisterTest("DetectFastPatternTest25", DetectFastPatternTest25); + UtRegisterTest("DetectFastPatternTest26", DetectFastPatternTest26); + UtRegisterTest("DetectFastPatternTest27", DetectFastPatternTest27); + UtRegisterTest("DetectFastPatternTest28", DetectFastPatternTest28); + UtRegisterTest("DetectFastPatternTest29", DetectFastPatternTest29); + UtRegisterTest("DetectFastPatternTest30", DetectFastPatternTest30); + UtRegisterTest("DetectFastPatternTest31", DetectFastPatternTest31); + UtRegisterTest("DetectFastPatternTest32", DetectFastPatternTest32); + UtRegisterTest("DetectFastPatternTest33", DetectFastPatternTest33); + UtRegisterTest("DetectFastPatternTest34", DetectFastPatternTest34); + UtRegisterTest("DetectFastPatternTest35", DetectFastPatternTest35); + UtRegisterTest("DetectFastPatternTest36", DetectFastPatternTest36); + UtRegisterTest("DetectFastPatternTest37", DetectFastPatternTest37); + UtRegisterTest("DetectFastPatternTest38", DetectFastPatternTest38); + UtRegisterTest("DetectFastPatternTest39", DetectFastPatternTest39); + UtRegisterTest("DetectFastPatternTest40", DetectFastPatternTest40); + UtRegisterTest("DetectFastPatternTest41", DetectFastPatternTest41); + UtRegisterTest("DetectFastPatternTest42", DetectFastPatternTest42); + UtRegisterTest("DetectFastPatternTest43", DetectFastPatternTest43); + UtRegisterTest("DetectFastPatternTest44", DetectFastPatternTest44); + UtRegisterTest("DetectFastPatternTest45", DetectFastPatternTest45); + UtRegisterTest("DetectFastPatternTest46", DetectFastPatternTest46); + UtRegisterTest("DetectFastPatternTest47", DetectFastPatternTest47); + UtRegisterTest("DetectFastPatternTest48", DetectFastPatternTest48); + UtRegisterTest("DetectFastPatternTest49", DetectFastPatternTest49); + UtRegisterTest("DetectFastPatternTest50", DetectFastPatternTest50); + UtRegisterTest("DetectFastPatternTest51", DetectFastPatternTest51); + UtRegisterTest("DetectFastPatternTest52", DetectFastPatternTest52); + UtRegisterTest("DetectFastPatternTest53", DetectFastPatternTest53); /* content fast_pattern tests ^ */ /* uricontent fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest54", DetectFastPatternTest54, 1); - UtRegisterTest("DetectFastPatternTest55", DetectFastPatternTest55, 1); - UtRegisterTest("DetectFastPatternTest56", DetectFastPatternTest56, 1); - UtRegisterTest("DetectFastPatternTest57", DetectFastPatternTest57, 1); - UtRegisterTest("DetectFastPatternTest58", DetectFastPatternTest58, 1); - UtRegisterTest("DetectFastPatternTest59", DetectFastPatternTest59, 1); - UtRegisterTest("DetectFastPatternTest60", DetectFastPatternTest60, 1); - UtRegisterTest("DetectFastPatternTest61", DetectFastPatternTest61, 1); - UtRegisterTest("DetectFastPatternTest62", DetectFastPatternTest62, 1); - UtRegisterTest("DetectFastPatternTest63", DetectFastPatternTest63, 1); - UtRegisterTest("DetectFastPatternTest64", DetectFastPatternTest64, 1); - UtRegisterTest("DetectFastPatternTest65", DetectFastPatternTest65, 1); - UtRegisterTest("DetectFastPatternTest66", DetectFastPatternTest66, 1); - UtRegisterTest("DetectFastPatternTest67", DetectFastPatternTest67, 1); - UtRegisterTest("DetectFastPatternTest68", DetectFastPatternTest68, 1); - UtRegisterTest("DetectFastPatternTest69", DetectFastPatternTest69, 1); - UtRegisterTest("DetectFastPatternTest70", DetectFastPatternTest70, 1); - UtRegisterTest("DetectFastPatternTest71", DetectFastPatternTest71, 1); - UtRegisterTest("DetectFastPatternTest72", DetectFastPatternTest72, 1); - UtRegisterTest("DetectFastPatternTest73", DetectFastPatternTest73, 1); - UtRegisterTest("DetectFastPatternTest74", DetectFastPatternTest74, 1); - UtRegisterTest("DetectFastPatternTest75", DetectFastPatternTest75, 1); - UtRegisterTest("DetectFastPatternTest76", DetectFastPatternTest76, 1); - UtRegisterTest("DetectFastPatternTest77", DetectFastPatternTest77, 1); - UtRegisterTest("DetectFastPatternTest78", DetectFastPatternTest78, 1); - UtRegisterTest("DetectFastPatternTest79", DetectFastPatternTest79, 1); - UtRegisterTest("DetectFastPatternTest80", DetectFastPatternTest80, 1); - UtRegisterTest("DetectFastPatternTest81", DetectFastPatternTest81, 1); - UtRegisterTest("DetectFastPatternTest82", DetectFastPatternTest82, 1); - UtRegisterTest("DetectFastPatternTest83", DetectFastPatternTest83, 1); - UtRegisterTest("DetectFastPatternTest84", DetectFastPatternTest84, 1); - UtRegisterTest("DetectFastPatternTest85", DetectFastPatternTest85, 1); - UtRegisterTest("DetectFastPatternTest86", DetectFastPatternTest86, 1); - UtRegisterTest("DetectFastPatternTest87", DetectFastPatternTest87, 1); - UtRegisterTest("DetectFastPatternTest88", DetectFastPatternTest88, 1); - UtRegisterTest("DetectFastPatternTest89", DetectFastPatternTest89, 1); - UtRegisterTest("DetectFastPatternTest90", DetectFastPatternTest90, 1); - UtRegisterTest("DetectFastPatternTest91", DetectFastPatternTest91, 1); - UtRegisterTest("DetectFastPatternTest92", DetectFastPatternTest92, 1); + UtRegisterTest("DetectFastPatternTest54", DetectFastPatternTest54); + UtRegisterTest("DetectFastPatternTest55", DetectFastPatternTest55); + UtRegisterTest("DetectFastPatternTest56", DetectFastPatternTest56); + UtRegisterTest("DetectFastPatternTest57", DetectFastPatternTest57); + UtRegisterTest("DetectFastPatternTest58", DetectFastPatternTest58); + UtRegisterTest("DetectFastPatternTest59", DetectFastPatternTest59); + UtRegisterTest("DetectFastPatternTest60", DetectFastPatternTest60); + UtRegisterTest("DetectFastPatternTest61", DetectFastPatternTest61); + UtRegisterTest("DetectFastPatternTest62", DetectFastPatternTest62); + UtRegisterTest("DetectFastPatternTest63", DetectFastPatternTest63); + UtRegisterTest("DetectFastPatternTest64", DetectFastPatternTest64); + UtRegisterTest("DetectFastPatternTest65", DetectFastPatternTest65); + UtRegisterTest("DetectFastPatternTest66", DetectFastPatternTest66); + UtRegisterTest("DetectFastPatternTest67", DetectFastPatternTest67); + UtRegisterTest("DetectFastPatternTest68", DetectFastPatternTest68); + UtRegisterTest("DetectFastPatternTest69", DetectFastPatternTest69); + UtRegisterTest("DetectFastPatternTest70", DetectFastPatternTest70); + UtRegisterTest("DetectFastPatternTest71", DetectFastPatternTest71); + UtRegisterTest("DetectFastPatternTest72", DetectFastPatternTest72); + UtRegisterTest("DetectFastPatternTest73", DetectFastPatternTest73); + UtRegisterTest("DetectFastPatternTest74", DetectFastPatternTest74); + UtRegisterTest("DetectFastPatternTest75", DetectFastPatternTest75); + UtRegisterTest("DetectFastPatternTest76", DetectFastPatternTest76); + UtRegisterTest("DetectFastPatternTest77", DetectFastPatternTest77); + UtRegisterTest("DetectFastPatternTest78", DetectFastPatternTest78); + UtRegisterTest("DetectFastPatternTest79", DetectFastPatternTest79); + UtRegisterTest("DetectFastPatternTest80", DetectFastPatternTest80); + UtRegisterTest("DetectFastPatternTest81", DetectFastPatternTest81); + UtRegisterTest("DetectFastPatternTest82", DetectFastPatternTest82); + UtRegisterTest("DetectFastPatternTest83", DetectFastPatternTest83); + UtRegisterTest("DetectFastPatternTest84", DetectFastPatternTest84); + UtRegisterTest("DetectFastPatternTest85", DetectFastPatternTest85); + UtRegisterTest("DetectFastPatternTest86", DetectFastPatternTest86); + UtRegisterTest("DetectFastPatternTest87", DetectFastPatternTest87); + UtRegisterTest("DetectFastPatternTest88", DetectFastPatternTest88); + UtRegisterTest("DetectFastPatternTest89", DetectFastPatternTest89); + UtRegisterTest("DetectFastPatternTest90", DetectFastPatternTest90); + UtRegisterTest("DetectFastPatternTest91", DetectFastPatternTest91); + UtRegisterTest("DetectFastPatternTest92", DetectFastPatternTest92); /* uricontent fast_pattern tests ^ */ /* http_uri fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest93", DetectFastPatternTest93, 1); - UtRegisterTest("DetectFastPatternTest94", DetectFastPatternTest94, 1); - UtRegisterTest("DetectFastPatternTest95", DetectFastPatternTest95, 1); - UtRegisterTest("DetectFastPatternTest96", DetectFastPatternTest96, 1); - UtRegisterTest("DetectFastPatternTest97", DetectFastPatternTest97, 1); - UtRegisterTest("DetectFastPatternTest98", DetectFastPatternTest98, 1); - UtRegisterTest("DetectFastPatternTest99", DetectFastPatternTest99, 1); - UtRegisterTest("DetectFastPatternTest100", DetectFastPatternTest100, 1); - UtRegisterTest("DetectFastPatternTest101", DetectFastPatternTest101, 1); - UtRegisterTest("DetectFastPatternTest102", DetectFastPatternTest102, 1); - UtRegisterTest("DetectFastPatternTest103", DetectFastPatternTest103, 1); - UtRegisterTest("DetectFastPatternTest104", DetectFastPatternTest104, 1); - UtRegisterTest("DetectFastPatternTest105", DetectFastPatternTest105, 1); - UtRegisterTest("DetectFastPatternTest106", DetectFastPatternTest106, 1); - UtRegisterTest("DetectFastPatternTest107", DetectFastPatternTest107, 1); - UtRegisterTest("DetectFastPatternTest108", DetectFastPatternTest108, 1); - UtRegisterTest("DetectFastPatternTest109", DetectFastPatternTest109, 1); - UtRegisterTest("DetectFastPatternTest110", DetectFastPatternTest110, 1); - UtRegisterTest("DetectFastPatternTest111", DetectFastPatternTest111, 1); - UtRegisterTest("DetectFastPatternTest112", DetectFastPatternTest112, 1); - UtRegisterTest("DetectFastPatternTest113", DetectFastPatternTest113, 1); - UtRegisterTest("DetectFastPatternTest114", DetectFastPatternTest114, 1); - UtRegisterTest("DetectFastPatternTest115", DetectFastPatternTest115, 1); - UtRegisterTest("DetectFastPatternTest116", DetectFastPatternTest116, 1); - UtRegisterTest("DetectFastPatternTest117", DetectFastPatternTest117, 1); - UtRegisterTest("DetectFastPatternTest118", DetectFastPatternTest118, 1); - UtRegisterTest("DetectFastPatternTest119", DetectFastPatternTest119, 1); - UtRegisterTest("DetectFastPatternTest120", DetectFastPatternTest120, 1); - UtRegisterTest("DetectFastPatternTest121", DetectFastPatternTest121, 1); - UtRegisterTest("DetectFastPatternTest122", DetectFastPatternTest122, 1); - UtRegisterTest("DetectFastPatternTest123", DetectFastPatternTest123, 1); - UtRegisterTest("DetectFastPatternTest124", DetectFastPatternTest124, 1); - UtRegisterTest("DetectFastPatternTest125", DetectFastPatternTest125, 1); - UtRegisterTest("DetectFastPatternTest126", DetectFastPatternTest126, 1); - UtRegisterTest("DetectFastPatternTest127", DetectFastPatternTest127, 1); - UtRegisterTest("DetectFastPatternTest128", DetectFastPatternTest128, 1); - UtRegisterTest("DetectFastPatternTest129", DetectFastPatternTest129, 1); - UtRegisterTest("DetectFastPatternTest130", DetectFastPatternTest130, 1); - UtRegisterTest("DetectFastPatternTest131", DetectFastPatternTest131, 1); - UtRegisterTest("DetectFastPatternTest132", DetectFastPatternTest132, 1); - UtRegisterTest("DetectFastPatternTest133", DetectFastPatternTest133, 1); + UtRegisterTest("DetectFastPatternTest93", DetectFastPatternTest93); + UtRegisterTest("DetectFastPatternTest94", DetectFastPatternTest94); + UtRegisterTest("DetectFastPatternTest95", DetectFastPatternTest95); + UtRegisterTest("DetectFastPatternTest96", DetectFastPatternTest96); + UtRegisterTest("DetectFastPatternTest97", DetectFastPatternTest97); + UtRegisterTest("DetectFastPatternTest98", DetectFastPatternTest98); + UtRegisterTest("DetectFastPatternTest99", DetectFastPatternTest99); + UtRegisterTest("DetectFastPatternTest100", DetectFastPatternTest100); + UtRegisterTest("DetectFastPatternTest101", DetectFastPatternTest101); + UtRegisterTest("DetectFastPatternTest102", DetectFastPatternTest102); + UtRegisterTest("DetectFastPatternTest103", DetectFastPatternTest103); + UtRegisterTest("DetectFastPatternTest104", DetectFastPatternTest104); + UtRegisterTest("DetectFastPatternTest105", DetectFastPatternTest105); + UtRegisterTest("DetectFastPatternTest106", DetectFastPatternTest106); + UtRegisterTest("DetectFastPatternTest107", DetectFastPatternTest107); + UtRegisterTest("DetectFastPatternTest108", DetectFastPatternTest108); + UtRegisterTest("DetectFastPatternTest109", DetectFastPatternTest109); + UtRegisterTest("DetectFastPatternTest110", DetectFastPatternTest110); + UtRegisterTest("DetectFastPatternTest111", DetectFastPatternTest111); + UtRegisterTest("DetectFastPatternTest112", DetectFastPatternTest112); + UtRegisterTest("DetectFastPatternTest113", DetectFastPatternTest113); + UtRegisterTest("DetectFastPatternTest114", DetectFastPatternTest114); + UtRegisterTest("DetectFastPatternTest115", DetectFastPatternTest115); + UtRegisterTest("DetectFastPatternTest116", DetectFastPatternTest116); + UtRegisterTest("DetectFastPatternTest117", DetectFastPatternTest117); + UtRegisterTest("DetectFastPatternTest118", DetectFastPatternTest118); + UtRegisterTest("DetectFastPatternTest119", DetectFastPatternTest119); + UtRegisterTest("DetectFastPatternTest120", DetectFastPatternTest120); + UtRegisterTest("DetectFastPatternTest121", DetectFastPatternTest121); + UtRegisterTest("DetectFastPatternTest122", DetectFastPatternTest122); + UtRegisterTest("DetectFastPatternTest123", DetectFastPatternTest123); + UtRegisterTest("DetectFastPatternTest124", DetectFastPatternTest124); + UtRegisterTest("DetectFastPatternTest125", DetectFastPatternTest125); + UtRegisterTest("DetectFastPatternTest126", DetectFastPatternTest126); + UtRegisterTest("DetectFastPatternTest127", DetectFastPatternTest127); + UtRegisterTest("DetectFastPatternTest128", DetectFastPatternTest128); + UtRegisterTest("DetectFastPatternTest129", DetectFastPatternTest129); + UtRegisterTest("DetectFastPatternTest130", DetectFastPatternTest130); + UtRegisterTest("DetectFastPatternTest131", DetectFastPatternTest131); + UtRegisterTest("DetectFastPatternTest132", DetectFastPatternTest132); + UtRegisterTest("DetectFastPatternTest133", DetectFastPatternTest133); /* http_uri fast_pattern tests ^ */ /* http_client_body fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest134", DetectFastPatternTest134, 1); - UtRegisterTest("DetectFastPatternTest135", DetectFastPatternTest135, 1); - UtRegisterTest("DetectFastPatternTest136", DetectFastPatternTest136, 1); - UtRegisterTest("DetectFastPatternTest137", DetectFastPatternTest137, 1); - UtRegisterTest("DetectFastPatternTest138", DetectFastPatternTest138, 1); - UtRegisterTest("DetectFastPatternTest139", DetectFastPatternTest139, 1); - UtRegisterTest("DetectFastPatternTest140", DetectFastPatternTest140, 1); - UtRegisterTest("DetectFastPatternTest141", DetectFastPatternTest141, 1); - UtRegisterTest("DetectFastPatternTest142", DetectFastPatternTest142, 1); - UtRegisterTest("DetectFastPatternTest143", DetectFastPatternTest143, 1); - UtRegisterTest("DetectFastPatternTest144", DetectFastPatternTest144, 1); - UtRegisterTest("DetectFastPatternTest145", DetectFastPatternTest145, 1); - UtRegisterTest("DetectFastPatternTest146", DetectFastPatternTest146, 1); - UtRegisterTest("DetectFastPatternTest147", DetectFastPatternTest147, 1); - UtRegisterTest("DetectFastPatternTest148", DetectFastPatternTest148, 1); - UtRegisterTest("DetectFastPatternTest149", DetectFastPatternTest149, 1); - UtRegisterTest("DetectFastPatternTest150", DetectFastPatternTest150, 1); - UtRegisterTest("DetectFastPatternTest151", DetectFastPatternTest151, 1); - UtRegisterTest("DetectFastPatternTest152", DetectFastPatternTest152, 1); - UtRegisterTest("DetectFastPatternTest153", DetectFastPatternTest153, 1); - UtRegisterTest("DetectFastPatternTest154", DetectFastPatternTest154, 1); - UtRegisterTest("DetectFastPatternTest155", DetectFastPatternTest155, 1); - UtRegisterTest("DetectFastPatternTest156", DetectFastPatternTest156, 1); - UtRegisterTest("DetectFastPatternTest157", DetectFastPatternTest157, 1); - UtRegisterTest("DetectFastPatternTest158", DetectFastPatternTest158, 1); - UtRegisterTest("DetectFastPatternTest159", DetectFastPatternTest159, 1); - UtRegisterTest("DetectFastPatternTest160", DetectFastPatternTest160, 1); - UtRegisterTest("DetectFastPatternTest161", DetectFastPatternTest161, 1); - UtRegisterTest("DetectFastPatternTest162", DetectFastPatternTest162, 1); - UtRegisterTest("DetectFastPatternTest163", DetectFastPatternTest163, 1); - UtRegisterTest("DetectFastPatternTest164", DetectFastPatternTest164, 1); - UtRegisterTest("DetectFastPatternTest165", DetectFastPatternTest165, 1); - UtRegisterTest("DetectFastPatternTest166", DetectFastPatternTest166, 1); - UtRegisterTest("DetectFastPatternTest167", DetectFastPatternTest167, 1); - UtRegisterTest("DetectFastPatternTest168", DetectFastPatternTest168, 1); - UtRegisterTest("DetectFastPatternTest169", DetectFastPatternTest169, 1); - UtRegisterTest("DetectFastPatternTest170", DetectFastPatternTest170, 1); - UtRegisterTest("DetectFastPatternTest171", DetectFastPatternTest171, 1); - UtRegisterTest("DetectFastPatternTest172", DetectFastPatternTest172, 1); - UtRegisterTest("DetectFastPatternTest173", DetectFastPatternTest173, 1); - UtRegisterTest("DetectFastPatternTest174", DetectFastPatternTest174, 1); + UtRegisterTest("DetectFastPatternTest134", DetectFastPatternTest134); + UtRegisterTest("DetectFastPatternTest135", DetectFastPatternTest135); + UtRegisterTest("DetectFastPatternTest136", DetectFastPatternTest136); + UtRegisterTest("DetectFastPatternTest137", DetectFastPatternTest137); + UtRegisterTest("DetectFastPatternTest138", DetectFastPatternTest138); + UtRegisterTest("DetectFastPatternTest139", DetectFastPatternTest139); + UtRegisterTest("DetectFastPatternTest140", DetectFastPatternTest140); + UtRegisterTest("DetectFastPatternTest141", DetectFastPatternTest141); + UtRegisterTest("DetectFastPatternTest142", DetectFastPatternTest142); + UtRegisterTest("DetectFastPatternTest143", DetectFastPatternTest143); + UtRegisterTest("DetectFastPatternTest144", DetectFastPatternTest144); + UtRegisterTest("DetectFastPatternTest145", DetectFastPatternTest145); + UtRegisterTest("DetectFastPatternTest146", DetectFastPatternTest146); + UtRegisterTest("DetectFastPatternTest147", DetectFastPatternTest147); + UtRegisterTest("DetectFastPatternTest148", DetectFastPatternTest148); + UtRegisterTest("DetectFastPatternTest149", DetectFastPatternTest149); + UtRegisterTest("DetectFastPatternTest150", DetectFastPatternTest150); + UtRegisterTest("DetectFastPatternTest151", DetectFastPatternTest151); + UtRegisterTest("DetectFastPatternTest152", DetectFastPatternTest152); + UtRegisterTest("DetectFastPatternTest153", DetectFastPatternTest153); + UtRegisterTest("DetectFastPatternTest154", DetectFastPatternTest154); + UtRegisterTest("DetectFastPatternTest155", DetectFastPatternTest155); + UtRegisterTest("DetectFastPatternTest156", DetectFastPatternTest156); + UtRegisterTest("DetectFastPatternTest157", DetectFastPatternTest157); + UtRegisterTest("DetectFastPatternTest158", DetectFastPatternTest158); + UtRegisterTest("DetectFastPatternTest159", DetectFastPatternTest159); + UtRegisterTest("DetectFastPatternTest160", DetectFastPatternTest160); + UtRegisterTest("DetectFastPatternTest161", DetectFastPatternTest161); + UtRegisterTest("DetectFastPatternTest162", DetectFastPatternTest162); + UtRegisterTest("DetectFastPatternTest163", DetectFastPatternTest163); + UtRegisterTest("DetectFastPatternTest164", DetectFastPatternTest164); + UtRegisterTest("DetectFastPatternTest165", DetectFastPatternTest165); + UtRegisterTest("DetectFastPatternTest166", DetectFastPatternTest166); + UtRegisterTest("DetectFastPatternTest167", DetectFastPatternTest167); + UtRegisterTest("DetectFastPatternTest168", DetectFastPatternTest168); + UtRegisterTest("DetectFastPatternTest169", DetectFastPatternTest169); + UtRegisterTest("DetectFastPatternTest170", DetectFastPatternTest170); + UtRegisterTest("DetectFastPatternTest171", DetectFastPatternTest171); + UtRegisterTest("DetectFastPatternTest172", DetectFastPatternTest172); + UtRegisterTest("DetectFastPatternTest173", DetectFastPatternTest173); + UtRegisterTest("DetectFastPatternTest174", DetectFastPatternTest174); /* http_client_body fast_pattern tests ^ */ /* content fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest175", DetectFastPatternTest175, 1); - UtRegisterTest("DetectFastPatternTest176", DetectFastPatternTest176, 1); - UtRegisterTest("DetectFastPatternTest177", DetectFastPatternTest177, 1); - UtRegisterTest("DetectFastPatternTest178", DetectFastPatternTest178, 1); + UtRegisterTest("DetectFastPatternTest175", DetectFastPatternTest175); + UtRegisterTest("DetectFastPatternTest176", DetectFastPatternTest176); + UtRegisterTest("DetectFastPatternTest177", DetectFastPatternTest177); + UtRegisterTest("DetectFastPatternTest178", DetectFastPatternTest178); /* content fast_pattern tests ^ */ /* http_header fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest179", DetectFastPatternTest179, 1); - UtRegisterTest("DetectFastPatternTest180", DetectFastPatternTest180, 1); - UtRegisterTest("DetectFastPatternTest181", DetectFastPatternTest181, 1); - UtRegisterTest("DetectFastPatternTest182", DetectFastPatternTest182, 1); - UtRegisterTest("DetectFastPatternTest183", DetectFastPatternTest183, 1); - UtRegisterTest("DetectFastPatternTest184", DetectFastPatternTest184, 1); - UtRegisterTest("DetectFastPatternTest185", DetectFastPatternTest185, 1); - UtRegisterTest("DetectFastPatternTest186", DetectFastPatternTest186, 1); - UtRegisterTest("DetectFastPatternTest187", DetectFastPatternTest187, 1); - UtRegisterTest("DetectFastPatternTest188", DetectFastPatternTest188, 1); - UtRegisterTest("DetectFastPatternTest189", DetectFastPatternTest189, 1); - UtRegisterTest("DetectFastPatternTest190", DetectFastPatternTest190, 1); - UtRegisterTest("DetectFastPatternTest191", DetectFastPatternTest191, 1); - UtRegisterTest("DetectFastPatternTest192", DetectFastPatternTest192, 1); - UtRegisterTest("DetectFastPatternTest193", DetectFastPatternTest193, 1); - UtRegisterTest("DetectFastPatternTest194", DetectFastPatternTest194, 1); - UtRegisterTest("DetectFastPatternTest195", DetectFastPatternTest195, 1); - UtRegisterTest("DetectFastPatternTest196", DetectFastPatternTest196, 1); - UtRegisterTest("DetectFastPatternTest197", DetectFastPatternTest197, 1); - UtRegisterTest("DetectFastPatternTest198", DetectFastPatternTest198, 1); - UtRegisterTest("DetectFastPatternTest199", DetectFastPatternTest199, 1); - UtRegisterTest("DetectFastPatternTest200", DetectFastPatternTest200, 1); - UtRegisterTest("DetectFastPatternTest201", DetectFastPatternTest201, 1); - UtRegisterTest("DetectFastPatternTest202", DetectFastPatternTest202, 1); - UtRegisterTest("DetectFastPatternTest203", DetectFastPatternTest203, 1); - UtRegisterTest("DetectFastPatternTest204", DetectFastPatternTest204, 1); - UtRegisterTest("DetectFastPatternTest205", DetectFastPatternTest205, 1); - UtRegisterTest("DetectFastPatternTest206", DetectFastPatternTest206, 1); - UtRegisterTest("DetectFastPatternTest207", DetectFastPatternTest207, 1); - UtRegisterTest("DetectFastPatternTest208", DetectFastPatternTest208, 1); - UtRegisterTest("DetectFastPatternTest209", DetectFastPatternTest209, 1); - UtRegisterTest("DetectFastPatternTest210", DetectFastPatternTest210, 1); - UtRegisterTest("DetectFastPatternTest211", DetectFastPatternTest211, 1); - UtRegisterTest("DetectFastPatternTest212", DetectFastPatternTest212, 1); - UtRegisterTest("DetectFastPatternTest213", DetectFastPatternTest213, 1); - UtRegisterTest("DetectFastPatternTest214", DetectFastPatternTest214, 1); - UtRegisterTest("DetectFastPatternTest215", DetectFastPatternTest215, 1); - UtRegisterTest("DetectFastPatternTest216", DetectFastPatternTest216, 1); - UtRegisterTest("DetectFastPatternTest217", DetectFastPatternTest217, 1); - UtRegisterTest("DetectFastPatternTest218", DetectFastPatternTest218, 1); - UtRegisterTest("DetectFastPatternTest219", DetectFastPatternTest219, 1); + UtRegisterTest("DetectFastPatternTest179", DetectFastPatternTest179); + UtRegisterTest("DetectFastPatternTest180", DetectFastPatternTest180); + UtRegisterTest("DetectFastPatternTest181", DetectFastPatternTest181); + UtRegisterTest("DetectFastPatternTest182", DetectFastPatternTest182); + UtRegisterTest("DetectFastPatternTest183", DetectFastPatternTest183); + UtRegisterTest("DetectFastPatternTest184", DetectFastPatternTest184); + UtRegisterTest("DetectFastPatternTest185", DetectFastPatternTest185); + UtRegisterTest("DetectFastPatternTest186", DetectFastPatternTest186); + UtRegisterTest("DetectFastPatternTest187", DetectFastPatternTest187); + UtRegisterTest("DetectFastPatternTest188", DetectFastPatternTest188); + UtRegisterTest("DetectFastPatternTest189", DetectFastPatternTest189); + UtRegisterTest("DetectFastPatternTest190", DetectFastPatternTest190); + UtRegisterTest("DetectFastPatternTest191", DetectFastPatternTest191); + UtRegisterTest("DetectFastPatternTest192", DetectFastPatternTest192); + UtRegisterTest("DetectFastPatternTest193", DetectFastPatternTest193); + UtRegisterTest("DetectFastPatternTest194", DetectFastPatternTest194); + UtRegisterTest("DetectFastPatternTest195", DetectFastPatternTest195); + UtRegisterTest("DetectFastPatternTest196", DetectFastPatternTest196); + UtRegisterTest("DetectFastPatternTest197", DetectFastPatternTest197); + UtRegisterTest("DetectFastPatternTest198", DetectFastPatternTest198); + UtRegisterTest("DetectFastPatternTest199", DetectFastPatternTest199); + UtRegisterTest("DetectFastPatternTest200", DetectFastPatternTest200); + UtRegisterTest("DetectFastPatternTest201", DetectFastPatternTest201); + UtRegisterTest("DetectFastPatternTest202", DetectFastPatternTest202); + UtRegisterTest("DetectFastPatternTest203", DetectFastPatternTest203); + UtRegisterTest("DetectFastPatternTest204", DetectFastPatternTest204); + UtRegisterTest("DetectFastPatternTest205", DetectFastPatternTest205); + UtRegisterTest("DetectFastPatternTest206", DetectFastPatternTest206); + UtRegisterTest("DetectFastPatternTest207", DetectFastPatternTest207); + UtRegisterTest("DetectFastPatternTest208", DetectFastPatternTest208); + UtRegisterTest("DetectFastPatternTest209", DetectFastPatternTest209); + UtRegisterTest("DetectFastPatternTest210", DetectFastPatternTest210); + UtRegisterTest("DetectFastPatternTest211", DetectFastPatternTest211); + UtRegisterTest("DetectFastPatternTest212", DetectFastPatternTest212); + UtRegisterTest("DetectFastPatternTest213", DetectFastPatternTest213); + UtRegisterTest("DetectFastPatternTest214", DetectFastPatternTest214); + UtRegisterTest("DetectFastPatternTest215", DetectFastPatternTest215); + UtRegisterTest("DetectFastPatternTest216", DetectFastPatternTest216); + UtRegisterTest("DetectFastPatternTest217", DetectFastPatternTest217); + UtRegisterTest("DetectFastPatternTest218", DetectFastPatternTest218); + UtRegisterTest("DetectFastPatternTest219", DetectFastPatternTest219); /* http_header fast_pattern tests ^ */ /* http_raw_header fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest220", DetectFastPatternTest220, 1); - UtRegisterTest("DetectFastPatternTest221", DetectFastPatternTest221, 1); - UtRegisterTest("DetectFastPatternTest222", DetectFastPatternTest222, 1); - UtRegisterTest("DetectFastPatternTest223", DetectFastPatternTest223, 1); - UtRegisterTest("DetectFastPatternTest224", DetectFastPatternTest224, 1); - UtRegisterTest("DetectFastPatternTest225", DetectFastPatternTest225, 1); - UtRegisterTest("DetectFastPatternTest226", DetectFastPatternTest226, 1); - UtRegisterTest("DetectFastPatternTest227", DetectFastPatternTest227, 1); - UtRegisterTest("DetectFastPatternTest228", DetectFastPatternTest228, 1); - UtRegisterTest("DetectFastPatternTest229", DetectFastPatternTest229, 1); - UtRegisterTest("DetectFastPatternTest230", DetectFastPatternTest230, 1); - UtRegisterTest("DetectFastPatternTest231", DetectFastPatternTest231, 1); - UtRegisterTest("DetectFastPatternTest232", DetectFastPatternTest232, 1); - UtRegisterTest("DetectFastPatternTest233", DetectFastPatternTest233, 1); - UtRegisterTest("DetectFastPatternTest234", DetectFastPatternTest234, 1); - UtRegisterTest("DetectFastPatternTest235", DetectFastPatternTest235, 1); - UtRegisterTest("DetectFastPatternTest236", DetectFastPatternTest236, 1); - UtRegisterTest("DetectFastPatternTest237", DetectFastPatternTest237, 1); - UtRegisterTest("DetectFastPatternTest238", DetectFastPatternTest238, 1); - UtRegisterTest("DetectFastPatternTest239", DetectFastPatternTest239, 1); - UtRegisterTest("DetectFastPatternTest240", DetectFastPatternTest240, 1); - UtRegisterTest("DetectFastPatternTest241", DetectFastPatternTest241, 1); - UtRegisterTest("DetectFastPatternTest242", DetectFastPatternTest242, 1); - UtRegisterTest("DetectFastPatternTest243", DetectFastPatternTest243, 1); - UtRegisterTest("DetectFastPatternTest244", DetectFastPatternTest244, 1); - UtRegisterTest("DetectFastPatternTest245", DetectFastPatternTest245, 1); - UtRegisterTest("DetectFastPatternTest246", DetectFastPatternTest246, 1); - UtRegisterTest("DetectFastPatternTest247", DetectFastPatternTest247, 1); - UtRegisterTest("DetectFastPatternTest248", DetectFastPatternTest248, 1); - UtRegisterTest("DetectFastPatternTest249", DetectFastPatternTest249, 1); - UtRegisterTest("DetectFastPatternTest250", DetectFastPatternTest250, 1); - UtRegisterTest("DetectFastPatternTest251", DetectFastPatternTest251, 1); - UtRegisterTest("DetectFastPatternTest252", DetectFastPatternTest252, 1); - UtRegisterTest("DetectFastPatternTest253", DetectFastPatternTest253, 1); - UtRegisterTest("DetectFastPatternTest254", DetectFastPatternTest254, 1); - UtRegisterTest("DetectFastPatternTest255", DetectFastPatternTest255, 1); - UtRegisterTest("DetectFastPatternTest256", DetectFastPatternTest256, 1); - UtRegisterTest("DetectFastPatternTest257", DetectFastPatternTest257, 1); - UtRegisterTest("DetectFastPatternTest258", DetectFastPatternTest258, 1); - UtRegisterTest("DetectFastPatternTest259", DetectFastPatternTest259, 1); - UtRegisterTest("DetectFastPatternTest260", DetectFastPatternTest260, 1); + UtRegisterTest("DetectFastPatternTest220", DetectFastPatternTest220); + UtRegisterTest("DetectFastPatternTest221", DetectFastPatternTest221); + UtRegisterTest("DetectFastPatternTest222", DetectFastPatternTest222); + UtRegisterTest("DetectFastPatternTest223", DetectFastPatternTest223); + UtRegisterTest("DetectFastPatternTest224", DetectFastPatternTest224); + UtRegisterTest("DetectFastPatternTest225", DetectFastPatternTest225); + UtRegisterTest("DetectFastPatternTest226", DetectFastPatternTest226); + UtRegisterTest("DetectFastPatternTest227", DetectFastPatternTest227); + UtRegisterTest("DetectFastPatternTest228", DetectFastPatternTest228); + UtRegisterTest("DetectFastPatternTest229", DetectFastPatternTest229); + UtRegisterTest("DetectFastPatternTest230", DetectFastPatternTest230); + UtRegisterTest("DetectFastPatternTest231", DetectFastPatternTest231); + UtRegisterTest("DetectFastPatternTest232", DetectFastPatternTest232); + UtRegisterTest("DetectFastPatternTest233", DetectFastPatternTest233); + UtRegisterTest("DetectFastPatternTest234", DetectFastPatternTest234); + UtRegisterTest("DetectFastPatternTest235", DetectFastPatternTest235); + UtRegisterTest("DetectFastPatternTest236", DetectFastPatternTest236); + UtRegisterTest("DetectFastPatternTest237", DetectFastPatternTest237); + UtRegisterTest("DetectFastPatternTest238", DetectFastPatternTest238); + UtRegisterTest("DetectFastPatternTest239", DetectFastPatternTest239); + UtRegisterTest("DetectFastPatternTest240", DetectFastPatternTest240); + UtRegisterTest("DetectFastPatternTest241", DetectFastPatternTest241); + UtRegisterTest("DetectFastPatternTest242", DetectFastPatternTest242); + UtRegisterTest("DetectFastPatternTest243", DetectFastPatternTest243); + UtRegisterTest("DetectFastPatternTest244", DetectFastPatternTest244); + UtRegisterTest("DetectFastPatternTest245", DetectFastPatternTest245); + UtRegisterTest("DetectFastPatternTest246", DetectFastPatternTest246); + UtRegisterTest("DetectFastPatternTest247", DetectFastPatternTest247); + UtRegisterTest("DetectFastPatternTest248", DetectFastPatternTest248); + UtRegisterTest("DetectFastPatternTest249", DetectFastPatternTest249); + UtRegisterTest("DetectFastPatternTest250", DetectFastPatternTest250); + UtRegisterTest("DetectFastPatternTest251", DetectFastPatternTest251); + UtRegisterTest("DetectFastPatternTest252", DetectFastPatternTest252); + UtRegisterTest("DetectFastPatternTest253", DetectFastPatternTest253); + UtRegisterTest("DetectFastPatternTest254", DetectFastPatternTest254); + UtRegisterTest("DetectFastPatternTest255", DetectFastPatternTest255); + UtRegisterTest("DetectFastPatternTest256", DetectFastPatternTest256); + UtRegisterTest("DetectFastPatternTest257", DetectFastPatternTest257); + UtRegisterTest("DetectFastPatternTest258", DetectFastPatternTest258); + UtRegisterTest("DetectFastPatternTest259", DetectFastPatternTest259); + UtRegisterTest("DetectFastPatternTest260", DetectFastPatternTest260); /* http_raw_header fast_pattern tests ^ */ /* http_method fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest261", DetectFastPatternTest261, 1); - UtRegisterTest("DetectFastPatternTest262", DetectFastPatternTest262, 1); - UtRegisterTest("DetectFastPatternTest263", DetectFastPatternTest263, 1); - UtRegisterTest("DetectFastPatternTest264", DetectFastPatternTest264, 1); - UtRegisterTest("DetectFastPatternTest265", DetectFastPatternTest265, 1); - UtRegisterTest("DetectFastPatternTest266", DetectFastPatternTest266, 1); - UtRegisterTest("DetectFastPatternTest267", DetectFastPatternTest267, 1); - UtRegisterTest("DetectFastPatternTest268", DetectFastPatternTest268, 1); - UtRegisterTest("DetectFastPatternTest269", DetectFastPatternTest269, 1); - UtRegisterTest("DetectFastPatternTest270", DetectFastPatternTest270, 1); - UtRegisterTest("DetectFastPatternTest271", DetectFastPatternTest271, 1); - UtRegisterTest("DetectFastPatternTest272", DetectFastPatternTest272, 1); - UtRegisterTest("DetectFastPatternTest273", DetectFastPatternTest273, 1); - UtRegisterTest("DetectFastPatternTest274", DetectFastPatternTest274, 1); - UtRegisterTest("DetectFastPatternTest275", DetectFastPatternTest275, 1); - UtRegisterTest("DetectFastPatternTest276", DetectFastPatternTest276, 1); - UtRegisterTest("DetectFastPatternTest277", DetectFastPatternTest277, 1); - UtRegisterTest("DetectFastPatternTest278", DetectFastPatternTest278, 1); - UtRegisterTest("DetectFastPatternTest279", DetectFastPatternTest279, 1); - UtRegisterTest("DetectFastPatternTest280", DetectFastPatternTest280, 1); - UtRegisterTest("DetectFastPatternTest281", DetectFastPatternTest281, 1); - UtRegisterTest("DetectFastPatternTest282", DetectFastPatternTest282, 1); - UtRegisterTest("DetectFastPatternTest283", DetectFastPatternTest283, 1); - UtRegisterTest("DetectFastPatternTest284", DetectFastPatternTest284, 1); - UtRegisterTest("DetectFastPatternTest285", DetectFastPatternTest285, 1); - UtRegisterTest("DetectFastPatternTest286", DetectFastPatternTest286, 1); - UtRegisterTest("DetectFastPatternTest287", DetectFastPatternTest287, 1); - UtRegisterTest("DetectFastPatternTest288", DetectFastPatternTest288, 1); - UtRegisterTest("DetectFastPatternTest289", DetectFastPatternTest289, 1); - UtRegisterTest("DetectFastPatternTest290", DetectFastPatternTest290, 1); - UtRegisterTest("DetectFastPatternTest291", DetectFastPatternTest291, 1); - UtRegisterTest("DetectFastPatternTest292", DetectFastPatternTest292, 1); - UtRegisterTest("DetectFastPatternTest293", DetectFastPatternTest293, 1); - UtRegisterTest("DetectFastPatternTest294", DetectFastPatternTest294, 1); - UtRegisterTest("DetectFastPatternTest295", DetectFastPatternTest295, 1); - UtRegisterTest("DetectFastPatternTest296", DetectFastPatternTest296, 1); - UtRegisterTest("DetectFastPatternTest297", DetectFastPatternTest297, 1); - UtRegisterTest("DetectFastPatternTest298", DetectFastPatternTest298, 1); - UtRegisterTest("DetectFastPatternTest299", DetectFastPatternTest299, 1); - UtRegisterTest("DetectFastPatternTest300", DetectFastPatternTest300, 1); - UtRegisterTest("DetectFastPatternTest301", DetectFastPatternTest301, 1); + UtRegisterTest("DetectFastPatternTest261", DetectFastPatternTest261); + UtRegisterTest("DetectFastPatternTest262", DetectFastPatternTest262); + UtRegisterTest("DetectFastPatternTest263", DetectFastPatternTest263); + UtRegisterTest("DetectFastPatternTest264", DetectFastPatternTest264); + UtRegisterTest("DetectFastPatternTest265", DetectFastPatternTest265); + UtRegisterTest("DetectFastPatternTest266", DetectFastPatternTest266); + UtRegisterTest("DetectFastPatternTest267", DetectFastPatternTest267); + UtRegisterTest("DetectFastPatternTest268", DetectFastPatternTest268); + UtRegisterTest("DetectFastPatternTest269", DetectFastPatternTest269); + UtRegisterTest("DetectFastPatternTest270", DetectFastPatternTest270); + UtRegisterTest("DetectFastPatternTest271", DetectFastPatternTest271); + UtRegisterTest("DetectFastPatternTest272", DetectFastPatternTest272); + UtRegisterTest("DetectFastPatternTest273", DetectFastPatternTest273); + UtRegisterTest("DetectFastPatternTest274", DetectFastPatternTest274); + UtRegisterTest("DetectFastPatternTest275", DetectFastPatternTest275); + UtRegisterTest("DetectFastPatternTest276", DetectFastPatternTest276); + UtRegisterTest("DetectFastPatternTest277", DetectFastPatternTest277); + UtRegisterTest("DetectFastPatternTest278", DetectFastPatternTest278); + UtRegisterTest("DetectFastPatternTest279", DetectFastPatternTest279); + UtRegisterTest("DetectFastPatternTest280", DetectFastPatternTest280); + UtRegisterTest("DetectFastPatternTest281", DetectFastPatternTest281); + UtRegisterTest("DetectFastPatternTest282", DetectFastPatternTest282); + UtRegisterTest("DetectFastPatternTest283", DetectFastPatternTest283); + UtRegisterTest("DetectFastPatternTest284", DetectFastPatternTest284); + UtRegisterTest("DetectFastPatternTest285", DetectFastPatternTest285); + UtRegisterTest("DetectFastPatternTest286", DetectFastPatternTest286); + UtRegisterTest("DetectFastPatternTest287", DetectFastPatternTest287); + UtRegisterTest("DetectFastPatternTest288", DetectFastPatternTest288); + UtRegisterTest("DetectFastPatternTest289", DetectFastPatternTest289); + UtRegisterTest("DetectFastPatternTest290", DetectFastPatternTest290); + UtRegisterTest("DetectFastPatternTest291", DetectFastPatternTest291); + UtRegisterTest("DetectFastPatternTest292", DetectFastPatternTest292); + UtRegisterTest("DetectFastPatternTest293", DetectFastPatternTest293); + UtRegisterTest("DetectFastPatternTest294", DetectFastPatternTest294); + UtRegisterTest("DetectFastPatternTest295", DetectFastPatternTest295); + UtRegisterTest("DetectFastPatternTest296", DetectFastPatternTest296); + UtRegisterTest("DetectFastPatternTest297", DetectFastPatternTest297); + UtRegisterTest("DetectFastPatternTest298", DetectFastPatternTest298); + UtRegisterTest("DetectFastPatternTest299", DetectFastPatternTest299); + UtRegisterTest("DetectFastPatternTest300", DetectFastPatternTest300); + UtRegisterTest("DetectFastPatternTest301", DetectFastPatternTest301); /* http_method fast_pattern tests ^ */ /* http_cookie fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest302", DetectFastPatternTest302, 1); - UtRegisterTest("DetectFastPatternTest303", DetectFastPatternTest303, 1); - UtRegisterTest("DetectFastPatternTest304", DetectFastPatternTest304, 1); - UtRegisterTest("DetectFastPatternTest305", DetectFastPatternTest305, 1); - UtRegisterTest("DetectFastPatternTest306", DetectFastPatternTest306, 1); - UtRegisterTest("DetectFastPatternTest307", DetectFastPatternTest307, 1); - UtRegisterTest("DetectFastPatternTest308", DetectFastPatternTest308, 1); - UtRegisterTest("DetectFastPatternTest309", DetectFastPatternTest309, 1); - UtRegisterTest("DetectFastPatternTest310", DetectFastPatternTest310, 1); - UtRegisterTest("DetectFastPatternTest311", DetectFastPatternTest311, 1); - UtRegisterTest("DetectFastPatternTest312", DetectFastPatternTest312, 1); - UtRegisterTest("DetectFastPatternTest313", DetectFastPatternTest313, 1); - UtRegisterTest("DetectFastPatternTest314", DetectFastPatternTest314, 1); - UtRegisterTest("DetectFastPatternTest315", DetectFastPatternTest315, 1); - UtRegisterTest("DetectFastPatternTest316", DetectFastPatternTest316, 1); - UtRegisterTest("DetectFastPatternTest317", DetectFastPatternTest317, 1); - UtRegisterTest("DetectFastPatternTest318", DetectFastPatternTest318, 1); - UtRegisterTest("DetectFastPatternTest319", DetectFastPatternTest319, 1); - UtRegisterTest("DetectFastPatternTest320", DetectFastPatternTest320, 1); - UtRegisterTest("DetectFastPatternTest321", DetectFastPatternTest321, 1); - UtRegisterTest("DetectFastPatternTest322", DetectFastPatternTest322, 1); - UtRegisterTest("DetectFastPatternTest323", DetectFastPatternTest323, 1); - UtRegisterTest("DetectFastPatternTest324", DetectFastPatternTest324, 1); - UtRegisterTest("DetectFastPatternTest325", DetectFastPatternTest325, 1); - UtRegisterTest("DetectFastPatternTest326", DetectFastPatternTest326, 1); - UtRegisterTest("DetectFastPatternTest327", DetectFastPatternTest327, 1); - UtRegisterTest("DetectFastPatternTest328", DetectFastPatternTest328, 1); - UtRegisterTest("DetectFastPatternTest329", DetectFastPatternTest329, 1); - UtRegisterTest("DetectFastPatternTest330", DetectFastPatternTest330, 1); - UtRegisterTest("DetectFastPatternTest331", DetectFastPatternTest331, 1); - UtRegisterTest("DetectFastPatternTest332", DetectFastPatternTest332, 1); - UtRegisterTest("DetectFastPatternTest333", DetectFastPatternTest333, 1); - UtRegisterTest("DetectFastPatternTest334", DetectFastPatternTest334, 1); - UtRegisterTest("DetectFastPatternTest335", DetectFastPatternTest335, 1); - UtRegisterTest("DetectFastPatternTest336", DetectFastPatternTest336, 1); - UtRegisterTest("DetectFastPatternTest337", DetectFastPatternTest337, 1); - UtRegisterTest("DetectFastPatternTest338", DetectFastPatternTest338, 1); - UtRegisterTest("DetectFastPatternTest339", DetectFastPatternTest339, 1); - UtRegisterTest("DetectFastPatternTest340", DetectFastPatternTest340, 1); - UtRegisterTest("DetectFastPatternTest341", DetectFastPatternTest341, 1); - UtRegisterTest("DetectFastPatternTest342", DetectFastPatternTest342, 1); + UtRegisterTest("DetectFastPatternTest302", DetectFastPatternTest302); + UtRegisterTest("DetectFastPatternTest303", DetectFastPatternTest303); + UtRegisterTest("DetectFastPatternTest304", DetectFastPatternTest304); + UtRegisterTest("DetectFastPatternTest305", DetectFastPatternTest305); + UtRegisterTest("DetectFastPatternTest306", DetectFastPatternTest306); + UtRegisterTest("DetectFastPatternTest307", DetectFastPatternTest307); + UtRegisterTest("DetectFastPatternTest308", DetectFastPatternTest308); + UtRegisterTest("DetectFastPatternTest309", DetectFastPatternTest309); + UtRegisterTest("DetectFastPatternTest310", DetectFastPatternTest310); + UtRegisterTest("DetectFastPatternTest311", DetectFastPatternTest311); + UtRegisterTest("DetectFastPatternTest312", DetectFastPatternTest312); + UtRegisterTest("DetectFastPatternTest313", DetectFastPatternTest313); + UtRegisterTest("DetectFastPatternTest314", DetectFastPatternTest314); + UtRegisterTest("DetectFastPatternTest315", DetectFastPatternTest315); + UtRegisterTest("DetectFastPatternTest316", DetectFastPatternTest316); + UtRegisterTest("DetectFastPatternTest317", DetectFastPatternTest317); + UtRegisterTest("DetectFastPatternTest318", DetectFastPatternTest318); + UtRegisterTest("DetectFastPatternTest319", DetectFastPatternTest319); + UtRegisterTest("DetectFastPatternTest320", DetectFastPatternTest320); + UtRegisterTest("DetectFastPatternTest321", DetectFastPatternTest321); + UtRegisterTest("DetectFastPatternTest322", DetectFastPatternTest322); + UtRegisterTest("DetectFastPatternTest323", DetectFastPatternTest323); + UtRegisterTest("DetectFastPatternTest324", DetectFastPatternTest324); + UtRegisterTest("DetectFastPatternTest325", DetectFastPatternTest325); + UtRegisterTest("DetectFastPatternTest326", DetectFastPatternTest326); + UtRegisterTest("DetectFastPatternTest327", DetectFastPatternTest327); + UtRegisterTest("DetectFastPatternTest328", DetectFastPatternTest328); + UtRegisterTest("DetectFastPatternTest329", DetectFastPatternTest329); + UtRegisterTest("DetectFastPatternTest330", DetectFastPatternTest330); + UtRegisterTest("DetectFastPatternTest331", DetectFastPatternTest331); + UtRegisterTest("DetectFastPatternTest332", DetectFastPatternTest332); + UtRegisterTest("DetectFastPatternTest333", DetectFastPatternTest333); + UtRegisterTest("DetectFastPatternTest334", DetectFastPatternTest334); + UtRegisterTest("DetectFastPatternTest335", DetectFastPatternTest335); + UtRegisterTest("DetectFastPatternTest336", DetectFastPatternTest336); + UtRegisterTest("DetectFastPatternTest337", DetectFastPatternTest337); + UtRegisterTest("DetectFastPatternTest338", DetectFastPatternTest338); + UtRegisterTest("DetectFastPatternTest339", DetectFastPatternTest339); + UtRegisterTest("DetectFastPatternTest340", DetectFastPatternTest340); + UtRegisterTest("DetectFastPatternTest341", DetectFastPatternTest341); + UtRegisterTest("DetectFastPatternTest342", DetectFastPatternTest342); /* http_cookie fast_pattern tests ^ */ /* http_raw_uri fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest343", DetectFastPatternTest343, 1); - UtRegisterTest("DetectFastPatternTest344", DetectFastPatternTest344, 1); - UtRegisterTest("DetectFastPatternTest345", DetectFastPatternTest345, 1); - UtRegisterTest("DetectFastPatternTest346", DetectFastPatternTest346, 1); - UtRegisterTest("DetectFastPatternTest347", DetectFastPatternTest347, 1); - UtRegisterTest("DetectFastPatternTest348", DetectFastPatternTest348, 1); - UtRegisterTest("DetectFastPatternTest349", DetectFastPatternTest349, 1); - UtRegisterTest("DetectFastPatternTest350", DetectFastPatternTest350, 1); - UtRegisterTest("DetectFastPatternTest351", DetectFastPatternTest351, 1); - UtRegisterTest("DetectFastPatternTest352", DetectFastPatternTest352, 1); - UtRegisterTest("DetectFastPatternTest353", DetectFastPatternTest353, 1); - UtRegisterTest("DetectFastPatternTest354", DetectFastPatternTest354, 1); - UtRegisterTest("DetectFastPatternTest355", DetectFastPatternTest355, 1); - UtRegisterTest("DetectFastPatternTest356", DetectFastPatternTest356, 1); - UtRegisterTest("DetectFastPatternTest357", DetectFastPatternTest357, 1); - UtRegisterTest("DetectFastPatternTest358", DetectFastPatternTest358, 1); - UtRegisterTest("DetectFastPatternTest359", DetectFastPatternTest359, 1); - UtRegisterTest("DetectFastPatternTest360", DetectFastPatternTest360, 1); - UtRegisterTest("DetectFastPatternTest361", DetectFastPatternTest361, 1); - UtRegisterTest("DetectFastPatternTest362", DetectFastPatternTest362, 1); - UtRegisterTest("DetectFastPatternTest363", DetectFastPatternTest363, 1); - UtRegisterTest("DetectFastPatternTest364", DetectFastPatternTest364, 1); - UtRegisterTest("DetectFastPatternTest365", DetectFastPatternTest365, 1); - UtRegisterTest("DetectFastPatternTest366", DetectFastPatternTest366, 1); - UtRegisterTest("DetectFastPatternTest367", DetectFastPatternTest367, 1); - UtRegisterTest("DetectFastPatternTest368", DetectFastPatternTest368, 1); - UtRegisterTest("DetectFastPatternTest369", DetectFastPatternTest369, 1); - UtRegisterTest("DetectFastPatternTest370", DetectFastPatternTest370, 1); - UtRegisterTest("DetectFastPatternTest371", DetectFastPatternTest371, 1); - UtRegisterTest("DetectFastPatternTest372", DetectFastPatternTest372, 1); - UtRegisterTest("DetectFastPatternTest373", DetectFastPatternTest373, 1); - UtRegisterTest("DetectFastPatternTest374", DetectFastPatternTest374, 1); - UtRegisterTest("DetectFastPatternTest375", DetectFastPatternTest375, 1); - UtRegisterTest("DetectFastPatternTest376", DetectFastPatternTest376, 1); - UtRegisterTest("DetectFastPatternTest377", DetectFastPatternTest377, 1); - UtRegisterTest("DetectFastPatternTest378", DetectFastPatternTest378, 1); - UtRegisterTest("DetectFastPatternTest379", DetectFastPatternTest379, 1); - UtRegisterTest("DetectFastPatternTest380", DetectFastPatternTest380, 1); - UtRegisterTest("DetectFastPatternTest381", DetectFastPatternTest381, 1); - UtRegisterTest("DetectFastPatternTest382", DetectFastPatternTest382, 1); - UtRegisterTest("DetectFastPatternTest383", DetectFastPatternTest383, 1); + UtRegisterTest("DetectFastPatternTest343", DetectFastPatternTest343); + UtRegisterTest("DetectFastPatternTest344", DetectFastPatternTest344); + UtRegisterTest("DetectFastPatternTest345", DetectFastPatternTest345); + UtRegisterTest("DetectFastPatternTest346", DetectFastPatternTest346); + UtRegisterTest("DetectFastPatternTest347", DetectFastPatternTest347); + UtRegisterTest("DetectFastPatternTest348", DetectFastPatternTest348); + UtRegisterTest("DetectFastPatternTest349", DetectFastPatternTest349); + UtRegisterTest("DetectFastPatternTest350", DetectFastPatternTest350); + UtRegisterTest("DetectFastPatternTest351", DetectFastPatternTest351); + UtRegisterTest("DetectFastPatternTest352", DetectFastPatternTest352); + UtRegisterTest("DetectFastPatternTest353", DetectFastPatternTest353); + UtRegisterTest("DetectFastPatternTest354", DetectFastPatternTest354); + UtRegisterTest("DetectFastPatternTest355", DetectFastPatternTest355); + UtRegisterTest("DetectFastPatternTest356", DetectFastPatternTest356); + UtRegisterTest("DetectFastPatternTest357", DetectFastPatternTest357); + UtRegisterTest("DetectFastPatternTest358", DetectFastPatternTest358); + UtRegisterTest("DetectFastPatternTest359", DetectFastPatternTest359); + UtRegisterTest("DetectFastPatternTest360", DetectFastPatternTest360); + UtRegisterTest("DetectFastPatternTest361", DetectFastPatternTest361); + UtRegisterTest("DetectFastPatternTest362", DetectFastPatternTest362); + UtRegisterTest("DetectFastPatternTest363", DetectFastPatternTest363); + UtRegisterTest("DetectFastPatternTest364", DetectFastPatternTest364); + UtRegisterTest("DetectFastPatternTest365", DetectFastPatternTest365); + UtRegisterTest("DetectFastPatternTest366", DetectFastPatternTest366); + UtRegisterTest("DetectFastPatternTest367", DetectFastPatternTest367); + UtRegisterTest("DetectFastPatternTest368", DetectFastPatternTest368); + UtRegisterTest("DetectFastPatternTest369", DetectFastPatternTest369); + UtRegisterTest("DetectFastPatternTest370", DetectFastPatternTest370); + UtRegisterTest("DetectFastPatternTest371", DetectFastPatternTest371); + UtRegisterTest("DetectFastPatternTest372", DetectFastPatternTest372); + UtRegisterTest("DetectFastPatternTest373", DetectFastPatternTest373); + UtRegisterTest("DetectFastPatternTest374", DetectFastPatternTest374); + UtRegisterTest("DetectFastPatternTest375", DetectFastPatternTest375); + UtRegisterTest("DetectFastPatternTest376", DetectFastPatternTest376); + UtRegisterTest("DetectFastPatternTest377", DetectFastPatternTest377); + UtRegisterTest("DetectFastPatternTest378", DetectFastPatternTest378); + UtRegisterTest("DetectFastPatternTest379", DetectFastPatternTest379); + UtRegisterTest("DetectFastPatternTest380", DetectFastPatternTest380); + UtRegisterTest("DetectFastPatternTest381", DetectFastPatternTest381); + UtRegisterTest("DetectFastPatternTest382", DetectFastPatternTest382); + UtRegisterTest("DetectFastPatternTest383", DetectFastPatternTest383); /* http_raw_uri fast_pattern tests ^ */ /* http_stat_msg fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest384", DetectFastPatternTest384, 1); - UtRegisterTest("DetectFastPatternTest385", DetectFastPatternTest385, 1); - UtRegisterTest("DetectFastPatternTest386", DetectFastPatternTest386, 1); - UtRegisterTest("DetectFastPatternTest387", DetectFastPatternTest387, 1); - UtRegisterTest("DetectFastPatternTest388", DetectFastPatternTest388, 1); - UtRegisterTest("DetectFastPatternTest389", DetectFastPatternTest389, 1); - UtRegisterTest("DetectFastPatternTest390", DetectFastPatternTest390, 1); - UtRegisterTest("DetectFastPatternTest391", DetectFastPatternTest391, 1); - UtRegisterTest("DetectFastPatternTest392", DetectFastPatternTest392, 1); - UtRegisterTest("DetectFastPatternTest393", DetectFastPatternTest393, 1); - UtRegisterTest("DetectFastPatternTest394", DetectFastPatternTest394, 1); - UtRegisterTest("DetectFastPatternTest395", DetectFastPatternTest395, 1); - UtRegisterTest("DetectFastPatternTest396", DetectFastPatternTest396, 1); - UtRegisterTest("DetectFastPatternTest397", DetectFastPatternTest397, 1); - UtRegisterTest("DetectFastPatternTest398", DetectFastPatternTest398, 1); - UtRegisterTest("DetectFastPatternTest399", DetectFastPatternTest399, 1); - UtRegisterTest("DetectFastPatternTest400", DetectFastPatternTest400, 1); - UtRegisterTest("DetectFastPatternTest401", DetectFastPatternTest401, 1); - UtRegisterTest("DetectFastPatternTest402", DetectFastPatternTest402, 1); - UtRegisterTest("DetectFastPatternTest403", DetectFastPatternTest403, 1); - UtRegisterTest("DetectFastPatternTest404", DetectFastPatternTest404, 1); - UtRegisterTest("DetectFastPatternTest405", DetectFastPatternTest405, 1); - UtRegisterTest("DetectFastPatternTest406", DetectFastPatternTest406, 1); - UtRegisterTest("DetectFastPatternTest407", DetectFastPatternTest407, 1); - UtRegisterTest("DetectFastPatternTest408", DetectFastPatternTest408, 1); - UtRegisterTest("DetectFastPatternTest409", DetectFastPatternTest409, 1); - UtRegisterTest("DetectFastPatternTest410", DetectFastPatternTest410, 1); - UtRegisterTest("DetectFastPatternTest411", DetectFastPatternTest411, 1); - UtRegisterTest("DetectFastPatternTest412", DetectFastPatternTest412, 1); - UtRegisterTest("DetectFastPatternTest413", DetectFastPatternTest413, 1); - UtRegisterTest("DetectFastPatternTest414", DetectFastPatternTest414, 1); - UtRegisterTest("DetectFastPatternTest415", DetectFastPatternTest415, 1); - UtRegisterTest("DetectFastPatternTest416", DetectFastPatternTest415, 1); - UtRegisterTest("DetectFastPatternTest417", DetectFastPatternTest417, 1); - UtRegisterTest("DetectFastPatternTest418", DetectFastPatternTest418, 1); - UtRegisterTest("DetectFastPatternTest419", DetectFastPatternTest419, 1); - UtRegisterTest("DetectFastPatternTest420", DetectFastPatternTest420, 1); - UtRegisterTest("DetectFastPatternTest421", DetectFastPatternTest421, 1); - UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422, 1); - UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423, 1); - UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424, 1); + UtRegisterTest("DetectFastPatternTest384", DetectFastPatternTest384); + UtRegisterTest("DetectFastPatternTest385", DetectFastPatternTest385); + UtRegisterTest("DetectFastPatternTest386", DetectFastPatternTest386); + UtRegisterTest("DetectFastPatternTest387", DetectFastPatternTest387); + UtRegisterTest("DetectFastPatternTest388", DetectFastPatternTest388); + UtRegisterTest("DetectFastPatternTest389", DetectFastPatternTest389); + UtRegisterTest("DetectFastPatternTest390", DetectFastPatternTest390); + UtRegisterTest("DetectFastPatternTest391", DetectFastPatternTest391); + UtRegisterTest("DetectFastPatternTest392", DetectFastPatternTest392); + UtRegisterTest("DetectFastPatternTest393", DetectFastPatternTest393); + UtRegisterTest("DetectFastPatternTest394", DetectFastPatternTest394); + UtRegisterTest("DetectFastPatternTest395", DetectFastPatternTest395); + UtRegisterTest("DetectFastPatternTest396", DetectFastPatternTest396); + UtRegisterTest("DetectFastPatternTest397", DetectFastPatternTest397); + UtRegisterTest("DetectFastPatternTest398", DetectFastPatternTest398); + UtRegisterTest("DetectFastPatternTest399", DetectFastPatternTest399); + UtRegisterTest("DetectFastPatternTest400", DetectFastPatternTest400); + UtRegisterTest("DetectFastPatternTest401", DetectFastPatternTest401); + UtRegisterTest("DetectFastPatternTest402", DetectFastPatternTest402); + UtRegisterTest("DetectFastPatternTest403", DetectFastPatternTest403); + UtRegisterTest("DetectFastPatternTest404", DetectFastPatternTest404); + UtRegisterTest("DetectFastPatternTest405", DetectFastPatternTest405); + UtRegisterTest("DetectFastPatternTest406", DetectFastPatternTest406); + UtRegisterTest("DetectFastPatternTest407", DetectFastPatternTest407); + UtRegisterTest("DetectFastPatternTest408", DetectFastPatternTest408); + UtRegisterTest("DetectFastPatternTest409", DetectFastPatternTest409); + UtRegisterTest("DetectFastPatternTest410", DetectFastPatternTest410); + UtRegisterTest("DetectFastPatternTest411", DetectFastPatternTest411); + UtRegisterTest("DetectFastPatternTest412", DetectFastPatternTest412); + UtRegisterTest("DetectFastPatternTest413", DetectFastPatternTest413); + UtRegisterTest("DetectFastPatternTest414", DetectFastPatternTest414); + UtRegisterTest("DetectFastPatternTest415", DetectFastPatternTest415); + UtRegisterTest("DetectFastPatternTest416", DetectFastPatternTest415); + UtRegisterTest("DetectFastPatternTest417", DetectFastPatternTest417); + UtRegisterTest("DetectFastPatternTest418", DetectFastPatternTest418); + UtRegisterTest("DetectFastPatternTest419", DetectFastPatternTest419); + UtRegisterTest("DetectFastPatternTest420", DetectFastPatternTest420); + UtRegisterTest("DetectFastPatternTest421", DetectFastPatternTest421); + UtRegisterTest("DetectFastPatternTest422", DetectFastPatternTest422); + UtRegisterTest("DetectFastPatternTest423", DetectFastPatternTest423); + UtRegisterTest("DetectFastPatternTest424", DetectFastPatternTest424); /* http_stat_msg fast_pattern tests ^ */ /* http_stat_code fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest425", DetectFastPatternTest425, 1); - UtRegisterTest("DetectFastPatternTest426", DetectFastPatternTest426, 1); - UtRegisterTest("DetectFastPatternTest427", DetectFastPatternTest427, 1); - UtRegisterTest("DetectFastPatternTest428", DetectFastPatternTest428, 1); - UtRegisterTest("DetectFastPatternTest429", DetectFastPatternTest429, 1); - UtRegisterTest("DetectFastPatternTest430", DetectFastPatternTest430, 1); - UtRegisterTest("DetectFastPatternTest431", DetectFastPatternTest431, 1); - UtRegisterTest("DetectFastPatternTest432", DetectFastPatternTest432, 1); - UtRegisterTest("DetectFastPatternTest433", DetectFastPatternTest433, 1); - UtRegisterTest("DetectFastPatternTest434", DetectFastPatternTest434, 1); - UtRegisterTest("DetectFastPatternTest435", DetectFastPatternTest435, 1); - UtRegisterTest("DetectFastPatternTest436", DetectFastPatternTest436, 1); - UtRegisterTest("DetectFastPatternTest437", DetectFastPatternTest437, 1); - UtRegisterTest("DetectFastPatternTest438", DetectFastPatternTest438, 1); - UtRegisterTest("DetectFastPatternTest439", DetectFastPatternTest439, 1); - UtRegisterTest("DetectFastPatternTest440", DetectFastPatternTest440, 1); - UtRegisterTest("DetectFastPatternTest441", DetectFastPatternTest441, 1); - UtRegisterTest("DetectFastPatternTest442", DetectFastPatternTest442, 1); - UtRegisterTest("DetectFastPatternTest443", DetectFastPatternTest443, 1); - UtRegisterTest("DetectFastPatternTest444", DetectFastPatternTest444, 1); - UtRegisterTest("DetectFastPatternTest445", DetectFastPatternTest445, 1); - UtRegisterTest("DetectFastPatternTest446", DetectFastPatternTest446, 1); - UtRegisterTest("DetectFastPatternTest447", DetectFastPatternTest447, 1); - UtRegisterTest("DetectFastPatternTest448", DetectFastPatternTest448, 1); - UtRegisterTest("DetectFastPatternTest449", DetectFastPatternTest449, 1); - UtRegisterTest("DetectFastPatternTest450", DetectFastPatternTest450, 1); - UtRegisterTest("DetectFastPatternTest451", DetectFastPatternTest451, 1); - UtRegisterTest("DetectFastPatternTest452", DetectFastPatternTest452, 1); - UtRegisterTest("DetectFastPatternTest453", DetectFastPatternTest453, 1); - UtRegisterTest("DetectFastPatternTest454", DetectFastPatternTest454, 1); - UtRegisterTest("DetectFastPatternTest455", DetectFastPatternTest455, 1); - UtRegisterTest("DetectFastPatternTest456", DetectFastPatternTest456, 1); - UtRegisterTest("DetectFastPatternTest457", DetectFastPatternTest457, 1); - UtRegisterTest("DetectFastPatternTest458", DetectFastPatternTest458, 1); - UtRegisterTest("DetectFastPatternTest459", DetectFastPatternTest459, 1); - UtRegisterTest("DetectFastPatternTest460", DetectFastPatternTest460, 1); - UtRegisterTest("DetectFastPatternTest461", DetectFastPatternTest461, 1); - UtRegisterTest("DetectFastPatternTest462", DetectFastPatternTest462, 1); - UtRegisterTest("DetectFastPatternTest463", DetectFastPatternTest463, 1); - UtRegisterTest("DetectFastPatternTest464", DetectFastPatternTest464, 1); - UtRegisterTest("DetectFastPatternTest465", DetectFastPatternTest465, 1); + UtRegisterTest("DetectFastPatternTest425", DetectFastPatternTest425); + UtRegisterTest("DetectFastPatternTest426", DetectFastPatternTest426); + UtRegisterTest("DetectFastPatternTest427", DetectFastPatternTest427); + UtRegisterTest("DetectFastPatternTest428", DetectFastPatternTest428); + UtRegisterTest("DetectFastPatternTest429", DetectFastPatternTest429); + UtRegisterTest("DetectFastPatternTest430", DetectFastPatternTest430); + UtRegisterTest("DetectFastPatternTest431", DetectFastPatternTest431); + UtRegisterTest("DetectFastPatternTest432", DetectFastPatternTest432); + UtRegisterTest("DetectFastPatternTest433", DetectFastPatternTest433); + UtRegisterTest("DetectFastPatternTest434", DetectFastPatternTest434); + UtRegisterTest("DetectFastPatternTest435", DetectFastPatternTest435); + UtRegisterTest("DetectFastPatternTest436", DetectFastPatternTest436); + UtRegisterTest("DetectFastPatternTest437", DetectFastPatternTest437); + UtRegisterTest("DetectFastPatternTest438", DetectFastPatternTest438); + UtRegisterTest("DetectFastPatternTest439", DetectFastPatternTest439); + UtRegisterTest("DetectFastPatternTest440", DetectFastPatternTest440); + UtRegisterTest("DetectFastPatternTest441", DetectFastPatternTest441); + UtRegisterTest("DetectFastPatternTest442", DetectFastPatternTest442); + UtRegisterTest("DetectFastPatternTest443", DetectFastPatternTest443); + UtRegisterTest("DetectFastPatternTest444", DetectFastPatternTest444); + UtRegisterTest("DetectFastPatternTest445", DetectFastPatternTest445); + UtRegisterTest("DetectFastPatternTest446", DetectFastPatternTest446); + UtRegisterTest("DetectFastPatternTest447", DetectFastPatternTest447); + UtRegisterTest("DetectFastPatternTest448", DetectFastPatternTest448); + UtRegisterTest("DetectFastPatternTest449", DetectFastPatternTest449); + UtRegisterTest("DetectFastPatternTest450", DetectFastPatternTest450); + UtRegisterTest("DetectFastPatternTest451", DetectFastPatternTest451); + UtRegisterTest("DetectFastPatternTest452", DetectFastPatternTest452); + UtRegisterTest("DetectFastPatternTest453", DetectFastPatternTest453); + UtRegisterTest("DetectFastPatternTest454", DetectFastPatternTest454); + UtRegisterTest("DetectFastPatternTest455", DetectFastPatternTest455); + UtRegisterTest("DetectFastPatternTest456", DetectFastPatternTest456); + UtRegisterTest("DetectFastPatternTest457", DetectFastPatternTest457); + UtRegisterTest("DetectFastPatternTest458", DetectFastPatternTest458); + UtRegisterTest("DetectFastPatternTest459", DetectFastPatternTest459); + UtRegisterTest("DetectFastPatternTest460", DetectFastPatternTest460); + UtRegisterTest("DetectFastPatternTest461", DetectFastPatternTest461); + UtRegisterTest("DetectFastPatternTest462", DetectFastPatternTest462); + UtRegisterTest("DetectFastPatternTest463", DetectFastPatternTest463); + UtRegisterTest("DetectFastPatternTest464", DetectFastPatternTest464); + UtRegisterTest("DetectFastPatternTest465", DetectFastPatternTest465); /* http_stat_code fast_pattern tests ^ */ /* http_server_body fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest466", DetectFastPatternTest466, 1); - UtRegisterTest("DetectFastPatternTest467", DetectFastPatternTest467, 1); - UtRegisterTest("DetectFastPatternTest468", DetectFastPatternTest468, 1); - UtRegisterTest("DetectFastPatternTest469", DetectFastPatternTest469, 1); - UtRegisterTest("DetectFastPatternTest470", DetectFastPatternTest470, 1); - UtRegisterTest("DetectFastPatternTest471", DetectFastPatternTest471, 1); - UtRegisterTest("DetectFastPatternTest472", DetectFastPatternTest472, 1); - UtRegisterTest("DetectFastPatternTest473", DetectFastPatternTest473, 1); - UtRegisterTest("DetectFastPatternTest474", DetectFastPatternTest474, 1); - UtRegisterTest("DetectFastPatternTest475", DetectFastPatternTest475, 1); - UtRegisterTest("DetectFastPatternTest476", DetectFastPatternTest476, 1); - UtRegisterTest("DetectFastPatternTest477", DetectFastPatternTest477, 1); - UtRegisterTest("DetectFastPatternTest478", DetectFastPatternTest478, 1); - UtRegisterTest("DetectFastPatternTest479", DetectFastPatternTest479, 1); - UtRegisterTest("DetectFastPatternTest480", DetectFastPatternTest480, 1); - UtRegisterTest("DetectFastPatternTest481", DetectFastPatternTest481, 1); - UtRegisterTest("DetectFastPatternTest482", DetectFastPatternTest482, 1); - UtRegisterTest("DetectFastPatternTest483", DetectFastPatternTest483, 1); - UtRegisterTest("DetectFastPatternTest484", DetectFastPatternTest484, 1); - UtRegisterTest("DetectFastPatternTest485", DetectFastPatternTest485, 1); - UtRegisterTest("DetectFastPatternTest486", DetectFastPatternTest486, 1); - UtRegisterTest("DetectFastPatternTest487", DetectFastPatternTest487, 1); - UtRegisterTest("DetectFastPatternTest488", DetectFastPatternTest488, 1); - UtRegisterTest("DetectFastPatternTest489", DetectFastPatternTest489, 1); - UtRegisterTest("DetectFastPatternTest490", DetectFastPatternTest490, 1); - UtRegisterTest("DetectFastPatternTest491", DetectFastPatternTest491, 1); - UtRegisterTest("DetectFastPatternTest492", DetectFastPatternTest492, 1); - UtRegisterTest("DetectFastPatternTest493", DetectFastPatternTest493, 1); - UtRegisterTest("DetectFastPatternTest494", DetectFastPatternTest494, 1); - UtRegisterTest("DetectFastPatternTest495", DetectFastPatternTest495, 1); - UtRegisterTest("DetectFastPatternTest496", DetectFastPatternTest496, 1); - UtRegisterTest("DetectFastPatternTest497", DetectFastPatternTest497, 1); - UtRegisterTest("DetectFastPatternTest498", DetectFastPatternTest498, 1); - UtRegisterTest("DetectFastPatternTest499", DetectFastPatternTest499, 1); - UtRegisterTest("DetectFastPatternTest500", DetectFastPatternTest500, 1); - UtRegisterTest("DetectFastPatternTest501", DetectFastPatternTest501, 1); - UtRegisterTest("DetectFastPatternTest502", DetectFastPatternTest502, 1); - UtRegisterTest("DetectFastPatternTest503", DetectFastPatternTest503, 1); - UtRegisterTest("DetectFastPatternTest504", DetectFastPatternTest504, 1); - UtRegisterTest("DetectFastPatternTest505", DetectFastPatternTest505, 1); - UtRegisterTest("DetectFastPatternTest506", DetectFastPatternTest506, 1); + UtRegisterTest("DetectFastPatternTest466", DetectFastPatternTest466); + UtRegisterTest("DetectFastPatternTest467", DetectFastPatternTest467); + UtRegisterTest("DetectFastPatternTest468", DetectFastPatternTest468); + UtRegisterTest("DetectFastPatternTest469", DetectFastPatternTest469); + UtRegisterTest("DetectFastPatternTest470", DetectFastPatternTest470); + UtRegisterTest("DetectFastPatternTest471", DetectFastPatternTest471); + UtRegisterTest("DetectFastPatternTest472", DetectFastPatternTest472); + UtRegisterTest("DetectFastPatternTest473", DetectFastPatternTest473); + UtRegisterTest("DetectFastPatternTest474", DetectFastPatternTest474); + UtRegisterTest("DetectFastPatternTest475", DetectFastPatternTest475); + UtRegisterTest("DetectFastPatternTest476", DetectFastPatternTest476); + UtRegisterTest("DetectFastPatternTest477", DetectFastPatternTest477); + UtRegisterTest("DetectFastPatternTest478", DetectFastPatternTest478); + UtRegisterTest("DetectFastPatternTest479", DetectFastPatternTest479); + UtRegisterTest("DetectFastPatternTest480", DetectFastPatternTest480); + UtRegisterTest("DetectFastPatternTest481", DetectFastPatternTest481); + UtRegisterTest("DetectFastPatternTest482", DetectFastPatternTest482); + UtRegisterTest("DetectFastPatternTest483", DetectFastPatternTest483); + UtRegisterTest("DetectFastPatternTest484", DetectFastPatternTest484); + UtRegisterTest("DetectFastPatternTest485", DetectFastPatternTest485); + UtRegisterTest("DetectFastPatternTest486", DetectFastPatternTest486); + UtRegisterTest("DetectFastPatternTest487", DetectFastPatternTest487); + UtRegisterTest("DetectFastPatternTest488", DetectFastPatternTest488); + UtRegisterTest("DetectFastPatternTest489", DetectFastPatternTest489); + UtRegisterTest("DetectFastPatternTest490", DetectFastPatternTest490); + UtRegisterTest("DetectFastPatternTest491", DetectFastPatternTest491); + UtRegisterTest("DetectFastPatternTest492", DetectFastPatternTest492); + UtRegisterTest("DetectFastPatternTest493", DetectFastPatternTest493); + UtRegisterTest("DetectFastPatternTest494", DetectFastPatternTest494); + UtRegisterTest("DetectFastPatternTest495", DetectFastPatternTest495); + UtRegisterTest("DetectFastPatternTest496", DetectFastPatternTest496); + UtRegisterTest("DetectFastPatternTest497", DetectFastPatternTest497); + UtRegisterTest("DetectFastPatternTest498", DetectFastPatternTest498); + UtRegisterTest("DetectFastPatternTest499", DetectFastPatternTest499); + UtRegisterTest("DetectFastPatternTest500", DetectFastPatternTest500); + UtRegisterTest("DetectFastPatternTest501", DetectFastPatternTest501); + UtRegisterTest("DetectFastPatternTest502", DetectFastPatternTest502); + UtRegisterTest("DetectFastPatternTest503", DetectFastPatternTest503); + UtRegisterTest("DetectFastPatternTest504", DetectFastPatternTest504); + UtRegisterTest("DetectFastPatternTest505", DetectFastPatternTest505); + UtRegisterTest("DetectFastPatternTest506", DetectFastPatternTest506); /* http_server_body fast_pattern tests ^ */ /* file_data fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest507", DetectFastPatternTest507, 1); - UtRegisterTest("DetectFastPatternTest508", DetectFastPatternTest508, 1); - UtRegisterTest("DetectFastPatternTest509", DetectFastPatternTest509, 1); - UtRegisterTest("DetectFastPatternTest510", DetectFastPatternTest510, 1); - UtRegisterTest("DetectFastPatternTest511", DetectFastPatternTest511, 1); - UtRegisterTest("DetectFastPatternTest512", DetectFastPatternTest512, 1); - UtRegisterTest("DetectFastPatternTest513", DetectFastPatternTest513, 1); - UtRegisterTest("DetectFastPatternTest514", DetectFastPatternTest514, 1); - UtRegisterTest("DetectFastPatternTest515", DetectFastPatternTest515, 1); - UtRegisterTest("DetectFastPatternTest516", DetectFastPatternTest516, 1); - UtRegisterTest("DetectFastPatternTest517", DetectFastPatternTest517, 1); - UtRegisterTest("DetectFastPatternTest518", DetectFastPatternTest518, 1); - UtRegisterTest("DetectFastPatternTest519", DetectFastPatternTest519, 1); - UtRegisterTest("DetectFastPatternTest520", DetectFastPatternTest520, 1); - UtRegisterTest("DetectFastPatternTest521", DetectFastPatternTest521, 1); - UtRegisterTest("DetectFastPatternTest522", DetectFastPatternTest522, 1); - UtRegisterTest("DetectFastPatternTest523", DetectFastPatternTest523, 1); - UtRegisterTest("DetectFastPatternTest524", DetectFastPatternTest524, 1); - UtRegisterTest("DetectFastPatternTest525", DetectFastPatternTest525, 1); - UtRegisterTest("DetectFastPatternTest526", DetectFastPatternTest526, 1); - UtRegisterTest("DetectFastPatternTest527", DetectFastPatternTest527, 1); - UtRegisterTest("DetectFastPatternTest528", DetectFastPatternTest528, 1); - UtRegisterTest("DetectFastPatternTest529", DetectFastPatternTest529, 1); - UtRegisterTest("DetectFastPatternTest530", DetectFastPatternTest530, 1); - UtRegisterTest("DetectFastPatternTest531", DetectFastPatternTest531, 1); - UtRegisterTest("DetectFastPatternTest532", DetectFastPatternTest532, 1); - UtRegisterTest("DetectFastPatternTest533", DetectFastPatternTest533, 1); - UtRegisterTest("DetectFastPatternTest534", DetectFastPatternTest534, 1); - UtRegisterTest("DetectFastPatternTest535", DetectFastPatternTest535, 1); - UtRegisterTest("DetectFastPatternTest536", DetectFastPatternTest536, 1); - UtRegisterTest("DetectFastPatternTest537", DetectFastPatternTest537, 1); - UtRegisterTest("DetectFastPatternTest538", DetectFastPatternTest538, 1); - UtRegisterTest("DetectFastPatternTest539", DetectFastPatternTest539, 1); - UtRegisterTest("DetectFastPatternTest540", DetectFastPatternTest540, 1); - UtRegisterTest("DetectFastPatternTest541", DetectFastPatternTest541, 1); - UtRegisterTest("DetectFastPatternTest542", DetectFastPatternTest542, 1); - UtRegisterTest("DetectFastPatternTest543", DetectFastPatternTest543, 1); - UtRegisterTest("DetectFastPatternTest544", DetectFastPatternTest544, 1); - UtRegisterTest("DetectFastPatternTest545", DetectFastPatternTest545, 1); - UtRegisterTest("DetectFastPatternTest546", DetectFastPatternTest546, 1); - UtRegisterTest("DetectFastPatternTest547", DetectFastPatternTest547, 1); + UtRegisterTest("DetectFastPatternTest507", DetectFastPatternTest507); + UtRegisterTest("DetectFastPatternTest508", DetectFastPatternTest508); + UtRegisterTest("DetectFastPatternTest509", DetectFastPatternTest509); + UtRegisterTest("DetectFastPatternTest510", DetectFastPatternTest510); + UtRegisterTest("DetectFastPatternTest511", DetectFastPatternTest511); + UtRegisterTest("DetectFastPatternTest512", DetectFastPatternTest512); + UtRegisterTest("DetectFastPatternTest513", DetectFastPatternTest513); + UtRegisterTest("DetectFastPatternTest514", DetectFastPatternTest514); + UtRegisterTest("DetectFastPatternTest515", DetectFastPatternTest515); + UtRegisterTest("DetectFastPatternTest516", DetectFastPatternTest516); + UtRegisterTest("DetectFastPatternTest517", DetectFastPatternTest517); + UtRegisterTest("DetectFastPatternTest518", DetectFastPatternTest518); + UtRegisterTest("DetectFastPatternTest519", DetectFastPatternTest519); + UtRegisterTest("DetectFastPatternTest520", DetectFastPatternTest520); + UtRegisterTest("DetectFastPatternTest521", DetectFastPatternTest521); + UtRegisterTest("DetectFastPatternTest522", DetectFastPatternTest522); + UtRegisterTest("DetectFastPatternTest523", DetectFastPatternTest523); + UtRegisterTest("DetectFastPatternTest524", DetectFastPatternTest524); + UtRegisterTest("DetectFastPatternTest525", DetectFastPatternTest525); + UtRegisterTest("DetectFastPatternTest526", DetectFastPatternTest526); + UtRegisterTest("DetectFastPatternTest527", DetectFastPatternTest527); + UtRegisterTest("DetectFastPatternTest528", DetectFastPatternTest528); + UtRegisterTest("DetectFastPatternTest529", DetectFastPatternTest529); + UtRegisterTest("DetectFastPatternTest530", DetectFastPatternTest530); + UtRegisterTest("DetectFastPatternTest531", DetectFastPatternTest531); + UtRegisterTest("DetectFastPatternTest532", DetectFastPatternTest532); + UtRegisterTest("DetectFastPatternTest533", DetectFastPatternTest533); + UtRegisterTest("DetectFastPatternTest534", DetectFastPatternTest534); + UtRegisterTest("DetectFastPatternTest535", DetectFastPatternTest535); + UtRegisterTest("DetectFastPatternTest536", DetectFastPatternTest536); + UtRegisterTest("DetectFastPatternTest537", DetectFastPatternTest537); + UtRegisterTest("DetectFastPatternTest538", DetectFastPatternTest538); + UtRegisterTest("DetectFastPatternTest539", DetectFastPatternTest539); + UtRegisterTest("DetectFastPatternTest540", DetectFastPatternTest540); + UtRegisterTest("DetectFastPatternTest541", DetectFastPatternTest541); + UtRegisterTest("DetectFastPatternTest542", DetectFastPatternTest542); + UtRegisterTest("DetectFastPatternTest543", DetectFastPatternTest543); + UtRegisterTest("DetectFastPatternTest544", DetectFastPatternTest544); + UtRegisterTest("DetectFastPatternTest545", DetectFastPatternTest545); + UtRegisterTest("DetectFastPatternTest546", DetectFastPatternTest546); + UtRegisterTest("DetectFastPatternTest547", DetectFastPatternTest547); /* file_data fast_pattern tests ^ */ /* http_user_agent fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest548", DetectFastPatternTest548, 1); - UtRegisterTest("DetectFastPatternTest549", DetectFastPatternTest549, 1); - UtRegisterTest("DetectFastPatternTest550", DetectFastPatternTest550, 1); - UtRegisterTest("DetectFastPatternTest551", DetectFastPatternTest551, 1); - UtRegisterTest("DetectFastPatternTest552", DetectFastPatternTest552, 1); - UtRegisterTest("DetectFastPatternTest553", DetectFastPatternTest553, 1); - UtRegisterTest("DetectFastPatternTest554", DetectFastPatternTest554, 1); - UtRegisterTest("DetectFastPatternTest555", DetectFastPatternTest555, 1); - UtRegisterTest("DetectFastPatternTest556", DetectFastPatternTest556, 1); - UtRegisterTest("DetectFastPatternTest557", DetectFastPatternTest557, 1); - UtRegisterTest("DetectFastPatternTest558", DetectFastPatternTest558, 1); - UtRegisterTest("DetectFastPatternTest559", DetectFastPatternTest559, 1); - UtRegisterTest("DetectFastPatternTest560", DetectFastPatternTest560, 1); - UtRegisterTest("DetectFastPatternTest561", DetectFastPatternTest561, 1); - UtRegisterTest("DetectFastPatternTest562", DetectFastPatternTest562, 1); - UtRegisterTest("DetectFastPatternTest563", DetectFastPatternTest563, 1); - UtRegisterTest("DetectFastPatternTest564", DetectFastPatternTest564, 1); - UtRegisterTest("DetectFastPatternTest565", DetectFastPatternTest565, 1); - UtRegisterTest("DetectFastPatternTest566", DetectFastPatternTest566, 1); - UtRegisterTest("DetectFastPatternTest567", DetectFastPatternTest567, 1); - UtRegisterTest("DetectFastPatternTest568", DetectFastPatternTest568, 1); - UtRegisterTest("DetectFastPatternTest569", DetectFastPatternTest569, 1); - UtRegisterTest("DetectFastPatternTest570", DetectFastPatternTest570, 1); - UtRegisterTest("DetectFastPatternTest571", DetectFastPatternTest571, 1); - UtRegisterTest("DetectFastPatternTest572", DetectFastPatternTest572, 1); - UtRegisterTest("DetectFastPatternTest573", DetectFastPatternTest573, 1); - UtRegisterTest("DetectFastPatternTest574", DetectFastPatternTest574, 1); - UtRegisterTest("DetectFastPatternTest575", DetectFastPatternTest575, 1); - UtRegisterTest("DetectFastPatternTest576", DetectFastPatternTest576, 1); - UtRegisterTest("DetectFastPatternTest577", DetectFastPatternTest577, 1); - UtRegisterTest("DetectFastPatternTest578", DetectFastPatternTest578, 1); - UtRegisterTest("DetectFastPatternTest579", DetectFastPatternTest579, 1); - UtRegisterTest("DetectFastPatternTest580", DetectFastPatternTest580, 1); - UtRegisterTest("DetectFastPatternTest581", DetectFastPatternTest581, 1); - UtRegisterTest("DetectFastPatternTest582", DetectFastPatternTest582, 1); - UtRegisterTest("DetectFastPatternTest583", DetectFastPatternTest583, 1); - UtRegisterTest("DetectFastPatternTest584", DetectFastPatternTest584, 1); - UtRegisterTest("DetectFastPatternTest585", DetectFastPatternTest585, 1); - UtRegisterTest("DetectFastPatternTest586", DetectFastPatternTest586, 1); - UtRegisterTest("DetectFastPatternTest587", DetectFastPatternTest587, 1); - UtRegisterTest("DetectFastPatternTest588", DetectFastPatternTest588, 1); + UtRegisterTest("DetectFastPatternTest548", DetectFastPatternTest548); + UtRegisterTest("DetectFastPatternTest549", DetectFastPatternTest549); + UtRegisterTest("DetectFastPatternTest550", DetectFastPatternTest550); + UtRegisterTest("DetectFastPatternTest551", DetectFastPatternTest551); + UtRegisterTest("DetectFastPatternTest552", DetectFastPatternTest552); + UtRegisterTest("DetectFastPatternTest553", DetectFastPatternTest553); + UtRegisterTest("DetectFastPatternTest554", DetectFastPatternTest554); + UtRegisterTest("DetectFastPatternTest555", DetectFastPatternTest555); + UtRegisterTest("DetectFastPatternTest556", DetectFastPatternTest556); + UtRegisterTest("DetectFastPatternTest557", DetectFastPatternTest557); + UtRegisterTest("DetectFastPatternTest558", DetectFastPatternTest558); + UtRegisterTest("DetectFastPatternTest559", DetectFastPatternTest559); + UtRegisterTest("DetectFastPatternTest560", DetectFastPatternTest560); + UtRegisterTest("DetectFastPatternTest561", DetectFastPatternTest561); + UtRegisterTest("DetectFastPatternTest562", DetectFastPatternTest562); + UtRegisterTest("DetectFastPatternTest563", DetectFastPatternTest563); + UtRegisterTest("DetectFastPatternTest564", DetectFastPatternTest564); + UtRegisterTest("DetectFastPatternTest565", DetectFastPatternTest565); + UtRegisterTest("DetectFastPatternTest566", DetectFastPatternTest566); + UtRegisterTest("DetectFastPatternTest567", DetectFastPatternTest567); + UtRegisterTest("DetectFastPatternTest568", DetectFastPatternTest568); + UtRegisterTest("DetectFastPatternTest569", DetectFastPatternTest569); + UtRegisterTest("DetectFastPatternTest570", DetectFastPatternTest570); + UtRegisterTest("DetectFastPatternTest571", DetectFastPatternTest571); + UtRegisterTest("DetectFastPatternTest572", DetectFastPatternTest572); + UtRegisterTest("DetectFastPatternTest573", DetectFastPatternTest573); + UtRegisterTest("DetectFastPatternTest574", DetectFastPatternTest574); + UtRegisterTest("DetectFastPatternTest575", DetectFastPatternTest575); + UtRegisterTest("DetectFastPatternTest576", DetectFastPatternTest576); + UtRegisterTest("DetectFastPatternTest577", DetectFastPatternTest577); + UtRegisterTest("DetectFastPatternTest578", DetectFastPatternTest578); + UtRegisterTest("DetectFastPatternTest579", DetectFastPatternTest579); + UtRegisterTest("DetectFastPatternTest580", DetectFastPatternTest580); + UtRegisterTest("DetectFastPatternTest581", DetectFastPatternTest581); + UtRegisterTest("DetectFastPatternTest582", DetectFastPatternTest582); + UtRegisterTest("DetectFastPatternTest583", DetectFastPatternTest583); + UtRegisterTest("DetectFastPatternTest584", DetectFastPatternTest584); + UtRegisterTest("DetectFastPatternTest585", DetectFastPatternTest585); + UtRegisterTest("DetectFastPatternTest586", DetectFastPatternTest586); + UtRegisterTest("DetectFastPatternTest587", DetectFastPatternTest587); + UtRegisterTest("DetectFastPatternTest588", DetectFastPatternTest588); /* http_user_agent fast_pattern tests ^ */ /* http_host fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest589", DetectFastPatternTest589, 1); - UtRegisterTest("DetectFastPatternTest590", DetectFastPatternTest590, 1); - UtRegisterTest("DetectFastPatternTest591", DetectFastPatternTest591, 1); - UtRegisterTest("DetectFastPatternTest592", DetectFastPatternTest592, 1); - UtRegisterTest("DetectFastPatternTest593", DetectFastPatternTest593, 1); - UtRegisterTest("DetectFastPatternTest594", DetectFastPatternTest594, 1); - UtRegisterTest("DetectFastPatternTest595", DetectFastPatternTest595, 1); - UtRegisterTest("DetectFastPatternTest596", DetectFastPatternTest596, 1); - UtRegisterTest("DetectFastPatternTest597", DetectFastPatternTest597, 1); - UtRegisterTest("DetectFastPatternTest598", DetectFastPatternTest598, 1); - UtRegisterTest("DetectFastPatternTest599", DetectFastPatternTest599, 1); - UtRegisterTest("DetectFastPatternTest600", DetectFastPatternTest600, 1); - UtRegisterTest("DetectFastPatternTest601", DetectFastPatternTest601, 1); - UtRegisterTest("DetectFastPatternTest602", DetectFastPatternTest602, 1); - UtRegisterTest("DetectFastPatternTest603", DetectFastPatternTest603, 1); - UtRegisterTest("DetectFastPatternTest604", DetectFastPatternTest604, 1); - UtRegisterTest("DetectFastPatternTest605", DetectFastPatternTest605, 1); - UtRegisterTest("DetectFastPatternTest606", DetectFastPatternTest606, 1); - UtRegisterTest("DetectFastPatternTest607", DetectFastPatternTest607, 1); - UtRegisterTest("DetectFastPatternTest608", DetectFastPatternTest608, 1); - UtRegisterTest("DetectFastPatternTest609", DetectFastPatternTest609, 1); - UtRegisterTest("DetectFastPatternTest610", DetectFastPatternTest610, 1); - UtRegisterTest("DetectFastPatternTest611", DetectFastPatternTest611, 1); - UtRegisterTest("DetectFastPatternTest612", DetectFastPatternTest612, 1); - UtRegisterTest("DetectFastPatternTest613", DetectFastPatternTest613, 1); - UtRegisterTest("DetectFastPatternTest614", DetectFastPatternTest614, 1); - UtRegisterTest("DetectFastPatternTest615", DetectFastPatternTest615, 1); - UtRegisterTest("DetectFastPatternTest616", DetectFastPatternTest616, 1); - UtRegisterTest("DetectFastPatternTest617", DetectFastPatternTest617, 1); - UtRegisterTest("DetectFastPatternTest618", DetectFastPatternTest618, 1); - UtRegisterTest("DetectFastPatternTest619", DetectFastPatternTest619, 1); - UtRegisterTest("DetectFastPatternTest620", DetectFastPatternTest620, 1); - UtRegisterTest("DetectFastPatternTest621", DetectFastPatternTest621, 1); - UtRegisterTest("DetectFastPatternTest622", DetectFastPatternTest622, 1); - UtRegisterTest("DetectFastPatternTest623", DetectFastPatternTest623, 1); - UtRegisterTest("DetectFastPatternTest624", DetectFastPatternTest624, 1); - UtRegisterTest("DetectFastPatternTest625", DetectFastPatternTest625, 1); - UtRegisterTest("DetectFastPatternTest626", DetectFastPatternTest626, 1); - UtRegisterTest("DetectFastPatternTest627", DetectFastPatternTest627, 1); - UtRegisterTest("DetectFastPatternTest628", DetectFastPatternTest628, 1); - UtRegisterTest("DetectFastPatternTest629", DetectFastPatternTest629, 1); + UtRegisterTest("DetectFastPatternTest589", DetectFastPatternTest589); + UtRegisterTest("DetectFastPatternTest590", DetectFastPatternTest590); + UtRegisterTest("DetectFastPatternTest591", DetectFastPatternTest591); + UtRegisterTest("DetectFastPatternTest592", DetectFastPatternTest592); + UtRegisterTest("DetectFastPatternTest593", DetectFastPatternTest593); + UtRegisterTest("DetectFastPatternTest594", DetectFastPatternTest594); + UtRegisterTest("DetectFastPatternTest595", DetectFastPatternTest595); + UtRegisterTest("DetectFastPatternTest596", DetectFastPatternTest596); + UtRegisterTest("DetectFastPatternTest597", DetectFastPatternTest597); + UtRegisterTest("DetectFastPatternTest598", DetectFastPatternTest598); + UtRegisterTest("DetectFastPatternTest599", DetectFastPatternTest599); + UtRegisterTest("DetectFastPatternTest600", DetectFastPatternTest600); + UtRegisterTest("DetectFastPatternTest601", DetectFastPatternTest601); + UtRegisterTest("DetectFastPatternTest602", DetectFastPatternTest602); + UtRegisterTest("DetectFastPatternTest603", DetectFastPatternTest603); + UtRegisterTest("DetectFastPatternTest604", DetectFastPatternTest604); + UtRegisterTest("DetectFastPatternTest605", DetectFastPatternTest605); + UtRegisterTest("DetectFastPatternTest606", DetectFastPatternTest606); + UtRegisterTest("DetectFastPatternTest607", DetectFastPatternTest607); + UtRegisterTest("DetectFastPatternTest608", DetectFastPatternTest608); + UtRegisterTest("DetectFastPatternTest609", DetectFastPatternTest609); + UtRegisterTest("DetectFastPatternTest610", DetectFastPatternTest610); + UtRegisterTest("DetectFastPatternTest611", DetectFastPatternTest611); + UtRegisterTest("DetectFastPatternTest612", DetectFastPatternTest612); + UtRegisterTest("DetectFastPatternTest613", DetectFastPatternTest613); + UtRegisterTest("DetectFastPatternTest614", DetectFastPatternTest614); + UtRegisterTest("DetectFastPatternTest615", DetectFastPatternTest615); + UtRegisterTest("DetectFastPatternTest616", DetectFastPatternTest616); + UtRegisterTest("DetectFastPatternTest617", DetectFastPatternTest617); + UtRegisterTest("DetectFastPatternTest618", DetectFastPatternTest618); + UtRegisterTest("DetectFastPatternTest619", DetectFastPatternTest619); + UtRegisterTest("DetectFastPatternTest620", DetectFastPatternTest620); + UtRegisterTest("DetectFastPatternTest621", DetectFastPatternTest621); + UtRegisterTest("DetectFastPatternTest622", DetectFastPatternTest622); + UtRegisterTest("DetectFastPatternTest623", DetectFastPatternTest623); + UtRegisterTest("DetectFastPatternTest624", DetectFastPatternTest624); + UtRegisterTest("DetectFastPatternTest625", DetectFastPatternTest625); + UtRegisterTest("DetectFastPatternTest626", DetectFastPatternTest626); + UtRegisterTest("DetectFastPatternTest627", DetectFastPatternTest627); + UtRegisterTest("DetectFastPatternTest628", DetectFastPatternTest628); + UtRegisterTest("DetectFastPatternTest629", DetectFastPatternTest629); /* http_host fast_pattern tests ^ */ /* http_rawhost fast_pattern tests v */ - UtRegisterTest("DetectFastPatternTest630", DetectFastPatternTest630, 1); - UtRegisterTest("DetectFastPatternTest631", DetectFastPatternTest631, 1); - UtRegisterTest("DetectFastPatternTest632", DetectFastPatternTest632, 1); - UtRegisterTest("DetectFastPatternTest633", DetectFastPatternTest633, 1); - UtRegisterTest("DetectFastPatternTest634", DetectFastPatternTest634, 1); - UtRegisterTest("DetectFastPatternTest635", DetectFastPatternTest635, 1); - UtRegisterTest("DetectFastPatternTest636", DetectFastPatternTest636, 1); - UtRegisterTest("DetectFastPatternTest637", DetectFastPatternTest637, 1); - UtRegisterTest("DetectFastPatternTest638", DetectFastPatternTest638, 1); - UtRegisterTest("DetectFastPatternTest639", DetectFastPatternTest639, 1); - UtRegisterTest("DetectFastPatternTest640", DetectFastPatternTest640, 1); - UtRegisterTest("DetectFastPatternTest641", DetectFastPatternTest641, 1); - UtRegisterTest("DetectFastPatternTest642", DetectFastPatternTest642, 1); - UtRegisterTest("DetectFastPatternTest643", DetectFastPatternTest643, 1); - UtRegisterTest("DetectFastPatternTest644", DetectFastPatternTest644, 1); - UtRegisterTest("DetectFastPatternTest645", DetectFastPatternTest645, 1); - UtRegisterTest("DetectFastPatternTest646", DetectFastPatternTest646, 1); - UtRegisterTest("DetectFastPatternTest647", DetectFastPatternTest647, 1); - UtRegisterTest("DetectFastPatternTest648", DetectFastPatternTest648, 1); - UtRegisterTest("DetectFastPatternTest649", DetectFastPatternTest649, 1); - UtRegisterTest("DetectFastPatternTest650", DetectFastPatternTest650, 1); - UtRegisterTest("DetectFastPatternTest651", DetectFastPatternTest651, 1); - UtRegisterTest("DetectFastPatternTest652", DetectFastPatternTest652, 1); - UtRegisterTest("DetectFastPatternTest653", DetectFastPatternTest653, 1); - UtRegisterTest("DetectFastPatternTest654", DetectFastPatternTest654, 1); - UtRegisterTest("DetectFastPatternTest655", DetectFastPatternTest655, 1); - UtRegisterTest("DetectFastPatternTest656", DetectFastPatternTest656, 1); - UtRegisterTest("DetectFastPatternTest657", DetectFastPatternTest657, 1); - UtRegisterTest("DetectFastPatternTest658", DetectFastPatternTest658, 1); - UtRegisterTest("DetectFastPatternTest659", DetectFastPatternTest659, 1); - UtRegisterTest("DetectFastPatternTest660", DetectFastPatternTest660, 1); - UtRegisterTest("DetectFastPatternTest661", DetectFastPatternTest661, 1); - UtRegisterTest("DetectFastPatternTest662", DetectFastPatternTest662, 1); - UtRegisterTest("DetectFastPatternTest663", DetectFastPatternTest663, 1); - UtRegisterTest("DetectFastPatternTest664", DetectFastPatternTest664, 1); - UtRegisterTest("DetectFastPatternTest665", DetectFastPatternTest665, 1); - UtRegisterTest("DetectFastPatternTest666", DetectFastPatternTest666, 1); - UtRegisterTest("DetectFastPatternTest667", DetectFastPatternTest667, 1); - UtRegisterTest("DetectFastPatternTest668", DetectFastPatternTest668, 1); - UtRegisterTest("DetectFastPatternTest669", DetectFastPatternTest669, 1); - UtRegisterTest("DetectFastPatternTest670", DetectFastPatternTest670, 1); + UtRegisterTest("DetectFastPatternTest630", DetectFastPatternTest630); + UtRegisterTest("DetectFastPatternTest631", DetectFastPatternTest631); + UtRegisterTest("DetectFastPatternTest632", DetectFastPatternTest632); + UtRegisterTest("DetectFastPatternTest633", DetectFastPatternTest633); + UtRegisterTest("DetectFastPatternTest634", DetectFastPatternTest634); + UtRegisterTest("DetectFastPatternTest635", DetectFastPatternTest635); + UtRegisterTest("DetectFastPatternTest636", DetectFastPatternTest636); + UtRegisterTest("DetectFastPatternTest637", DetectFastPatternTest637); + UtRegisterTest("DetectFastPatternTest638", DetectFastPatternTest638); + UtRegisterTest("DetectFastPatternTest639", DetectFastPatternTest639); + UtRegisterTest("DetectFastPatternTest640", DetectFastPatternTest640); + UtRegisterTest("DetectFastPatternTest641", DetectFastPatternTest641); + UtRegisterTest("DetectFastPatternTest642", DetectFastPatternTest642); + UtRegisterTest("DetectFastPatternTest643", DetectFastPatternTest643); + UtRegisterTest("DetectFastPatternTest644", DetectFastPatternTest644); + UtRegisterTest("DetectFastPatternTest645", DetectFastPatternTest645); + UtRegisterTest("DetectFastPatternTest646", DetectFastPatternTest646); + UtRegisterTest("DetectFastPatternTest647", DetectFastPatternTest647); + UtRegisterTest("DetectFastPatternTest648", DetectFastPatternTest648); + UtRegisterTest("DetectFastPatternTest649", DetectFastPatternTest649); + UtRegisterTest("DetectFastPatternTest650", DetectFastPatternTest650); + UtRegisterTest("DetectFastPatternTest651", DetectFastPatternTest651); + UtRegisterTest("DetectFastPatternTest652", DetectFastPatternTest652); + UtRegisterTest("DetectFastPatternTest653", DetectFastPatternTest653); + UtRegisterTest("DetectFastPatternTest654", DetectFastPatternTest654); + UtRegisterTest("DetectFastPatternTest655", DetectFastPatternTest655); + UtRegisterTest("DetectFastPatternTest656", DetectFastPatternTest656); + UtRegisterTest("DetectFastPatternTest657", DetectFastPatternTest657); + UtRegisterTest("DetectFastPatternTest658", DetectFastPatternTest658); + UtRegisterTest("DetectFastPatternTest659", DetectFastPatternTest659); + UtRegisterTest("DetectFastPatternTest660", DetectFastPatternTest660); + UtRegisterTest("DetectFastPatternTest661", DetectFastPatternTest661); + UtRegisterTest("DetectFastPatternTest662", DetectFastPatternTest662); + UtRegisterTest("DetectFastPatternTest663", DetectFastPatternTest663); + UtRegisterTest("DetectFastPatternTest664", DetectFastPatternTest664); + UtRegisterTest("DetectFastPatternTest665", DetectFastPatternTest665); + UtRegisterTest("DetectFastPatternTest666", DetectFastPatternTest666); + UtRegisterTest("DetectFastPatternTest667", DetectFastPatternTest667); + UtRegisterTest("DetectFastPatternTest668", DetectFastPatternTest668); + UtRegisterTest("DetectFastPatternTest669", DetectFastPatternTest669); + UtRegisterTest("DetectFastPatternTest670", DetectFastPatternTest670); /* Unittest to check * - if we assign different content_ids to duplicate patterns, but one of the @@ -20117,7 +19547,7 @@ void DetectFastPatternRegisterTests(void) * - if 2 unique patterns get unique ids. * - if 2 duplicate patterns, with no chop set get unique ids. */ - UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671, 1); + UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671); #endif return; diff --git a/src/detect-fast-pattern.h b/src/detect-fast-pattern.h index 8298e7bbf9de..ff8bc5cc3708 100644 --- a/src/detect-fast-pattern.h +++ b/src/detect-fast-pattern.h @@ -59,6 +59,8 @@ static inline int FastPatternSupportEnabledForSigMatchList(int list_id) return 0; } +void SupportFastPatternForSigMatchList(int list_id, int priority); + void SupportFastPatternForSigMatchTypes(void); void DetectFastPatternRegister(void); diff --git a/src/detect-file-data.c b/src/detect-file-data.c index 694f4d297d1d..da9a011bc7ed 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -34,6 +34,9 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-filedata-smtp.h" +#include "detect-engine-hsbd.h" + #include "flow.h" #include "flow-var.h" #include "flow-util.h" @@ -44,6 +47,9 @@ #include "util-unittest-helper.h" static int DetectFiledataSetup (DetectEngineCtx *, Signature *, char *); +static void DetectFiledataRegisterTests(void); +static void DetectFiledataSetupCallback(Signature *s); +static int g_file_data_buffer_id = 0; /** * \brief Registration function for keyword: file_data @@ -52,14 +58,32 @@ void DetectFiledataRegister(void) { sigmatch_table[DETECT_FILE_DATA].name = "file_data"; sigmatch_table[DETECT_FILE_DATA].desc = "make content keywords match on HTTP response body"; - sigmatch_table[DETECT_FILE_DATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#file_data"; + sigmatch_table[DETECT_FILE_DATA].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#file-data"; sigmatch_table[DETECT_FILE_DATA].Match = NULL; - sigmatch_table[DETECT_FILE_DATA].AppLayerMatch = NULL; - sigmatch_table[DETECT_FILE_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILE_DATA].Setup = DetectFiledataSetup; sigmatch_table[DETECT_FILE_DATA].Free = NULL; - sigmatch_table[DETECT_FILE_DATA].RegisterTests = NULL; + sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests; sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("file_data", SIG_FLAG_TOSERVER, 2, + PrefilterTxSmtpFiledataRegister); + DetectAppLayerMpmRegister("file_data", SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseBodyRegister); + + DetectAppLayerInspectEngineRegister("file_data", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpServerBody); + DetectAppLayerInspectEngineRegister("file_data", + ALPROTO_SMTP, SIG_FLAG_TOSERVER, + DetectEngineInspectSMTPFiledata); + + DetectBufferTypeRegisterSetupCallback("file_data", + DetectFiledataSetupCallback); + + DetectBufferTypeSetDescriptionByName("file_data", + "http response body or smtp attachments data"); + + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); } /** @@ -76,12 +100,283 @@ void DetectFiledataRegister(void) static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); - if ((s->init_flags & SIG_FLAG_INIT_FLOW) && (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with flow:to_server or from_client with http."); + + if (!DetectProtoContainsProto(&s->proto, IPPROTO_TCP) || + (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP && + s->alproto != ALPROTO_SMTP)) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); + return -1; + } + + if (s->alproto == ALPROTO_HTTP && (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) && + (s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with " + "flow:to_server or flow:from_client with http."); return -1; } - s->list = DETECT_SM_LIST_HSBDMATCH; + if (s->alproto == ALPROTO_SMTP && (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) && + !(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Can't use file_data with " + "flow:to_client or flow:from_server with smtp."); + return -1; + } + s->init_data->list = DetectBufferTypeGetByName("file_data"); return 0; } + +static void DetectFiledataSetupCallback(Signature *s) +{ + if (s->alproto == ALPROTO_HTTP || s->alproto == ALPROTO_UNKNOWN) { + AppLayerHtpEnableRequestBodyCallback(); + } + if (s->alproto == ALPROTO_HTTP) { + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; + } else if (s->alproto == ALPROTO_SMTP) { + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + } + + SCLogDebug("callback invoked by %u", s->id); +} + +#ifdef UNITTESTS +#include "detect-isdataat.h" + +static int DetectFiledataParseTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any " + "(msg:\"test\"; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("content is still in FILEDATA list: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +static int DetectFiledataParseTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(msg:\"test\"; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("content is still in PMATCH list: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +static int DetectFiledataParseTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any 25 " + "(msg:\"test\"; flow:to_server,established; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + printf("content is still in PMATCH list: "); + goto end; + } + + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("content not in FILEDATA list: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test the file_data fails with flow:to_server. + */ +static int DetectFiledataParseTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert smtp any any -> any any " + "(msg:\"test\"; flow:to_client,established; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result = 1; + } + +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Test the file_data fails with flow:to_server. + */ +static int DetectFiledataParseTest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, + "alert http any any -> any any " + "(msg:\"test\"; flow:to_server,established; file_data; content:\"abc\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result = 1; + } + +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +static int DetectFiledataIsdataatParseTest1(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "file_data; content:\"one\"; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists[g_file_data_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_CONTENT); + sm = sm->next; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +static int DetectFiledataIsdataatParseTest2(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "file_data; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_file_data_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif + +void DetectFiledataRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectFiledataParseTest01", DetectFiledataParseTest01); + UtRegisterTest("DetectFiledataParseTest02", DetectFiledataParseTest02); + UtRegisterTest("DetectFiledataParseTest03", DetectFiledataParseTest03); + UtRegisterTest("DetectFiledataParseTest04", DetectFiledataParseTest04); + UtRegisterTest("DetectFiledataParseTest05", DetectFiledataParseTest05); + + UtRegisterTest("DetectFiledataIsdataatParseTest1", + DetectFiledataIsdataatParseTest1); + UtRegisterTest("DetectFiledataIsdataatParseTest2", + DetectFiledataIsdataatParseTest2); +#endif +} diff --git a/src/detect-file-hash-common.c b/src/detect-file-hash-common.c new file mode 100644 index 000000000000..3e5d433d987c --- /dev/null +++ b/src/detect-file-hash-common.c @@ -0,0 +1,363 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-file-hash-common.h" + +#include "app-layer-htp.h" + +#ifdef HAVE_NSS + +/** + * \brief Read the bytes of a hash from an hexadecimal string + * + * \param hash buffer to store the resulting bytes + * \param string hexadecimal string representing the hash + * \param filename file name from where the string was read + * \param line_no file line number from where the string was read + * \param expected_len the expected length of the string that was read + * + * \retval -1 the hexadecimal string is invalid + * \retval 1 the hexadecimal string was read successfully + */ +int ReadHashString(uint8_t *hash, char *string, char *filename, int line_no, + uint16_t expected_len) +{ + if (strlen(string) != expected_len) { + SCLogError(SC_ERR_INVALID_HASH, "%s:%d hash string not %d characters", + filename, line_no, expected_len); + return -1; + } + + int i, x; + for (x = 0, i = 0; i < expected_len; i+=2, x++) { + char buf[3] = { 0, 0, 0 }; + buf[0] = string[i]; + buf[1] = string[i+1]; + + long value = strtol(buf, NULL, 16); + if (value >= 0 && value <= 255) + hash[x] = (uint8_t)value; + else { + SCLogError(SC_ERR_INVALID_HASH, "%s:%d hash byte out of range %ld", + filename, line_no, value); + return -1; + } + } + + return 1; +} + +/** + * \brief Store a hash into the hash table + * + * \param hash_table hash table that will hold the hash + * \param string hexadecimal string representing the hash + * \param filename file name from where the string was read + * \param line_no file line number from where the string was read + * \param type the hash algorithm + * + * \retval -1 failed to load the hash into the hash table + * \retval 1 successfully loaded the has into the hash table + */ +int LoadHashTable(ROHashTable *hash_table, char *string, char *filename, + int line_no, uint32_t type) +{ + /* allocate the maximum size a hash can have (in this case is SHA256, 32 bytes) */ + uint8_t hash[32]; + /* specify the actual size that should be read depending on the hash algorithm */ + uint16_t size = 32; + + if (type == DETECT_FILEMD5) { + size = 16; + } + else if (type == DETECT_FILESHA1) { + size = 20; + } + + /* every byte represented with hexadecimal digits is two characters */ + uint16_t expected_len = (size * 2); + + if (ReadHashString(hash, string, filename, line_no, expected_len) == 1) { + if (ROHashInitQueueValue(hash_table, &hash, size) != 1) + return -1; + } + + return 1; +} + +/** + * \brief Match a hash stored in a hash table + * + * \param hash_table hash table that will hold the hash + * \param hash buffer containing the bytes of the has + * \param hash_len length of the hash buffer + * + * \retval 0 didn't find the specified hash + * \retval 1 the hash matched a stored value + */ +static int HashMatchHashTable(ROHashTable *hash_table, uint8_t *hash, + size_t hash_len) +{ + void *ptr = ROHashLookup(hash_table, hash, (uint16_t)hash_len); + if (ptr == NULL) + return 0; + else + return 1; +} + +/** + * \brief Match the specified file hash + * + * \param t thread local vars + * \param det_ctx pattern matcher thread local data + * \param f *LOCKED* flow + * \param flags direction flags + * \param file file being inspected + * \param s signature being inspected + * \param m sigmatch that we will cast into DetectFileHashData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectFileHashMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) +{ + SCEnter(); + int ret = 0; + DetectFileHashData *filehash = (DetectFileHashData *)m; + + if (file->txid < det_ctx->tx_id) { + SCReturnInt(0); + } + + if (file->txid > det_ctx->tx_id) { + SCReturnInt(0); + } + + if (file->state != FILE_STATE_CLOSED) { + SCReturnInt(0); + } + + int match = -1; + + if (s->file_flags & FILE_SIG_NEED_MD5 && file->flags & FILE_MD5) { + match = HashMatchHashTable(filehash->hash, file->md5, sizeof(file->md5)); + } + else if (s->file_flags & FILE_SIG_NEED_SHA1 && file->flags & FILE_SHA1) { + match = HashMatchHashTable(filehash->hash, file->sha1, sizeof(file->sha1)); + } + else if (s->file_flags & FILE_SIG_NEED_SHA256 && file->flags & FILE_SHA256) { + match = HashMatchHashTable(filehash->hash, file->sha256, sizeof(file->sha256)); + } + + if (match == 1) { + if (filehash->negated == 0) + ret = 1; + else + ret = 0; + } + else if (match == 0) { + if (filehash->negated == 0) + ret = 0; + else + ret = 1; + } + + SCReturnInt(ret); +} + +static const char *hexcodes = "ABCDEFabcdef0123456789"; + +/** + * \brief Parse the filemd5, filesha1 or filesha256 keyword + * + * \param det_ctx pattern matcher thread local data + * \param str Pointer to the user provided option + * \param type the hash algorithm + * + * \retval hash pointer to DetectFileHashData on success + * \retval NULL on failure + */ +static DetectFileHashData *DetectFileHashParse (const DetectEngineCtx *de_ctx, + char *str, uint32_t type) +{ + DetectFileHashData *filehash = NULL; + FILE *fp = NULL; + char *filename = NULL; + + /* We have a correct hash algorithm option */ + filehash = SCMalloc(sizeof(DetectFileHashData)); + if (unlikely(filehash == NULL)) + goto error; + + memset(filehash, 0x00, sizeof(DetectFileHashData)); + + if (strlen(str) && str[0] == '!') { + filehash->negated = 1; + str++; + } + + if (type == DETECT_FILEMD5) { + filehash->hash = ROHashInit(18, 16); + } + else if (type == DETECT_FILESHA1) { + filehash->hash = ROHashInit(18, 20); + } + else if (type == DETECT_FILESHA256) { + filehash->hash = ROHashInit(18, 32); + } + + if (filehash->hash == NULL) { + goto error; + } + + /* get full filename */ + filename = DetectLoadCompleteSigPath(de_ctx, str); + if (filename == NULL) { + goto error; + } + + char line[8192] = ""; + fp = fopen(filename, "r"); + if (fp == NULL) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening hash file %s: %s", filename, strerror(errno)); + goto error; + } + + int line_no = 0; + while(fgets(line, (int)sizeof(line), fp) != NULL) { + size_t valid = 0, len = strlen(line); + line_no++; + + while (strchr(hexcodes, line[valid]) != NULL && valid++ < len); + + /* lines that do not contain sequentially any valid character are ignored */ + if (valid == 0) + continue; + + /* ignore anything after the sequence of valid characters */ + line[valid] = '\0'; + + if (LoadHashTable(filehash->hash, line, filename, line_no, type) != 1) { + goto error; + } + } + fclose(fp); + fp = NULL; + + if (ROHashInitFinalize(filehash->hash) != 1) { + goto error; + } + SCLogInfo("Hash hash table size %u bytes%s", ROHashMemorySize(filehash->hash), filehash->negated ? ", negated match" : ""); + + SCFree(filename); + return filehash; + +error: + if (filehash != NULL) + DetectFileHashFree(filehash); + if (fp != NULL) + fclose(fp); + if (filename != NULL) + SCFree(filename); + return NULL; +} + +/** + * \brief this function is used to parse filemd5, filesha1 and filesha256 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filemd5", "filesha1" or "filesha256" option + * \param type type of file hash to setup + * + * \retval 0 on Success + * \retval -1 on Failure + */ +int DetectFileHashSetup (DetectEngineCtx *de_ctx, Signature *s, char *str, + uint32_t type, int list) +{ + DetectFileHashData *filehash = NULL; + SigMatch *sm = NULL; + + filehash = DetectFileHashParse(de_ctx, str, type); + if (filehash == NULL) + goto error; + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = type; + sm->ctx = (void *)filehash; + + SigMatchAppendSMToList(s, sm, list); + + s->file_flags |= FILE_SIG_NEED_FILE; + + // Setup the file flags depending on the hashing algorithm + if (type == DETECT_FILEMD5) { + s->file_flags |= FILE_SIG_NEED_MD5; + } + if (type == DETECT_FILESHA1) { + s->file_flags |= FILE_SIG_NEED_SHA1; + } + if (type == DETECT_FILESHA256) { + s->file_flags |= FILE_SIG_NEED_SHA256; + } + return 0; + +error: + if (filehash != NULL) + DetectFileHashFree(filehash); + if (sm != NULL) + SCFree(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectFileHashData + * + * \param filehash pointer to DetectFileHashData + */ +void DetectFileHashFree(void *ptr) +{ + if (ptr != NULL) { + DetectFileHashData *filehash = (DetectFileHashData *)ptr; + if (filehash->hash != NULL) + ROHashFree(filehash->hash); + SCFree(filehash); + } +} + +#endif /* HAVE_NSS */ diff --git a/src/detect-file-hash-common.h b/src/detect-file-hash-common.h new file mode 100644 index 000000000000..68fd34dd6fd6 --- /dev/null +++ b/src/detect-file-hash-common.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + * + */ + +#ifndef __UTIL_DETECT_FILE_HASH_H__ +#define __UTIL_DETECT_FILE_HASH_H__ + +#include "util-rohash.h" + +typedef struct DetectFileHashData_ { + ROHashTable *hash; + int negated; +} DetectFileHashData; + +/* prototypes */ +int ReadHashString(uint8_t *, char *, char *, int, uint16_t); +int LoadHashTable(ROHashTable *, char *, char *, int, uint32_t); + +int DetectFileHashMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, + File *, const Signature *, const SigMatchCtx *); +int DetectFileHashSetup(DetectEngineCtx *, Signature *, char *, uint32_t, int); +void DetectFileHashFree(void *); + +#endif /* __UTIL_DETECT_FILE_HASH_H__ */ diff --git a/src/detect-fileext.c b/src/detect-fileext.c index 98b8bcb90f05..a052d97d7523 100644 --- a/src/detect-fileext.c +++ b/src/detect-fileext.c @@ -52,10 +52,11 @@ #include "detect-fileext.h" static int DetectFileextMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, Signature *, SigMatch *); + uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFileextSetup (DetectEngineCtx *, Signature *, char *); static void DetectFileextRegisterTests(void); static void DetectFileextFree(void *); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: fileext @@ -64,13 +65,14 @@ void DetectFileextRegister(void) { sigmatch_table[DETECT_FILEEXT].name = "fileext"; sigmatch_table[DETECT_FILEEXT].desc = "match on the extension of a file name"; - sigmatch_table[DETECT_FILEEXT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#fileext"; + sigmatch_table[DETECT_FILEEXT].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#fileext"; sigmatch_table[DETECT_FILEEXT].FileMatch = DetectFileextMatch; - sigmatch_table[DETECT_FILEEXT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEEXT].Setup = DetectFileextSetup; sigmatch_table[DETECT_FILEEXT].Free = DetectFileextFree; sigmatch_table[DETECT_FILEEXT].RegisterTests = DetectFileextRegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering fileext rule option"); return; } @@ -90,12 +92,12 @@ void DetectFileextRegister(void) * \retval 1 match */ static int DetectFileextMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFileextData *fileext = (DetectFileextData *)m->ctx; + DetectFileextData *fileext = (DetectFileextData *)m; if (file->name == NULL) SCReturnInt(0); @@ -209,16 +211,8 @@ static int DetectFileextSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) sm->type = DETECT_FILEEXT; sm->ctx = (void *)fileext; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + SigMatchAppendSMToList(s, sm, g_file_match_list_id); - AppLayerHtpNeedFileInspection(); - s->alproto = ALPROTO_HTTP; s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; @@ -307,8 +301,8 @@ int DetectFileextTestParse03 (void) void DetectFileextRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFileextTestParse01", DetectFileextTestParse01, 1); - UtRegisterTest("DetectFileextTestParse02", DetectFileextTestParse02, 1); - UtRegisterTest("DetectFileextTestParse03", DetectFileextTestParse03, 1); + UtRegisterTest("DetectFileextTestParse01", DetectFileextTestParse01); + UtRegisterTest("DetectFileextTestParse02", DetectFileextTestParse02); + UtRegisterTest("DetectFileextTestParse03", DetectFileextTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-filemagic.c b/src/detect-filemagic.c index 9edecd2cfc9c..34f6c6fca0ce 100644 --- a/src/detect-filemagic.c +++ b/src/detect-filemagic.c @@ -53,13 +53,34 @@ #include "detect-filemagic.h" #include "conf.h" -#include "util-magic.h" + +#ifndef HAVE_MAGIC + +static int DetectFilemagicSetupNoSupport (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCLogError(SC_ERR_NO_MAGIC_SUPPORT, "no libmagic support built in, needed for filemagic keyword"); + return -1; +} + +/** + * \brief Registration function for keyword: filemagic + */ +void DetectFilemagicRegister(void) +{ + sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; + sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; + sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; + sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetupNoSupport; +} + +#else /* HAVE_MAGIC */ static int DetectFilemagicMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, Signature *, SigMatch *); + uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilemagicRegisterTests(void); static void DetectFilemagicFree(void *); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filemagic @@ -68,13 +89,14 @@ void DetectFilemagicRegister(void) { sigmatch_table[DETECT_FILEMAGIC].name = "filemagic"; sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file"; - sigmatch_table[DETECT_FILEMAGIC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemagic"; + sigmatch_table[DETECT_FILEMAGIC].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filemagic"; sigmatch_table[DETECT_FILEMAGIC].FileMatch = DetectFilemagicMatch; - sigmatch_table[DETECT_FILEMAGIC].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup; sigmatch_table[DETECT_FILEMAGIC].Free = DetectFilemagicFree; sigmatch_table[DETECT_FILEMAGIC].RegisterTests = DetectFilemagicRegisterTests; + g_file_match_list_id = DetectBufferTypeRegister("files"); + SCLogDebug("registering filemagic rule option"); return; } @@ -91,40 +113,21 @@ void DetectFilemagicRegister(void) */ int FilemagicGlobalLookup(File *file) { - if (file == NULL || file->chunks_head == NULL) { + if (file == NULL || FileDataSize(file) == 0) { SCReturnInt(-1); } - /* initial chunk already matching our requirement */ - if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicGlobalLookup(file->chunks_head->data, FILEMAGIC_MIN_SIZE); - } else { - uint8_t *buf = SCMalloc(FILEMAGIC_MIN_SIZE); - uint32_t size = 0; - - if (likely(buf != NULL)) { - FileData *ffd = file->chunks_head; - - for ( ; ffd != NULL; ffd = ffd->next) { - uint32_t copy_len = ffd->len; - if (size + ffd->len > FILEMAGIC_MIN_SIZE) - copy_len = FILEMAGIC_MIN_SIZE - size; - - memcpy(buf + size, ffd->data, copy_len); - size += copy_len; - - if (size >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicGlobalLookup(buf, size); - break; - } - /* file is done but smaller than FILEMAGIC_MIN_SIZE */ - if (ffd->next == NULL && file->state >= FILE_STATE_CLOSED) { - file->magic = MagicGlobalLookup(buf, size); - break; - } - } - - SCFree(buf); + const uint8_t *data = NULL; + uint32_t data_len = 0; + uint64_t offset = 0; + + StreamingBufferGetData(file->sb, + &data, &data_len, &offset); + if (offset == 0) { + if (FileDataSize(file) >= FILEMAGIC_MIN_SIZE) { + file->magic = MagicGlobalLookup(data, data_len); + } else if (file->state >= FILE_STATE_CLOSED) { + file->magic = MagicGlobalLookup(data, data_len); } } @@ -141,43 +144,23 @@ int FilemagicGlobalLookup(File *file) */ int FilemagicThreadLookup(magic_t *ctx, File *file) { - if (ctx == NULL || file == NULL || file->chunks_head == NULL) { + if (ctx == NULL || file == NULL || FileDataSize(file) == 0) { SCReturnInt(-1); } - /* initial chunk already matching our requirement */ - if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicThreadLookup(ctx, file->chunks_head->data, FILEMAGIC_MIN_SIZE); - } else { - uint8_t *buf = SCMalloc(FILEMAGIC_MIN_SIZE); - uint32_t size = 0; - - if (likely(buf != NULL)) { - FileData *ffd = file->chunks_head; - - for ( ; ffd != NULL; ffd = ffd->next) { - uint32_t copy_len = ffd->len; - if (size + ffd->len > FILEMAGIC_MIN_SIZE) - copy_len = FILEMAGIC_MIN_SIZE - size; - - memcpy(buf + size, ffd->data, copy_len); - size += copy_len; - - if (size >= FILEMAGIC_MIN_SIZE) { - file->magic = MagicThreadLookup(ctx, buf, size); - break; - } - /* file is done but smaller than FILEMAGIC_MIN_SIZE */ - if (ffd->next == NULL && file->state >= FILE_STATE_CLOSED) { - file->magic = MagicThreadLookup(ctx, buf, size); - break; - } - } - - SCFree(buf); + const uint8_t *data = NULL; + uint32_t data_len = 0; + uint64_t offset = 0; + + StreamingBufferGetData(file->sb, + &data, &data_len, &offset); + if (offset == 0) { + if (FileDataSize(file) >= FILEMAGIC_MIN_SIZE) { + file->magic = MagicThreadLookup(ctx, data, data_len); + } else if (file->state >= FILE_STATE_CLOSED) { + file->magic = MagicThreadLookup(ctx, data, data_len); } } - SCReturnInt(0); } @@ -196,11 +179,11 @@ int FilemagicThreadLookup(magic_t *ctx, File *file) * \retval 1 match */ static int DetectFilemagicMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFilemagicData *filemagic = (DetectFilemagicData *)m->ctx; + DetectFilemagicData *filemagic = (DetectFilemagicData *)m; if (file->txid < det_ctx->tx_id) SCReturnInt(0); @@ -322,13 +305,20 @@ static void *DetectFilemagicThreadInit(void *data) (void)ConfGet("magic-file", &filename); if (filename != NULL) { - SCLogInfo("using magic-file %s", filename); + if (strlen(filename) == 0) { + /* set filename to NULL on *nix systems so magic_load uses system default path (see man libmagic) */ + SCLogInfo("using system default magic-file"); + filename = NULL; + } + else { + SCLogInfo("using magic-file %s", filename); - if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); - goto error; + if ( (fd = fopen(filename, "r")) == NULL) { + SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); + goto error; + } + fclose(fd); } - fclose(fd); } if (magic_load(t->ctx, filename) != 0) { @@ -390,17 +380,7 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st sm->type = DETECT_FILEMAGIC; sm->ctx = (void *)filemagic; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - AppLayerHtpNeedFileInspection(); - - /** \todo remove this once we support more than http */ - s->alproto = ALPROTO_HTTP; + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC); return 0; @@ -492,8 +472,11 @@ int DetectFilemagicTestParse03 (void) void DetectFilemagicRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFilemagicTestParse01", DetectFilemagicTestParse01, 1); - UtRegisterTest("DetectFilemagicTestParse02", DetectFilemagicTestParse02, 1); - UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03, 1); + UtRegisterTest("DetectFilemagicTestParse01", DetectFilemagicTestParse01); + UtRegisterTest("DetectFilemagicTestParse02", DetectFilemagicTestParse02); + UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03); #endif /* UNITTESTS */ } + +#endif /* HAVE_MAGIC */ + diff --git a/src/detect-filemagic.h b/src/detect-filemagic.h index 97cd79543fb5..e36dfcbcfe8d 100644 --- a/src/detect-filemagic.h +++ b/src/detect-filemagic.h @@ -24,8 +24,8 @@ #ifndef __DETECT_FILEMAGIC_H__ #define __DETECT_FILEMAGIC_H__ +#ifdef HAVE_MAGIC #include "util-spm-bm.h" -#include typedef struct DetectFilemagicThreadData { magic_t ctx; @@ -40,7 +40,8 @@ typedef struct DetectFilemagicData { } DetectFilemagicData; /* prototypes */ -void DetectFilemagicRegister (void); int FilemagicGlobalLookup(File *file); +#endif +void DetectFilemagicRegister (void); #endif /* __DETECT_FILEMAGIC_H__ */ diff --git a/src/detect-filemd5.c b/src/detect-filemd5.c index a81ba25d6d5b..29320832fc3c 100644 --- a/src/detect-filemd5.c +++ b/src/detect-filemd5.c @@ -23,37 +23,14 @@ */ #include "suricata-common.h" -#include "threads.h" -#include "debug.h" -#include "decode.h" - -#include "detect.h" -#include "detect-parse.h" #include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "detect-engine-state.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-spm-bm.h" -#include "util-print.h" - +#include "detect-file-hash-common.h" #include "util-unittest.h" #include "util-unittest-helper.h" -#include "app-layer.h" - -#include "stream-tcp.h" - #include "detect-filemd5.h" -#include "queue.h" -#include "util-rohash.h" - #ifndef HAVE_NSS static int DetectFileMd5SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) @@ -69,23 +46,21 @@ void DetectFileMd5Register(void) { sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].FileMatch = NULL; - sigmatch_table[DETECT_FILEMD5].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5SetupNoSupport; sigmatch_table[DETECT_FILEMD5].Free = NULL; sigmatch_table[DETECT_FILEMD5].RegisterTests = NULL; sigmatch_table[DETECT_FILEMD5].flags = SIGMATCH_NOT_BUILT; - SCLogDebug("registering filemd5 rule option"); + SCLogDebug("registering filemd5 rule option"); return; } #else /* HAVE_NSS */ -static int DetectFileMd5Match (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, Signature *, SigMatch *); +static int g_file_match_list_id = 0; + static int DetectFileMd5Setup (DetectEngineCtx *, Signature *, char *); static void DetectFileMd5RegisterTests(void); -static void DetectFileMd5Free(void *); /** * \brief Registration function for keyword: filemd5 @@ -94,203 +69,16 @@ void DetectFileMd5Register(void) { sigmatch_table[DETECT_FILEMD5].name = "filemd5"; sigmatch_table[DETECT_FILEMD5].desc = "match file MD5 against list of MD5 checksums"; - sigmatch_table[DETECT_FILEMD5].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filemd5"; - sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileMd5Match; - sigmatch_table[DETECT_FILEMD5].alproto = ALPROTO_HTTP; + sigmatch_table[DETECT_FILEMD5].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filemd5"; + sigmatch_table[DETECT_FILEMD5].FileMatch = DetectFileHashMatch; sigmatch_table[DETECT_FILEMD5].Setup = DetectFileMd5Setup; - sigmatch_table[DETECT_FILEMD5].Free = DetectFileMd5Free; + sigmatch_table[DETECT_FILEMD5].Free = DetectFileHashFree; sigmatch_table[DETECT_FILEMD5].RegisterTests = DetectFileMd5RegisterTests; - SCLogDebug("registering filemd5 rule option"); - return; -} - -static int Md5ReadString(uint8_t *md5, char *str, char *filename, int line_no) -{ - if (strlen(str) != 32) { - SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 string not 32 bytes", - filename, line_no); - return -1; - } - - int i, x; - for (x = 0, i = 0; i < 32; i+=2, x++) { - char buf[3] = { 0, 0, 0}; - buf[0] = str[i]; - buf[1] = str[i+1]; - - long value = strtol(buf, NULL, 16); - if (value >= 0 && value <= 255) - md5[x] = (uint8_t)value; - else { - SCLogError(SC_ERR_INVALID_MD5, "%s:%d md5 byte out of range %ld", - filename, line_no, value); - return -1; - } - } - - return 1; -} - -static int MD5LoadHash(ROHashTable *hash, char *string, char *filename, int line_no) -{ - uint8_t md5[16]; - - if (Md5ReadString(md5, string, filename, line_no) == 1) { - if (ROHashInitQueueValue(hash, &md5, (uint16_t)sizeof(md5)) != 1) - return -1; - } - - return 1; -} - -static int MD5MatchLookupBuffer(ROHashTable *hash, uint8_t *buf, size_t buflen) -{ - void *ptr = ROHashLookup(hash, buf, (uint16_t)buflen); - if (ptr == NULL) - return 0; - else - return 1; -} - -/** - * \brief match the specified filemd5 - * - * \param t thread local vars - * \param det_ctx pattern matcher thread local data - * \param f *LOCKED* flow - * \param flags direction flags - * \param file file being inspected - * \param s signature being inspected - * \param m sigmatch that we will cast into DetectFileMd5Data - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectFileMd5Match (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) -{ - SCEnter(); - int ret = 0; - DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)m->ctx; - - if (file->txid < det_ctx->tx_id) { - SCReturnInt(0); - } - - if (file->txid > det_ctx->tx_id) { - SCReturnInt(0); - } - - if (file->state != FILE_STATE_CLOSED) { - SCReturnInt(0); - } - - if (file->flags & FILE_MD5) { - if (MD5MatchLookupBuffer(filemd5->hash, file->md5, sizeof(file->md5)) == 1) { - if (filemd5->negated == 0) - ret = 1; - else - ret = 0; - } else { - if (filemd5->negated == 0) - ret = 0; - else - ret = 1; - } - } - - SCReturnInt(ret); -} + g_file_match_list_id = DetectBufferTypeRegister("files"); -/** - * \brief Parse the filemd5 keyword - * - * \param idstr Pointer to the user provided option - * - * \retval filemd5 pointer to DetectFileMd5Data on success - * \retval NULL on failure - */ -static DetectFileMd5Data *DetectFileMd5Parse (char *str) -{ - DetectFileMd5Data *filemd5 = NULL; - FILE *fp = NULL; - char *filename = NULL; - - /* We have a correct filemd5 option */ - filemd5 = SCMalloc(sizeof(DetectFileMd5Data)); - if (unlikely(filemd5 == NULL)) - goto error; - - memset(filemd5, 0x00, sizeof(DetectFileMd5Data)); - - if (strlen(str) && str[0] == '!') { - filemd5->negated = 1; - str++; - } - - filemd5->hash = ROHashInit(18, 16); - if (filemd5->hash == NULL) { - goto error; - } - - /* get full filename */ - filename = DetectLoadCompleteSigPath(str); - if (filename == NULL) { - goto error; - } - - char line[8192] = ""; - fp = fopen(filename, "r"); - if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening md5 file %s: %s", filename, strerror(errno)); - goto error; - } - - int line_no = 0; - while(fgets(line, (int)sizeof(line), fp) != NULL) { - size_t len = strlen(line); - line_no++; - - /* ignore comments and empty lines */ - if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t') - continue; - - while (isspace(line[--len])); - - /* Check if we have a trailing newline, and remove it */ - len = strlen(line); - if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { - line[len - 1] = '\0'; - } - - /* cut off longer lines */ - if (strlen(line) > 32) - line[32] = 0x00; - - if (MD5LoadHash(filemd5->hash, line, filename, line_no) != 1) { - goto error; - } - } - fclose(fp); - fp = NULL; - - if (ROHashInitFinalize(filemd5->hash) != 1) { - goto error; - } - SCLogInfo("MD5 hash size %u bytes%s", ROHashMemorySize(filemd5->hash), filemd5->negated ? ", negated match" : ""); - - SCFree(filename); - return filemd5; - -error: - if (filemd5 != NULL) - DetectFileMd5Free(filemd5); - if (fp != NULL) - fclose(fp); - if (filename != NULL) - SCFree(filename); - return NULL; + SCLogDebug("registering filemd5 rule option"); + return; } /** @@ -306,65 +94,14 @@ static DetectFileMd5Data *DetectFileMd5Parse (char *str) */ static int DetectFileMd5Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - DetectFileMd5Data *filemd5 = NULL; - SigMatch *sm = NULL; - - filemd5 = DetectFileMd5Parse(str); - if (filemd5 == NULL) - goto error; - - /* Okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - sm = SigMatchAlloc(); - if (sm == NULL) - goto error; - - sm->type = DETECT_FILEMD5; - sm->ctx = (void *)filemd5; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - AppLayerHtpNeedFileInspection(); - - /** \todo remove this once we support more than http */ - s->alproto = ALPROTO_HTTP; - - s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MD5); - return 0; - -error: - if (filemd5 != NULL) - DetectFileMd5Free(filemd5); - if (sm != NULL) - SCFree(sm); - return -1; -} - -/** - * \brief this function will free memory associated with DetectFileMd5Data - * - * \param filemd5 pointer to DetectFileMd5Data - */ -static void DetectFileMd5Free(void *ptr) -{ - if (ptr != NULL) { - DetectFileMd5Data *filemd5 = (DetectFileMd5Data *)ptr; - if (filemd5->hash != NULL) - ROHashFree(filemd5->hash); - SCFree(filemd5); - } + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILEMD5, g_file_match_list_id); } #ifdef UNITTESTS static int MD5MatchLookupString(ROHashTable *hash, char *string) { uint8_t md5[16]; - if (Md5ReadString(md5, string, "file", 88) == 1) { + if (ReadHashString(md5, string, "file", 88, 32) == 1) { void *ptr = ROHashLookup(hash, &md5, (uint16_t)sizeof(md5)); if (ptr == NULL) return 0; @@ -380,17 +117,17 @@ static int MD5MatchTest01(void) if (hash == NULL) { return 0; } - if (MD5LoadHash(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1) != 1) + if (LoadHashTable(hash, "d80f93a93dc5f3ee945704754d6e0a36", "file", 1, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2) != 1) + if (LoadHashTable(hash, "92a49985b384f0d993a36e4c2d45e206", "file", 2, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3) != 1) + if (LoadHashTable(hash, "11adeaacc8c309815f7bc3e33888f281", "file", 3, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4) != 1) + if (LoadHashTable(hash, "22e10a8fe02344ade0bea8836a1714af", "file", 4, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5) != 1) + if (LoadHashTable(hash, "c3db2cbf02c68f073afcaee5634677bc", "file", 5, DETECT_FILEMD5) != 1) return 0; - if (MD5LoadHash(hash, "7ed095da259638f42402fb9e74287a17", "file", 6) != 1) + if (LoadHashTable(hash, "7ed095da259638f42402fb9e74287a17", "file", 6, DETECT_FILEMD5) != 1) return 0; if (ROHashInitFinalize(hash) != 1) { @@ -409,7 +146,7 @@ static int MD5MatchTest01(void) return 0; if (MD5MatchLookupString(hash, "7ed095da259638f42402fb9e74287a17") != 1) return 0; - /* shouldnt match */ + /* shouldn't match */ if (MD5MatchLookupString(hash, "33333333333333333333333333333333") == 1) return 0; @@ -421,7 +158,7 @@ static int MD5MatchTest01(void) void DetectFileMd5RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MD5MatchTest01", MD5MatchTest01, 1); + UtRegisterTest("MD5MatchTest01", MD5MatchTest01); #endif } diff --git a/src/detect-filemd5.h b/src/detect-filemd5.h index 486812f7c625..0905fc4ce02b 100644 --- a/src/detect-filemd5.h +++ b/src/detect-filemd5.h @@ -24,13 +24,6 @@ #ifndef __DETECT_FILEMD5_H__ #define __DETECT_FILEMD5_H__ -#include "util-rohash.h" - -typedef struct DetectFileMd5Data { - ROHashTable *hash; - int negated; -} DetectFileMd5Data; - /* prototypes */ void DetectFileMd5Register (void); diff --git a/src/detect-filename.c b/src/detect-filename.c index c8cea7f3590f..fcfff9b3997f 100644 --- a/src/detect-filename.c +++ b/src/detect-filename.c @@ -34,6 +34,7 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-file.h" #include "flow.h" #include "flow-var.h" @@ -49,12 +50,14 @@ #include "stream-tcp.h" #include "detect-filename.h" +#include "app-layer-parser.h" static int DetectFilenameMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, File *, Signature *, SigMatch *); + uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilenameSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilenameRegisterTests(void); static void DetectFilenameFree(void *); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filename @@ -63,13 +66,25 @@ void DetectFilenameRegister(void) { sigmatch_table[DETECT_FILENAME].name = "filename"; sigmatch_table[DETECT_FILENAME].desc = "match on the file name"; - sigmatch_table[DETECT_FILENAME].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filename"; + sigmatch_table[DETECT_FILENAME].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filename"; sigmatch_table[DETECT_FILENAME].FileMatch = DetectFilenameMatch; - sigmatch_table[DETECT_FILENAME].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILENAME].Setup = DetectFilenameSetup; sigmatch_table[DETECT_FILENAME].Free = DetectFilenameFree; sigmatch_table[DETECT_FILENAME].RegisterTests = DetectFilenameRegisterTests; + DetectAppLayerInspectEngineRegister("files", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectFileInspectHttp); + DetectAppLayerInspectEngineRegister("files", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectFileInspectHttp); + + DetectAppLayerInspectEngineRegister("files", + ALPROTO_SMTP, SIG_FLAG_TOSERVER, + DetectFileInspectSmtp); + + g_file_match_list_id = DetectBufferTypeGetByName("files"); + SCLogDebug("registering filename rule option"); return; } @@ -89,12 +104,12 @@ void DetectFilenameRegister(void) * \retval 1 match */ static int DetectFilenameMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, File *file, Signature *s, SigMatch *m) + Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); int ret = 0; - DetectFilenameData *filename = m->ctx; + DetectFilenameData *filename = (DetectFilenameData *)m; if (file->name == NULL) SCReturnInt(0); @@ -213,16 +228,7 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, char *str sm->type = DETECT_FILENAME; sm->ctx = (void *)filename; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - AppLayerHtpNeedFileInspection(); - - s->alproto = ALPROTO_HTTP; + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_FILENAME); return 0; @@ -314,8 +320,8 @@ int DetectFilenameTestParse03 (void) void DetectFilenameRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFilenameTestParse01", DetectFilenameTestParse01, 1); - UtRegisterTest("DetectFilenameTestParse02", DetectFilenameTestParse02, 1); - UtRegisterTest("DetectFilenameTestParse03", DetectFilenameTestParse03, 1); + UtRegisterTest("DetectFilenameTestParse01", DetectFilenameTestParse01); + UtRegisterTest("DetectFilenameTestParse02", DetectFilenameTestParse02); + UtRegisterTest("DetectFilenameTestParse03", DetectFilenameTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-filesha1.c b/src/detect-filesha1.c new file mode 100644 index 000000000000..84fd68929642 --- /dev/null +++ b/src/detect-filesha1.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "detect-engine.h" +#include "detect-file-hash-common.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect-filesha1.h" + +#ifndef HAVE_NSS + +static int DetectFileSha1SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) +{ + SCLogError(SC_ERR_NO_SHA1_SUPPORT, "no SHA-1 calculation support built in, needed for filesha1 keyword"); + return -1; +} + +/** + * \brief Registration function for keyword: filesha1 + */ +void DetectFileSha1Register(void) +{ + sigmatch_table[DETECT_FILESHA1].name = "filesha1"; + sigmatch_table[DETECT_FILESHA1].FileMatch = NULL; + sigmatch_table[DETECT_FILESHA1].Setup = DetectFileSha1SetupNoSupport; + sigmatch_table[DETECT_FILESHA1].Free = NULL; + sigmatch_table[DETECT_FILESHA1].RegisterTests = NULL; + sigmatch_table[DETECT_FILESHA1].flags = SIGMATCH_NOT_BUILT; + + SCLogDebug("registering filesha1 rule option"); + return; +} + +#else /* HAVE_NSS */ + +static int DetectFileSha1Setup (DetectEngineCtx *, Signature *, char *); +static void DetectFileSha1RegisterTests(void); +static int g_file_match_list_id = 0; + +/** + * \brief Registration function for keyword: filesha1 + */ +void DetectFileSha1Register(void) +{ + sigmatch_table[DETECT_FILESHA1].name = "filesha1"; + sigmatch_table[DETECT_FILESHA1].desc = "match file SHA-1 against list of SHA-1 checksums"; + sigmatch_table[DETECT_FILESHA1].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filesha1"; + sigmatch_table[DETECT_FILESHA1].FileMatch = DetectFileHashMatch; + sigmatch_table[DETECT_FILESHA1].Setup = DetectFileSha1Setup; + sigmatch_table[DETECT_FILESHA1].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILESHA1].RegisterTests = DetectFileSha1RegisterTests; + + g_file_match_list_id = DetectBufferTypeRegister("files"); + + SCLogDebug("registering filesha1 rule option"); + return; +} + +/** + * \brief this function is used to parse filesha1 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filesha1" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectFileSha1Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA1, g_file_match_list_id); +} + +#ifdef UNITTESTS +static int SHA1MatchLookupString(ROHashTable *hash, char *string) +{ + uint8_t sha1[20]; + if (ReadHashString(sha1, string, "file", 88, 40) == 1) { + void *ptr = ROHashLookup(hash, &sha1, (uint16_t)sizeof(sha1)); + if (ptr == NULL) + return 0; + else + return 1; + } + return 0; +} + +static int SHA1MatchTest01(void) +{ + ROHashTable *hash = ROHashInit(4, 20); + if (hash == NULL) { + return 0; + } + if (LoadHashTable(hash, "447661c5de965bd4d837b50244467e37bddc184d", "file", 1, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "75a9af1e34dc0bb2f7fcde9d56b2503072ac35dd", "file", 2, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "53224a297bbb30631670fdcd2d295d87a1d328e9", "file", 3, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "3395856ce81f2b7382dee72602f798b642f14140", "file", 4, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "65559245709fe98052eb284577f1fd61c01ad20d", "file", 5, DETECT_FILESHA1) != 1) + return 0; + if (LoadHashTable(hash, "0931fd4e05e6ea81c75f8488ecc1db9e66f22cbb", "file", 6, DETECT_FILESHA1) != 1) + return 0; + + if (ROHashInitFinalize(hash) != 1) { + return 0; + } + + if (SHA1MatchLookupString(hash, "447661c5de965bd4d837b50244467e37bddc184d") != 1) + return 0; + if (SHA1MatchLookupString(hash, "75a9af1e34dc0bb2f7fcde9d56b2503072ac35dd") != 1) + return 0; + if (SHA1MatchLookupString(hash, "53224a297bbb30631670fdcd2d295d87a1d328e9") != 1) + return 0; + if (SHA1MatchLookupString(hash, "3395856ce81f2b7382dee72602f798b642f14140") != 1) + return 0; + if (SHA1MatchLookupString(hash, "65559245709fe98052eb284577f1fd61c01ad20d") != 1) + return 0; + if (SHA1MatchLookupString(hash, "0931fd4e05e6ea81c75f8488ecc1db9e66f22cbb") != 1) + return 0; + /* Shouldn't match */ + if (SHA1MatchLookupString(hash, "3333333333333333333333333333333333333333") == 1) + return 0; + + ROHashFree(hash); + return 1; +} +#endif + +void DetectFileSha1RegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SHA1MatchTest01", SHA1MatchTest01); +#endif +} + +#endif /* HAVE_NSS */ diff --git a/src/detect-filesha1.h b/src/detect-filesha1.h new file mode 100644 index 000000000000..d7504344c606 --- /dev/null +++ b/src/detect-filesha1.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + */ + +#ifndef __DETECT_FILESHA1_H__ +#define __DETECT_FILESHA1_H__ + +/* prototypes */ +void DetectFileSha1Register (void); + +#endif /* __DETECT_FILESHA1_H__ */ diff --git a/src/detect-filesha256.c b/src/detect-filesha256.c new file mode 100644 index 000000000000..59f06d2f7878 --- /dev/null +++ b/src/detect-filesha256.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + * + */ + +#include "suricata-common.h" + +#include "detect-engine.h" +#include "detect-file-hash-common.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect-filesha256.h" + +#ifndef HAVE_NSS + +static int DetectFileSha256SetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) +{ + SCLogError(SC_ERR_NO_SHA256_SUPPORT, "no SHA-256 calculation support built in, needed for filesha256 keyword"); + return -1; +} + +/** + * \brief Registration function for keyword: filesha256 + */ +void DetectFileSha256Register(void) +{ + sigmatch_table[DETECT_FILESHA256].name = "filesha256"; + sigmatch_table[DETECT_FILESHA256].FileMatch = NULL; + sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256SetupNoSupport; + sigmatch_table[DETECT_FILESHA256].Free = NULL; + sigmatch_table[DETECT_FILESHA256].RegisterTests = NULL; + sigmatch_table[DETECT_FILESHA256].flags = SIGMATCH_NOT_BUILT; + + SCLogDebug("registering filesha256 rule option"); + return; +} + +#else /* HAVE_NSS */ + +static int DetectFileSha256Setup (DetectEngineCtx *, Signature *, char *); +static void DetectFileSha256RegisterTests(void); +static int g_file_match_list_id = 0; + +/** + * \brief Registration function for keyword: filesha256 + */ +void DetectFileSha256Register(void) +{ + sigmatch_table[DETECT_FILESHA256].name = "filesha256"; + sigmatch_table[DETECT_FILESHA256].desc = "match file SHA-256 against list of SHA-256 checksums"; + sigmatch_table[DETECT_FILESHA256].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filesha256"; + sigmatch_table[DETECT_FILESHA256].FileMatch = DetectFileHashMatch; + sigmatch_table[DETECT_FILESHA256].Setup = DetectFileSha256Setup; + sigmatch_table[DETECT_FILESHA256].Free = DetectFileHashFree; + sigmatch_table[DETECT_FILESHA256].RegisterTests = DetectFileSha256RegisterTests; + + g_file_match_list_id = DetectBufferTypeRegister("files"); + + SCLogDebug("registering filesha256 rule option"); + return; +} + +/** + * \brief this function is used to parse filesha256 options + * \brief into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param str pointer to the user provided "filesha256" option + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectFileSha256Setup (DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + return DetectFileHashSetup(de_ctx, s, str, DETECT_FILESHA256, g_file_match_list_id); +} + +#ifdef UNITTESTS +static int SHA256MatchLookupString(ROHashTable *hash, char *string) +{ + uint8_t sha256[32]; + if (ReadHashString(sha256, string, "file", 88, 64) == 1) { + void *ptr = ROHashLookup(hash, &sha256, (uint16_t)sizeof(sha256)); + if (ptr == NULL) + return 0; + else + return 1; + } + return 0; +} + +static int SHA256MatchTest01(void) +{ + ROHashTable *hash = ROHashInit(4, 32); + if (hash == NULL) { + return 0; + } + if (LoadHashTable(hash, "9c891edb5da763398969b6aaa86a5d46971bd28a455b20c2067cb512c9f9a0f8", "file", 1, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "6eee51705f34b6cfc7f0c872a7949ec3e3172a908303baf5d67d03b98f70e7e3", "file", 2, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "b12c7d57507286bbbe36d7acf9b34c22c96606ffd904e3c23008399a4a50c047", "file", 3, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "ca496e1ddadc290050339dd75ce8830ad3028ce1556a5368874a4aec3aee114b", "file", 4, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f", "file", 5, DETECT_FILESHA256) != 1) + return 0; + if (LoadHashTable(hash, "d765e722e295969c0a5c2d90f549db8b89ab617900bf4698db41c7cdad993bb9", "file", 6, DETECT_FILESHA256) != 1) + return 0; + + if (ROHashInitFinalize(hash) != 1) { + return 0; + } + + if (SHA256MatchLookupString(hash, "9c891edb5da763398969b6aaa86a5d46971bd28a455b20c2067cb512c9f9a0f8") != 1) + return 0; + if (SHA256MatchLookupString(hash, "6eee51705f34b6cfc7f0c872a7949ec3e3172a908303baf5d67d03b98f70e7e3") != 1) + return 0; + if (SHA256MatchLookupString(hash, "b12c7d57507286bbbe36d7acf9b34c22c96606ffd904e3c23008399a4a50c047") != 1) + return 0; + if (SHA256MatchLookupString(hash, "ca496e1ddadc290050339dd75ce8830ad3028ce1556a5368874a4aec3aee114b") != 1) + return 0; + if (SHA256MatchLookupString(hash, "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f") != 1) + return 0; + if (SHA256MatchLookupString(hash, "d765e722e295969c0a5c2d90f549db8b89ab617900bf4698db41c7cdad993bb9") != 1) + return 0; + /* Shouldn't match */ + if (SHA256MatchLookupString(hash, "3333333333333333333333333333333333333333333333333333333333333333") == 1) + return 0; + + ROHashFree(hash); + return 1; +} +#endif + +void DetectFileSha256RegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SHA256MatchTest01", SHA256MatchTest01); +#endif +} + +#endif /* HAVE_NSS */ diff --git a/src/detect-filesha256.h b/src/detect-filesha256.h new file mode 100644 index 000000000000..a205b48699a0 --- /dev/null +++ b/src/detect-filesha256.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Duarte Silva + */ + +#ifndef __DETECT_FILESHA256_H__ +#define __DETECT_FILESHA256_H__ + +/* prototypes */ +void DetectFileSha256Register (void); + +#endif /* __DETECT_FILESHA256_H__ */ diff --git a/src/detect-filesize.c b/src/detect-filesize.c index d8c49bcf7888..151579f27b92 100644 --- a/src/detect-filesize.c +++ b/src/detect-filesize.c @@ -31,6 +31,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-engine-state.h" #include "detect-filesize.h" @@ -49,10 +50,11 @@ static pcre_extra *parse_regex_study; /*prototypes*/ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, Signature *s, SigMatch *m); + uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m); static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilesizeFree (void *); static void DetectFilesizeRegisterTests (void); +static int g_file_match_list_id = 0; /** * \brief Registration function for filesize: keyword @@ -62,38 +64,15 @@ void DetectFilesizeRegister(void) { sigmatch_table[DETECT_FILESIZE].name = "filesize"; sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; - sigmatch_table[DETECT_FILESIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filesize"; - sigmatch_table[DETECT_FILESIZE].alproto = ALPROTO_HTTP; + sigmatch_table[DETECT_FILESIZE].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filesize"; sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests; - sigmatch_table[DETECT_FILESIZE].flags |= SIGMATCH_PAYLOAD; /** XXX necessary? */ - - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); -error: - if (parse_regex != NULL) - SCFree(parse_regex); - if (parse_regex_study != NULL) - SCFree(parse_regex_study); - return; + g_file_match_list_id = DetectBufferTypeRegister("files"); } /** @@ -111,36 +90,38 @@ void DetectFilesizeRegister(void) * \retval 1 match */ static int DetectFilesizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, Signature *s, SigMatch *m) + uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectFilesizeData *fsd = m->ctx; + DetectFilesizeData *fsd = (DetectFilesizeData *)m; int ret = 0; - SCLogDebug("file size %"PRIu64", check %"PRIu64, file->size, fsd->size1); + uint64_t file_size = FileTrackedSize(file); + + SCLogDebug("file size %"PRIu64", check %"PRIu64, file_size, fsd->size1); if (file->state == FILE_STATE_CLOSED) { switch (fsd->mode) { case DETECT_FILESIZE_EQ: - if (file->size == fsd->size1) + if (file_size == fsd->size1) ret = 1; break; case DETECT_FILESIZE_LT: - if (file->size < fsd->size1) + if (file_size < fsd->size1) ret = 1; break; case DETECT_FILESIZE_GT: - if (file->size > fsd->size1) + if (file_size > fsd->size1) ret = 1; break; case DETECT_FILESIZE_RA: - if (file->size > fsd->size1 && file->size < fsd->size2) + if (file_size > fsd->size1 && file_size < fsd->size2) ret = 1; break; } /* truncated, error: only see if what we have meets the GT condition */ } else if (file->state > FILE_STATE_CLOSED) { - if (fsd->mode == DETECT_FILESIZE_GT && file->size > fsd->size1) + if (fsd->mode == DETECT_FILESIZE_GT && file_size > fsd->size1) ret = 1; } SCReturnInt(ret); @@ -306,19 +287,9 @@ static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *str goto error; sm->type = DETECT_FILESIZE; - sm->ctx = (void *)fsd; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - AppLayerHtpNeedFileInspection(); + sm->ctx = (SigMatchCtx *)fsd; - /** \todo remove this once we support more than http */ - s->alproto = ALPROTO_HTTP; + SigMatchAppendSMToList(s, sm, g_file_match_list_id); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); SCReturnInt(0); @@ -343,11 +314,9 @@ static void DetectFilesizeFree(void *ptr) } #ifdef UNITTESTS - #include "stream.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "app-layer-parser.h" @@ -523,11 +492,11 @@ static int DetectFilesizeSetpTest01(void) void DetectFilesizeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01, 1); - UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02, 1); - UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03, 1); - UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04, 1); - UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05, 1); - UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01, 1); + UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01); + UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02); + UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03); + UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04); + UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05); + UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-filestore.c b/src/detect-filestore.c index f9bfdf55c25b..d64b9b44d881 100644 --- a/src/detect-filestore.c +++ b/src/detect-filestore.c @@ -60,9 +60,11 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectFilestoreMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t, File *, Signature *, SigMatch *); + Flow *, uint8_t, File *, const Signature *, const SigMatchCtx *); static int DetectFilestoreSetup (DetectEngineCtx *, Signature *, char *); static void DetectFilestoreFree(void *); +static void DetectFilestoreRegisterTests(void); +static int g_file_match_list_id = 0; /** * \brief Registration function for keyword: filestore @@ -71,42 +73,22 @@ void DetectFilestoreRegister(void) { sigmatch_table[DETECT_FILESTORE].name = "filestore"; sigmatch_table[DETECT_FILESTORE].desc = "stores files to disk if the rule matched"; - sigmatch_table[DETECT_FILESTORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/File-keywords#filestore"; + sigmatch_table[DETECT_FILESTORE].url = DOC_URL DOC_VERSION "/rules/file-keywords.html#filestore"; sigmatch_table[DETECT_FILESTORE].FileMatch = DetectFilestoreMatch; - sigmatch_table[DETECT_FILESTORE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_FILESTORE].Setup = DetectFilestoreSetup; sigmatch_table[DETECT_FILESTORE].Free = DetectFilestoreFree; - sigmatch_table[DETECT_FILESTORE].RegisterTests = NULL; + sigmatch_table[DETECT_FILESTORE].RegisterTests = DetectFilestoreRegisterTests; sigmatch_table[DETECT_FILESTORE].flags = SIGMATCH_OPTIONAL_OPT; - const char *eb; - int eo; - int opts = 0; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - SCLogDebug("registering filestore rule option"); - return; -error: - /* XXX */ - return; + g_file_match_list_id = DetectBufferTypeRegister("files"); } /** * \brief apply the post match filestore with options */ -static int FilestorePostMatchWithOptions(Packet *p, Flow *f, DetectFilestoreData *filestore, FileContainer *fc, +static int FilestorePostMatchWithOptions(Packet *p, Flow *f, const DetectFilestoreData *filestore, FileContainer *fc, uint16_t file_id, uint16_t tx_id) { if (filestore == NULL) { @@ -201,7 +183,7 @@ static int FilestorePostMatchWithOptions(Packet *p, Flow *f, DetectFilestoreData * When we are sure all parts of the signature matched, we run this function * to finalize the filestore. */ -int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s) +int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s) { uint8_t flags = 0; @@ -211,7 +193,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack SCReturnInt(0); } - if (s->filestore_sm == NULL || p->flow == NULL) { + if ((s->filestore_ctx == NULL && !(s->flags & SIG_FLAG_FILESTORE)) || p->flow == NULL) { #ifndef DEBUG SCReturnInt(0); #else @@ -219,33 +201,33 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack #endif } + /* set filestore depth for stream reassembling */ + TcpSession *ssn = (TcpSession *)p->flow->protoctx; + TcpSessionSetReassemblyDepth(ssn, FileReassemblyDepth()); + if (p->flowflags & FLOW_PKT_TOCLIENT) flags |= STREAM_TOCLIENT; else flags |= STREAM_TOSERVER; - FLOWLOCK_WRLOCK(p->flow); - FileContainer *ffc = AppLayerParserGetFiles(p->flow->proto, p->flow->alproto, p->flow->alstate, flags); /* filestore for single files only */ - if (s->filestore_sm->ctx == NULL) { + if (s->filestore_ctx == NULL) { uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { FileStoreFileById(ffc, det_ctx->filestore[u].file_id); } } else { - DetectFilestoreData *filestore = s->filestore_sm->ctx; uint16_t u; for (u = 0; u < det_ctx->filestore_cnt; u++) { - FilestorePostMatchWithOptions(p, p->flow, filestore, ffc, + FilestorePostMatchWithOptions(p, p->flow, s->filestore_ctx, ffc, det_ctx->filestore[u].file_id, det_ctx->filestore[u].tx_id); } } - FLOWLOCK_UNLOCK(p->flow); SCReturnInt(0); } @@ -267,7 +249,7 @@ int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack * needs to be put behind a api. */ static int DetectFilestoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, File *file, Signature *s, SigMatch *m) + uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) { uint16_t file_id = 0; @@ -316,6 +298,13 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; + /* filestore and bypass keywords can't work together */ + if (s->flags & SIG_FLAG_BYPASS) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "filestore can't work with bypass keyword"); + return -1; + } + sm = SigMatchAlloc(); if (sm == NULL) goto error; @@ -406,22 +395,17 @@ static int DetectFilestoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *st fd->scope = FILESTORE_SCOPE_DEFAULT; } - sm->ctx = fd; + sm->ctx = (SigMatchCtx*)fd; } else { - sm->ctx = NULL; + sm->ctx = (SigMatchCtx*)NULL; } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_FILEMATCH); - s->filestore_sm = sm; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); } - AppLayerHtpNeedFileInspection(); - - s->alproto = ALPROTO_HTTP; + SigMatchAppendSMToList(s, sm, g_file_match_list_id); + s->filestore_ctx = (const DetectFilestoreData *)sm->ctx; s->flags |= SIG_FLAG_FILESTORE; return 0; @@ -438,3 +422,38 @@ static void DetectFilestoreFree(void *ptr) SCFree(ptr); } } + +#ifdef UNITTESTS +/* + * The purpose of this test is to confirm that + * filestore and bypass keywords can't + * can't work together + */ +static int DetectFilestoreTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 1; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(bypass; filestore; " + "content:\"message\"; http_host; " + "sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + + return result; +} +#endif /* UNITTESTS */ + +void DetectFilestoreRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectFilestoreTest01", DetectFilestoreTest01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-filestore.h b/src/detect-filestore.h index 1879b87532e2..09d2e25f18da 100644 --- a/src/detect-filestore.h +++ b/src/detect-filestore.h @@ -41,5 +41,7 @@ typedef struct DetectFilestoreData_ { /* prototypes */ void DetectFilestoreRegister (void); -int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *); +int DetectFilestorePostMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *); + #endif /* __DETECT_FILESTORE_H__ */ diff --git a/src/detect-flags.c b/src/detect-flags.c index f06f0f444ec3..72ac60d7295f 100644 --- a/src/detect-flags.c +++ b/src/detect-flags.c @@ -29,6 +29,8 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "flow-var.h" #include "decode-events.h" @@ -56,10 +58,14 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectFlagsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlagsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFlagsFree(void *); +static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s); +static int PrefilterSetupTcpFlags(SigGroupHead *sgh); + /** * \brief Registration function for flags: keyword */ @@ -72,87 +78,47 @@ void DetectFlagsRegister (void) sigmatch_table[DETECT_FLAGS].Free = DetectFlagsFree; sigmatch_table[DETECT_FLAGS].RegisterTests = FlagsRegisterTests; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; + sigmatch_table[DETECT_FLAGS].SupportsPrefilter = PrefilterTcpFlagsIsPrefilterable; + sigmatch_table[DETECT_FLAGS].SetupPrefilter = PrefilterSetupTcpFlags; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \internal - * \brief This function is used to match flags on a packet with those passed via flags: - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param s pointer to the Signature - * \param m pointer to the sigmatch - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static inline int FlagsMatch(const uint8_t pflags, const uint8_t modifier, + const uint8_t dflags, const uint8_t iflags) { - SCEnter(); - - uint8_t flags = 0; - DetectFlagsData *de = (DetectFlagsData *)m->ctx; - - if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { - SCReturnInt(0); - } - - flags = p->tcph->th_flags; - - if (!de->flags && flags) { - if(de->modifier == MODIFIER_NOT) { + if (!dflags && pflags) { + if(modifier == MODIFIER_NOT) { SCReturnInt(1); } SCReturnInt(0); } - flags &= de->ignored_flags; + const uint8_t flags = pflags & iflags; - switch (de->modifier) { + switch (modifier) { case MODIFIER_ANY: - if ((flags & de->flags) > 0) { + if ((flags & dflags) > 0) { SCReturnInt(1); } SCReturnInt(0); case MODIFIER_PLUS: - if (((flags & de->flags) == de->flags)) { + if (((flags & dflags) == dflags)) { SCReturnInt(1); } SCReturnInt(0); case MODIFIER_NOT: - if ((flags & de->flags) != de->flags) { + if ((flags & dflags) != dflags) { SCReturnInt(1); } SCReturnInt(0); default: - SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"",flags,de->flags); - if (flags == de->flags) { + SCLogDebug("flags %"PRIu8" and de->flags %"PRIu8"", flags, dflags); + if (flags == dflags) { SCReturnInt(1); } } @@ -160,6 +126,34 @@ static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Pack SCReturnInt(0); } +/** + * \internal + * \brief This function is used to match flags on a packet with those passed via flags: + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param s pointer to the Signature + * \param m pointer to the sigmatch + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectFlagsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { + SCReturnInt(0); + } + + const DetectFlagsData *de = (const DetectFlagsData *)ctx; + const uint8_t flags = p->tcph->th_flags; + + return FlagsMatch(flags, de->modifier, de->flags, de->ignored_flags); +} + /** * \internal * \brief This function is used to parse flags options passed via flags: keyword @@ -497,7 +491,7 @@ static int DetectFlagsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -522,6 +516,105 @@ static void DetectFlagsFree(void *de_ptr) if(de) SCFree(de); } +int DetectFlagsSignatureNeedsSynPackets(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLAGS: + { + const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; + + if (!(fl->modifier == MODIFIER_NOT) && (fl->flags & TH_SYN)) { + return 1; + } + break; + } + } + } + return 0; +} + +int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLAGS: + { + const DetectFlagsData *fl = (const DetectFlagsData *)sm->ctx; + + if (!(fl->modifier == MODIFIER_NOT) && (fl->flags == TH_SYN)) { + return 1; + } + break; + } + } + } + return 0; +} + +static void +PrefilterPacketFlagsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + const uint8_t flags = p->tcph->th_flags; + if (FlagsMatch(flags, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) + { + SCLogDebug("packet matches TCP flags %02x", ctx->v1.u8[1]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFlagsSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFlagsData *a = smctx; + v->u8[0] = a->modifier; + v->u8[1] = a->flags; + v->u8[2] = a->ignored_flags; + SCLogDebug("v->u8[0] = %02x", v->u8[0]); +} + +static _Bool +PrefilterPacketFlagsCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFlagsData *a = smctx; + if (v.u8[0] == a->modifier && + v.u8[1] == a->flags && + v.u8[2] == a->ignored_flags) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTcpFlags(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FLAGS, + PrefilterPacketFlagsSet, + PrefilterPacketFlagsCompare, + PrefilterPacketFlagsMatch); + +} + +static _Bool PrefilterTcpFlagsIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLAGS: + return TRUE; + } + } + return FALSE; +} + /* * ONLY TESTS BELOW THIS COMMENT */ @@ -557,10 +650,10 @@ static int FlagsTestParse02 (void) de = DetectFlagsParse("G"); if (de) { DetectFlagsFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -600,9 +693,9 @@ static int FlagsTestParse03 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -655,22 +748,23 @@ static int FlagsTestParse04 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -710,22 +804,23 @@ static int FlagsTestParse05 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -765,9 +860,9 @@ static int FlagsTestParse06 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -820,22 +915,23 @@ static int FlagsTestParse07 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -875,9 +971,9 @@ static int FlagsTestParse08 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -930,9 +1026,9 @@ static int FlagsTestParse09 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -985,9 +1081,9 @@ static int FlagsTestParse10 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -1040,22 +1136,23 @@ static int FlagsTestParse11 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -1097,22 +1194,23 @@ static int FlagsTestParse12 (void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 1; + return 0; } + /* Expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } /** @@ -1181,9 +1279,9 @@ static int FlagsTestParse15(void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if (ret) { if (de) @@ -1234,9 +1332,9 @@ static int FlagsTestParse16(void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if (ret) { if (de) @@ -1290,9 +1388,9 @@ static int FlagsTestParse17(void) goto error; sm->type = DETECT_FLAGS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm); + ret = DetectFlagsMatch(&tv, NULL, p, NULL, sm->ctx); if (ret == 0) { if (de) @@ -1320,22 +1418,22 @@ static int FlagsTestParse17(void) void FlagsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlagsTestParse01", FlagsTestParse01, 1); - UtRegisterTest("FlagsTestParse02", FlagsTestParse02, 0); - UtRegisterTest("FlagsTestParse03", FlagsTestParse03, 1); - UtRegisterTest("FlagsTestParse04", FlagsTestParse04, 0); - UtRegisterTest("FlagsTestParse05", FlagsTestParse05, 0); - UtRegisterTest("FlagsTestParse06", FlagsTestParse06, 1); - UtRegisterTest("FlagsTestParse07", FlagsTestParse07, 0); - UtRegisterTest("FlagsTestParse08", FlagsTestParse08, 1); - UtRegisterTest("FlagsTestParse09", FlagsTestParse09, 1); - UtRegisterTest("FlagsTestParse10", FlagsTestParse10, 1); - UtRegisterTest("FlagsTestParse11", FlagsTestParse11, 0); - UtRegisterTest("FlagsTestParse12", FlagsTestParse12, 0); - UtRegisterTest("FlagsTestParse13", FlagsTestParse13, 1); - UtRegisterTest("FlagsTestParse14", FlagsTestParse14, 1); - UtRegisterTest("FlagsTestParse15", FlagsTestParse15, 1); - UtRegisterTest("FlagsTestParse16", FlagsTestParse16, 1); - UtRegisterTest("FlagsTestParse17", FlagsTestParse17, 1); + UtRegisterTest("FlagsTestParse01", FlagsTestParse01); + UtRegisterTest("FlagsTestParse02", FlagsTestParse02); + UtRegisterTest("FlagsTestParse03", FlagsTestParse03); + UtRegisterTest("FlagsTestParse04", FlagsTestParse04); + UtRegisterTest("FlagsTestParse05", FlagsTestParse05); + UtRegisterTest("FlagsTestParse06", FlagsTestParse06); + UtRegisterTest("FlagsTestParse07", FlagsTestParse07); + UtRegisterTest("FlagsTestParse08", FlagsTestParse08); + UtRegisterTest("FlagsTestParse09", FlagsTestParse09); + UtRegisterTest("FlagsTestParse10", FlagsTestParse10); + UtRegisterTest("FlagsTestParse11", FlagsTestParse11); + UtRegisterTest("FlagsTestParse12", FlagsTestParse12); + UtRegisterTest("FlagsTestParse13", FlagsTestParse13); + UtRegisterTest("FlagsTestParse14", FlagsTestParse14); + UtRegisterTest("FlagsTestParse15", FlagsTestParse15); + UtRegisterTest("FlagsTestParse16", FlagsTestParse16); + UtRegisterTest("FlagsTestParse17", FlagsTestParse17); #endif /* UNITTESTS */ } diff --git a/src/detect-flags.h b/src/detect-flags.h index 0eaaa28214c6..333ed910215c 100644 --- a/src/detect-flags.h +++ b/src/detect-flags.h @@ -56,4 +56,7 @@ void DetectFlagsRegister (void); void FlagsRegisterTests(void); +int DetectFlagsSignatureNeedsSynPackets(const Signature *s); +int DetectFlagsSignatureNeedsSynOnlyPackets(const Signature *s); + #endif /*__DETECT_FLAGS_H__ */ diff --git a/src/detect-flow.c b/src/detect-flow.c index 8f908419ff5c..bde034165161 100644 --- a/src/detect-flow.c +++ b/src/detect-flow.c @@ -30,6 +30,7 @@ #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" +#include "detect-engine-prefilter-common.h" #include "flow.h" #include "flow-var.h" @@ -48,11 +49,15 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFlowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlowSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowRegisterTests(void); void DetectFlowFree(void *); +static int PrefilterSetupFlow(SigGroupHead *sgh); +static _Bool PrefilterFlowIsPrefilterable(const Signature *s); + /** * \brief Registration function for flow: keyword */ @@ -60,41 +65,62 @@ void DetectFlowRegister (void) { sigmatch_table[DETECT_FLOW].name = "flow"; sigmatch_table[DETECT_FLOW].desc = "match on direction and state of the flow"; - sigmatch_table[DETECT_FLOW].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flow"; + sigmatch_table[DETECT_FLOW].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flow"; sigmatch_table[DETECT_FLOW].Match = DetectFlowMatch; sigmatch_table[DETECT_FLOW].Setup = DetectFlowSetup; sigmatch_table[DETECT_FLOW].Free = DetectFlowFree; sigmatch_table[DETECT_FLOW].RegisterTests = DetectFlowRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_FLOW].SupportsPrefilter = PrefilterFlowIsPrefilterable; + sigmatch_table[DETECT_FLOW].SetupPrefilter = PrefilterSetupFlow; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} + +/** + * \param pflags packet flags (p->flags) + * \param pflowflags packet flow flags (p->flowflags) + * \param tflags detection flags (det_ctx->flags) + * \param dflags detect flow flags + * \param match_cnt number of matches to trigger + */ +static inline int FlowMatch(const uint32_t pflags, const uint8_t pflowflags, + const uint16_t tflags, const uint16_t dflags, const uint8_t match_cnt) +{ + uint8_t cnt = 0; + + if ((dflags & DETECT_FLOW_FLAG_NO_FRAG) && + (!(pflags & PKT_REBUILT_FRAGMENT))) { + cnt++; + } else if ((dflags & DETECT_FLOW_FLAG_ONLY_FRAG) && + (pflags & PKT_REBUILT_FRAGMENT)) { + cnt++; } - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; + if ((dflags & DETECT_FLOW_FLAG_TOSERVER) && (pflowflags & FLOW_PKT_TOSERVER)) { + cnt++; + } else if ((dflags & DETECT_FLOW_FLAG_TOCLIENT) && (pflowflags & FLOW_PKT_TOCLIENT)) { + cnt++; } - return; -error: - /* XXX */ - return; -} + if ((dflags & DETECT_FLOW_FLAG_ESTABLISHED) && (pflowflags & FLOW_PKT_ESTABLISHED)) { + cnt++; + } else if (dflags & DETECT_FLOW_FLAG_NOT_ESTABLISHED && (!(pflowflags & FLOW_PKT_ESTABLISHED))) { + cnt++; + } else if (dflags & DETECT_FLOW_FLAG_STATELESS) { + cnt++; + } -/* - * returns 0: no match - * 1: match - * -1: error - */ + if (tflags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { + if (dflags & DETECT_FLOW_FLAG_ONLYSTREAM) + cnt++; + } else { + if (dflags & DETECT_FLOW_FLAG_NOSTREAM) + cnt++; + } + + return (match_cnt == cnt) ? 1 : 0; +} /** * \brief This function is used to match flow flags set on a packet with those passed via flow: @@ -107,7 +133,8 @@ void DetectFlowRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); @@ -121,36 +148,13 @@ int DetectFlowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, S if (p->flowflags & FLOW_PKT_ESTABLISHED) { SCLogDebug("FLOW_PKT_ESTABLISHED"); - } else if (p->flowflags & FLOW_PKT_STATELESS) { - SCLogDebug("FLOW_PKT_STATELESS"); - } - - uint8_t cnt = 0; - DetectFlowData *fd = (DetectFlowData *)m->ctx; - - if ((fd->flags & FLOW_PKT_TOSERVER) && (p->flowflags & FLOW_PKT_TOSERVER)) { - cnt++; - } else if ((fd->flags & FLOW_PKT_TOCLIENT) && (p->flowflags & FLOW_PKT_TOCLIENT)) { - cnt++; - } - - if ((fd->flags & FLOW_PKT_ESTABLISHED) && (p->flowflags & FLOW_PKT_ESTABLISHED)) { - cnt++; - } else if (fd->flags & FLOW_PKT_STATELESS) { - cnt++; } - if (det_ctx->flags & DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH) { - if (fd->flags & FLOW_PKT_ONLYSTREAM) - cnt++; - } else { - if (fd->flags & FLOW_PKT_NOSTREAM) - cnt++; - } + const DetectFlowData *fd = (const DetectFlowData *)ctx; - int ret = (fd->match_cnt == cnt) ? 1 : 0; - SCLogDebug("returning %" PRId32 " cnt %" PRIu8 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", - ret, cnt, fd->match_cnt, fd->flags, p->flowflags); + int ret = FlowMatch(p->flags, p->flowflags, det_ctx->flags, fd->flags, fd->match_cnt);; + SCLogDebug("returning %" PRId32 " fd->match_cnt %" PRId32 " fd->flags 0x%02X p->flowflags 0x%02X", + ret, fd->match_cnt, fd->flags, p->flowflags); SCReturnInt(ret); } @@ -214,59 +218,86 @@ DetectFlowData *DetectFlowParse (char *flowstr) if (args[i]) { /* inspect our options and set the flags */ if (strcasecmp(args[i], "established") == 0) { - if (fd->flags & FLOW_PKT_ESTABLISHED) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_ESTABLISHED flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_ESTABLISHED flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_STATELESS) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS already set"); goto error; } - fd->flags |= FLOW_PKT_ESTABLISHED; + fd->flags |= DETECT_FLOW_FLAG_ESTABLISHED; + } else if (strcasecmp(args[i], "not_established") == 0) { + if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_NOT_ESTABLISHED flag is already set"); + goto error; + } else if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_NOT_ESTABLISHED, DETECT_FLOW_FLAG_ESTABLISHED already set"); + goto error; + } + fd->flags |= DETECT_FLOW_FLAG_NOT_ESTABLISHED; } else if (strcasecmp(args[i], "stateless") == 0) { - if (fd->flags & FLOW_PKT_STATELESS) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_STATELESS) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_ESTABLISHED) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_STATELESS, FLOW_PKT_ESTABLISHED already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_STATELESS, DETECT_FLOW_FLAG_ESTABLISHED already set"); goto error; } - fd->flags |= FLOW_PKT_STATELESS; + fd->flags |= DETECT_FLOW_FLAG_STATELESS; } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) { - if (fd->flags & FLOW_PKT_TOCLIENT) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOCLIENT flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_TOCLIENT flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_TOSERVER) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, FLOW_PKT_TOSERVER already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, DETECT_FLOW_FLAG_TOSERVER already set"); goto error; } - fd->flags |= FLOW_PKT_TOCLIENT; + fd->flags |= DETECT_FLOW_FLAG_TOCLIENT; } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){ - if (fd->flags & FLOW_PKT_TOSERVER) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOSERVER flag is already set"); + if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_TOSERVER flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_TOCLIENT) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, FLOW_PKT_TO_CLIENT flag already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, DETECT_FLOW_FLAG_TO_CLIENT flag already set"); goto error; } - fd->flags |= FLOW_PKT_TOSERVER; + fd->flags |= DETECT_FLOW_FLAG_TOSERVER; } else if (strcasecmp(args[i], "only_stream") == 0) { - if (fd->flags & FLOW_PKT_ONLYSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_NOSTREAM) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, FLOW_PKT_NOSTREAM already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, DETECT_FLOW_FLAG_NOSTREAM already set"); goto error; } - fd->flags |= FLOW_PKT_ONLYSTREAM; + fd->flags |= DETECT_FLOW_FLAG_ONLYSTREAM; } else if (strcasecmp(args[i], "no_stream") == 0) { - if (fd->flags & FLOW_PKT_NOSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag is already set"); goto error; - } else if (fd->flags & FLOW_PKT_ONLYSTREAM) { - SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, FLOW_PKT_ONLYSTREAM already set"); + } else if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, DETECT_FLOW_FLAG_ONLYSTREAM already set"); goto error; } - fd->flags |= FLOW_PKT_NOSTREAM; + fd->flags |= DETECT_FLOW_FLAG_NOSTREAM; + } else if (strcasecmp(args[i], "no_frag") == 0) { + if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_frag flag is already set"); + goto error; + } else if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_frag flag, only_frag already set"); + goto error; + } + fd->flags |= DETECT_FLOW_FLAG_NO_FRAG; + } else if (strcasecmp(args[i], "only_frag") == 0) { + if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_frag flag is already set"); + goto error; + } else if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) { + SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_frag flag, no_frag already set"); + goto error; + } + fd->flags |= DETECT_FLOW_FLAG_ONLY_FRAG; } else { SCLogError(SC_ERR_INVALID_VALUE, "invalid flow option \"%s\"", args[i]); goto error; @@ -305,7 +336,7 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) goto error; /*ensure only one flow option*/ - if (s->init_flags & SIG_FLAG_INIT_FLOW) { + if (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) { SCLogError (SC_ERR_INVALID_SIGNATURE, "A signature may have only one flow option."); goto error; } @@ -317,26 +348,26 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr) goto error; sm->type = DETECT_FLOW; - sm->ctx = (void *)fd; + sm->ctx = (SigMatchCtx *)fd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); /* set the signature direction flags */ - if (fd->flags & FLOW_PKT_TOSERVER) { + if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) { s->flags |= SIG_FLAG_TOSERVER; - } else if (fd->flags & FLOW_PKT_TOCLIENT) { + } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) { s->flags |= SIG_FLAG_TOCLIENT; } else { s->flags |= SIG_FLAG_TOSERVER; s->flags |= SIG_FLAG_TOCLIENT; } - if (fd->flags & FLOW_PKT_ONLYSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) { s->flags |= SIG_FLAG_REQUIRE_STREAM; } - if (fd->flags & FLOW_PKT_NOSTREAM) { + if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) { s->flags |= SIG_FLAG_REQUIRE_PACKET; } else { - s->init_flags |= SIG_FLAG_INIT_FLOW; + s->init_data->init_flags |= SIG_FLAG_INIT_FLOW; } return 0; @@ -361,6 +392,60 @@ void DetectFlowFree(void *ptr) SCFree(fd); } +static void +PrefilterPacketFlowMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + if (FlowMatch(p->flags, p->flowflags, det_ctx->flags, ctx->v1.u8[0], ctx->v1.u8[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFlowSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFlowData *fb = smctx; + v->u8[0] = fb->flags; + v->u8[1] = fb->match_cnt; +} + +static _Bool +PrefilterPacketFlowCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFlowData *fb = smctx; + if (v.u8[0] == fb->flags && + v.u8[1] == fb->match_cnt) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFlow(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FLOW, + PrefilterPacketFlowSet, + PrefilterPacketFlowCompare, + PrefilterPacketFlowMatch); +} + +static _Bool PrefilterFlowIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FLOW: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS /** @@ -369,15 +454,11 @@ void DetectFlowFree(void *ptr) */ int DetectFlowTestParse01 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); - if (fd != NULL) { - DetectFlowFree(fd); - result = 1; - } - - return result; + FAIL_IF_NULL(fd); + DetectFlowFree(fd); + PASS; } /** @@ -385,19 +466,12 @@ int DetectFlowTestParse01 (void) */ int DetectFlowTestParse02 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && + fd->match_cnt == 1); + PASS; } /** @@ -405,19 +479,12 @@ int DetectFlowTestParse02 (void) */ int DetectFlowTestParse03 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("stateless"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -425,19 +492,12 @@ int DetectFlowTestParse03 (void) */ int DetectFlowTestParse04 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -445,19 +505,12 @@ int DetectFlowTestParse04 (void) */ int DetectFlowTestParse05 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_server"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -465,19 +518,12 @@ int DetectFlowTestParse05 (void) */ int DetectFlowTestParse06 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -485,19 +531,12 @@ int DetectFlowTestParse06 (void) */ int DetectFlowTestParse07 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_client"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -505,19 +544,12 @@ int DetectFlowTestParse07 (void) */ int DetectFlowTestParse08 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("established,to_client"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -525,19 +557,14 @@ int DetectFlowTestParse08 (void) */ int DetectFlowTestParse09 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,stateless"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -545,19 +572,14 @@ int DetectFlowTestParse09 (void) */ int DetectFlowTestParse10 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,stateless"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -565,19 +587,14 @@ int DetectFlowTestParse10 (void) */ int DetectFlowTestParse11 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse(" from_server , stateless "); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -586,15 +603,11 @@ int DetectFlowTestParse11 (void) */ int DetectFlowTestParseNocase01 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); - if (fd != NULL) { - DetectFlowFree(fd); - result = 1; - } - - return result; + FAIL_IF_NULL(fd); + DetectFlowFree(fd); + PASS; } /** @@ -602,19 +615,13 @@ int DetectFlowTestParseNocase01 (void) */ int DetectFlowTestParseNocase02 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED && + fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -622,19 +629,11 @@ int DetectFlowTestParseNocase02 (void) */ int DetectFlowTestParseNocase03 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("STATELESS"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1); DetectFlowFree(fd); + PASS; } /** @@ -642,19 +641,12 @@ int DetectFlowTestParseNocase03 (void) */ int DetectFlowTestParseNocase04 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -662,19 +654,12 @@ int DetectFlowTestParseNocase04 (void) */ int DetectFlowTestParseNocase05 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_SERVER"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -682,19 +667,12 @@ int DetectFlowTestParseNocase05 (void) */ int DetectFlowTestParseNocase06 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -702,19 +680,12 @@ int DetectFlowTestParseNocase06 (void) */ int DetectFlowTestParseNocase07 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_CLIENT"); - if (fd != NULL) { - if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1); + DetectFlowFree(fd); + PASS; } /** @@ -722,19 +693,14 @@ int DetectFlowTestParseNocase07 (void) */ int DetectFlowTestParseNocase08 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("ESTABLISHED,TO_CLIENT"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -742,19 +708,14 @@ int DetectFlowTestParseNocase08 (void) */ int DetectFlowTestParseNocase09 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("TO_CLIENT,STATELESS"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) { - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -762,19 +723,14 @@ int DetectFlowTestParseNocase09 (void) */ int DetectFlowTestParseNocase10 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,STATELESS"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } /** @@ -782,37 +738,25 @@ int DetectFlowTestParseNocase10 (void) */ int DetectFlowTestParseNocase11 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse(" FROM_SERVER , STATELESS "); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_STATELESS && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){ - result = 1; - } else { - printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->match_cnt == 2); + DetectFlowFree(fd); + PASS; } - /** * \test DetectFlowTestParse12 is a test for setting an invalid seperator : */ int DetectFlowTestParse12 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server:stateless"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -820,32 +764,21 @@ int DetectFlowTestParse12 (void) */ int DetectFlowTestParse13 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("invalidoptiontest"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } + /** * \test DetectFlowTestParse14 is a test for a empty option */ int DetectFlowTestParse14 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse(""); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -853,16 +786,10 @@ int DetectFlowTestParse14 (void) */ int DetectFlowTestParse15 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("established,stateless"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -870,16 +797,10 @@ int DetectFlowTestParse15 (void) */ int DetectFlowTestParse16 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,to_server"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -888,16 +809,10 @@ int DetectFlowTestParse16 (void) */ int DetectFlowTestParse17 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("to_client,from_server"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -905,20 +820,15 @@ int DetectFlowTestParse17 (void) */ int DetectFlowTestParse18 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3, - fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } /** @@ -926,20 +836,15 @@ int DetectFlowTestParse18 (void) */ int DetectFlowTestParseNocase18 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,ONLY_STREAM"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3, - fd->flags, fd->match_cnt); - } - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } @@ -948,16 +853,10 @@ int DetectFlowTestParseNocase18 (void) */ int DetectFlowTestParse19 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,only_stream,a"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } /** @@ -965,21 +864,15 @@ int DetectFlowTestParse19 (void) */ int DetectFlowTestParse20 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,established,no_stream"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_NOSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_NOSTREAM, 3, - fd->flags, fd->match_cnt); - } - - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_NOSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } /** @@ -987,21 +880,15 @@ int DetectFlowTestParse20 (void) */ int DetectFlowTestParseNocase20 (void) { - int result = 0; DetectFlowData *fd = NULL; fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,NO_STREAM"); - if (fd != NULL) { - if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_NOSTREAM && fd->match_cnt == 3) { - result = 1; - } else { - printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_NOSTREAM, 3, - fd->flags, fd->match_cnt); - } - - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && + fd->flags & DETECT_FLOW_FLAG_TOCLIENT && + fd->flags & DETECT_FLOW_FLAG_NOSTREAM && + fd->match_cnt == 3); + DetectFlowFree(fd); + PASS; } /** @@ -1009,21 +896,14 @@ int DetectFlowTestParseNocase20 (void) */ int DetectFlowTestParse21 (void) { - int result = 1; DetectFlowData *fd = NULL; fd = DetectFlowParse("from_server,a,no_stream"); - if (fd != NULL) { - printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt); - result = 0; - DetectFlowFree(fd); - } - - return result; + FAIL_IF_NOT_NULL(fd); + PASS; } static int DetectFlowSigTest01(void) { - int result = 0; ThreadVars th_v; DecodeThreadVars dtv; DetectEngineCtx *de_ctx = NULL; @@ -1032,10 +912,7 @@ static int DetectFlowSigTest01(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - if (p->flow != NULL) { - printf("packet has flow set\n"); - goto end; - } + FAIL_IF_NULL(p); char *sig1 = "alert tcp any any -> any any (msg:\"dummy\"; " "content:\"nova\"; flow:no_stream; sid:1;)"; @@ -1044,29 +921,18 @@ static int DetectFlowSigTest01(void) memset(&th_v, 0, sizeof(th_v)); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - printf("de_ctx == NULL: "); - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, sig1); - if (de_ctx->sig_list == NULL) { - printf("signature == NULL: "); - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - goto end; - } - - result = 1; + FAIL_IF(PacketAlertCheck(p, 1) != 1); - end: if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); @@ -1079,8 +945,91 @@ static int DetectFlowSigTest01(void) if (p != NULL) UTHFreePacket(p); - return result; + PASS; } + +/** + * \test Test parsing of the not_established keyword. + */ +static int DetectFlowTestParseNotEstablished(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("not_established"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED); + DetectFlowFree(fd); + PASS; +} + +/** + * \test Test parsing of the "no_frag" flow argument. + */ +static int DetectFlowTestParseNoFrag(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("no_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NO_FRAG); + DetectFlowFree(fd); + PASS; +} + +/** + * \test Test parsing of the "only_frag" flow argument. + */ +static int DetectFlowTestParseOnlyFrag(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("only_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG); + DetectFlowFree(fd); + PASS; +} + +/** + * \test Test that parsing of only_frag and no_frag together fails. + */ +static int DetectFlowTestParseNoFragOnlyFrag(void) +{ + DetectFlowData *fd = NULL; + fd = DetectFlowParse("no_frag,only_frag"); + FAIL_IF_NOT_NULL(fd); + PASS; +} + +/** + * \test Test no_frag matching. + */ +static int DetectFlowTestNoFragMatch(void) +{ + uint32_t pflags = 0; + DetectFlowData *fd = DetectFlowParse("no_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NO_FRAG); + FAIL_IF_NOT(fd->match_cnt == 1); + FAIL_IF_NOT(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + pflags |= PKT_REBUILT_FRAGMENT; + FAIL_IF(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + PASS; +} + +/** + * \test Test only_frag matching. + */ +static int DetectFlowTestOnlyFragMatch(void) +{ + uint32_t pflags = 0; + DetectFlowData *fd = DetectFlowParse("only_frag"); + FAIL_IF_NULL(fd); + FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG); + FAIL_IF_NOT(fd->match_cnt == 1); + FAIL_IF(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + pflags |= PKT_REBUILT_FRAGMENT; + FAIL_IF_NOT(FlowMatch(pflags, 0, 0, fd->flags, fd->match_cnt)); + PASS; +} + #endif /* UNITTESTS */ /** @@ -1089,41 +1038,50 @@ static int DetectFlowSigTest01(void) void DetectFlowRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFlowTestParse01", DetectFlowTestParse01, 1); - UtRegisterTest("DetectFlowTestParse02", DetectFlowTestParse02, 1); - UtRegisterTest("DetectFlowTestParse03", DetectFlowTestParse03, 1); - UtRegisterTest("DetectFlowTestParse04", DetectFlowTestParse04, 1); - UtRegisterTest("DetectFlowTestParse05", DetectFlowTestParse05, 1); - UtRegisterTest("DetectFlowTestParse06", DetectFlowTestParse06, 1); - UtRegisterTest("DetectFlowTestParse07", DetectFlowTestParse07, 1); - UtRegisterTest("DetectFlowTestParse08", DetectFlowTestParse08, 1); - UtRegisterTest("DetectFlowTestParse09", DetectFlowTestParse09, 1); - UtRegisterTest("DetectFlowTestParse10", DetectFlowTestParse10, 1); - UtRegisterTest("DetectFlowTestParse11", DetectFlowTestParse11, 1); - UtRegisterTest("DetectFlowTestParseNocase01", DetectFlowTestParseNocase01, 1); - UtRegisterTest("DetectFlowTestParseNocase02", DetectFlowTestParseNocase02, 1); - UtRegisterTest("DetectFlowTestParseNocase03", DetectFlowTestParseNocase03, 1); - UtRegisterTest("DetectFlowTestParseNocase04", DetectFlowTestParseNocase04, 1); - UtRegisterTest("DetectFlowTestParseNocase05", DetectFlowTestParseNocase05, 1); - UtRegisterTest("DetectFlowTestParseNocase06", DetectFlowTestParseNocase06, 1); - UtRegisterTest("DetectFlowTestParseNocase07", DetectFlowTestParseNocase07, 1); - UtRegisterTest("DetectFlowTestParseNocase08", DetectFlowTestParseNocase08, 1); - UtRegisterTest("DetectFlowTestParseNocase09", DetectFlowTestParseNocase09, 1); - UtRegisterTest("DetectFlowTestParseNocase10", DetectFlowTestParseNocase10, 1); - UtRegisterTest("DetectFlowTestParseNocase11", DetectFlowTestParseNocase11, 1); - UtRegisterTest("DetectFlowTestParse12", DetectFlowTestParse12, 1); - UtRegisterTest("DetectFlowTestParse13", DetectFlowTestParse13, 1); - UtRegisterTest("DetectFlowTestParse14", DetectFlowTestParse14, 1); - UtRegisterTest("DetectFlowTestParse15", DetectFlowTestParse15, 1); - UtRegisterTest("DetectFlowTestParse16", DetectFlowTestParse16, 1); - UtRegisterTest("DetectFlowTestParse17", DetectFlowTestParse17, 1); - UtRegisterTest("DetectFlowTestParse18", DetectFlowTestParse18, 1); - UtRegisterTest("DetectFlowTestParseNocase18", DetectFlowTestParseNocase18, 1); - UtRegisterTest("DetectFlowTestParse19", DetectFlowTestParse19, 1); - UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20, 1); - UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20, 1); - UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21, 1); - - UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01, 1); + UtRegisterTest("DetectFlowTestParse01", DetectFlowTestParse01); + UtRegisterTest("DetectFlowTestParse02", DetectFlowTestParse02); + UtRegisterTest("DetectFlowTestParse03", DetectFlowTestParse03); + UtRegisterTest("DetectFlowTestParse04", DetectFlowTestParse04); + UtRegisterTest("DetectFlowTestParse05", DetectFlowTestParse05); + UtRegisterTest("DetectFlowTestParse06", DetectFlowTestParse06); + UtRegisterTest("DetectFlowTestParse07", DetectFlowTestParse07); + UtRegisterTest("DetectFlowTestParse08", DetectFlowTestParse08); + UtRegisterTest("DetectFlowTestParse09", DetectFlowTestParse09); + UtRegisterTest("DetectFlowTestParse10", DetectFlowTestParse10); + UtRegisterTest("DetectFlowTestParse11", DetectFlowTestParse11); + UtRegisterTest("DetectFlowTestParseNocase01", DetectFlowTestParseNocase01); + UtRegisterTest("DetectFlowTestParseNocase02", DetectFlowTestParseNocase02); + UtRegisterTest("DetectFlowTestParseNocase03", DetectFlowTestParseNocase03); + UtRegisterTest("DetectFlowTestParseNocase04", DetectFlowTestParseNocase04); + UtRegisterTest("DetectFlowTestParseNocase05", DetectFlowTestParseNocase05); + UtRegisterTest("DetectFlowTestParseNocase06", DetectFlowTestParseNocase06); + UtRegisterTest("DetectFlowTestParseNocase07", DetectFlowTestParseNocase07); + UtRegisterTest("DetectFlowTestParseNocase08", DetectFlowTestParseNocase08); + UtRegisterTest("DetectFlowTestParseNocase09", DetectFlowTestParseNocase09); + UtRegisterTest("DetectFlowTestParseNocase10", DetectFlowTestParseNocase10); + UtRegisterTest("DetectFlowTestParseNocase11", DetectFlowTestParseNocase11); + UtRegisterTest("DetectFlowTestParse12", DetectFlowTestParse12); + UtRegisterTest("DetectFlowTestParse13", DetectFlowTestParse13); + UtRegisterTest("DetectFlowTestParse14", DetectFlowTestParse14); + UtRegisterTest("DetectFlowTestParse15", DetectFlowTestParse15); + UtRegisterTest("DetectFlowTestParse16", DetectFlowTestParse16); + UtRegisterTest("DetectFlowTestParse17", DetectFlowTestParse17); + UtRegisterTest("DetectFlowTestParse18", DetectFlowTestParse18); + UtRegisterTest("DetectFlowTestParseNocase18", DetectFlowTestParseNocase18); + UtRegisterTest("DetectFlowTestParse19", DetectFlowTestParse19); + UtRegisterTest("DetectFlowTestParse20", DetectFlowTestParse20); + UtRegisterTest("DetectFlowTestParseNocase20", DetectFlowTestParseNocase20); + UtRegisterTest("DetectFlowTestParse21", DetectFlowTestParse21); + UtRegisterTest("DetectFlowTestParseNotEstablished", + DetectFlowTestParseNotEstablished); + UtRegisterTest("DetectFlowTestParseNoFrag", DetectFlowTestParseNoFrag); + UtRegisterTest("DetectFlowTestParseOnlyFrag", + DetectFlowTestParseOnlyFrag); + UtRegisterTest("DetectFlowTestParseNoFragOnlyFrag", + DetectFlowTestParseNoFragOnlyFrag); + UtRegisterTest("DetectFlowTestNoFragMatch", DetectFlowTestNoFragMatch); + UtRegisterTest("DetectFlowTestOnlyFragMatch", DetectFlowTestOnlyFragMatch); + + UtRegisterTest("DetectFlowSigTest01", DetectFlowSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-flow.h b/src/detect-flow.h index 37e1f970995b..dc050b40d9a0 100644 --- a/src/detect-flow.h +++ b/src/detect-flow.h @@ -24,9 +24,19 @@ #ifndef __DETECT_FLOW_H__ #define __DETECT_FLOW_H__ +#define DETECT_FLOW_FLAG_TOSERVER BIT_U16(0) +#define DETECT_FLOW_FLAG_TOCLIENT BIT_U16(1) +#define DETECT_FLOW_FLAG_ESTABLISHED BIT_U16(2) +#define DETECT_FLOW_FLAG_NOT_ESTABLISHED BIT_U16(3) +#define DETECT_FLOW_FLAG_STATELESS BIT_U16(4) +#define DETECT_FLOW_FLAG_ONLYSTREAM BIT_U16(5) +#define DETECT_FLOW_FLAG_NOSTREAM BIT_U16(6) +#define DETECT_FLOW_FLAG_NO_FRAG BIT_U16(7) +#define DETECT_FLOW_FLAG_ONLY_FRAG BIT_U16(8) + typedef struct DetectFlowData_ { - uint8_t flags; /* flags to match */ - uint8_t match_cnt; /* number of matches we need */ + uint16_t flags; /* flags to match */ + uint8_t match_cnt; /* number of matches we need */ } DetectFlowData; /* prototypes */ diff --git a/src/detect-flowbits.c b/src/detect-flowbits.c index 129403792482..34d4eaf12127 100644 --- a/src/detect-flowbits.c +++ b/src/detect-flowbits.c @@ -41,16 +41,16 @@ #include "detect-engine-mpm.h" #include "detect-engine-state.h" -#include "flow-bit.h" #include "util-var-name.h" #include "util-unittest.h" #include "util-debug.h" -#define PARSE_REGEX "([a-z]+)(?:,(.*))?" +#define PARSE_REGEX "([a-z]+)(?:,\\s*(.*))?" static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFlowbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, char *); void DetectFlowbitFree (void *); void FlowBitsRegisterTests(void); @@ -59,7 +59,7 @@ void DetectFlowbitsRegister (void) { sigmatch_table[DETECT_FLOWBITS].name = "flowbits"; sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag"; - sigmatch_table[DETECT_FLOWBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#Flowbits"; + sigmatch_table[DETECT_FLOWBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits"; sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch; sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup; sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree; @@ -67,59 +67,41 @@ void DetectFlowbitsRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -static int DetectFlowbitMatchToggle (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; FlowBitToggle(p->flow,fd->idx); + return 1; } -static int DetectFlowbitMatchUnset (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; FlowBitUnset(p->flow,fd->idx); + return 1; } -static int DetectFlowbitMatchSet (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; FlowBitSet(p->flow,fd->idx); + return 1; } -static int DetectFlowbitMatchIsset (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -127,7 +109,7 @@ static int DetectFlowbitMatchIsset (Packet *p, DetectFlowbitsData *fd) return FlowBitIsset(p->flow,fd->idx); } -static int DetectFlowbitMatchIsnotset (Packet *p, DetectFlowbitsData *fd) +static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd) { if (p->flow == NULL) return 0; @@ -141,9 +123,10 @@ static int DetectFlowbitMatchIsnotset (Packet *p, DetectFlowbitsData *fd) * -1: error */ -int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - DetectFlowbitsData *fd = (DetectFlowbitsData *)m->ctx; + const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx; if (fd == NULL) return 0; @@ -166,36 +149,65 @@ int DetectFlowbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p return 0; } -int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +static int DetectFlowbitParse(char *str, char *cmd, int cmd_len, char *name, + int name_len) { - DetectFlowbitsData *cd = NULL; - SigMatch *sm = NULL; - uint8_t fb_cmd = 0; -#define MAX_SUBSTRINGS 30 - int ret = 0, res = 0; - int ov[MAX_SUBSTRINGS]; - char fb_cmd_str[16] = "", fb_name[256] = ""; - - ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 2 && ret != 3) { - SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowbits.", rawstr); - return -1; + const int max_substrings = 30; + int count, rc; + int ov[max_substrings]; + + count = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, + ov, max_substrings); + if (count != 2 && count != 3) { + SCLogError(SC_ERR_PCRE_MATCH, + "\"%s\" is not a valid setting for flowbits.", str); + return 0; } - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); - if (res < 0) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len); + if (rc < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - return -1; + return 0; } - if (ret == 3) { - res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); - if (res < 0) { + if (count == 3) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name, + name_len); + if (rc < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; + return 0; + } + + /* Trim trailing whitespace. */ + while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) { + name[strlen(name) - 1] = '\0'; + } + + /* Validate name, spaces are not allowed. */ + for (size_t i = 0; i < strlen(name); i++) { + if (isblank(name[i])) { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "spaces not allowed in flowbit names"); + return 0; + } } } + return 1; +} + +int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + DetectFlowbitsData *cd = NULL; + SigMatch *sm = NULL; + uint8_t fb_cmd = 0; + char fb_cmd_str[16] = "", fb_name[256] = ""; + + if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name, + sizeof(fb_name))) { + return -1; + } + if (strcmp(fb_cmd_str,"noalert") == 0) { fb_cmd = DETECT_FLOWBITS_CMD_NOALERT; } else if (strcmp(fb_cmd_str,"isset") == 0) { @@ -234,7 +246,7 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) if (unlikely(cd == NULL)) goto error; - cd->idx = VariableNameGetIdx(de_ctx, fb_name, DETECT_FLOWBITS); + cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_FLOW_BIT); cd->cmd = fb_cmd; SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", @@ -247,12 +259,10 @@ int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) goto error; sm->type = DETECT_FLOWBITS; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; switch (fb_cmd) { - case DETECT_FLOWBITS_CMD_NOALERT: - /* nothing to do */ - break; + /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */ case DETECT_FLOWBITS_CMD_ISNOTSET: case DETECT_FLOWBITS_CMD_ISSET: @@ -289,6 +299,47 @@ void DetectFlowbitFree (void *ptr) } #ifdef UNITTESTS + +static int FlowBitsTestParse01(void) +{ + char command[16] = "", name[16] = ""; + + /* Single argument version. */ + FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "noalert") != 0); + + /* No leading or trailing spaces. */ + FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); + + /* Leading space. */ + FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); + + /* Trailing space. */ + FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); + + /* Leading and trailing space. */ + FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name, + sizeof(name))); + FAIL_IF(strcmp(command, "set") != 0); + FAIL_IF(strcmp(name, "flowbit") != 0); + + /* Spaces are not allowed in the name. */ + FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command), + name, sizeof(name))); + + PASS; +} + /** * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option * @@ -298,70 +349,20 @@ void DetectFlowbitFree (void *ptr) static int FlowBitsTestSig01(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NOT_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - return result; + PASS; } /** @@ -373,117 +374,36 @@ static int FlowBitsTestSig01(void) static int FlowBitsTestSig02(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - int error_count = 0; memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)"); - - if (s == NULL) { - error_count++; - } + FAIL_IF_NOT_NULL(s); s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)"); - - if (s == NULL) { - error_count++; - } - - if(error_count == 5) - goto end; + FAIL_IF_NOT_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - if (PacketAlertCheck(p, 1)) { - goto cleanup; - } - if (PacketAlertCheck(p, 2)) { - goto cleanup; - } - if (PacketAlertCheck(p, 3)) { - goto cleanup; - } - if (PacketAlertCheck(p, 4)) { - goto cleanup; - } - if (PacketAlertCheck(p, 5)) { - goto cleanup; - } - - result = 1; - -cleanup: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - return result; + PASS; } /** @@ -495,73 +415,20 @@ static int FlowBitsTestSig02(void) static int FlowBitsTestSig03(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NOT_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - - SCFree(p); - return result; + PASS; } /** @@ -573,77 +440,24 @@ static int FlowBitsTestSig03(void) static int FlowBitsTestSig04(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; int idx = 0; - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); - idx = VariableNameGetIdx(de_ctx, "fbt", DETECT_FLOWBITS); - - if (s == NULL || idx != 1) { - goto end; - } + idx = VarNameStoreSetupAdd("fbt", VAR_TYPE_FLOW_BIT); + FAIL_IF(idx != 1); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p); - return result; - -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - return result; + PASS; } /** @@ -655,74 +469,21 @@ static int FlowBitsTestSig04(void) static int FlowBitsTestSig05(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; Signature *s = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)"); - - if (s == NULL || ((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT)) { - goto end; - } + FAIL_IF_NULL(s); + FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - - SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - SCFree(p); - return result; + PASS; } /** @@ -740,8 +501,7 @@ static int FlowBitsTestSig06(void) "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -749,7 +509,7 @@ static int FlowBitsTestSig06(void) Flow f; GenericVar flowvar, *gv = NULL; int result = 0; - int idx = 0; + uint32_t idx = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -769,64 +529,35 @@ static int FlowBitsTestSig06(void) p->flowflags |= FLOW_PKT_TOSERVER; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); + FAIL_IF_NULL(s); - if (s == NULL) { - goto end; - } - + idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); - gv = p->flow->flowvar; - + FAIL_IF_NULL(gv); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; } } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(result); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - if(gv) GenericVarFree(gv); - FLOW_DESTROY(&f); - SCFree(p); - return result; + PASS; } /** @@ -844,8 +575,7 @@ static int FlowBitsTestSig07(void) "\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF_NULL(p); Signature *s = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; @@ -853,7 +583,7 @@ static int FlowBitsTestSig07(void) Flow f; GenericVar flowvar, *gv = NULL; int result = 0; - int idx = 0; + uint32_t idx = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -871,69 +601,39 @@ static int FlowBitsTestSig07(void) p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); + idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); - gv = p->flow->flowvar; + FAIL_IF_NULL(gv); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; } } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF(result); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - if(gv) GenericVarFree(gv); - FLOW_DESTROY(&f); - - SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); - return result; + PASS; } /** @@ -960,7 +660,7 @@ static int FlowBitsTestSig08(void) Flow f; GenericVar flowvar, *gv = NULL; int result = 0; - int idx = 0; + uint32_t idx = 0; memset(p, 0, SIZE_OF_PACKET); memset(&th_v, 0, sizeof(th_v)); @@ -978,71 +678,39 @@ static int FlowBitsTestSig08(void) p->proto = IPPROTO_TCP; de_ctx = DetectEngineCtxInit(); - - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); - - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)"); + FAIL_IF_NULL(s); - if (s == NULL) { - goto end; - } - + idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - idx = VariableNameGetIdx(de_ctx, "myflow", DETECT_FLOWBITS); - gv = p->flow->flowvar; + FAIL_IF_NULL(gv); for ( ; gv != NULL; gv = gv->next) { if (gv->type == DETECT_FLOWBITS && gv->idx == idx) { result = 1; } } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF(result); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - if(gv) GenericVarFree(gv); - FLOW_DESTROY(&f); - - SCFree(p); - return result; -end: - - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } - - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } - - if(gv) GenericVarFree(gv); FLOW_DESTROY(&f); SCFree(p); - return result; + PASS; } #endif /* UNITTESTS */ @@ -1052,13 +720,14 @@ static int FlowBitsTestSig08(void) void FlowBitsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01, 0); - UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02, 0); - UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03, 0); - UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04, 1); - UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05, 1); - UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06, 1); - UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07, 0); - UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08, 0); + UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01); + UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01); + UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02); + UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03); + UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04); + UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05); + UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06); + UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07); + UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08); #endif /* UNITTESTS */ } diff --git a/src/detect-flowbits.h b/src/detect-flowbits.h index 8961da3fd898..7d50edb83542 100644 --- a/src/detect-flowbits.h +++ b/src/detect-flowbits.h @@ -34,7 +34,7 @@ #define DETECT_FLOWBITS_CMD_MAX 6 typedef struct DetectFlowbitsData_ { - uint16_t idx; + uint32_t idx; uint8_t cmd; } DetectFlowbitsData; diff --git a/src/detect-flowint.c b/src/detect-flowint.c index 6ae36551d58d..76bcb1a5a7b9 100644 --- a/src/detect-flowint.c +++ b/src/detect-flowint.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -35,24 +35,26 @@ #include "util-var-name.h" #include "util-debug.h" #include "util-unittest.h" +#include "util-unittest-helper.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-sigorder.h" #include "pkt-var.h" #include "host.h" #include "util-profiling.h" /* name modifiers value */ -#define PARSE_REGEX "^\\s*([a-zA-Z][\\w\\d_.]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})?\\s*$" +#define PARSE_REGEX "^\\s*([a-zA-Z][\\w\\d_./]+)\\s*,\\s*([+=-]{1}|==|!=|<|<=|>|>=|isset|notset)\\s*,?\\s*([a-zA-Z][\\w\\d]+|[\\d]{1,10})?\\s*$" /* Varnames must begin with a letter */ static pcre *parse_regex; static pcre_extra *parse_regex_study; int DetectFlowintMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + const Signature *, const SigMatchCtx *); static int DetectFlowintSetup(DetectEngineCtx *, Signature *, char *); void DetectFlowintFree(void *); void DetectFlowintRegisterTests(void); @@ -61,33 +63,13 @@ void DetectFlowintRegister(void) { sigmatch_table[DETECT_FLOWINT].name = "flowint"; sigmatch_table[DETECT_FLOWINT].desc = "operate on a per-flow integer"; - sigmatch_table[DETECT_FLOWINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flowint"; + sigmatch_table[DETECT_FLOWINT].url = DOC_URL DOC_VERSION "/rules/flowint.html"; sigmatch_table[DETECT_FLOWINT].Match = DetectFlowintMatch; sigmatch_table[DETECT_FLOWINT].Setup = DetectFlowintSetup; sigmatch_table[DETECT_FLOWINT].Free = DetectFlowintFree; sigmatch_table[DETECT_FLOWINT].RegisterTests = DetectFlowintRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; -error: - SCLogInfo("Error registering flowint detection plugin"); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -105,12 +87,13 @@ void DetectFlowintRegister(void) * condition */ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectFlowintData *sfd =(DetectFlowintData *) m->ctx; + const DetectFlowintData *sfd = (const DetectFlowintData *)ctx; FlowVar *fv; FlowVar *fvt; uint32_t targetval; + int ret = 0; /** ATM If we are going to compare the current var with another * that doesn't exist, the default value will be zero; @@ -121,9 +104,9 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * return zero(not match). */ if (sfd->targettype == FLOWINT_TARGET_VAR) { - sfd->target.tvar.idx = VariableNameGetIdx(det_ctx->de_ctx, sfd->target.tvar.name, DETECT_FLOWINT); + uint32_t tvar_idx = VarNameStoreLookupByName(sfd->target.tvar.name, VAR_TYPE_FLOW_INT); - fvt = FlowVarGet(p->flow, sfd->target.tvar.idx); + fvt = FlowVarGet(p->flow, tvar_idx); /* We don't have that variable initialized yet */ if (fvt == NULL) targetval = 0; @@ -136,9 +119,10 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCLogDebug("Our var %s is at idx: %"PRIu16"", sfd->name, sfd->idx); if (sfd->modifier == FLOWINT_MODIFIER_SET) { - FlowVarAddInt(p->flow, sfd->idx, targetval); + FlowVarAddIntNoLock(p->flow, sfd->idx, targetval); SCLogDebug("Setting %s = %u", sfd->name, targetval); - return 1; + ret = 1; + goto end; } fv = FlowVarGet(p->flow, sfd->idx); @@ -146,58 +130,58 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, if (sfd->modifier == FLOWINT_MODIFIER_ISSET) { SCLogDebug(" Isset %s? = %u", sfd->name,(fv) ? 1 : 0); if (fv != NULL) - return 1; - else - return 0; + ret = 1; + goto end; } if (sfd->modifier == FLOWINT_MODIFIER_NOTSET) { SCLogDebug(" Not set %s? = %u", sfd->name,(fv) ? 0 : 1); - if (fv != NULL) - return 0; - else - return 1; + if (fv == NULL) + ret = 1; + goto end; } if (fv != NULL && fv->datatype == FLOWVAR_TYPE_INT) { if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s", targetval, sfd->name); - FlowVarAddInt(p->flow, sfd->idx, fv->data.fv_int.value + + FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value + targetval); - return 1; + ret = 1; + goto end; } if (sfd->modifier == FLOWINT_MODIFIER_SUB) { SCLogDebug("Substracting %u to %s", targetval, sfd->name); - FlowVarAddInt(p->flow, sfd->idx, fv->data.fv_int.value - + FlowVarAddIntNoLock(p->flow, sfd->idx, fv->data.fv_int.value - targetval); - return 1; + ret = 1; + goto end; } switch(sfd->modifier) { case FLOWINT_MODIFIER_EQ: SCLogDebug("( %u EQ %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value == targetval; + ret = (fv->data.fv_int.value == targetval); break; case FLOWINT_MODIFIER_NE: SCLogDebug("( %u NE %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value != targetval; + ret = (fv->data.fv_int.value != targetval); break; case FLOWINT_MODIFIER_LT: SCLogDebug("( %u LT %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value < targetval; + ret = (fv->data.fv_int.value < targetval); break; case FLOWINT_MODIFIER_LE: SCLogDebug("( %u LE %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value <= targetval; + ret = (fv->data.fv_int.value <= targetval); break; case FLOWINT_MODIFIER_GT: SCLogDebug("( %u GT %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value > targetval; + ret = (fv->data.fv_int.value > targetval); break; case FLOWINT_MODIFIER_GE: SCLogDebug("( %u GE %u )", fv->data.fv_int.value, targetval); - return fv->data.fv_int.value >= targetval; + ret = (fv->data.fv_int.value >= targetval); break; default: SCLogDebug("Unknown Modifier!"); @@ -210,18 +194,19 @@ int DetectFlowintMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * so implying a 0 set. */ if (sfd->modifier == FLOWINT_MODIFIER_ADD) { SCLogDebug("Adding %u to %s (new var)", targetval, sfd->name); - FlowVarAddInt(p->flow, sfd->idx, targetval); - return 1; + FlowVarAddIntNoLock(p->flow, sfd->idx, targetval); + ret = 1; } else { - SCLogDebug("Var not found!"); /* It doesn't exist because it wasn't set * or it is a string var, that we don't compare here */ - return 0; + ret = 0; } } - return 0; + +end: + return ret; } /** @@ -322,6 +307,7 @@ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) " Values should be between 0 and %"PRIu32, UINT32_MAX); goto error; } + sfd->target.value = (uint32_t) value_long; } else { sfd->targettype = FLOWINT_TARGET_VAR; sfd->target.tvar.name = SCStrdup(varval); @@ -340,9 +326,8 @@ DetectFlowintData *DetectFlowintParse(DetectEngineCtx *de_ctx, char *rawstr) SCLogError(SC_ERR_MEM_ALLOC, "malloc from strdup failed"); goto error; } - if (de_ctx != NULL) - sfd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWINT); - sfd->target.value = (uint32_t) value_long; + sfd->idx = VarNameStoreSetupAdd(varname, VAR_TYPE_FLOW_INT); + SCLogDebug("sfd->name %s id %u", sfd->name, sfd->idx); sfd->modifier = modifier; pcre_free_substring(varname); @@ -388,7 +373,7 @@ static int DetectFlowintSetup(DetectEngineCtx *de_ctx, Signature *s, char *rawst goto error; sm->type = DETECT_FLOWINT; - sm->ctx = (void *)sfd; + sm->ctx = (SigMatchCtx *)sfd; switch (sfd->modifier) { case FLOWINT_MODIFIER_SET: @@ -451,8 +436,8 @@ void DetectFlowintPrintData(DetectFlowintData *sfd) sfd->name, sfd->modifier, sfd->idx); switch(sfd->targettype) { case FLOWINT_TARGET_VAR: - SCLogDebug("target_var: %s, target_idx: %"PRIu16, - sfd->target.tvar.name, sfd->target.tvar.idx); + SCLogDebug("target_var: %s", + sfd->target.tvar.name); break; case FLOWINT_TARGET_VAL: SCLogDebug("Value: %"PRIu32"; ", sfd->target.value); @@ -1112,673 +1097,144 @@ int DetectFlowintTestParseInvalidSyntaxis01(void) */ int DetectFlowintTestPacket01Real() { - int result = 1; - - uint8_t pkt1[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, - 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt2[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, - 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, - 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, - 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt3[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, - 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63 - }; - - uint8_t pkt4[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, - 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, - 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, - 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, - 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, - 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, - 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, - 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, - 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, - 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, - 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, - 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, - 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, - 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, - 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a - }; - - uint8_t pkt5[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, - 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt6[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, - 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, - 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, - 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, - 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, - 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, - 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, - 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, - 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, - 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, - 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, - 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, - 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, - 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, - 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, - 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, - 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, - 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, - 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, - 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, - 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, - 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, - 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, - 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, - 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, - 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, - 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, - 0x3e, 0x0a - }; - - uint8_t pkt7[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt8[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, - 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt9[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt10[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, - 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt11[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, - 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, - 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, - 0x43, 0x8a - }; - - uint8_t *pkts[] = { - pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, - pkt9, pkt10, pkt11 - }; - - uint16_t pktssizes[] = { - sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), - sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), - sizeof(pkt11) - }; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); - FlowInitConfig(FLOW_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - /* Now that we have the array of packets for the flow, prepare the signatures */ - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"); - - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"); - - de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, 0; sid:103;)"); - - de_ctx->sig_list->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; noalert;sid:104;)"); - - /* comparation of myvar with maxvar */ - de_ctx->sig_list->next->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, ==, maxvar; sid:105;)"); - - /* I know it's a bit ugly, */ - de_ctx->sig_list->next->next->next->next->next = NULL; - + char *sigs[5]; + sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint:myvar,=,1; flowint:maxvar,=,6; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint: myvar,+,2; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar,==,3; flowint: cntpackets, =, 0; sid:103;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: myvar,==,3; flowint: cntpackets, +, 1; noalert;sid:104;)"; + sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, ==, maxvar; sid:105;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 5) == 0); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); - /* Decode the packets, and test the matches*/ - int i; - for (i = 0;i < 11;i++) { - memset(p, 0, SIZE_OF_PACKET); - PACKET_INITIALIZE(p); - DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - switch(i) { - case 3: - if (PacketAlertCheck(p, 101) == 0) { - SCLogDebug("Not declared/initialized!"); - result = 0; - } - break; - case 5: - if (PacketAlertCheck(p, 102) == 0) { - SCLogDebug("Not incremented!"); - result = 0; - } - - if (PacketAlertCheck(p, 103) == 0) { - SCLogDebug("myvar is not 3 or bad cmp!!"); - result = 0; - } - break; - case 10: - if (PacketAlertCheck(p, 105) == 0) { - SCLogDebug("Not declared/initialized/or well incremented the" - " second var!"); - result = 0; - } - break; - } - SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); - PACKET_RECYCLE(p); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", + 41424, 80); + FAIL_IF(f == NULL); + f->proto = IPPROTO_TCP; + + p = UTHBuildPacket((uint8_t *)"GET", 3, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 101)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"Unauthorized", 12, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 102)); + FAIL_IF(!PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"1", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"X", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 105)); + UTHFreePacket(p); + + UTHFreeFlow(f); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - SCFree(p); - return result; -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - if (de_ctx) - DetectEngineCtxFree(de_ctx); - - PACKET_RECYCLE(p); - FlowShutdown(); - SCFree(p); - return result; + PASS; } /** * \test DetectFlowintTestPacket02Real * \brief like DetectFlowintTestPacket01Real but using isset/notset keywords */ -int DetectFlowintTestPacket02Real() +static int DetectFlowintTestPacket02Real() { - int result = 1; - - uint8_t pkt1[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, - 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt2[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, - 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, - 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, - 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt3[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, - 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63 - }; - - uint8_t pkt4[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, - 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, - 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, - 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, - 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, - 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, - 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, - 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, - 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, - 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, - 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, - 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, - 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, - 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, - 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a - }; - - uint8_t pkt5[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, - 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt6[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, - 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, - 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, - 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, - 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, - 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, - 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, - 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, - 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, - 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, - 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, - 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, - 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, - 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, - 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, - 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, - 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, - 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, - 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, - 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, - 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, - 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, - 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, - 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, - 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, - 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, - 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, - 0x3e, 0x0a - }; - - uint8_t pkt7[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt8[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, - 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt9[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt10[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, - 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt11[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, - 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, - 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, - 0x43, 0x8a - }; - - uint8_t *pkts[] = { - pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, - pkt9, pkt10, pkt11 - }; - - uint16_t pktssizes[] = { - sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), - sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), - sizeof(pkt11) - }; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; - + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); - FlowInitConfig(FLOW_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - /* Now that we have the array of packets for the flow, prepare the signatures */ - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: maxvar,=,6; sid:101;)"); - - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"); - - de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"); - - de_ctx->sig_list->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, 1; noalert;sid:104;)"); - - /* comparation of myvar with maxvar */ - de_ctx->sig_list->next->next->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"); - - /* I know it's a bit ugly, */ - de_ctx->sig_list->next->next->next->next->next = NULL; - + char *sigs[5]; + sigs[0] = "alert tcp any any -> any any (msg:\"Setting a flowint counter\"; content:\"GET\"; flowint: myvar, notset; flowint:maxvar,notset; flowint: myvar,=,1; flowint: maxvar,=,6; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"Adding to flowint counter\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: myvar,+,2; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"if the flowint counter is 3 create a new counter\"; content:\"Unauthorized\"; flowint: myvar, isset; flowint: myvar,==,3; flowint:cntpackets,notset; flowint: cntpackets, =, 0; sid:103;)"; + sigs[3] = "alert tcp any any -> any any (msg:\"and count the rest of the packets received without generating alerts!!!\"; flowint: cntpackets,isset; flowint: cntpackets, +, 1; noalert;sid:104;)"; + sigs[4] = "alert tcp any any -> any any (msg:\" and fire this when it reach 6\"; flowint: cntpackets, isset; flowint: maxvar,isset; flowint: cntpackets, ==, maxvar; sid:105;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 5) == 0); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); - int i; - - /* Decode the packets, and test the matches*/ - for (i = 0;i < 11;i++) { - memset(p, 0, SIZE_OF_PACKET); - PACKET_INITIALIZE(p); - DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - switch(i) { - case 3: - if (PacketAlertCheck(p, 101) == 0) { - SCLogDebug("Not declared/initialized!"); - result = 0; - } - break; - case 5: - if (PacketAlertCheck(p, 102) == 0) { - SCLogDebug("Not incremented!"); - result = 0; - } - - if (PacketAlertCheck(p, 103) == 0) { - SCLogDebug("myvar is not 3 or bad cmp!!"); - result = 0; - } - break; - case 10: - if (PacketAlertCheck(p, 105) == 0) { - SCLogDebug("Not declared/initialized/or well incremented the" - " second var!"); - result = 0; - } - break; - } - SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); - PACKET_RECYCLE(p); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", + 41424, 80); + FAIL_IF(f == NULL); + f->proto = IPPROTO_TCP; + + p = UTHBuildPacket((uint8_t *)"GET", 3, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 101)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"Unauthorized", 12, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 102)); + FAIL_IF(!PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"1", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"X", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 105)); + UTHFreePacket(p); + + UTHFreeFlow(f); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - SCFree(p); - return result; -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); - if (de_ctx) - DetectEngineCtxFree(de_ctx); - - FlowShutdown(); - SCFree(p); - return result; + PASS; } /** @@ -1787,328 +1243,61 @@ int DetectFlowintTestPacket02Real() */ int DetectFlowintTestPacket03Real() { - int result = 1; - - uint8_t pkt1[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xc2, 0x26, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x67, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0xe8, 0xb0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x72, - 0x40, 0x93, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt2[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06, - 0xb6, 0x8e, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xdd, 0x17, 0x51, 0x82, 0xb6, 0xa0, 0x12, - 0x16, 0x80, 0x17, 0x8a, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xac, 0x04, 0x02, 0x08, 0x0a, 0x01, 0x29, - 0x23, 0x63, 0x01, 0x72, 0x40, 0x93, 0x01, 0x03, - 0x03, 0x07 - }; - - uint8_t pkt3[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x27, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6e, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x10, - 0x00, 0x2e, 0x5c, 0xa0, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63 - }; - - uint8_t pkt4[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x01, 0x12, 0xc2, 0x28, 0x40, 0x00, 0x40, 0x06, - 0xf3, 0x8f, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x82, 0xb6, 0x21, 0x04, 0x8b, 0xde, 0x80, 0x18, - 0x00, 0x2e, 0x24, 0x39, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x93, 0x01, 0x29, - 0x23, 0x63, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, - 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x63, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x73, 0x67, 0x6d, 0x6c, 0x2c, - 0x20, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, - 0x2e, 0x30, 0x31, 0x0d, 0x0a, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f, - 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x67, 0x7a, - 0x69, 0x70, 0x2c, 0x20, 0x62, 0x7a, 0x69, 0x70, - 0x32, 0x0d, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, - 0x67, 0x65, 0x3a, 0x20, 0x65, 0x6e, 0x0d, 0x0a, - 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x3a, 0x20, 0x4c, 0x79, 0x6e, 0x78, - 0x2f, 0x32, 0x2e, 0x38, 0x2e, 0x36, 0x72, 0x65, - 0x6c, 0x2e, 0x34, 0x20, 0x6c, 0x69, 0x62, 0x77, - 0x77, 0x77, 0x2d, 0x46, 0x4d, 0x2f, 0x32, 0x2e, - 0x31, 0x34, 0x20, 0x53, 0x53, 0x4c, 0x2d, 0x4d, - 0x4d, 0x2f, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x20, - 0x47, 0x4e, 0x55, 0x54, 0x4c, 0x53, 0x2f, 0x32, - 0x2e, 0x30, 0x2e, 0x34, 0x0d, 0x0a, 0x0d, 0x0a - }; - - uint8_t pkt5[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbd, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd9, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x10, - 0x00, 0x2d, 0x5b, 0xc3, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x63, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt6[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x01, 0xe4, 0xa8, 0xbe, 0x40, 0x00, 0x40, 0x06, - 0x0c, 0x28, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8b, 0xde, 0x17, 0x51, 0x83, 0x94, 0x80, 0x18, - 0x00, 0x2d, 0x1b, 0x84, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, - 0x2e, 0x31, 0x20, 0x34, 0x30, 0x31, 0x20, 0x55, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x65, 0x64, 0x0d, 0x0a, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x3a, 0x20, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, - 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3a, - 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, - 0x65, 0x0d, 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, - 0x20, 0x57, 0x65, 0x64, 0x2c, 0x20, 0x31, 0x34, - 0x20, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x39, 0x20, 0x31, 0x33, 0x3a, 0x34, 0x39, 0x3a, - 0x35, 0x33, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x3a, 0x20, 0x42, 0x61, 0x73, 0x69, 0x63, 0x20, - 0x72, 0x65, 0x61, 0x6c, 0x6d, 0x3d, 0x22, 0x44, - 0x53, 0x4c, 0x20, 0x52, 0x6f, 0x75, 0x74, 0x65, - 0x72, 0x22, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, - 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, - 0x0d, 0x0a, 0x3c, 0x48, 0x54, 0x4d, 0x4c, 0x3e, - 0x3c, 0x48, 0x45, 0x41, 0x44, 0x3e, 0x3c, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x34, 0x30, 0x31, - 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x3c, 0x2f, 0x54, - 0x49, 0x54, 0x4c, 0x45, 0x3e, 0x3c, 0x2f, 0x48, - 0x45, 0x41, 0x44, 0x3e, 0x0a, 0x3c, 0x42, 0x4f, - 0x44, 0x59, 0x20, 0x42, 0x47, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x3d, 0x22, 0x23, 0x63, 0x63, 0x39, - 0x39, 0x39, 0x39, 0x22, 0x3e, 0x3c, 0x48, 0x34, - 0x3e, 0x34, 0x30, 0x31, 0x20, 0x55, 0x6e, 0x61, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x3c, 0x2f, 0x48, 0x34, 0x3e, 0x0a, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x2e, 0x0a, 0x3c, - 0x48, 0x52, 0x3e, 0x0a, 0x3c, 0x41, 0x44, 0x44, - 0x52, 0x45, 0x53, 0x53, 0x3e, 0x3c, 0x41, 0x20, - 0x48, 0x52, 0x45, 0x46, 0x3d, 0x22, 0x68, 0x74, - 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, - 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x2f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x5f, 0x68, 0x74, 0x74, 0x70, 0x64, 0x2f, 0x22, - 0x3e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x5f, 0x68, - 0x74, 0x74, 0x70, 0x64, 0x3c, 0x2f, 0x41, 0x3e, - 0x3c, 0x2f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, - 0x53, 0x3e, 0x0a, 0x3c, 0x2f, 0x42, 0x4f, 0x44, - 0x59, 0x3e, 0x3c, 0x2f, 0x48, 0x54, 0x4d, 0x4c, - 0x3e, 0x0a - }; - - uint8_t pkt7[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x29, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6c, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8e, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xfa, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0x9c, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt8[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xa8, 0xbf, 0x40, 0x00, 0x40, 0x06, - 0x0d, 0xd7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8e, 0x17, 0x51, 0x83, 0x94, 0x80, 0x11, - 0x00, 0x2d, 0x5a, 0x0b, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x23, 0x6a, 0x01, 0x72, - 0x40, 0x93 - }; - - uint8_t pkt9[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2a, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6b, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x10, - 0x00, 0x36, 0x59, 0xef, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x40, 0xa6, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt10[] = { - 0x00, 0x1a, 0x2b, 0x19, 0x52, 0xa8, 0x00, 0x13, - 0x20, 0x65, 0x1a, 0x9e, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0xc2, 0x2b, 0x40, 0x00, 0x40, 0x06, - 0xf4, 0x6a, 0xc0, 0xa8, 0x01, 0xdc, 0xc0, 0xa8, - 0x01, 0x01, 0xe7, 0xf5, 0x00, 0x50, 0x17, 0x51, - 0x83, 0x94, 0x21, 0x04, 0x8d, 0x8f, 0x80, 0x11, - 0x00, 0x36, 0x57, 0x0a, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x72, 0x43, 0x8a, 0x01, 0x29, - 0x23, 0x6a - }; - - uint8_t pkt11[] = { - 0x00, 0x13, 0x20, 0x65, 0x1a, 0x9e, 0x00, 0x1a, - 0x2b, 0x19, 0x52, 0xa8, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x34, 0x10, 0xaf, 0x40, 0x00, 0x40, 0x06, - 0xa5, 0xe7, 0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, - 0x01, 0xdc, 0x00, 0x50, 0xe7, 0xf5, 0x21, 0x04, - 0x8d, 0x8f, 0x17, 0x51, 0x83, 0x95, 0x80, 0x10, - 0x00, 0x2d, 0x54, 0xbb, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x0a, 0x01, 0x29, 0x25, 0xc2, 0x01, 0x72, - 0x43, 0x8a - }; - - uint8_t *pkts[] = { - pkt1, pkt2, pkt3, pkt4, pkt5, pkt6, pkt7, pkt8, - pkt9, pkt10, pkt11 - }; - - uint16_t pktssizes[] = { - sizeof(pkt1), sizeof(pkt2), sizeof(pkt3), sizeof(pkt4), sizeof(pkt5), - sizeof(pkt6), sizeof(pkt7), sizeof(pkt8), sizeof(pkt9), sizeof(pkt10), - sizeof(pkt11) - }; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; - + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - - memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); - FlowInitConfig(FLOW_QUIET); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; - /* Now that we have the array of packets for the flow, prepare the signatures */ - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"); - - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: other,isset; sid:102;)"); - - de_ctx->sig_list->next->next = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; flowint:lala,isset; sid:103;)"); - - de_ctx->sig_list->next->next->next = NULL; + char *sigs[3]; + sigs[0] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"GET\"; flowint: myvar, notset; flowint: myvar,=,0; flowint: other,=,10; sid:101;)"; + sigs[1] = "alert tcp any any -> any any (msg:\"check isset\"; content:\"Unauthorized\"; flowint:myvar,isset; flowint: other,isset; sid:102;)"; + sigs[2] = "alert tcp any any -> any any (msg:\"check notset\"; content:\"Unauthorized\"; flowint:lala,isset; sid:103;)"; + FAIL_IF(UTHAppendSigs(de_ctx, sigs, 3) == 0); + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *) de_ctx,(void *) &det_ctx); - int i; - - /* Decode the packets, and test the matches*/ - for (i = 0;i < 11;i++) { - memset(p, 0, SIZE_OF_PACKET); - PACKET_INITIALIZE(p); - DecodeEthernet(&th_v, &dtv, p, pkts[i], pktssizes[i], NULL); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - - switch(i) { - case 3: - if (PacketAlertCheck(p, 101) == 0) { - SCLogDebug("Not declared/initialized but match!"); - result = 0; - } - if (PacketAlertCheck(p, 103) != 0) { - SCLogDebug(" var lala is never set, it should NOT match!!"); - result = 0; - } - break; - case 5: - if (PacketAlertCheck(p, 102) == 0) { - SCLogDebug("Not incremented!"); - result = 0; - } - - if (PacketAlertCheck(p, 103) != 0) { - SCLogDebug(" var lala is never set, it should NOT match!!"); - result = 0; - } - break; - } - SCLogDebug("Raw Packet %d has %u alerts ", i, p->alerts.cnt); - PACKET_RECYCLE(p); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - + Flow *f = UTHBuildFlow(AF_INET, "192.168.1.5", "192.168.1.1", + 41424, 80); + FAIL_IF(f == NULL); + f->proto = IPPROTO_TCP; + + p = UTHBuildPacket((uint8_t *)"GET", 3, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 101)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"Unauthorized", 12, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 102)); + FAIL_IF(PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + p = UTHBuildPacket((uint8_t *)"1", 1, IPPROTO_TCP); + FAIL_IF(p == NULL); + p->flow = f; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(PacketAlertCheck(p, 102)); + FAIL_IF(PacketAlertCheck(p, 103)); + UTHFreePacket(p); + + UTHFreeFlow(f); DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - SCFree(p); - return result; -end: - if (de_ctx) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v,(void *) det_ctx); - //PatternMatchDestroy(mpm_ctx); - if (de_ctx) - DetectEngineCtxFree(de_ctx); - - FlowShutdown(); - SCFree(p); - return result; + PASS; } #endif /* UNITTESTS */ @@ -2119,51 +1308,33 @@ int DetectFlowintTestPacket03Real() void DetectFlowintRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectFlowintTestParseVal01", - DetectFlowintTestParseVal01, 1); - UtRegisterTest("DetectFlowintTestParseVar01", - DetectFlowintTestParseVar01, 1); - UtRegisterTest("DetectFlowintTestParseVal02", - DetectFlowintTestParseVal02, 1); - UtRegisterTest("DetectFlowintTestParseVar02", - DetectFlowintTestParseVar02, 1); - UtRegisterTest("DetectFlowintTestParseVal03", - DetectFlowintTestParseVal03, 1); - UtRegisterTest("DetectFlowintTestParseVar03", - DetectFlowintTestParseVar03, 1); - UtRegisterTest("DetectFlowintTestParseVal04", - DetectFlowintTestParseVal04, 1); - UtRegisterTest("DetectFlowintTestParseVar04", - DetectFlowintTestParseVar04, 1); - UtRegisterTest("DetectFlowintTestParseVal05", - DetectFlowintTestParseVal05, 1); - UtRegisterTest("DetectFlowintTestParseVar05", - DetectFlowintTestParseVar05, 1); - UtRegisterTest("DetectFlowintTestParseVal06", - DetectFlowintTestParseVal06, 1); - UtRegisterTest("DetectFlowintTestParseVar06", - DetectFlowintTestParseVar06, 1); - UtRegisterTest("DetectFlowintTestParseVal07", - DetectFlowintTestParseVal07, 1); - UtRegisterTest("DetectFlowintTestParseVar07", - DetectFlowintTestParseVar07, 1); - UtRegisterTest("DetectFlowintTestParseVal08", - DetectFlowintTestParseVal08, 1); - UtRegisterTest("DetectFlowintTestParseVar08", - DetectFlowintTestParseVar08, 1); - UtRegisterTest("DetectFlowintTestParseVal09", - DetectFlowintTestParseVal09, 1); - UtRegisterTest("DetectFlowintTestParseVar09", - DetectFlowintTestParseVar09, 1); + UtRegisterTest("DetectFlowintTestParseVal01", DetectFlowintTestParseVal01); + UtRegisterTest("DetectFlowintTestParseVar01", DetectFlowintTestParseVar01); + UtRegisterTest("DetectFlowintTestParseVal02", DetectFlowintTestParseVal02); + UtRegisterTest("DetectFlowintTestParseVar02", DetectFlowintTestParseVar02); + UtRegisterTest("DetectFlowintTestParseVal03", DetectFlowintTestParseVal03); + UtRegisterTest("DetectFlowintTestParseVar03", DetectFlowintTestParseVar03); + UtRegisterTest("DetectFlowintTestParseVal04", DetectFlowintTestParseVal04); + UtRegisterTest("DetectFlowintTestParseVar04", DetectFlowintTestParseVar04); + UtRegisterTest("DetectFlowintTestParseVal05", DetectFlowintTestParseVal05); + UtRegisterTest("DetectFlowintTestParseVar05", DetectFlowintTestParseVar05); + UtRegisterTest("DetectFlowintTestParseVal06", DetectFlowintTestParseVal06); + UtRegisterTest("DetectFlowintTestParseVar06", DetectFlowintTestParseVar06); + UtRegisterTest("DetectFlowintTestParseVal07", DetectFlowintTestParseVal07); + UtRegisterTest("DetectFlowintTestParseVar07", DetectFlowintTestParseVar07); + UtRegisterTest("DetectFlowintTestParseVal08", DetectFlowintTestParseVal08); + UtRegisterTest("DetectFlowintTestParseVar08", DetectFlowintTestParseVar08); + UtRegisterTest("DetectFlowintTestParseVal09", DetectFlowintTestParseVal09); + UtRegisterTest("DetectFlowintTestParseVar09", DetectFlowintTestParseVar09); UtRegisterTest("DetectFlowintTestParseIsset10", - DetectFlowintTestParseIsset10, 1); + DetectFlowintTestParseIsset10); UtRegisterTest("DetectFlowintTestParseInvalidSyntaxis01", - DetectFlowintTestParseInvalidSyntaxis01, 1); + DetectFlowintTestParseInvalidSyntaxis01); UtRegisterTest("DetectFlowintTestPacket01Real", - DetectFlowintTestPacket01Real, 1); + DetectFlowintTestPacket01Real); UtRegisterTest("DetectFlowintTestPacket02Real", - DetectFlowintTestPacket02Real, 1); + DetectFlowintTestPacket02Real); UtRegisterTest("DetectFlowintTestPacket03Real", - DetectFlowintTestPacket03Real, 1); + DetectFlowintTestPacket03Real); #endif /* UNITTESTS */ } diff --git a/src/detect-flowint.h b/src/detect-flowint.h index 973321ad0df7..9caf68258cc7 100644 --- a/src/detect-flowint.h +++ b/src/detect-flowint.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -55,7 +55,6 @@ enum { /** If the target is another var, get the name and the idx */ typedef struct TargetVar_ { - uint16_t idx; char *name; } TargetVar; @@ -65,7 +64,7 @@ typedef struct DetectFlowintData_ { * against the target */ char *name; /* Internal id of the var */ - uint16_t idx; + uint32_t idx; /* The modifier/operation/condition we are * going to execute */ diff --git a/src/detect-flowvar.c b/src/detect-flowvar.c index b9f9696079fc..bd7ff4038cf6 100644 --- a/src/detect-flowvar.c +++ b/src/detect-flowvar.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -33,6 +33,7 @@ #include "threads.h" #include "flow.h" #include "flow-var.h" +#include "pkt-var.h" #include "detect-flowvar.h" #include "util-spm.h" @@ -44,9 +45,11 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectFlowvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFlowvarSetup (DetectEngineCtx *, Signature *, char *); -static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm); +static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx); static void DetectFlowvarDataFree(void *ptr); void DetectFlowvarRegister (void) @@ -64,28 +67,7 @@ void DetectFlowvarRegister (void) sigmatch_table[DETECT_FLOWVAR_POSTMATCH].Free = DetectFlowvarDataFree; sigmatch_table[DETECT_FLOWVAR_POSTMATCH].RegisterTests = NULL; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -114,13 +96,11 @@ static void DetectFlowvarDataFree(void *ptr) * -1: error */ -int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; - DetectFlowvarData *fd = (DetectFlowvarData *)m->ctx; - - /* we need a lock */ - FLOWLOCK_RDLOCK(p->flow); + DetectFlowvarData *fd = (DetectFlowvarData *)ctx; FlowVar *fv = FlowVarGet(p->flow, fd->idx); if (fv != NULL) { @@ -130,7 +110,6 @@ int DetectFlowvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p if (ptr != NULL) ret = 1; } - FLOWLOCK_UNLOCK(p->flow); return ret; } @@ -188,7 +167,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws fd->name = SCStrdup(varname); if (unlikely(fd->name == NULL)) goto error; - fd->idx = VariableNameGetIdx(de_ctx, varname, DETECT_FLOWVAR); + fd->idx = VarNameStoreSetupAdd(varname, VAR_TYPE_FLOW_VAR); /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -197,7 +176,7 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws goto error; sm->type = DETECT_FLOWVAR; - sm->ctx = (void *)fd; + sm->ctx = (SigMatchCtx *)fd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -214,12 +193,32 @@ static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *raws return -1; } +/** \brief Store flowvar in det_ctx so we can exec it post-match */ +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *det_ctx, + uint8_t *key, uint16_t key_len, + uint8_t *buffer, uint16_t len, int type) +{ + DetectVarList *fs = SCCalloc(1, sizeof(*fs)); + if (unlikely(fs == NULL)) + return -1; + + fs->len = len; + fs->type = type; + fs->buffer = buffer; + fs->key = key; + fs->key_len = key_len; + + fs->next = det_ctx->varlist; + det_ctx->varlist = fs; + return 0; +} /** \brief Store flowvar in det_ctx so we can exec it post-match */ -int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint16_t idx, +int DetectVarStoreMatch(DetectEngineThreadCtx *det_ctx, + uint32_t idx, uint8_t *buffer, uint16_t len, int type) { - DetectFlowvarList *fs = det_ctx->flowvarlist; + DetectVarList *fs = det_ctx->varlist; /* first check if we have had a previous match for this idx */ for ( ; fs != NULL; fs = fs->next) { @@ -232,14 +231,14 @@ int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint16_t idx, } if (fs == NULL) { - fs = SCMalloc(sizeof(*fs)); + fs = SCCalloc(1, sizeof(*fs)); if (unlikely(fs == NULL)) return -1; fs->idx = idx; - fs->next = det_ctx->flowvarlist; - det_ctx->flowvarlist = fs; + fs->next = det_ctx->varlist; + det_ctx->varlist = fs; } fs->len = len; @@ -251,7 +250,7 @@ int DetectFlowvarStoreMatch(DetectEngineThreadCtx *det_ctx, uint16_t idx, /** \brief Setup a post-match for flowvar storage * We're piggyback riding the DetectFlowvarData struct */ -int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) +int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx) { SigMatch *sm = NULL; DetectFlowvarData *fv = NULL; @@ -269,7 +268,7 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) goto error; sm->type = DETECT_FLOWVAR_POSTMATCH; - sm->ctx = (void *)fv; + sm->ctx = (SigMatchCtx *)fv; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); return 0; @@ -284,31 +283,49 @@ int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx) * \param sm sigmatch containing the idx to store * \retval 1 or -1 in case of error */ -static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) +static int DetectFlowvarPostMatch(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectFlowvarList *fs, *prev; - DetectFlowvarData *fd; + DetectVarList *fs, *prev; + const DetectFlowvarData *fd; - if (det_ctx->flowvarlist == NULL || p->flow == NULL) + if (det_ctx->varlist == NULL) return 1; - fd = (DetectFlowvarData *)sm->ctx; + fd = (const DetectFlowvarData *)ctx; prev = NULL; - fs = det_ctx->flowvarlist; + fs = det_ctx->varlist; while (fs != NULL) { - if (fd->idx == fs->idx) { + if (fd->idx == 0 || fd->idx == fs->idx) { SCLogDebug("adding to the flow %u:", fs->idx); //PrintRawDataFp(stdout, fs->buffer, fs->len); - FlowVarAddStr(p->flow, fs->idx, fs->buffer, fs->len); - /* memory at fs->buffer is now the responsibility of - * the flowvar code. */ + if (fs->type == DETECT_VAR_TYPE_FLOW_POSTMATCH && p && p->flow) { + FlowVarAddIdValue(p->flow, fs->idx, fs->buffer, fs->len); + /* memory at fs->buffer is now the responsibility of + * the flowvar code. */ + } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && fs->key && p) { + /* pkt key/value */ + if (PktVarAddKeyValue(p, (uint8_t *)fs->key, fs->key_len, + (uint8_t *)fs->buffer, fs->len) == -1) + { + SCFree(fs->key); + SCFree(fs->buffer); + /* the rest of fs is freed below */ + } + } else if (fs->type == DETECT_VAR_TYPE_PKT_POSTMATCH && p) { + if (PktVarAdd(p, fs->idx, fs->buffer, fs->len) == -1) { + SCFree(fs->buffer); + /* the rest of fs is freed below */ + } + } - if (fs == det_ctx->flowvarlist) { - det_ctx->flowvarlist = fs->next; + if (fs == det_ctx->varlist) { + det_ctx->varlist = fs->next; SCFree(fs); - fs = det_ctx->flowvarlist; + fs = det_ctx->varlist; } else { prev->next = fs->next; SCFree(fs); @@ -322,36 +339,22 @@ static int DetectFlowvarPostMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx return 1; } -/** \brief Handle flowvar candidate list in det_ctx: - * - clean up the list - * - enforce storage for type ALWAYS (luajit) */ -void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f) +/** \brief Handle flowvar candidate list in det_ctx: clean up the list + * + * Only called from DetectVarProcessList() when varlist is not NULL. + */ +void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p) { - DetectFlowvarList *fs, *next; - - SCLogDebug("det_ctx->flowvarlist %p", det_ctx->flowvarlist); + DetectVarList *next; - if (det_ctx->flowvarlist != NULL) { - fs = det_ctx->flowvarlist; - while (fs != NULL) { - next = fs->next; + do { + next = fs->next; - if (fs->type == DETECT_FLOWVAR_TYPE_ALWAYS) { - BUG_ON(f == NULL); - SCLogDebug("adding to the flow %u:", fs->idx); - //PrintRawDataFp(stdout, fs->buffer, fs->len); - - FlowVarAddStr(f, fs->idx, fs->buffer, fs->len); - /* memory at fs->buffer is now the responsibility of - * the flowvar code. */ - } else { - SCFree(fs->buffer); - } - SCFree(fs); - fs = next; + if (fs->key) { + SCFree(fs->key); } - - det_ctx->flowvarlist = NULL; - } + SCFree(fs->buffer); + SCFree(fs); + fs = next; + } while (fs != NULL); } - diff --git a/src/detect-flowvar.h b/src/detect-flowvar.h index a2975f05210c..f919c3b031ea 100644 --- a/src/detect-flowvar.h +++ b/src/detect-flowvar.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -26,7 +26,7 @@ typedef struct DetectFlowvarData_ { char *name; - uint16_t idx; + uint32_t idx; uint8_t *content; uint8_t content_len; uint8_t flags; @@ -35,9 +35,23 @@ typedef struct DetectFlowvarData_ { /* prototypes */ void DetectFlowvarRegister (void); -int DetectFlowvarPostMatchSetup(Signature *s, uint16_t idx); -int DetectFlowvarStoreMatch(DetectEngineThreadCtx *, uint16_t, uint8_t *, uint16_t, int); -void DetectFlowvarProcessList(DetectEngineThreadCtx *det_ctx, Flow *); +int DetectFlowvarPostMatchSetup(Signature *s, uint32_t idx); +int DetectVarStoreMatch(DetectEngineThreadCtx *, + uint32_t, uint8_t *, uint16_t, int); +int DetectVarStoreMatchKeyValue(DetectEngineThreadCtx *, + uint8_t *, uint16_t, uint8_t *, uint16_t, int); -#endif /* __DETECT_FLOWVAR_H__ */ +/* For use only by DetectFlowvarProcessList() */ +void DetectVarProcessListInternal(DetectVarList *fs, Flow *f, Packet *p); +static inline void DetectVarProcessList(DetectEngineThreadCtx *det_ctx, Flow *f, Packet *p) +{ + DetectVarList *fs = det_ctx->varlist; + + SCLogDebug("flow %p det_ctx->varlist %p", f, fs); + if ((f || p) && fs != NULL) { + det_ctx->varlist = NULL; + DetectVarProcessListInternal(fs, f, p); + } +} +#endif /* __DETECT_FLOWVAR_H__ */ diff --git a/src/detect-fragbits.c b/src/detect-fragbits.c index 2be69b76d2eb..fd1fbf18a3b2 100644 --- a/src/detect-fragbits.c +++ b/src/detect-fragbits.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -19,6 +19,7 @@ * \file * * \author Breno Silva + * \author Victor Julien * * Implements fragbits keyword */ @@ -29,6 +30,8 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "flow-var.h" #include "decode-events.h" @@ -65,10 +68,14 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectFragBitsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectFragBitsSetup (DetectEngineCtx *, Signature *, char *); static void DetectFragBitsFree(void *); +static int PrefilterSetupFragBits(SigGroupHead *sgh); +static _Bool PrefilterFragBitsIsPrefilterable(const Signature *s); + /** * \brief Registration function for fragbits: keyword */ @@ -77,33 +84,43 @@ void DetectFragBitsRegister (void) { sigmatch_table[DETECT_FRAGBITS].name = "fragbits"; sigmatch_table[DETECT_FRAGBITS].desc = "check if the fragmentation and reserved bits are set in the IP header"; - sigmatch_table[DETECT_FRAGBITS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Fragbits"; + sigmatch_table[DETECT_FRAGBITS].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#fragbits"; sigmatch_table[DETECT_FRAGBITS].Match = DetectFragBitsMatch; sigmatch_table[DETECT_FRAGBITS].Setup = DetectFragBitsSetup; sigmatch_table[DETECT_FRAGBITS].Free = DetectFragBitsFree; sigmatch_table[DETECT_FRAGBITS].RegisterTests = FragBitsRegisterTests; - const char *eb; - int opts = 0; - int eo; + sigmatch_table[DETECT_FRAGBITS].SetupPrefilter = PrefilterSetupFragBits; + sigmatch_table[DETECT_FRAGBITS].SupportsPrefilter = PrefilterFragBitsIsPrefilterable; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } +static inline int +FragBitsMatch(const uint8_t pbits, const uint8_t modifier, + const uint8_t dbits) +{ + switch (modifier) { + case MODIFIER_ANY: + if ((pbits & dbits) > 0) + return 1; + return 0; -error: - return; + case MODIFIER_PLUS: + if (((pbits & dbits) == dbits) && (((pbits - dbits) > 0))) + return 1; + return 0; + + case MODIFIER_NOT: + if ((pbits & dbits) != dbits) + return 1; + return 0; + default: + if (pbits == dbits) + return 1; + } + return 0; } /** @@ -119,15 +136,14 @@ void DetectFragBitsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint16_t fragbits = 0; - DetectFragBitsData *de = (DetectFragBitsData *)m->ctx; - - if (!de || !PKT_IS_IPV4(p) || !p || PKT_IS_PSEUDOPKT(p)) - return ret; + if (!ctx || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) + return 0; + uint8_t fragbits = 0; + const DetectFragBitsData *de = (const DetectFragBitsData *)ctx; if(IPV4_GET_MF(p)) fragbits |= FRAGBITS_HAVE_MF; if(IPV4_GET_DF(p)) @@ -135,25 +151,7 @@ static int DetectFragBitsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, P if(IPV4_GET_RF(p)) fragbits |= FRAGBITS_HAVE_RF; - switch(de->modifier) { - case MODIFIER_ANY: - if((fragbits & de->fragbits) > 0) - return 1; - return ret; - case MODIFIER_PLUS: - if(((fragbits & de->fragbits) == de->fragbits) && (((fragbits - de->fragbits) > 0))) - return 1; - return ret; - case MODIFIER_NOT: - if((fragbits & de->fragbits) != de->fragbits) - return 1; - return ret; - default: - if(fragbits == de->fragbits) - return 1; - } - - return ret; + return FragBitsMatch(fragbits, de->modifier, de->fragbits); } /** @@ -302,7 +300,7 @@ static int DetectFragBitsSetup (DetectEngineCtx *de_ctx, Signature *s, char *raw goto error; sm->type = DETECT_FRAGBITS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -327,6 +325,68 @@ static void DetectFragBitsFree(void *de_ptr) if(de) SCFree(de); } +static void +PrefilterPacketFragBitsMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) + return; + + uint8_t fragbits = 0; + if (IPV4_GET_MF(p)) + fragbits |= FRAGBITS_HAVE_MF; + if (IPV4_GET_DF(p)) + fragbits |= FRAGBITS_HAVE_DF; + if (IPV4_GET_RF(p)) + fragbits |= FRAGBITS_HAVE_RF; + + if (FragBitsMatch(fragbits, ctx->v1.u8[0], ctx->v1.u8[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFragBitsSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFragBitsData *fb = smctx; + v->u8[0] = fb->modifier; + v->u8[1] = fb->fragbits; +} + +static _Bool +PrefilterPacketFragBitsCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFragBitsData *fb = smctx; + if (v.u8[0] == fb->modifier && + v.u8[1] == fb->fragbits) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFragBits(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FRAGBITS, + PrefilterPacketFragBitsSet, + PrefilterPacketFragBitsCompare, + PrefilterPacketFragBitsMatch); +} + +static _Bool PrefilterFragBitsIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FRAGBITS: + return TRUE; + } + } + return FALSE; +} + /* * ONLY TESTS BELOW THIS COMMENT */ @@ -362,10 +422,10 @@ static int FragBitsTestParse02 (void) de = DetectFragBitsParse("G"); if (de) { DetectFragBitsFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -446,9 +506,9 @@ static int FragBitsTestParse03 (void) goto error; sm->type = DETECT_FRAGBITS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFragBitsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFragBitsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -544,9 +604,9 @@ static int FragBitsTestParse04 (void) goto error; sm->type = DETECT_FRAGBITS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectFragBitsMatch(&tv,NULL,p,NULL,sm); + ret = DetectFragBitsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { if (de) SCFree(de); @@ -554,16 +614,17 @@ static int FragBitsTestParse04 (void) PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); - return 0; + return 1; } #endif /* UNITTESTS */ @@ -573,9 +634,9 @@ static int FragBitsTestParse04 (void) void FragBitsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FragBitsTestParse01", FragBitsTestParse01, 1); - UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02, 0); - UtRegisterTest("FragBitsTestParse03", FragBitsTestParse03, 1); - UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04, 0); + UtRegisterTest("FragBitsTestParse01", FragBitsTestParse01); + UtRegisterTest("FragBitsTestParse02", FragBitsTestParse02); + UtRegisterTest("FragBitsTestParse03", FragBitsTestParse03); + UtRegisterTest("FragBitsTestParse04", FragBitsTestParse04); #endif /* UNITTESTS */ } diff --git a/src/detect-fragbits.h b/src/detect-fragbits.h index 2fdf03237ee8..d85886670334 100644 --- a/src/detect-fragbits.h +++ b/src/detect-fragbits.h @@ -39,7 +39,7 @@ */ typedef struct DetectFragBitsData_ { - uint16_t fragbits; /**< TCP fragbits */ + uint8_t fragbits; /**< IP fragbits */ uint8_t modifier; /**< !(1) +(2) *(3) modifiers */ } DetectFragBitsData; diff --git a/src/detect-fragoffset.c b/src/detect-fragoffset.c index 3c5cc1697daf..5f7a9ec2ed6a 100644 --- a/src/detect-fragoffset.c +++ b/src/detect-fragoffset.c @@ -31,6 +31,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-fragoffset.h" @@ -43,11 +44,15 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectFragOffsetMatch(ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); static int DetectFragOffsetSetup(DetectEngineCtx *, Signature *, char *); void DetectFragOffsetRegisterTests(void); void DetectFragOffsetFree(void *); +static int PrefilterSetupFragOffset(SigGroupHead *sgh); +static _Bool PrefilterFragOffsetIsPrefilterable(const Signature *s); + /** * \brief Registration function for fragoffset */ @@ -55,31 +60,35 @@ void DetectFragOffsetRegister (void) { sigmatch_table[DETECT_FRAGOFFSET].name = "fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].desc = "match on specific decimal values of the IP fragment offset field"; - sigmatch_table[DETECT_FRAGOFFSET].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Fragoffset"; + sigmatch_table[DETECT_FRAGOFFSET].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#fragoffset"; sigmatch_table[DETECT_FRAGOFFSET].Match = DetectFragOffsetMatch; sigmatch_table[DETECT_FRAGOFFSET].Setup = DetectFragOffsetSetup; sigmatch_table[DETECT_FRAGOFFSET].Free = DetectFragOffsetFree; sigmatch_table[DETECT_FRAGOFFSET].RegisterTests = DetectFragOffsetRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_FRAGOFFSET].SupportsPrefilter = PrefilterFragOffsetIsPrefilterable; + sigmatch_table[DETECT_FRAGOFFSET].SetupPrefilter = PrefilterSetupFragOffset; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; +static inline int FragOffsetMatch(const uint16_t poffset, const uint8_t mode, + const uint16_t doffset) +{ + switch (mode) { + case FRAG_LESS: + if (poffset < doffset) + return 1; + break; + case FRAG_MORE: + if (poffset > doffset) + return 1; + break; + default: + if (poffset == doffset) + return 1; } - return; - -error: - return; + return 0; } /** @@ -94,10 +103,11 @@ void DetectFragOffsetRegister (void) * \retval 1 match * */ -int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *ctx) { uint16_t frag = 0; - DetectFragOffsetData *fragoff = (DetectFragOffsetData *)m->ctx; + const DetectFragOffsetData *fragoff = (const DetectFragOffsetData *)ctx; if (PKT_IS_PSEUDOPKT(p)) return 0; @@ -105,7 +115,7 @@ int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet if (PKT_IS_IPV4(p)) { frag = IPV4_GET_IPOFFSET(p); } else if (PKT_IS_IPV6(p)) { - if(IPV6_EXTHDR_FH(p)) { + if (IPV6_EXTHDR_ISSET_FH(p)) { frag = IPV6_EXTHDR_GET_FH_OFFSET(p); } else { return 0; @@ -115,18 +125,7 @@ int DetectFragOffsetMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet return 0; } - switch (fragoff->mode) { - case FRAG_LESS: - if (frag < fragoff->frag_off) return 1; - break; - case FRAG_MORE: - if (frag > fragoff->frag_off) return 1; - break; - default: - if (frag == fragoff->frag_off) return 1; - } - - return 0; + return FragOffsetMatch(frag, fragoff->mode, fragoff->frag_off);; } /** @@ -230,7 +229,7 @@ static int DetectFragOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *f if (sm == NULL) goto error; sm->type = DETECT_FRAGOFFSET; - sm->ctx = (void *)fragoff; + sm->ctx = (SigMatchCtx *)fragoff; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -255,9 +254,75 @@ void DetectFragOffsetFree (void *ptr) SCFree(fragoff); } -#ifdef UNITTESTS +static void +PrefilterPacketFragOffsetMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) + return; -#include "detect-parse.h" + uint16_t frag; + + if (PKT_IS_IPV4(p)) { + frag = IPV4_GET_IPOFFSET(p); + } else if (PKT_IS_IPV6(p)) { + if (IPV6_EXTHDR_ISSET_FH(p)) { + frag = IPV6_EXTHDR_GET_FH_OFFSET(p); + } else { + return; + } + } else { + SCLogDebug("No IPv4 or IPv6 packet"); + return; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + if (FragOffsetMatch(frag, ctx->v1.u8[0], ctx->v1.u16[1])) + { + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketFragOffsetSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectFragOffsetData *fb = smctx; + v->u8[0] = fb->mode; + v->u16[1] = fb->frag_off; +} + +static _Bool +PrefilterPacketFragOffsetCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectFragOffsetData *fb = smctx; + if (v.u8[0] == fb->mode && + v.u16[1] == fb->frag_off) + { + return TRUE; + } + return FALSE; +} + +static int PrefilterSetupFragOffset(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_FRAGOFFSET, + PrefilterPacketFragOffsetSet, + PrefilterPacketFragOffsetCompare, + PrefilterPacketFragOffsetMatch); +} + +static _Bool PrefilterFragOffsetIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_FRAGOFFSET: + return TRUE; + } + } + return FALSE; +} + +#ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -299,9 +364,9 @@ int DetectFragOffsetParseTest03 (void) fragoff = DetectFragOffsetParse("badc"); if (fragoff != NULL) { DetectFragOffsetFree(fragoff); - return 1; + return 0; } - return 0; + return 1; } /** @@ -387,10 +452,10 @@ int DetectFragOffsetMatchTest01 (void) void DetectFragOffsetRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01, 1); - UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02, 1); - UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03, 0); - UtRegisterTest("DetectFragOffsetMatchTest01", DetectFragOffsetMatchTest01, 1); + UtRegisterTest("DetectFragOffsetParseTest01", DetectFragOffsetParseTest01); + UtRegisterTest("DetectFragOffsetParseTest02", DetectFragOffsetParseTest02); + UtRegisterTest("DetectFragOffsetParseTest03", DetectFragOffsetParseTest03); + UtRegisterTest("DetectFragOffsetMatchTest01", DetectFragOffsetMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-ftpbounce.c b/src/detect-ftpbounce.c index 39e1c5a2a027..8e33aaf9d0dc 100644 --- a/src/detect-ftpbounce.c +++ b/src/detect-ftpbounce.c @@ -47,15 +47,19 @@ #include "stream-tcp.h" #include "util-byte.h" -int DetectFtpbounceMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); -int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); +static int DetectFtpbounceALMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); + static int DetectFtpbounceSetup(DetectEngineCtx *, Signature *, char *); -int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, - uint32_t ip_orig, uint16_t offset); -void DetectFtpbounceRegisterTests(void); -void DetectFtpbounceFree(void *); +static void DetectFtpbounceRegisterTests(void); +static int g_ftp_request_list_id = 0; + +static int InspectFtpRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); /** * \brief Registration function for ftpbounce: keyword @@ -65,13 +69,24 @@ void DetectFtpbounceRegister(void) { sigmatch_table[DETECT_FTPBOUNCE].name = "ftpbounce"; sigmatch_table[DETECT_FTPBOUNCE].Setup = DetectFtpbounceSetup; - sigmatch_table[DETECT_FTPBOUNCE].Match = NULL; - sigmatch_table[DETECT_FTPBOUNCE].AppLayerMatch = DetectFtpbounceALMatch; - sigmatch_table[DETECT_FTPBOUNCE].alproto = ALPROTO_FTP; - sigmatch_table[DETECT_FTPBOUNCE].Free = NULL; + sigmatch_table[DETECT_FTPBOUNCE].AppLayerTxMatch = DetectFtpbounceALMatch; sigmatch_table[DETECT_FTPBOUNCE].RegisterTests = DetectFtpbounceRegisterTests; sigmatch_table[DETECT_FTPBOUNCE].flags = SIGMATCH_NOOPT; - return; + + g_ftp_request_list_id = DetectBufferTypeRegister("ftp_request"); + + DetectAppLayerInspectEngineRegister("ftp_request", + ALPROTO_FTP, SIG_FLAG_TOSERVER, InspectFtpRequest); +} + +static int InspectFtpRequest(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } /** @@ -84,7 +99,7 @@ void DetectFtpbounceRegister(void) * * \retval 1 if ftpbounce detected, 0 if not */ -int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, +static int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, uint32_t ip_orig, uint16_t offset) { SCEnter(); @@ -169,19 +184,20 @@ int DetectFtpbounceMatchArgs(uint8_t *payload, uint16_t payload_len, * \retval 0 no match * \retval 1 match */ -int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, - SigMatch *m) +static int DetectFtpbounceALMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, + void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - FtpState *ftp_state =(FtpState *)state; + + FtpState *ftp_state = (FtpState *)state; if (ftp_state == NULL) { SCLogDebug("no ftp state, no match"); SCReturnInt(0); } int ret = 0; - if (ftp_state->command == FTP_COMMAND_PORT) { ret = DetectFtpbounceMatchArgs(ftp_state->port_line, ftp_state->port_line_len, f->src.address.address_un_data32[0], @@ -209,9 +225,12 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_FTP) != 0) + return -1; + sm = SigMatchAlloc(); if (sm == NULL) { - goto error;; + return -1; } sm->type = DETECT_FTPBOUNCE; @@ -227,22 +246,8 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces */ sm->ctx = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_FTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - - s->alproto = ALPROTO_FTP; - s->flags |= SIG_FLAG_APPLAYER; + SigMatchAppendSMToList(s, sm, g_ftp_request_list_id); SCReturnInt(0); - -error: - if (sm != NULL) { - SigMatchFree(sm); - } - SCReturnInt(-1); } #ifdef UNITTESTS @@ -250,20 +255,19 @@ int DetectFtpbounceSetup(DetectEngineCtx *de_ctx, Signature *s, char *ftpbounces /** * \test DetectFtpbounceTestSetup01 is a test for the Setup ftpbounce */ -int DetectFtpbounceTestSetup01(void) +static int DetectFtpbounceTestSetup01(void) { - int res = 0; DetectEngineCtx *de_ctx = NULL; Signature *s = SigAlloc(); - if (s == NULL) - return 0; + FAIL_IF (s == NULL); /* ftpbounce doesn't accept options so the str is NULL */ - res = !DetectFtpbounceSetup(de_ctx, s, NULL); - res &= s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL && s->sm_lists[DETECT_SM_LIST_AMATCH]->type & DETECT_FTPBOUNCE; + FAIL_IF_NOT(DetectFtpbounceSetup(de_ctx, s, NULL) == 0); + FAIL_IF(s->sm_lists[g_ftp_request_list_id] == NULL); + FAIL_IF_NOT(s->sm_lists[g_ftp_request_list_id]->type & DETECT_FTPBOUNCE); SigFree(s); - return res; + PASS; } #include "stream-tcp-reassemble.h" @@ -330,40 +334,44 @@ static int DetectFtpbounceTestALMatch02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf3, ftplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf4, ftplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf4, ftplen4); if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -471,39 +479,43 @@ static int DetectFtpbounceTestALMatch03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v,(void *)de_ctx,(void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, ftpbuf1, ftplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, + STREAM_TOSERVER, ftpbuf1, ftplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf2, ftplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf2, ftplen2); if (r != 0) { SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf3, ftplen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf3, ftplen3); if (r != 0) { SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f,ALPROTO_FTP, STREAM_TOSERVER, ftpbuf4, ftplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER, + ftpbuf4, ftplen4); if (r != 0) { SCLogDebug("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FtpState *ftp_state = f.alstate; if (ftp_state == NULL) { @@ -551,10 +563,10 @@ static int DetectFtpbounceTestALMatch03(void) void DetectFtpbounceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectFtpbounceTestSetup01", DetectFtpbounceTestSetup01, 1); + UtRegisterTest("DetectFtpbounceTestSetup01", DetectFtpbounceTestSetup01); UtRegisterTest("DetectFtpbounceTestALMatch02", - DetectFtpbounceTestALMatch02, 1); + DetectFtpbounceTestALMatch02); UtRegisterTest("DetectFtpbounceTestALMatch03", - DetectFtpbounceTestALMatch03, 1); + DetectFtpbounceTestALMatch03); #endif /* UNITTESTS */ } diff --git a/src/detect-geoip.c b/src/detect-geoip.c index 5c7244969073..1af990c1e492 100644 --- a/src/detect-geoip.c +++ b/src/detect-geoip.c @@ -63,7 +63,7 @@ void DetectGeoipRegister(void) static int DetectGeoipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + const Signature *, const SigMatchCtx *); static int DetectGeoipSetup(DetectEngineCtx *, Signature *, char *); static void DetectGeoipRegisterTests(void); static void DetectGeoipDataFree(void *); @@ -131,7 +131,7 @@ static const char *GeolocateIPv4(GeoIP *geoengine, uint32_t ip) * \retval 0 no match * \retval 1 match */ -static int CheckGeoMatchIPv4(DetectGeoipData *geoipdata, uint32_t ip) +static int CheckGeoMatchIPv4(const DetectGeoipData *geoipdata, uint32_t ip) { const char *country; int i; @@ -165,9 +165,9 @@ static int CheckGeoMatchIPv4(DetectGeoipData *geoipdata, uint32_t ip) * \retval 1 match */ static int DetectGeoipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectGeoipData *geoipdata = (DetectGeoipData *)m->ctx; + const DetectGeoipData *geoipdata = (const DetectGeoipData *)ctx; int matches = 0; if (PKT_IS_PSEUDOPKT(p)) @@ -339,7 +339,7 @@ static int DetectGeoipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr) goto error; sm->type = DETECT_GEOIP; - sm->ctx = (void *)geoipdata; + sm->ctx = (SigMatchCtx *)geoipdata; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -597,21 +597,21 @@ static int GeoipMatchTest07(void) static void DetectGeoipRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("GeoipParseTest01", GeoipParseTest01, 1); - UtRegisterTest("GeoipParseTest02", GeoipParseTest02, 1); - UtRegisterTest("GeoipParseTest03", GeoipParseTest03, 1); - UtRegisterTest("GeoipParseTest04", GeoipParseTest04, 1); - UtRegisterTest("GeoipParseTest05", GeoipParseTest05, 1); - UtRegisterTest("GeoipParseTest06", GeoipParseTest06, 1); - UtRegisterTest("GeoipParseTest07", GeoipParseTest07, 1); - - UtRegisterTest("GeoipMatchTest01", GeoipMatchTest01, 1); - UtRegisterTest("GeoipMatchTest02", GeoipMatchTest02, 1); - UtRegisterTest("GeoipMatchTest03", GeoipMatchTest03, 1); - UtRegisterTest("GeoipMatchTest04", GeoipMatchTest04, 2); - UtRegisterTest("GeoipMatchTest05", GeoipMatchTest05, 1); - UtRegisterTest("GeoipMatchTest06", GeoipMatchTest06, 1); - UtRegisterTest("GeoipMatchTest07", GeoipMatchTest07, 2); + UtRegisterTest("GeoipParseTest01", GeoipParseTest01); + UtRegisterTest("GeoipParseTest02", GeoipParseTest02); + UtRegisterTest("GeoipParseTest03", GeoipParseTest03); + UtRegisterTest("GeoipParseTest04", GeoipParseTest04); + UtRegisterTest("GeoipParseTest05", GeoipParseTest05); + UtRegisterTest("GeoipParseTest06", GeoipParseTest06); + UtRegisterTest("GeoipParseTest07", GeoipParseTest07); + + UtRegisterTest("GeoipMatchTest01", GeoipMatchTest01); + UtRegisterTest("GeoipMatchTest02", GeoipMatchTest02); + UtRegisterTest("GeoipMatchTest03", GeoipMatchTest03); + UtRegisterTest("GeoipMatchTest04", GeoipMatchTest04); + UtRegisterTest("GeoipMatchTest05", GeoipMatchTest05); + UtRegisterTest("GeoipMatchTest06", GeoipMatchTest06); + UtRegisterTest("GeoipMatchTest07", GeoipMatchTest07); #endif /* UNITTESTS */ } diff --git a/src/detect-gid.c b/src/detect-gid.c index b25dc0157957..5fe93e494c86 100644 --- a/src/detect-gid.c +++ b/src/detect-gid.c @@ -36,8 +36,6 @@ #include "util-unittest.h" #include "util-debug.h" -#define PARSE_REGEX "[0-9]+" - static int DetectGidSetup (DetectEngineCtx *, Signature *, char *); /** @@ -48,7 +46,7 @@ void DetectGidRegister (void) { sigmatch_table[DETECT_GID].name = "gid"; sigmatch_table[DETECT_GID].desc = "give different groups of signatures another id value"; - sigmatch_table[DETECT_GID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Gid-group-id"; + sigmatch_table[DETECT_GID].url = DOC_URL DOC_VERSION "/rules/meta.html#gid-group-id"; sigmatch_table[DETECT_GID].Match = NULL; sigmatch_table[DETECT_GID].Setup = DetectGidSetup; sigmatch_table[DETECT_GID].Free = NULL; @@ -69,16 +67,18 @@ void DetectGidRegister (void) static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { char *str = rawstr; - char dubbed = 0; + char duped = 0; - /* strip "'s */ - if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') { - str = SCStrdup(rawstr+1); - if (unlikely(str == NULL)) + /* Strip leading and trailing "s. */ + if (rawstr[0] == '\"') { + str = SCStrdup(rawstr + 1); + if (unlikely(str == NULL)) { return -1; - - str[strlen(rawstr)-2] = '\0'; - dubbed = 1; + } + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\"'; + } + duped = 1; } unsigned long gid = 0; @@ -96,12 +96,12 @@ static int DetectGidSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) s->gid = (uint32_t)gid; - if (dubbed) + if (duped) SCFree(str); return 0; error: - if (dubbed) + if (duped) SCFree(str); return -1; } @@ -160,6 +160,31 @@ static int GidTestParse02 (void) DetectEngineCtxFree(de_ctx); return result; } + +/** + * \test Test a gid consisting of a single quote. + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int GidTestParse03 (void) +{ + int result = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + if (DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"ABC\"; gid:\";)") != NULL) + goto end; + + result = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} #endif /* UNITTESTS */ /** @@ -168,7 +193,8 @@ static int GidTestParse02 (void) void GidRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("GidTestParse01", GidTestParse01, 1); - UtRegisterTest("GidTestParse02", GidTestParse02, 1); + UtRegisterTest("GidTestParse01", GidTestParse01); + UtRegisterTest("GidTestParse02", GidTestParse02); + UtRegisterTest("GidTestParse03", GidTestParse03); #endif /* UNITTESTS */ } diff --git a/src/detect-hostbits.c b/src/detect-hostbits.c new file mode 100644 index 000000000000..bf1b728824d1 --- /dev/null +++ b/src/detect-hostbits.c @@ -0,0 +1,1240 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements the hostbits keyword + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "threads.h" +#include "flow.h" +#include "flow-util.h" +#include "detect-hostbits.h" +#include "util-spm.h" + +#include "detect-engine-sigorder.h" + +#include "app-layer-parser.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow-bit.h" +#include "host-bit.h" +#include "util-var-name.h" +#include "util-unittest.h" +#include "util-debug.h" + +/* + hostbits:isset,bitname; + hostbits:set,bitname; + + hostbits:set,bitname,src; + hostbits:set,bitname,dst; +TODO: + hostbits:set,bitname,both; + + hostbits:set,bitname,src,3600; + hostbits:set,bitname,dst,60; + hostbits:set,bitname,both,120; + */ + +#define PARSE_REGEX "([a-z]+)" /* Action */ \ + "(?:\\s*,\\s*([^\\s,]+))?(?:\\s*)?" /* Name. */ \ + "(?:\\s*,\\s*([^,\\s]+))?(?:\\s*)?" /* Direction. */ \ + "(.+)?" /* Any remainding data. */ +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +static int DetectHostbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); +static int DetectHostbitSetup (DetectEngineCtx *, Signature *, char *); +void DetectHostbitFree (void *); +void HostBitsRegisterTests(void); + +void DetectHostbitsRegister (void) +{ + sigmatch_table[DETECT_HOSTBITS].name = "hostbits"; + sigmatch_table[DETECT_HOSTBITS].desc = "operate on host flag"; +// sigmatch_table[DETECT_HOSTBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits"; + sigmatch_table[DETECT_HOSTBITS].Match = DetectHostbitMatch; + sigmatch_table[DETECT_HOSTBITS].Setup = DetectHostbitSetup; + sigmatch_table[DETECT_HOSTBITS].Free = DetectHostbitFree; + sigmatch_table[DETECT_HOSTBITS].RegisterTests = HostBitsRegisterTests; + /* this is compatible to ip-only signatures */ + sigmatch_table[DETECT_HOSTBITS].flags |= SIGMATCH_IPONLY_COMPAT; + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} + +static int DetectHostbitMatchToggle (Packet *p, const DetectXbitsData *fd) +{ + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } + else + HostLock(p->host_src); + + HostBitToggle(p->host_src,fd->idx,p->ts.tv_sec + fd->expire); + HostUnlock(p->host_src); + break; + case DETECT_XBITS_TRACK_IPDST: + if (p->host_dst == NULL) { + p->host_dst = HostGetHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 0; + } + else + HostLock(p->host_dst); + + HostBitToggle(p->host_dst,fd->idx,p->ts.tv_sec + fd->expire); + HostUnlock(p->host_dst); + break; + } + return 1; +} + +/* return true even if bit not found */ +static int DetectHostbitMatchUnset (Packet *p, const DetectXbitsData *fd) +{ + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: + if (p->host_src == NULL) { + p->host_src = HostLookupHostFromHash(&p->src); + if (p->host_src == NULL) + return 1; + } else + HostLock(p->host_src); + + HostBitUnset(p->host_src,fd->idx); + HostUnlock(p->host_src); + break; + case DETECT_XBITS_TRACK_IPDST: + if (p->host_dst == NULL) { + p->host_dst = HostLookupHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 1; + } else + HostLock(p->host_dst); + + HostBitUnset(p->host_dst,fd->idx); + HostUnlock(p->host_dst); + break; + } + return 1; +} + +static int DetectHostbitMatchSet (Packet *p, const DetectXbitsData *fd) +{ + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: + if (p->host_src == NULL) { + p->host_src = HostGetHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } else + HostLock(p->host_src); + + HostBitSet(p->host_src,fd->idx,p->ts.tv_sec + fd->expire); + HostUnlock(p->host_src); + break; + case DETECT_XBITS_TRACK_IPDST: + if (p->host_dst == NULL) { + p->host_dst = HostGetHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 0; + } else + HostLock(p->host_dst); + + HostBitSet(p->host_dst,fd->idx, p->ts.tv_sec + fd->expire); + HostUnlock(p->host_dst); + break; + } + return 1; +} + +static int DetectHostbitMatchIsset (Packet *p, const DetectXbitsData *fd) +{ + int r = 0; + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: + if (p->host_src == NULL) { + p->host_src = HostLookupHostFromHash(&p->src); + if (p->host_src == NULL) + return 0; + } else + HostLock(p->host_src); + + r = HostBitIsset(p->host_src,fd->idx, p->ts.tv_sec); + HostUnlock(p->host_src); + return r; + case DETECT_XBITS_TRACK_IPDST: + if (p->host_dst == NULL) { + p->host_dst = HostLookupHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 0; + } else + HostLock(p->host_dst); + + r = HostBitIsset(p->host_dst,fd->idx, p->ts.tv_sec); + HostUnlock(p->host_dst); + return r; + } + return 0; +} + +static int DetectHostbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) +{ + int r = 0; + switch (fd->tracker) { + case DETECT_XBITS_TRACK_IPSRC: + if (p->host_src == NULL) { + p->host_src = HostLookupHostFromHash(&p->src); + if (p->host_src == NULL) + return 1; + } else + HostLock(p->host_src); + + r = HostBitIsnotset(p->host_src,fd->idx, p->ts.tv_sec); + HostUnlock(p->host_src); + return r; + case DETECT_XBITS_TRACK_IPDST: + if (p->host_dst == NULL) { + p->host_dst = HostLookupHostFromHash(&p->dst); + if (p->host_dst == NULL) + return 1; + } else + HostLock(p->host_dst); + + r = HostBitIsnotset(p->host_dst,fd->idx, p->ts.tv_sec); + HostUnlock(p->host_dst); + return r; + } + return 0; +} + +int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd) +{ + switch (xd->cmd) { + case DETECT_XBITS_CMD_ISSET: + return DetectHostbitMatchIsset(p,xd); + case DETECT_XBITS_CMD_ISNOTSET: + return DetectHostbitMatchIsnotset(p,xd); + case DETECT_XBITS_CMD_SET: + return DetectHostbitMatchSet(p,xd); + case DETECT_XBITS_CMD_UNSET: + return DetectHostbitMatchUnset(p,xd); + case DETECT_XBITS_CMD_TOGGLE: + return DetectHostbitMatchToggle(p,xd); + default: + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", xd->cmd); + return 0; + } + + return 0; +} + +/* + * returns 0: no match + * 1: match + * -1: error + */ + +static int DetectHostbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) +{ + const DetectXbitsData *xd = (const DetectXbitsData *)ctx; + if (xd == NULL) + return 0; + + return DetectXbitMatchHost(p, xd); +} + +static int DetectHostbitParse(const char *str, char *cmd, int cmd_len, + char *name, int name_len, char *dir, int dir_len) +{ + const int max_substrings = 30; + int count, rc; + int ov[max_substrings]; + + count = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0, + ov, max_substrings); + if (count != 2 && count != 3 && count != 4) { + SCLogError(SC_ERR_PCRE_MATCH, + "\"%s\" is not a valid setting for hostbits.", str); + return 0; + } + + rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len); + if (rc < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return 0; + } + + if (count >= 3) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name, + name_len); + if (rc < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return 0; + } + if (count >= 4) { + rc = pcre_copy_substring((char *)str, ov, max_substrings, 3, dir, + dir_len); + if (rc < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, + "pcre_copy_substring failed"); + return 0; + } + } + } + + return 1; +} + +int DetectHostbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + DetectXbitsData *cd = NULL; + SigMatch *sm = NULL; + uint8_t fb_cmd = 0; + uint8_t hb_dir = 0; + char fb_cmd_str[16] = "", fb_name[256] = ""; + char hb_dir_str[16] = ""; + + if (!DetectHostbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), + fb_name, sizeof(fb_name), hb_dir_str, sizeof(hb_dir_str))) { + return -1; + } + + if (strlen(hb_dir_str) > 0) { + if (strcmp(hb_dir_str, "src") == 0) + hb_dir = DETECT_XBITS_TRACK_IPSRC; + else if (strcmp(hb_dir_str, "dst") == 0) + hb_dir = DETECT_XBITS_TRACK_IPDST; + else if (strcmp(hb_dir_str, "both") == 0) { + //hb_dir = DETECT_XBITS_TRACK_IPBOTH; + SCLogError(SC_ERR_UNIMPLEMENTED, "'both' not implemented"); + goto error; + } else { + // TODO + goto error; + } + } + + if (strcmp(fb_cmd_str,"noalert") == 0) { + fb_cmd = DETECT_XBITS_CMD_NOALERT; + } else if (strcmp(fb_cmd_str,"isset") == 0) { + fb_cmd = DETECT_XBITS_CMD_ISSET; + } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + fb_cmd = DETECT_XBITS_CMD_ISNOTSET; + } else if (strcmp(fb_cmd_str,"set") == 0) { + fb_cmd = DETECT_XBITS_CMD_SET; + } else if (strcmp(fb_cmd_str,"unset") == 0) { + fb_cmd = DETECT_XBITS_CMD_UNSET; + } else if (strcmp(fb_cmd_str,"toggle") == 0) { + fb_cmd = DETECT_XBITS_CMD_TOGGLE; + } else { + SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str); + goto error; + } + + switch (fb_cmd) { + case DETECT_XBITS_CMD_NOALERT: + if (strlen(fb_name) != 0) + goto error; + s->flags |= SIG_FLAG_NOALERT; + return 0; + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: + default: + if (strlen(fb_name) == 0) + goto error; + break; + } + + cd = SCMalloc(sizeof(DetectXbitsData)); + if (unlikely(cd == NULL)) + goto error; + + cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_HOST_BIT); + cd->cmd = fb_cmd; + cd->tracker = hb_dir; + cd->type = VAR_TYPE_HOST_BIT; + cd->expire = 300; + + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", + cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_HOSTBITS; + sm->ctx = (void *)cd; + + switch (fb_cmd) { + /* case DETECT_XBITS_CMD_NOALERT can't happen here */ + + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + /* checks, so packet list */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + break; + + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: + /* modifiers, only run when entire sig has matched */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + break; + } + + return 0; + +error: + if (cd != NULL) + SCFree(cd); + if (sm != NULL) + SCFree(sm); + return -1; +} + +void DetectHostbitFree (void *ptr) +{ + DetectXbitsData *fd = (DetectXbitsData *)ptr; + + if (fd == NULL) + return; + + SCFree(fd); +} + +#ifdef UNITTESTS + +static void HostBitsTestSetup(void) +{ + StorageInit(); + HostBitInitCtx(); + StorageFinalize(); + HostInitConfig(TRUE); +} + +static void HostBitsTestShutdown(void) +{ + HostCleanup(); + StorageCleanup(); +} + +static int HostBitsTestParse01(void) +{ + char cmd[16] = "", name[256] = "", dir[16] = ""; + + /* No direction. */ + FAIL_IF(!DetectHostbitParse("isset,name", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strlen(dir)); + + /* No direction, leading space. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(!DetectHostbitParse("isset, name", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + + /* No direction, trailing space. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(!DetectHostbitParse("isset,name ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + + /* No direction, leading and trailing space. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(!DetectHostbitParse("isset, name ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + + /* With direction. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(!DetectHostbitParse("isset,name,src", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strcmp(dir, "src") != 0); + + /* With direction - leading and trailing spaces on name. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(!DetectHostbitParse("isset, name ,src", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strcmp(dir, "src") != 0); + + /* With direction - space around direction. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(!DetectHostbitParse("isset, name , src ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + FAIL_IF(strcmp(cmd, "isset") != 0); + FAIL_IF(strcmp(name, "name") != 0); + FAIL_IF(strcmp(dir, "src") != 0); + + /* Name with space, no direction - should fail. */ + *cmd = '\0'; + *name = '\0'; + *dir = '\0'; + FAIL_IF(DetectHostbitParse("isset, name withspace ", cmd, sizeof(cmd), name, + sizeof(name), dir, sizeof(dir))); + + PASS; +} + +/** + * \test HostBitsTestSig01 is a test for a valid noalert flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig01(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p); + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + HostBitsTestSetup(); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (hostbits:set,abc; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostBitsTestShutdown(); + + SCFree(p); + PASS; +} + +/** + * \test various options + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig02(void) +{ + Signature *s = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:isset,abc,src; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:isnotset,abc,dst; content:\"GET \"; sid:2;)"); + FAIL_IF_NULL(s); + +/* TODO reenable after both is supported + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:set,abc,both; content:\"GET \"; sid:3;)"); + FAIL_IF_NULL(s); +*/ + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:unset,abc,src; content:\"GET \"; sid:4;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:toggle,abc,dst; content:\"GET \"; sid:5;)"); + FAIL_IF_NULL(s); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#if 0 +/** + * \test HostBitsTestSig03 is a test for a invalid flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig03(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + result = 1; + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + + SCFree(p); + return result; +} +#endif + +/** + * \test HostBitsTestSig04 is a test check idx value + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig04(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + int idx = 0; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + HostBitsTestSetup(); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; hostbits:isset,fbt; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + + idx = VarNameStoreSetupAdd("fbt", VAR_TYPE_HOST_BIT); + FAIL_IF(idx != 1); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + HostBitsTestShutdown(); + + SCFree(p); + PASS; +} + +/** + * \test HostBitsTestSig05 is a test check noalert flag + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig05(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + HostBitsTestSetup(); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (hostbits:noalert; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(PacketAlertCheck(p, 1)); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostBitsTestShutdown(); + + SCFree(p); + PASS; +} + +#if 0 +/** + * \test HostBitsTestSig06 is a test set flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig06(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + GenericVar flowvar, *gv = NULL; + int result = 0; + int idx = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + memset(&flowvar, 0, sizeof(GenericVar)); + + FLOW_INITIALIZE(&f); + p->flow = &f; + p->flow->flowvar = &flowvar; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->flags |= PKT_HAS_FLOW; + p->flowflags |= FLOW_PKT_TOSERVER; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)"); + + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_HOST_BIT); + + gv = p->flow->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + SCFree(p); + return result; +} + +/** + * \test HostBitsTestSig07 is a test unset flowbits option + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int HostBitsTestSig07(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + GenericVar flowvar, *gv = NULL; + int result = 0; + int idx = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + memset(&flowvar, 0, sizeof(GenericVar)); + + FLOW_INITIALIZE(&f); + p->flow = &f; + p->flow->flowvar = &flowvar; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)"); + if (s == NULL) { + goto end; + } + + s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + idx = VariableNameGetIdx(de_ctx, "myflow", VAR_TYPE_HOST_BIT); + + gv = p->flow->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_HOSTBITS && gv->idx == idx) { + result = 1; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result; +end: + + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + + if(gv) GenericVarFree(gv); + FLOW_DESTROY(&f); + + SCFree(p); + return result;} +#endif + +/** + * \test set / isset + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int HostBitsTestSig07(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + int result = 0; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + + HostBitsTestSetup(); + + FLOW_INITIALIZE(&f); + p->flow = &f; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, + "alert ip any any -> any any (hostbits:set,myflow2; sid:10;)"); + FAIL_IF_NULL(s); + + s = s->next = SigInit(de_ctx, + "alert ip any any -> any any (hostbits:isset,myflow2; sid:11;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + SCLogInfo("p->host_src %p", p->host_src); + + if (HostHasHostBits(p->host_src) == 1) { + if (PacketAlertCheck(p, 11)) { + result = 1; + } + } + FAIL_IF_NOT(result); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + + HostBitsTestShutdown(); + SCFree(p); + PASS; +} + +/** + * \test set / toggle / toggle / isset + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int HostBitsTestSig08(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + + memset(p, 0, SIZE_OF_PACKET); + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(Flow)); + + HostBitsTestSetup(); + + FLOW_INITIALIZE(&f); + p->flow = &f; + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:set,myflow2; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:toggle,myflow2; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:toggle,myflow2; sid:12;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (hostbits:isset,myflow2; sid:13;)"); + FAIL_IF_NULL(s); + + SCSigRegisterSignatureOrderingFuncs(de_ctx); + SCSigOrderSignatures(de_ctx); + SCSigSignatureOrderingModuleCleanup(de_ctx); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + SCLogInfo("p->host_src %p", p->host_src); + + if (HostHasHostBits(p->host_src) == 1) { + if (PacketAlertCheck(p, 10)) { + SCLogInfo("sid 10 matched"); + } + if (PacketAlertCheck(p, 11)) { + SCLogInfo("sid 11 matched"); + } + if (PacketAlertCheck(p, 12)) { + SCLogInfo("sid 12 matched"); + } + if (PacketAlertCheck(p, 13)) { + SCLogInfo("sid 13 matched"); + } else { + FAIL; + } + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + FLOW_DESTROY(&f); + + HostBitsTestShutdown(); + + SCFree(p); + PASS; +} +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for HostBits + */ +void HostBitsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HostBitsTestParse01", HostBitsTestParse01); + UtRegisterTest("HostBitsTestSig01", HostBitsTestSig01); + UtRegisterTest("HostBitsTestSig02", HostBitsTestSig02); +#if 0 + UtRegisterTest("HostBitsTestSig03", HostBitsTestSig03, 0); +#endif + UtRegisterTest("HostBitsTestSig04", HostBitsTestSig04); + UtRegisterTest("HostBitsTestSig05", HostBitsTestSig05); +#if 0 + UtRegisterTest("HostBitsTestSig06", HostBitsTestSig06, 1); +#endif + UtRegisterTest("HostBitsTestSig07", HostBitsTestSig07); + UtRegisterTest("HostBitsTestSig08", HostBitsTestSig08); +#endif /* UNITTESTS */ +} diff --git a/src/detect-hostbits.h b/src/detect-hostbits.h new file mode 100644 index 000000000000..6e9c7f5f0e42 --- /dev/null +++ b/src/detect-hostbits.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HOSTBITS_H__ +#define __DETECT_HOSTBITS_H__ + +#include "detect-xbits.h" + +int DetectXbitMatchHost(Packet *p, const DetectXbitsData *xd); + +/* prototypes */ +void DetectHostbitsRegister (void); + +#endif /* __DETECT_HOSTBITS_H__ */ diff --git a/src/detect-http-client-body.c b/src/detect-http-client-body.c index 112e11efef53..d227890e218e 100644 --- a/src/detect-http-client-body.c +++ b/src/detect-http-client-body.c @@ -55,11 +55,14 @@ #include "app-layer-parser.h" #include "app-layer-htp.h" #include "detect-http-client-body.h" +#include "detect-engine-hcbd.h" #include "stream-tcp.h" -int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpClientBodyRegisterTests(void); -void DetectHttpClientBodyFree(void *); +static int DetectHttpClientBodySetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpClientBodyRegisterTests(void); +static void DetectHttpClientBodyFree(void *); +static void DetectHttpClientBodySetupCallback(Signature *s); +static int g_http_client_body_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_client_body" keyword. @@ -68,22 +71,35 @@ void DetectHttpClientBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].name = "http_client_body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].desc = "content modifier to match only on HTTP request-body"; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_client_body"; + sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_client-body"; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Setup = DetectHttpClientBodySetup; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].Free = DetectHttpClientBodyFree; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].RegisterTests = DetectHttpClientBodyRegisterTests; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_CLIENT_BODY].flags |= SIGMATCH_PAYLOAD ; + + DetectAppLayerMpmRegister("http_client_body", SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestBodyRegister); + + DetectAppLayerInspectEngineRegister("http_client_body", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpClientBody); + + DetectBufferTypeSetDescriptionByName("http_client_body", + "http request body"); + + DetectBufferTypeRegisterSetupCallback("http_client_body", + DetectHttpClientBodySetupCallback); + + g_http_client_body_buffer_id = DetectBufferTypeGetByName("http_client_body"); } static void DetectHttpClientBodySetupCallback(Signature *s) { + SCLogDebug("callback invoked by %u", s->id); AppLayerHtpEnableRequestBodyCallback(); - return; + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } /** @@ -103,9 +119,8 @@ int DetectHttpClientBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_CLIENT_BODY, - DETECT_SM_LIST_HCBDMATCH, - ALPROTO_HTTP, - DetectHttpClientBodySetupCallback); + g_http_client_body_buffer_id, + ALPROTO_HTTP); } /** @@ -123,7 +138,7 @@ void DetectHttpClientBodyFree(void *ptr) if (hcbd->content != NULL) SCFree(hcbd->content); - BoyerMooreCtxDeInit(hcbd->bm_ctx); + SpmDestroyCtx(hcbd->spm_ctx); SCFree(hcbd); SCReturn; @@ -133,6 +148,7 @@ void DetectHttpClientBodyFree(void *ptr) #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** @@ -345,15 +361,16 @@ static int DetectHttpClientBodyTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -456,15 +473,16 @@ static int DetectHttpClientBodyTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -480,14 +498,15 @@ static int DetectHttpClientBodyTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -583,15 +602,16 @@ static int DetectHttpClientBodyTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -608,15 +628,16 @@ static int DetectHttpClientBodyTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -713,15 +734,16 @@ static int DetectHttpClientBodyTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -738,15 +760,16 @@ static int DetectHttpClientBodyTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -843,15 +866,16 @@ static int DetectHttpClientBodyTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -868,15 +892,16 @@ static int DetectHttpClientBodyTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -964,15 +989,16 @@ static int DetectHttpClientBodyTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1066,15 +1092,16 @@ static int DetectHttpClientBodyTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1168,15 +1195,16 @@ static int DetectHttpClientBodyTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1276,14 +1304,15 @@ static int DetectHttpClientBodyTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1293,32 +1322,34 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) { printf("sig 1 alerted (2): "); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1328,15 +1359,16 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1346,14 +1378,15 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1363,14 +1396,15 @@ static int DetectHttpClientBodyTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1382,14 +1416,15 @@ static int DetectHttpClientBodyTest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1495,14 +1530,15 @@ static int DetectHttpClientBodyTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1512,14 +1548,15 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1529,14 +1566,15 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1546,15 +1584,16 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1564,14 +1603,15 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1581,14 +1621,15 @@ static int DetectHttpClientBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1600,14 +1641,15 @@ static int DetectHttpClientBodyTest15(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1641,7 +1683,9 @@ static int DetectHttpClientBodyTest15(void) goto end; } - if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, + (uint8_t *)"Body one!!", 10) != 1) + { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -1654,7 +1698,9 @@ static int DetectHttpClientBodyTest15(void) goto end; } - if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { + if (StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, + (uint8_t *)"Body two!!", 10) != 1) + { SCLogDebug("Body data in t1 is not correctly set: "); goto end; } @@ -1713,15 +1759,15 @@ int DetectHttpClientBodyTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1768,15 +1814,15 @@ int DetectHttpClientBodyTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1822,15 +1868,15 @@ int DetectHttpClientBodyTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1877,15 +1923,15 @@ int DetectHttpClientBodyTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1933,15 +1979,15 @@ int DetectHttpClientBodyTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2016,15 +2062,15 @@ int DetectHttpClientBodyTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2071,13 +2117,13 @@ int DetectHttpClientBodyTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2115,13 +2161,13 @@ int DetectHttpClientBodyTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "one", hcbd1->content_len) != 0 || hcbd2->flags != DETECT_CONTENT_WITHIN || @@ -2231,21 +2277,21 @@ int DetectHttpClientBodyTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { @@ -2282,21 +2328,21 @@ int DetectHttpClientBodyTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hcbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectContentData *hcbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hcbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hcbd1->content, "two", hcbd1->content_len) != 0) { @@ -2333,21 +2379,21 @@ int DetectHttpClientBodyTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_client_body_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->prev->ctx; - DetectContentData *hcbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->prev->ctx; + DetectContentData *hcbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_client_body_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hcbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hcbd2->content, "two", hcbd2->content_len) != 0) { @@ -2362,42 +2408,71 @@ int DetectHttpClientBodyTest36(void) return result; } +static int DetectHttpClientBodyIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_client_body; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_client_body_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ void DetectHttpClientBodyRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpClientBodyTest01", DetectHttpClientBodyTest01, 1); - UtRegisterTest("DetectHttpClientBodyTest02", DetectHttpClientBodyTest02, 1); - UtRegisterTest("DetectHttpClientBodyTest03", DetectHttpClientBodyTest03, 1); - UtRegisterTest("DetectHttpClientBodyTest04", DetectHttpClientBodyTest04, 1); - UtRegisterTest("DetectHttpClientBodyTest05", DetectHttpClientBodyTest05, 1); - UtRegisterTest("DetectHttpClientBodyTest06", DetectHttpClientBodyTest06, 1); - UtRegisterTest("DetectHttpClientBodyTest07", DetectHttpClientBodyTest07, 1); - UtRegisterTest("DetectHttpClientBodyTest08", DetectHttpClientBodyTest08, 1); - UtRegisterTest("DetectHttpClientBodyTest09", DetectHttpClientBodyTest09, 1); - UtRegisterTest("DetectHttpClientBodyTest10", DetectHttpClientBodyTest10, 1); - UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11, 1); - UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12, 1); - UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13, 1); - UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14, 1); - UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15, 1); - - UtRegisterTest("DetectHttpClientBodyTest22", DetectHttpClientBodyTest22, 1); - UtRegisterTest("DetectHttpClientBodyTest23", DetectHttpClientBodyTest23, 1); - UtRegisterTest("DetectHttpClientBodyTest24", DetectHttpClientBodyTest24, 1); - UtRegisterTest("DetectHttpClientBodyTest25", DetectHttpClientBodyTest25, 1); - UtRegisterTest("DetectHttpClientBodyTest26", DetectHttpClientBodyTest26, 1); - UtRegisterTest("DetectHttpClientBodyTest27", DetectHttpClientBodyTest27, 1); - UtRegisterTest("DetectHttpClientBodyTest28", DetectHttpClientBodyTest28, 1); - UtRegisterTest("DetectHttpClientBodyTest29", DetectHttpClientBodyTest29, 1); - UtRegisterTest("DetectHttpClientBodyTest30", DetectHttpClientBodyTest30, 1); - UtRegisterTest("DetectHttpClientBodyTest31", DetectHttpClientBodyTest31, 1); - UtRegisterTest("DetectHttpClientBodyTest32", DetectHttpClientBodyTest32, 1); - UtRegisterTest("DetectHttpClientBodyTest33", DetectHttpClientBodyTest33, 1); - UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34, 1); - UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35, 1); - UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36, 1); + UtRegisterTest("DetectHttpClientBodyTest01", DetectHttpClientBodyTest01); + UtRegisterTest("DetectHttpClientBodyTest02", DetectHttpClientBodyTest02); + UtRegisterTest("DetectHttpClientBodyTest03", DetectHttpClientBodyTest03); + UtRegisterTest("DetectHttpClientBodyTest04", DetectHttpClientBodyTest04); + UtRegisterTest("DetectHttpClientBodyTest05", DetectHttpClientBodyTest05); + UtRegisterTest("DetectHttpClientBodyTest06", DetectHttpClientBodyTest06); + UtRegisterTest("DetectHttpClientBodyTest07", DetectHttpClientBodyTest07); + UtRegisterTest("DetectHttpClientBodyTest08", DetectHttpClientBodyTest08); + UtRegisterTest("DetectHttpClientBodyTest09", DetectHttpClientBodyTest09); + UtRegisterTest("DetectHttpClientBodyTest10", DetectHttpClientBodyTest10); + UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11); + UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12); + UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13); + UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14); + UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15); + + UtRegisterTest("DetectHttpClientBodyTest22", DetectHttpClientBodyTest22); + UtRegisterTest("DetectHttpClientBodyTest23", DetectHttpClientBodyTest23); + UtRegisterTest("DetectHttpClientBodyTest24", DetectHttpClientBodyTest24); + UtRegisterTest("DetectHttpClientBodyTest25", DetectHttpClientBodyTest25); + UtRegisterTest("DetectHttpClientBodyTest26", DetectHttpClientBodyTest26); + UtRegisterTest("DetectHttpClientBodyTest27", DetectHttpClientBodyTest27); + UtRegisterTest("DetectHttpClientBodyTest28", DetectHttpClientBodyTest28); + UtRegisterTest("DetectHttpClientBodyTest29", DetectHttpClientBodyTest29); + UtRegisterTest("DetectHttpClientBodyTest30", DetectHttpClientBodyTest30); + UtRegisterTest("DetectHttpClientBodyTest31", DetectHttpClientBodyTest31); + UtRegisterTest("DetectHttpClientBodyTest32", DetectHttpClientBodyTest32); + UtRegisterTest("DetectHttpClientBodyTest33", DetectHttpClientBodyTest33); + UtRegisterTest("DetectHttpClientBodyTest34", DetectHttpClientBodyTest34); + UtRegisterTest("DetectHttpClientBodyTest35", DetectHttpClientBodyTest35); + UtRegisterTest("DetectHttpClientBodyTest36", DetectHttpClientBodyTest36); + + UtRegisterTest("DetectHttpClientBodyIsdataatParseTest", + DetectHttpClientBodyIsdataatParseTest); + #endif /* UNITTESTS */ return; diff --git a/src/detect-http-cookie.c b/src/detect-http-cookie.c index 94f76765ad17..391dce187dd2 100644 --- a/src/detect-http-cookie.c +++ b/src/detect-http-cookie.c @@ -58,11 +58,14 @@ #include "app-layer-htp.h" #include "detect-http-cookie.h" +#include "detect-engine-hcd.h" #include "stream-tcp.h" static int DetectHttpCookieSetup (DetectEngineCtx *, Signature *, char *); -void DetectHttpCookieRegisterTests(void); -void DetectHttpCookieFree(void *); +static void DetectHttpCookieRegisterTests(void); +static void DetectHttpCookieFree(void *); +static void DetectHttpCookieSetupCallback(Signature *s); +static int g_http_cookie_buffer_id = 0; /** * \brief Registration function for keyword: http_cookie @@ -71,16 +74,33 @@ void DetectHttpCookieRegister(void) { sigmatch_table[DETECT_AL_HTTP_COOKIE].name = "http_cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].desc = "content modifier to match only on the HTTP cookie-buffer"; - sigmatch_table[DETECT_AL_HTTP_COOKIE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_cookie"; + sigmatch_table[DETECT_AL_HTTP_COOKIE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-cookie"; sigmatch_table[DETECT_AL_HTTP_COOKIE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_COOKIE].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_COOKIE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_COOKIE].Setup = DetectHttpCookieSetup; sigmatch_table[DETECT_AL_HTTP_COOKIE].Free = DetectHttpCookieFree; sigmatch_table[DETECT_AL_HTTP_COOKIE].RegisterTests = DetectHttpCookieRegisterTests; sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_COOKIE].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOSERVER, 2, + PrefilterTxRequestCookieRegister); + DetectAppLayerMpmRegister("http_cookie", SIG_FLAG_TOCLIENT, 2, + PrefilterTxResponseCookieRegister); + + DetectAppLayerInspectEngineRegister("http_cookie", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpCookie); + DetectAppLayerInspectEngineRegister("http_cookie", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpCookie); + + DetectBufferTypeSetDescriptionByName("http_cookie", + "http cookie header"); + + DetectBufferTypeRegisterSetupCallback("http_cookie", + DetectHttpCookieSetupCallback); + + g_http_cookie_buffer_id = DetectBufferTypeGetByName("http_cookie"); } /** @@ -113,22 +133,31 @@ static int DetectHttpCookieSetup(DetectEngineCtx *de_ctx, Signature *s, char *st { return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_COOKIE, - DETECT_SM_LIST_HCDMATCH, - ALPROTO_HTTP, - NULL); + g_http_cookie_buffer_id, + ALPROTO_HTTP); } +static void DetectHttpCookieSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + + /******************************** UNITESTS **********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" +static int g_http_uri_buffer_id = 0; + /** * \test Checks if a http_cookie is registered in a Signature, if content is not * specified in the signature */ -int DetectHttpCookieTest01(void) +static int DetectHttpCookieTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -152,7 +181,7 @@ int DetectHttpCookieTest01(void) * \test Checks if a http_cookie is registered in a Signature, if some parameter * is specified with http_cookie in the signature */ -int DetectHttpCookieTest02(void) +static int DetectHttpCookieTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -176,7 +205,7 @@ int DetectHttpCookieTest02(void) /** * \test Checks if a http_cookie is registered in a Signature */ -int DetectHttpCookieTest03(void) +static int DetectHttpCookieTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; @@ -197,7 +226,7 @@ int DetectHttpCookieTest03(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_cookie_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -223,7 +252,7 @@ int DetectHttpCookieTest03(void) * \test Checks if a http_cookie is registered in a Signature, when fast_pattern * is also specified in the signature (now it should) */ -int DetectHttpCookieTest04(void) +static int DetectHttpCookieTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -248,7 +277,7 @@ int DetectHttpCookieTest04(void) * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ -int DetectHttpCookieTest05(void) +static int DetectHttpCookieTest05(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -273,7 +302,7 @@ int DetectHttpCookieTest05(void) * \test Checks if a http_cookie is registered in a Signature, when rawbytes is * also specified in the signature */ -int DetectHttpCookieTest06(void) +static int DetectHttpCookieTest06(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -290,17 +319,17 @@ int DetectHttpCookieTest06(void) Signature *s = de_ctx->sig_list; - BUG_ON(s->sm_lists[DETECT_SM_LIST_HCDMATCH] == NULL); + BUG_ON(s->sm_lists[g_http_cookie_buffer_id] == NULL); - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH]->type != DETECT_CONTENT) + if (s->sm_lists[g_http_cookie_buffer_id]->type != DETECT_CONTENT) goto end; - if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { + if (s->sm_lists[g_http_uri_buffer_id] == NULL) { printf("expected another SigMatch, got NULL: "); goto end; } - if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_CONTENT) { + if (s->sm_lists[g_http_uri_buffer_id]->type != DETECT_CONTENT) { goto end; } @@ -371,15 +400,16 @@ static int DetectHttpCookieSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -470,15 +500,16 @@ static int DetectHttpCookieSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -563,15 +594,16 @@ static int DetectHttpCookieSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -657,15 +689,16 @@ static int DetectHttpCookieSigTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -751,15 +784,16 @@ static int DetectHttpCookieSigTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -846,14 +880,15 @@ static int DetectHttpCookieSigTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -938,15 +973,16 @@ static int DetectHttpCookieSigTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1049,16 +1085,17 @@ static int DetectHttpCookieSigTest08(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request */ - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf_request, httpbuf_request_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf_request, + httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1073,16 +1110,17 @@ static int DetectHttpCookieSigTest08(void) } /* response */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, - httpbuf_response, httpbuf_response_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf_response, + httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1186,16 +1224,17 @@ static int DetectHttpCookieSigTest09(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); /* request */ - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, - httpbuf_request, httpbuf_request_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf_request, + httpbuf_request_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1210,16 +1249,17 @@ static int DetectHttpCookieSigTest09(void) } /* response */ - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, - httpbuf_response, httpbuf_response_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf_response, + httpbuf_response_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1246,6 +1286,31 @@ static int DetectHttpCookieSigTest09(void) return result; } +static int DetectHttpCookieIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_cookie; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_cookie_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** @@ -1254,21 +1319,25 @@ static int DetectHttpCookieSigTest09(void) void DetectHttpCookieRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01, 1); - UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02, 1); - UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03, 1); - UtRegisterTest("DetectHttpCookieTest04", DetectHttpCookieTest04, 1); - UtRegisterTest("DetectHttpCookieTest05", DetectHttpCookieTest05, 1); - UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06, 1); - UtRegisterTest("DetectHttpCookieSigTest01", DetectHttpCookieSigTest01, 1); - UtRegisterTest("DetectHttpCookieSigTest02", DetectHttpCookieSigTest02, 1); - UtRegisterTest("DetectHttpCookieSigTest03", DetectHttpCookieSigTest03, 1); - UtRegisterTest("DetectHttpCookieSigTest04", DetectHttpCookieSigTest04, 1); - UtRegisterTest("DetectHttpCookieSigTest05", DetectHttpCookieSigTest05, 1); - UtRegisterTest("DetectHttpCookieSigTest06", DetectHttpCookieSigTest06, 1); - UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07, 1); - UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08, 1); - UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09, 1); + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); + + UtRegisterTest("DetectHttpCookieTest01", DetectHttpCookieTest01); + UtRegisterTest("DetectHttpCookieTest02", DetectHttpCookieTest02); + UtRegisterTest("DetectHttpCookieTest03", DetectHttpCookieTest03); + UtRegisterTest("DetectHttpCookieTest04", DetectHttpCookieTest04); + UtRegisterTest("DetectHttpCookieTest05", DetectHttpCookieTest05); + UtRegisterTest("DetectHttpCookieTest06", DetectHttpCookieTest06); + UtRegisterTest("DetectHttpCookieSigTest01", DetectHttpCookieSigTest01); + UtRegisterTest("DetectHttpCookieSigTest02", DetectHttpCookieSigTest02); + UtRegisterTest("DetectHttpCookieSigTest03", DetectHttpCookieSigTest03); + UtRegisterTest("DetectHttpCookieSigTest04", DetectHttpCookieSigTest04); + UtRegisterTest("DetectHttpCookieSigTest05", DetectHttpCookieSigTest05); + UtRegisterTest("DetectHttpCookieSigTest06", DetectHttpCookieSigTest06); + UtRegisterTest("DetectHttpCookieSigTest07", DetectHttpCookieSigTest07); + UtRegisterTest("DetectHttpCookieSigTest08", DetectHttpCookieSigTest08); + UtRegisterTest("DetectHttpCookieSigTest09", DetectHttpCookieSigTest09); + UtRegisterTest("DetectHttpCookieIsdataatParseTest", + DetectHttpCookieIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-http-header-common.c b/src/detect-http-header-common.c new file mode 100644 index 000000000000..1ab9b73595f3 --- /dev/null +++ b/src/detect-http-header-common.c @@ -0,0 +1,206 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#include "detect-http-header-common.h" + +static inline int CreateSpace(HttpHeaderThreadData *td, uint64_t size); + +void *HttpHeaderThreadDataInit(void *data) +{ + HttpHeaderThreadData *td = SCCalloc(1, sizeof(*td)); + if (td != NULL) { + if (data == NULL) { + td->tx_step = 4; + td->size_step = 512; + } else { + HttpHeaderThreadDataConfig *c = data; + td->tx_step = c->tx_step; + td->size_step = c->size_step; + } + + /* initialize minimal buffers */ + (void)CreateSpace(td, 1); + int i; + for (i = 0; i < td->buffers_size; i++) { + (void)HttpHeaderExpandBuffer(td, &td->buffers[i], 1); + } + } + return td; +} + +void HttpHeaderThreadDataFree(void *data) +{ + HttpHeaderThreadData *hdrnames = data; + + int i; + for (i = 0; i < hdrnames->buffers_size; i++) { + if (hdrnames->buffers[i].buffer) + SCFree(hdrnames->buffers[i].buffer); + if (hdrnames->buffers[i].size) { + SCLogDebug("hdrnames->buffers[%d].size %u (%u)", + i, hdrnames->buffers[i].size, hdrnames->buffers_size); + } + } + SCFree(hdrnames->buffers); + SCFree(hdrnames); +} + +static void Reset(HttpHeaderThreadData *hdrnames, uint64_t tick) +{ + uint16_t i; + for (i = 0; i < hdrnames->buffers_list_len; i++) { + hdrnames->buffers[i].len = 0; + } + hdrnames->buffers_list_len = 0; + hdrnames->start_tx_id = 0; + hdrnames->tick = tick; +} + +static inline int CreateSpace(HttpHeaderThreadData *td, uint64_t size) +{ + if (size >= SHRT_MAX) + return -1; + + if (size > td->buffers_size) { + uint16_t extra = td->tx_step; + while (td->buffers_size + extra < size) { + extra += td->tx_step; + } + SCLogDebug("adding %u to the buffer", (uint)extra); + + void *ptmp = SCRealloc(td->buffers, + (td->buffers_size + extra) * sizeof(HttpHeaderBuffer)); + if (ptmp == NULL) { + SCFree(td->buffers); + td->buffers = NULL; + td->buffers_size = 0; + td->buffers_list_len = 0; + return -1; + } + td->buffers = ptmp; + memset(td->buffers + td->buffers_size, 0, extra * sizeof(HttpHeaderBuffer)); + td->buffers_size += extra; + } + return 0; +} + +int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, + HttpHeaderBuffer *buf, uint32_t size) +{ + size_t extra = td->size_step; + while ((buf->size + extra) < (size + buf->len)) { + extra += td->size_step; + } + SCLogDebug("adding %u to the buffer", (uint)extra); + + uint8_t *new_buffer = SCRealloc(buf->buffer, buf->size + extra); + if (unlikely(new_buffer == NULL)) { + buf->len = 0; + return -1; + } + buf->buffer = new_buffer; + buf->size += extra; + return 0; +} + +HttpHeaderBuffer *HttpHeaderGetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, uint64_t tx_id, const int keyword_id, + HttpHeaderThreadData **ret_hdr_td) +{ + int index = 0; + *ret_hdr_td = NULL; + + HttpHeaderThreadData *hdr_td = + DetectThreadCtxGetGlobalKeywordThreadCtx(det_ctx, keyword_id); + if (hdr_td == NULL) + return NULL; + if (hdr_td->tick != det_ctx->ticker) + Reset(hdr_td, det_ctx->ticker); + *ret_hdr_td = hdr_td; + + if (hdr_td->buffers_list_len == 0) { + /* get the inspect id to use as a 'base id' */ + uint64_t base_inspect_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); + BUG_ON(base_inspect_id > tx_id); + /* see how many space we need for the current tx_id */ + uint64_t txs = (tx_id - base_inspect_id) + 1; + if (CreateSpace(hdr_td, txs) < 0) + return NULL; + + index = (tx_id - base_inspect_id); + hdr_td->start_tx_id = base_inspect_id; + hdr_td->buffers_list_len = txs; + } else { + /* tx fits in our current buffers */ + if ((tx_id - hdr_td->start_tx_id) < hdr_td->buffers_list_len) { + /* if we previously reassembled, return that buffer */ + if (hdr_td->buffers[(tx_id - hdr_td->start_tx_id)].len != 0) { + return &hdr_td->buffers[(tx_id - hdr_td->start_tx_id)]; + } + /* otherwise fall through */ + } else { + /* not enough space, lets expand */ + uint64_t txs = (tx_id - hdr_td->start_tx_id) + 1; + if (CreateSpace(hdr_td, txs) < 0) + return NULL; + + hdr_td->buffers_list_len = txs; + } + index = (tx_id - hdr_td->start_tx_id); + } + HttpHeaderBuffer *buf = &hdr_td->buffers[index]; + return buf; +} diff --git a/src/detect-http-header-common.h b/src/detect-http-header-common.h new file mode 100644 index 000000000000..c6fc5c684b89 --- /dev/null +++ b/src/detect-http-header-common.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_HEADER_COMMON_H__ +#define __DETECT_HTTP_HEADER_COMMON_H__ + +typedef struct HttpHeaderBuffer_ { + uint8_t *buffer; + uint32_t size; /**< buffer size */ + uint32_t len; /**< part of buffer in use */ +} HttpHeaderBuffer; + +typedef struct HttpHeaderThreadConfig_ { + uint16_t tx_step; + uint16_t size_step; +} HttpHeaderThreadDataConfig; + +typedef struct HttpHeaderThreadData_ { + HttpHeaderBuffer *buffers; /**< array of buffers */ + uint16_t buffers_size; /**< number of buffers */ + uint16_t buffers_list_len; + uint16_t size_step; /**< increase size of HttpHeaderBuffer::buffer with this */ + uint16_t tx_step; /**< increase number of txs with this */ + uint64_t start_tx_id; + uint64_t tick; +} HttpHeaderThreadData; + +void *HttpHeaderThreadDataInit(void *data); +void HttpHeaderThreadDataFree(void *data); + +HttpHeaderBuffer *HttpHeaderGetBufferSpaceForTXID(DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, uint64_t tx_id, const int keyword_id, + HttpHeaderThreadData **ret_hdr_td); + +int HttpHeaderExpandBuffer(HttpHeaderThreadData *td, + HttpHeaderBuffer *buf, uint32_t size); + +#endif /* __DETECT_HTTP_HEADER_COMMON_H__ */ diff --git a/src/detect-http-header-names.c b/src/detect-http-header-names.c new file mode 100644 index 000000000000..1fc8f3546ad1 --- /dev/null +++ b/src/detect-http-header-names.c @@ -0,0 +1,411 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_header_names + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-http-header-common.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#define KEYWORD_NAME "http_header_names" +#define KEYWORD_DOC "http-keywords#http-header-names" +#define BUFFER_NAME "http_header_names" +#define BUFFER_DESC "http header names" +static int g_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_TX_STEP 4 +#define BUFFER_SIZE_STEP 256 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_TX_STEP, BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, uint8_t flags, + uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = HttpHeaderGetBufferSpaceForTXID(det_ctx, f, flags, + tx_id, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } else if (buf->len > 0) { + /* already filled buf, reuse */ + *buffer_len = buf->len; + return buf->buffer; + } + + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + } + if (headers == NULL) + return NULL; + + /* fill the buffer. \r\nName1\r\nName2\r\n\r\n */ + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size = bstr_size(h->name) + 2; // for \r\n + if (i == 0) + size += 2; + if (i + 1 == no_of_headers) + size += 2; + + SCLogDebug("size %u + buf->len %u vs buf->size %u", (uint)size, buf->len, buf->size); + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + /* start with a \r\n */ + if (i == 0) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + + /* end with an extra \r\n */ + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + } + + *buffer_len = buf->len; + return buf->buffer; +} + +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestHeaderNames(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, + flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->request_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +int PrefilterTxHttpRequestHeaderNamesRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaderNames, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, + ALPROTO_HTTP, HTP_REQUEST_TRAILER, + mpm_ctx, NULL, "http_header (request)"); +#endif +} + +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseHeaderNames(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, NULL, det_ctx, + f, htp_state, flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->response_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +int PrefilterTxHttpResponseHeaderNamesRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaderNames, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER, + mpm_ctx, NULL, "http_header (response)"); +#endif +} + +int InspectEngineHttpHeaderNames(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)alstate; + uint32_t buffer_len = 0; + uint8_t *buffer = GetBufferForTX(tx, tx_id, + de_ctx, det_ctx, f, htp_state, + flags, &buffer_len); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +/** + * \brief The setup function for the http_header keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to signature for the current Signature being parsed + * from the rules. + * \param m Pointer to the head of the SigMatchs for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int DetectHttpHeaderNamesSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectHttpHeaderNamesSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpHeaderNamesRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].Setup = DetectHttpHeaderNamesSetup; + + sigmatch_table[DETECT_AL_HTTP_HEADER_NAMES].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestHeaderNamesRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseHeaderNamesRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + InspectEngineHttpHeaderNames); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + InspectEngineHttpHeaderNames); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectHttpHeaderNamesSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, + HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); + + SCLogDebug("keyword %s registered. Thread id %d. " + "Buffer %s registered. Buffer id %d", + KEYWORD_NAME, g_keyword_thread_id, + BUFFER_NAME, g_buffer_id); +} diff --git a/src/detect-http-header-names.h b/src/detect-http-header-names.h new file mode 100644 index 000000000000..f45a0ae00a60 --- /dev/null +++ b/src/detect-http-header-names.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_HEADER_NAMES_H__ +#define __DETECT_HTTP_HEADER_NAMES_H__ + +void DetectHttpHeaderNamesRegister(void); + +#endif /* __DETECT_HTTP_HEADER_NAMES_H__ */ diff --git a/src/detect-http-header.c b/src/detect-http-header.c index 8f902cc9ae3e..635d221c22a5 100644 --- a/src/detect-http-header.c +++ b/src/detect-http-header.c @@ -39,6 +39,8 @@ #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" #include "detect-content.h" #include "detect-pcre.h" @@ -51,55 +53,305 @@ #include "util-unittest-helper.h" #include "util-spm.h" #include "util-print.h" +#include "util-memcmp.h" #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-htp.h" #include "detect-http-header.h" +#include "detect-http-header-common.h" #include "stream-tcp.h" -int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpHeaderRegisterTests(void); -void DetectHttpHeaderFree(void *); +static int DetectHttpHeaderSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpHeaderRegisterTests(void); +static void DetectHttpHeaderSetupCallback(Signature *); +static int g_http_header_buffer_id = 0; +static int g_keyword_thread_id = 0; -/** - * \brief Registers the keyword handlers for the "http_header" keyword. +#define BUFFER_TX_STEP 4 +#define BUFFER_SIZE_STEP 1024 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_TX_STEP, BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, uint8_t flags, + uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = HttpHeaderGetBufferSpaceForTXID(det_ctx, f, flags, + tx_id, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } else if (buf->len > 0) { + /* already filled buf, reuse */ + *buffer_len = buf->len; + return buf->buffer; + } + + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_REQUEST_HEADERS) + return NULL; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + } + if (headers == NULL) + return NULL; + + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); + + if (flags & STREAM_TOSERVER) { + if (size1 == 6 && + SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { + continue; + } + } else { + if (size1 == 10 && + SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { + continue; + } + } + + size_t size = size1 + size2 + 4; +#if 0 + if (i + 1 == no_of_headers) + size += 2; +#endif + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = ':'; + buf->buffer[buf->len++] = ' '; + memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); + buf->len += bstr_size(h->value); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; +#if 0 // looks like this breaks existing rules + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } +#endif + } + + *buffer_len = buf->len; + return buf->buffer; +} + +/** \brief HTTP Headers Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -void DetectHttpHeaderRegister(void) +static void PrefilterTxHttpRequestHeaders(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; - sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; - sigmatch_table[DETECT_AL_HTTP_HEADER].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_header"; - sigmatch_table[DETECT_AL_HTTP_HEADER].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_HEADER].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; - sigmatch_table[DETECT_AL_HTTP_HEADER].Free = DetectHttpHeaderFree; - sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; - sigmatch_table[DETECT_AL_HTTP_HEADER].alproto = ALPROTO_HTTP; + SCEnter(); - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_PAYLOAD ; + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - return; + if (tx->request_headers == NULL) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, + flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } } +#if 0 +static void PrefilterTxHttpRequestTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); -/** - * \brief this function clears the memory of http_header modifier keyword + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->request_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +static int PrefilterTxHttpRequestHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestHeaders, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, "http_header (request)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestTrailers, + ALPROTO_HTTP, HTP_REQUEST_TRAILER, + mpm_ctx, NULL, "http_header (request)"); +#endif +} + +/** \brief HTTP Headers Mpm prefilter callback * - * \param ptr Pointer to the Detection Header Data + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context */ -void DetectHttpHeaderFree(void *ptr) +static void PrefilterTxHttpResponseHeaders(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) { - DetectContentData *hhd = (DetectContentData *)ptr; - if (hhd == NULL) + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_headers == NULL) return; - if (hhd->content != NULL) - SCFree(hhd->content); - SCFree(hhd); + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#if 0 +static void PrefilterTxHttpResponseTrailers(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; - return; + if (tx->response_headers == NULL) + return; + const HtpTxUserData *htud = (const HtpTxUserData *)htp_tx_get_user_data(tx); + /* if the request wasn't flagged as having a trailer, we skip */ + if (htud && !htud->response_has_trailers) + return; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = DetectEngineHHDGetBufferForTX(tx, idx, + NULL, det_ctx, + f, htp_state, + flags, + &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} +#endif +static int PrefilterTxHttpResponseHeadersRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseHeaders, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, "http_header (response)"); + return r; +#if 0 + if (r != 0) + return r; + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseTrailers, + ALPROTO_HTTP, HTP_RESPONSE_TRAILER, + mpm_ctx, NULL, "http_header (response)"); +#endif +} + +static int DetectEngineInspectHttpHeader(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)alstate; + uint32_t buffer_len = 0; + uint8_t *buffer = GetBufferForTX(tx, tx_id, de_ctx, det_ctx, + f, htp_state, + flags, &buffer_len); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, + buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; } /** @@ -115,19 +367,62 @@ void DetectHttpHeaderFree(void *ptr) * \retval 0 On success. * \retval -1 On failure. */ -int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectHttpHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HEADER, - DETECT_SM_LIST_HHDMATCH, - ALPROTO_HTTP, - NULL); + g_http_header_buffer_id, + ALPROTO_HTTP); +} + +static void DetectHttpHeaderSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpHeaderRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_HEADER].name = "http_header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].desc = "content modifier to match only on the HTTP header-buffer"; + sigmatch_table[DETECT_AL_HTTP_HEADER].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-header"; + sigmatch_table[DETECT_AL_HTTP_HEADER].Setup = DetectHttpHeaderSetup; + sigmatch_table[DETECT_AL_HTTP_HEADER].RegisterTests = DetectHttpHeaderRegisterTests; + + sigmatch_table[DETECT_AL_HTTP_HEADER].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestHeadersRegister); + DetectAppLayerMpmRegister("http_header", SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseHeadersRegister); + + DetectAppLayerInspectEngineRegister("http_header", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpHeader); + DetectAppLayerInspectEngineRegister("http_header", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpHeader); + + DetectBufferTypeSetDescriptionByName("http_header", + "http headers"); + + DetectBufferTypeRegisterSetupCallback("http_header", + DetectHttpHeaderSetupCallback); + + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs("http_header", + HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); } /************************************Unittests*********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** @@ -155,7 +450,7 @@ static int DetectHttpHeaderTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_header_buffer_id]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); @@ -352,15 +647,16 @@ static int DetectHttpHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -461,15 +757,16 @@ static int DetectHttpHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -486,15 +783,16 @@ static int DetectHttpHeaderTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -588,15 +886,16 @@ static int DetectHttpHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -613,15 +912,16 @@ static int DetectHttpHeaderTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -705,7 +1005,7 @@ static int DetectHttpHeaderTest09(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http header test\"; " @@ -717,15 +1017,16 @@ static int DetectHttpHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -742,15 +1043,16 @@ static int DetectHttpHeaderTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -845,15 +1147,16 @@ static int DetectHttpHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -870,15 +1173,16 @@ static int DetectHttpHeaderTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -965,15 +1269,16 @@ static int DetectHttpHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1066,15 +1371,16 @@ static int DetectHttpHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1168,15 +1474,16 @@ static int DetectHttpHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1232,13 +1539,13 @@ int DetectHttpHeaderTest20(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_DISTANCE || @@ -1276,13 +1583,13 @@ int DetectHttpHeaderTest21(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "one", hhd1->content_len) != 0 || hhd2->flags != DETECT_CONTENT_WITHIN || @@ -1392,21 +1699,21 @@ int DetectHttpHeaderTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1443,21 +1750,21 @@ int DetectHttpHeaderTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { @@ -1494,21 +1801,21 @@ int DetectHttpHeaderTest27(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1575,15 +1882,16 @@ static int DetectHttpHeaderTest28(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1662,15 +1970,16 @@ static int DetectHttpHeaderTest29(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1749,15 +2058,16 @@ static int DetectHttpHeaderTest30(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1784,35 +2094,3547 @@ static int DetectHttpHeaderTest30(void) return result; } +static int DetectHttpHeaderIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "flow:to_server; " + "content:\"one\"; http_header; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_header_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest01(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest02(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; depth:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest03(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; depth:5; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest04(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; depth:5; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest05(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; depth:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest06(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; offset:10; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest07(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; offset:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest08(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; offset:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest09(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:!\"one\"; offset:10; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest10(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"three\"; http_header; within:10; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest11(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"three\"; http_header; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest12(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"three\"; http_header; within:10; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest13(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"three\"; http_header; within:5; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest14(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"five\"; http_header; distance:7; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest15(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"five\"; http_header; distance:15; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (!(PacketAlertCheck(p, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest16(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:!\"five\"; http_header; distance:7; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +/** + *\test Test that the http_header content matches against a http request + * which holds the content. + */ +static int DetectEngineHttpHeaderTest17(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.onetwothreefourfivesixseven.org\r\n\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"one\"; http_header; content:\"five\"; http_header; distance:15; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: "); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + if (PacketAlertCheck(p, 1)) { + printf("sid 1 matched but shouldn't have: "); + goto end; + } + + result = 1; +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} + +static int DetectEngineHttpHeaderTest20(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; http_header; within:7; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest21(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; within:7; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest22(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; distance:3; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest23(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:!\"dummy\"; distance:13; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest24(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; within:15; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest25(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; within:10; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest26(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; distance:8; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest27(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: This_is_dummy_body1"; + uint8_t http2_buf[] = + "This_is_dummy_message_body2\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http client body test\"; " + "pcre:/body1/H; " + "content:\"dummy\"; distance:14; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest28(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 6\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + FAIL_IF(!PacketAlertCheck(p2, 1)); + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +static int DetectEngineHttpHeaderTest29(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 7\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +#if 0 + +static int DetectEngineHttpHeaderTest30(void) +{ + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + if (de_ctx == NULL) { + goto end; + } + + de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"Content-Length: 6\"; http_header; " + "content:\"User-Agent: Mozilla\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list != NULL) { + goto end; + } + + result = 1; + + end: + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif /* #if 0 */ + +static int DetectEngineHttpHeaderTest30(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf1[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7\r\n" + "\r\n"; + uint32_t http_buf1_len = sizeof(http_buf1) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 ok\r\n" + "Set-Cookie: dummycookieset\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef"; + uint32_t http_buf2_len = sizeof(http_buf2) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(msg:\"http header test\"; " + "content:\"dummycookieset\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, http_buf2, http_buf2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (PacketAlertCheck(p2, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + +/** \test reassembly bug where headers with names of length 6 were + * skipped + */ +static int DetectEngineHttpHeaderTest31(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Accept: blah\r\n" + "Cookie: blah\r\n" + "Crazy6: blah\r\n" + "SixZix: blah\r\n\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(content:\"Accept|3a|\"; http_header; " + "content:!\"Cookie|3a|\"; http_header; " + "content:\"Crazy6|3a|\"; http_header; " + "content:\"SixZix|3a|\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + return result; +} + +/** + * \test Trailing headers. + */ +static int DetectEngineHttpHeaderTest32(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n" + "Dummy-Header: kaboom\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(content:\"Dummy\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (!(PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match but should have: "); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + return result; +} + +/** + * \test Trailing headers. + */ +static int DetectEngineHttpHeaderTest33(void) +{ + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http1_buf[] = + "GET /index.html HTTP/1.0\r\n" + "host: boom\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "13\r\n" + "This is dummy body1\r\n" + "0\r\n"; + uint8_t http2_buf[] = + "Dummy-Header: kaboom\r\n" + "\r\n"; + uint32_t http1_len = sizeof(http1_buf) - 1; + uint32_t http2_len = sizeof(http2_buf) - 1; + int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p1->flow = &f; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2->flow = &f; + p2->flowflags |= FLOW_PKT_TOSERVER; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(content:\"Dummy\"; http_header; " + "sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + http_state = f.alstate; + if (http_state == NULL) { + printf("no http state: \n"); + result = 0; + goto end; + } + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 matched but shouldn't have\n"); + goto end; + } + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + + if (!PacketAlertCheck(p2, 1)) { + printf("sid 1 didn't match but should have\n"); + goto end; + } + + result = 1; + +end: + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + SigCleanSignatures(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + return result; +} + #endif /* UNITTESTS */ void DetectHttpHeaderRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpHeaderTest01", DetectHttpHeaderTest01, 1); - UtRegisterTest("DetectHttpHeaderTest02", DetectHttpHeaderTest02, 1); - UtRegisterTest("DetectHttpHeaderTest03", DetectHttpHeaderTest03, 1); - UtRegisterTest("DetectHttpHeaderTest04", DetectHttpHeaderTest04, 1); - UtRegisterTest("DetectHttpHeaderTest05", DetectHttpHeaderTest05, 1); - UtRegisterTest("DetectHttpHeaderTest06", DetectHttpHeaderTest06, 1); - UtRegisterTest("DetectHttpHeaderTest07", DetectHttpHeaderTest07, 1); - UtRegisterTest("DetectHttpHeaderTest08", DetectHttpHeaderTest08, 1); - UtRegisterTest("DetectHttpHeaderTest09", DetectHttpHeaderTest09, 1); - UtRegisterTest("DetectHttpHeaderTest10", DetectHttpHeaderTest10, 1); - UtRegisterTest("DetectHttpHeaderTest11", DetectHttpHeaderTest11, 1); - UtRegisterTest("DetectHttpHeaderTest12", DetectHttpHeaderTest12, 1); - UtRegisterTest("DetectHttpHeaderTest13", DetectHttpHeaderTest13, 1); - UtRegisterTest("DetectHttpHeaderTest20", DetectHttpHeaderTest20, 1); - UtRegisterTest("DetectHttpHeaderTest21", DetectHttpHeaderTest21, 1); - UtRegisterTest("DetectHttpHeaderTest22", DetectHttpHeaderTest22, 1); - UtRegisterTest("DetectHttpHeaderTest23", DetectHttpHeaderTest23, 1); - UtRegisterTest("DetectHttpHeaderTest24", DetectHttpHeaderTest24, 1); - UtRegisterTest("DetectHttpHeaderTest25", DetectHttpHeaderTest25, 1); - UtRegisterTest("DetectHttpHeaderTest26", DetectHttpHeaderTest26, 1); - UtRegisterTest("DetectHttpHeaderTest27", DetectHttpHeaderTest27, 1); - UtRegisterTest("DetectHttpHeaderTest28", DetectHttpHeaderTest28, 1); - UtRegisterTest("DetectHttpHeaderTest29", DetectHttpHeaderTest29, 1); - UtRegisterTest("DetectHttpHeaderTest30", DetectHttpHeaderTest30, 1); + UtRegisterTest("DetectHttpHeaderTest01", DetectHttpHeaderTest01); + UtRegisterTest("DetectHttpHeaderTest02", DetectHttpHeaderTest02); + UtRegisterTest("DetectHttpHeaderTest03", DetectHttpHeaderTest03); + UtRegisterTest("DetectHttpHeaderTest04", DetectHttpHeaderTest04); + UtRegisterTest("DetectHttpHeaderTest05", DetectHttpHeaderTest05); + UtRegisterTest("DetectHttpHeaderTest06", DetectHttpHeaderTest06); + UtRegisterTest("DetectHttpHeaderTest07", DetectHttpHeaderTest07); + UtRegisterTest("DetectHttpHeaderTest08", DetectHttpHeaderTest08); + UtRegisterTest("DetectHttpHeaderTest09", DetectHttpHeaderTest09); + UtRegisterTest("DetectHttpHeaderTest10", DetectHttpHeaderTest10); + UtRegisterTest("DetectHttpHeaderTest11", DetectHttpHeaderTest11); + UtRegisterTest("DetectHttpHeaderTest12", DetectHttpHeaderTest12); + UtRegisterTest("DetectHttpHeaderTest13", DetectHttpHeaderTest13); + UtRegisterTest("DetectHttpHeaderTest20", DetectHttpHeaderTest20); + UtRegisterTest("DetectHttpHeaderTest21", DetectHttpHeaderTest21); + UtRegisterTest("DetectHttpHeaderTest22", DetectHttpHeaderTest22); + UtRegisterTest("DetectHttpHeaderTest23", DetectHttpHeaderTest23); + UtRegisterTest("DetectHttpHeaderTest24", DetectHttpHeaderTest24); + UtRegisterTest("DetectHttpHeaderTest25", DetectHttpHeaderTest25); + UtRegisterTest("DetectHttpHeaderTest26", DetectHttpHeaderTest26); + UtRegisterTest("DetectHttpHeaderTest27", DetectHttpHeaderTest27); + UtRegisterTest("DetectHttpHeaderTest28", DetectHttpHeaderTest28); + UtRegisterTest("DetectHttpHeaderTest29", DetectHttpHeaderTest29); + UtRegisterTest("DetectHttpHeaderTest30", DetectHttpHeaderTest30); + + UtRegisterTest("DetectHttpHeaderIsdataatParseTest", + DetectHttpHeaderIsdataatParseTest); + + UtRegisterTest("DetectEngineHttpHeaderTest01", + DetectEngineHttpHeaderTest01); + UtRegisterTest("DetectEngineHttpHeaderTest02", + DetectEngineHttpHeaderTest02); + UtRegisterTest("DetectEngineHttpHeaderTest03", + DetectEngineHttpHeaderTest03); + UtRegisterTest("DetectEngineHttpHeaderTest04", + DetectEngineHttpHeaderTest04); + UtRegisterTest("DetectEngineHttpHeaderTest05", + DetectEngineHttpHeaderTest05); + UtRegisterTest("DetectEngineHttpHeaderTest06", + DetectEngineHttpHeaderTest06); + UtRegisterTest("DetectEngineHttpHeaderTest07", + DetectEngineHttpHeaderTest07); + UtRegisterTest("DetectEngineHttpHeaderTest08", + DetectEngineHttpHeaderTest08); + UtRegisterTest("DetectEngineHttpHeaderTest09", + DetectEngineHttpHeaderTest09); + UtRegisterTest("DetectEngineHttpHeaderTest10", + DetectEngineHttpHeaderTest10); + UtRegisterTest("DetectEngineHttpHeaderTest11", + DetectEngineHttpHeaderTest11); + UtRegisterTest("DetectEngineHttpHeaderTest12", + DetectEngineHttpHeaderTest12); + UtRegisterTest("DetectEngineHttpHeaderTest13", + DetectEngineHttpHeaderTest13); + UtRegisterTest("DetectEngineHttpHeaderTest14", + DetectEngineHttpHeaderTest14); + UtRegisterTest("DetectEngineHttpHeaderTest15", + DetectEngineHttpHeaderTest15); + UtRegisterTest("DetectEngineHttpHeaderTest16", + DetectEngineHttpHeaderTest16); + UtRegisterTest("DetectEngineHttpHeaderTest17", + DetectEngineHttpHeaderTest17); + UtRegisterTest("DetectEngineHttpHeaderTest20", + DetectEngineHttpHeaderTest20); + UtRegisterTest("DetectEngineHttpHeaderTest21", + DetectEngineHttpHeaderTest21); + UtRegisterTest("DetectEngineHttpHeaderTest22", + DetectEngineHttpHeaderTest22); + UtRegisterTest("DetectEngineHttpHeaderTest23", + DetectEngineHttpHeaderTest23); + UtRegisterTest("DetectEngineHttpHeaderTest24", + DetectEngineHttpHeaderTest24); + UtRegisterTest("DetectEngineHttpHeaderTest25", + DetectEngineHttpHeaderTest25); + UtRegisterTest("DetectEngineHttpHeaderTest26", + DetectEngineHttpHeaderTest26); + UtRegisterTest("DetectEngineHttpHeaderTest27", + DetectEngineHttpHeaderTest27); + UtRegisterTest("DetectEngineHttpHeaderTest28", + DetectEngineHttpHeaderTest28); + UtRegisterTest("DetectEngineHttpHeaderTest29", + DetectEngineHttpHeaderTest29); + UtRegisterTest("DetectEngineHttpHeaderTest30", + DetectEngineHttpHeaderTest30); + UtRegisterTest("DetectEngineHttpHeaderTest31", + DetectEngineHttpHeaderTest31); +#if 0 + UtRegisterTest("DetectEngineHttpHeaderTest30", + DetectEngineHttpHeaderTest30, 1); +#endif + UtRegisterTest("DetectEngineHttpHeaderTest32", + DetectEngineHttpHeaderTest32); + UtRegisterTest("DetectEngineHttpHeaderTest33", + DetectEngineHttpHeaderTest33); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-header.h b/src/detect-http-header.h index 5327b5b81583..6a26f55a0ff1 100644 --- a/src/detect-http-header.h +++ b/src/detect-http-header.h @@ -27,4 +27,6 @@ void DetectHttpHeaderRegister(void); void DetectHttpRawHeaderRegister(void); +void DetectEngineCleanHHDBuffers(DetectEngineThreadCtx *det_ctx); + #endif /* __DETECT_HTTP_HEADER_H__ */ diff --git a/src/detect-http-hh.c b/src/detect-http-hh.c index 4df0fe329a80..182a49e68597 100644 --- a/src/detect-http-hh.c +++ b/src/detect-http-hh.c @@ -57,10 +57,14 @@ #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-hh.h" +#include "detect-engine-hhhd.h" -int DetectHttpHHSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpHHRegisterTests(void); -void DetectHttpHHFree(void *); +static int DetectHttpHHSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpHHRegisterTests(void); +static void DetectHttpHHFree(void *); +static void DetectHttpHostSetupCallback(Signature *s); +static _Bool DetectHttpHostValidateCallback(const Signature *s); +static int g_http_host_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_host" keyword. @@ -70,16 +74,29 @@ void DetectHttpHHRegister(void) sigmatch_table[DETECT_AL_HTTP_HOST].name = "http_host"; sigmatch_table[DETECT_AL_HTTP_HOST].desc = "content modifier to match only on the HTTP hostname"; sigmatch_table[DETECT_AL_HTTP_HOST].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_HOST].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_HOST].Setup = DetectHttpHHSetup; sigmatch_table[DETECT_AL_HTTP_HOST].Free = DetectHttpHHFree; sigmatch_table[DETECT_AL_HTTP_HOST].RegisterTests = DetectHttpHHRegisterTests; - sigmatch_table[DETECT_AL_HTTP_HOST].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_HOST].flags |= SIGMATCH_PAYLOAD ; - return; + DetectAppLayerMpmRegister("http_host", SIG_FLAG_TOSERVER, 2, + PrefilterTxHostnameRegister); + + DetectAppLayerInspectEngineRegister("http_host", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpHH); + + DetectBufferTypeSetDescriptionByName("http_host", + "http host header"); + + DetectBufferTypeRegisterSetupCallback("http_host", + DetectHttpHostSetupCallback); + + DetectBufferTypeRegisterValidateCallback("http_host", + DetectHttpHostValidateCallback); + + g_http_host_buffer_id = DetectBufferTypeGetByName("http_host"); } /** @@ -99,9 +116,47 @@ int DetectHttpHHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_HOST, - DETECT_SM_LIST_HHHDMATCH, - ALPROTO_HTTP, - NULL); + g_http_host_buffer_id, + ALPROTO_HTTP); +} + +static void DetectHttpHostSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +static _Bool DetectHttpHostValidateCallback(const Signature *s) +{ + const SigMatch *sm = s->init_data->smlists[g_http_host_buffer_id]; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_CONTENT) { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if (cd->flags & DETECT_CONTENT_NOCASE) { + SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_host keyword " + "specified along with \"nocase\". " + "Since the hostname buffer we match against " + "is actually lowercase. So having a " + "nocase is redundant."); + } else { + uint32_t u; + for (u = 0; u < cd->content_len; u++) { + if (isupper(cd->content[u])) + break; + } + if (u != cd->content_len) { + SCLogWarning(SC_ERR_INVALID_SIGNATURE, "A pattern with " + "uppercase chars detected for http_host. " + "Since the hostname buffer we match against " + "is lowercase only, please specify a " + "lowercase pattern."); + return FALSE; + } + } + } + } + + return TRUE; } /** @@ -118,7 +173,7 @@ void DetectHttpHHFree(void *ptr) if (hhhd->content != NULL) SCFree(hhhd->content); - BoyerMooreCtxDeInit(hhhd->bm_ctx); + SpmDestroyCtx(hhhd->spm_ctx); SCFree(hhhd); return; @@ -272,6 +327,22 @@ static int DetectHttpHHTest05(void) return result; } +/** \test invalid sig: uppercase content */ +static int DetectHttpHHTest05a(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any " + "(content:\"ABC\"; http_host; sid:1;)"); + FAIL_IF_NOT_NULL(s); + + DetectEngineCtxFree(de_ctx); + PASS; +} + /** *\test Test that the http_host content matches against a http request * which holds the content. @@ -330,15 +401,16 @@ static int DetectHttpHHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -437,15 +509,16 @@ static int DetectHttpHHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -461,14 +534,15 @@ static int DetectHttpHHTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -560,15 +634,16 @@ static int DetectHttpHHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -585,15 +660,16 @@ static int DetectHttpHHTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -690,15 +766,16 @@ static int DetectHttpHHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -715,15 +792,16 @@ static int DetectHttpHHTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -820,15 +898,16 @@ static int DetectHttpHHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -845,15 +924,16 @@ static int DetectHttpHHTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ @@ -940,15 +1020,16 @@ static int DetectHttpHHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1039,15 +1120,16 @@ static int DetectHttpHHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1139,15 +1221,16 @@ static int DetectHttpHHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1247,14 +1330,15 @@ static int DetectHttpHHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1264,14 +1348,15 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1281,14 +1366,15 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1298,14 +1384,15 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1315,14 +1402,15 @@ static int DetectHttpHHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1334,14 +1422,15 @@ static int DetectHttpHHTest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1381,16 +1470,6 @@ static int DetectHttpHHTest14(void) return result; } - - - - - - - - - - int DetectHttpHHTest22(void) { DetectEngineCtx *de_ctx = NULL; @@ -1413,15 +1492,15 @@ int DetectHttpHHTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1468,15 +1547,15 @@ int DetectHttpHHTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1522,15 +1601,15 @@ int DetectHttpHHTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1577,15 +1656,15 @@ int DetectHttpHHTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1633,15 +1712,15 @@ int DetectHttpHHTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1716,15 +1795,15 @@ int DetectHttpHHTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1771,13 +1850,13 @@ int DetectHttpHHTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || @@ -1815,13 +1894,13 @@ int DetectHttpHHTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "one", hhhd1->content_len) != 0 || hhhd2->flags != (DETECT_CONTENT_WITHIN) || @@ -1931,21 +2010,21 @@ int DetectHttpHHTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { @@ -1982,21 +2061,21 @@ int DetectHttpHHTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectContentData *hhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hhhd1->content, "two", hhhd1->content_len) != 0) { @@ -2033,21 +2112,21 @@ int DetectHttpHHTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->prev->ctx; - DetectContentData *hhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->prev->ctx; + DetectContentData *hhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hhhd2->content, "two", hhhd2->content_len) != 0) { @@ -2067,36 +2146,37 @@ int DetectHttpHHTest36(void) void DetectHttpHHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpHHTest01", DetectHttpHHTest01, 1); - UtRegisterTest("DetectHttpHHTest02", DetectHttpHHTest02, 1); - UtRegisterTest("DetectHttpHHTest03", DetectHttpHHTest03, 1); - UtRegisterTest("DetectHttpHHTest04", DetectHttpHHTest04, 1); - UtRegisterTest("DetectHttpHHTest05", DetectHttpHHTest05, 1); - UtRegisterTest("DetectHttpHHTest06", DetectHttpHHTest06, 1); - UtRegisterTest("DetectHttpHHTest07", DetectHttpHHTest07, 1); - UtRegisterTest("DetectHttpHHTest08", DetectHttpHHTest08, 1); - UtRegisterTest("DetectHttpHHTest09", DetectHttpHHTest09, 1); - UtRegisterTest("DetectHttpHHTest10", DetectHttpHHTest10, 1); - UtRegisterTest("DetectHttpHHTest11", DetectHttpHHTest11, 1); - UtRegisterTest("DetectHttpHHTest12", DetectHttpHHTest12, 1); - UtRegisterTest("DetectHttpHHTest13", DetectHttpHHTest13, 1); - UtRegisterTest("DetectHttpHHTest14", DetectHttpHHTest14, 1); - - UtRegisterTest("DetectHttpHHTest22", DetectHttpHHTest22, 1); - UtRegisterTest("DetectHttpHHTest23", DetectHttpHHTest23, 1); - UtRegisterTest("DetectHttpHHTest24", DetectHttpHHTest24, 1); - UtRegisterTest("DetectHttpHHTest25", DetectHttpHHTest25, 1); - UtRegisterTest("DetectHttpHHTest26", DetectHttpHHTest26, 1); - UtRegisterTest("DetectHttpHHTest27", DetectHttpHHTest27, 1); - UtRegisterTest("DetectHttpHHTest28", DetectHttpHHTest28, 1); - UtRegisterTest("DetectHttpHHTest29", DetectHttpHHTest29, 1); - UtRegisterTest("DetectHttpHHTest30", DetectHttpHHTest30, 1); - UtRegisterTest("DetectHttpHHTest31", DetectHttpHHTest31, 1); - UtRegisterTest("DetectHttpHHTest32", DetectHttpHHTest32, 1); - UtRegisterTest("DetectHttpHHTest33", DetectHttpHHTest33, 1); - UtRegisterTest("DetectHttpHHTest34", DetectHttpHHTest34, 1); - UtRegisterTest("DetectHttpHHTest35", DetectHttpHHTest35, 1); - UtRegisterTest("DetectHttpHHTest36", DetectHttpHHTest36, 1); + UtRegisterTest("DetectHttpHHTest01", DetectHttpHHTest01); + UtRegisterTest("DetectHttpHHTest02", DetectHttpHHTest02); + UtRegisterTest("DetectHttpHHTest03", DetectHttpHHTest03); + UtRegisterTest("DetectHttpHHTest04", DetectHttpHHTest04); + UtRegisterTest("DetectHttpHHTest05", DetectHttpHHTest05); + UtRegisterTest("DetectHttpHHTest05a", DetectHttpHHTest05a); + UtRegisterTest("DetectHttpHHTest06", DetectHttpHHTest06); + UtRegisterTest("DetectHttpHHTest07", DetectHttpHHTest07); + UtRegisterTest("DetectHttpHHTest08", DetectHttpHHTest08); + UtRegisterTest("DetectHttpHHTest09", DetectHttpHHTest09); + UtRegisterTest("DetectHttpHHTest10", DetectHttpHHTest10); + UtRegisterTest("DetectHttpHHTest11", DetectHttpHHTest11); + UtRegisterTest("DetectHttpHHTest12", DetectHttpHHTest12); + UtRegisterTest("DetectHttpHHTest13", DetectHttpHHTest13); + UtRegisterTest("DetectHttpHHTest14", DetectHttpHHTest14); + + UtRegisterTest("DetectHttpHHTest22", DetectHttpHHTest22); + UtRegisterTest("DetectHttpHHTest23", DetectHttpHHTest23); + UtRegisterTest("DetectHttpHHTest24", DetectHttpHHTest24); + UtRegisterTest("DetectHttpHHTest25", DetectHttpHHTest25); + UtRegisterTest("DetectHttpHHTest26", DetectHttpHHTest26); + UtRegisterTest("DetectHttpHHTest27", DetectHttpHHTest27); + UtRegisterTest("DetectHttpHHTest28", DetectHttpHHTest28); + UtRegisterTest("DetectHttpHHTest29", DetectHttpHHTest29); + UtRegisterTest("DetectHttpHHTest30", DetectHttpHHTest30); + UtRegisterTest("DetectHttpHHTest31", DetectHttpHHTest31); + UtRegisterTest("DetectHttpHHTest32", DetectHttpHHTest32); + UtRegisterTest("DetectHttpHHTest33", DetectHttpHHTest33); + UtRegisterTest("DetectHttpHHTest34", DetectHttpHHTest34); + UtRegisterTest("DetectHttpHHTest35", DetectHttpHHTest35); + UtRegisterTest("DetectHttpHHTest36", DetectHttpHHTest36); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-hrh.c b/src/detect-http-hrh.c index fd15544c374d..a477a5157033 100644 --- a/src/detect-http-hrh.c +++ b/src/detect-http-hrh.c @@ -57,10 +57,13 @@ #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-hrh.h" +#include "detect-engine-hrhhd.h" -int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpHRHRegisterTests(void); -void DetectHttpHRHFree(void *); +static int DetectHttpHRHSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpHRHRegisterTests(void); +static void DetectHttpHRHFree(void *); +static void DetectHttpHostRawSetupCallback(Signature *); +static int g_http_raw_host_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_raw_host" keyword. @@ -70,16 +73,26 @@ void DetectHttpHRHRegister(void) sigmatch_table[DETECT_AL_HTTP_RAW_HOST].name = "http_raw_host"; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].desc = "content modifier to match only on the HTTP host header or the raw hostname from the HTTP uri"; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Setup = DetectHttpHRHSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].Free = DetectHttpHRHFree; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].RegisterTests = DetectHttpHRHRegisterTests; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_NOOPT ; - sigmatch_table[DETECT_AL_HTTP_RAW_HOST].flags |= SIGMATCH_PAYLOAD ; - return; + DetectAppLayerMpmRegister("http_raw_host", SIG_FLAG_TOSERVER, 2, + PrefilterTxHostnameRawRegister); + + DetectAppLayerInspectEngineRegister("http_raw_host", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpHRH); + + DetectBufferTypeSetDescriptionByName("http_raw_host", + "http raw host header"); + + DetectBufferTypeRegisterSetupCallback("http_raw_host", + DetectHttpHostRawSetupCallback); + + g_http_raw_host_buffer_id = DetectBufferTypeGetByName("http_raw_host"); } /** @@ -99,9 +112,14 @@ int DetectHttpHRHSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_HOST, - DETECT_SM_LIST_HRHHDMATCH, - ALPROTO_HTTP, - NULL); + g_http_raw_host_buffer_id, + ALPROTO_HTTP); +} + +static void DetectHttpHostRawSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } /** @@ -118,7 +136,7 @@ void DetectHttpHRHFree(void *ptr) if (hrhhd->content != NULL) SCFree(hrhhd->content); - BoyerMooreCtxDeInit(hrhhd->bm_ctx); + SpmDestroyCtx(hrhhd->spm_ctx); SCFree(hrhhd); return; @@ -330,15 +348,16 @@ static int DetectHttpHRHTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -437,15 +456,16 @@ static int DetectHttpHRHTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -461,14 +481,15 @@ static int DetectHttpHRHTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -560,15 +581,16 @@ static int DetectHttpHRHTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -585,15 +607,16 @@ static int DetectHttpHRHTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -690,15 +713,16 @@ static int DetectHttpHRHTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -715,15 +739,16 @@ static int DetectHttpHRHTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -820,15 +845,16 @@ static int DetectHttpHRHTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -845,15 +871,16 @@ static int DetectHttpHRHTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -939,15 +966,16 @@ static int DetectHttpHRHTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1038,15 +1066,16 @@ static int DetectHttpHRHTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1138,15 +1167,16 @@ static int DetectHttpHRHTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1246,14 +1276,15 @@ static int DetectHttpHRHTest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1263,14 +1294,15 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1280,14 +1312,15 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1297,14 +1330,15 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1314,14 +1348,15 @@ static int DetectHttpHRHTest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1333,14 +1368,15 @@ static int DetectHttpHRHTest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1380,13 +1416,6 @@ static int DetectHttpHRHTest14(void) return result; } - - - - - - - int DetectHttpHRHTest22(void) { DetectEngineCtx *de_ctx = NULL; @@ -1409,15 +1438,15 @@ int DetectHttpHRHTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1464,15 +1493,15 @@ int DetectHttpHRHTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1518,15 +1547,15 @@ int DetectHttpHRHTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || @@ -1573,15 +1602,15 @@ int DetectHttpHRHTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1629,15 +1658,15 @@ int DetectHttpHRHTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1712,15 +1741,15 @@ int DetectHttpHRHTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1767,13 +1796,13 @@ int DetectHttpHRHTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || @@ -1811,13 +1840,13 @@ int DetectHttpHRHTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "one", hrhhd1->content_len) != 0 || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || @@ -1927,21 +1956,21 @@ int DetectHttpHRHTest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_WITHIN) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { @@ -1978,21 +2007,21 @@ int DetectHttpHRHTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hrhhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectContentData *hrhhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE | DETECT_PCRE_CASELESS) || hrhhd1->flags != (DETECT_CONTENT_RELATIVE_NEXT) || memcmp(hrhhd1->content, "two", hrhhd1->content_len) != 0) { @@ -2029,21 +2058,21 @@ int DetectHttpHRHTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_host_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->prev->ctx; - DetectContentData *hrhhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->prev->ctx; + DetectContentData *hrhhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_host_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT | DETECT_PCRE_CASELESS) || hrhhd2->flags != (DETECT_CONTENT_DISTANCE) || memcmp(hrhhd2->content, "two", hrhhd2->content_len) != 0) { @@ -2127,15 +2156,16 @@ static int DetectHttpHRHTest37(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2152,15 +2182,16 @@ static int DetectHttpHRHTest37(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2193,37 +2224,37 @@ static int DetectHttpHRHTest37(void) void DetectHttpHRHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpHRHTest01", DetectHttpHRHTest01, 1); - UtRegisterTest("DetectHttpHRHTest02", DetectHttpHRHTest02, 1); - UtRegisterTest("DetectHttpHRHTest03", DetectHttpHRHTest03, 1); - UtRegisterTest("DetectHttpHRHTest04", DetectHttpHRHTest04, 1); - UtRegisterTest("DetectHttpHRHTest05", DetectHttpHRHTest05, 1); - UtRegisterTest("DetectHttpHRHTest06", DetectHttpHRHTest06, 1); - UtRegisterTest("DetectHttpHRHTest07", DetectHttpHRHTest07, 1); - UtRegisterTest("DetectHttpHRHTest08", DetectHttpHRHTest08, 1); - UtRegisterTest("DetectHttpHRHTest09", DetectHttpHRHTest09, 1); - UtRegisterTest("DetectHttpHRHTest10", DetectHttpHRHTest10, 1); - UtRegisterTest("DetectHttpHRHTest11", DetectHttpHRHTest11, 1); - UtRegisterTest("DetectHttpHRHTest12", DetectHttpHRHTest12, 1); - UtRegisterTest("DetectHttpHRHTest13", DetectHttpHRHTest13, 1); - UtRegisterTest("DetectHttpHRHTest14", DetectHttpHRHTest14, 1); - - UtRegisterTest("DetectHttpHRHTest22", DetectHttpHRHTest22, 1); - UtRegisterTest("DetectHttpHRHTest23", DetectHttpHRHTest23, 1); - UtRegisterTest("DetectHttpHRHTest24", DetectHttpHRHTest24, 1); - UtRegisterTest("DetectHttpHRHTest25", DetectHttpHRHTest25, 1); - UtRegisterTest("DetectHttpHRHTest26", DetectHttpHRHTest26, 1); - UtRegisterTest("DetectHttpHRHTest27", DetectHttpHRHTest27, 1); - UtRegisterTest("DetectHttpHRHTest28", DetectHttpHRHTest28, 1); - UtRegisterTest("DetectHttpHRHTest29", DetectHttpHRHTest29, 1); - UtRegisterTest("DetectHttpHRHTest30", DetectHttpHRHTest30, 1); - UtRegisterTest("DetectHttpHRHTest31", DetectHttpHRHTest31, 1); - UtRegisterTest("DetectHttpHRHTest32", DetectHttpHRHTest32, 1); - UtRegisterTest("DetectHttpHRHTest33", DetectHttpHRHTest33, 1); - UtRegisterTest("DetectHttpHRHTest34", DetectHttpHRHTest34, 1); - UtRegisterTest("DetectHttpHRHTest35", DetectHttpHRHTest35, 1); - UtRegisterTest("DetectHttpHRHTest36", DetectHttpHRHTest36, 1); - UtRegisterTest("DetectHttpHRHTest37", DetectHttpHRHTest37, 1); + UtRegisterTest("DetectHttpHRHTest01", DetectHttpHRHTest01); + UtRegisterTest("DetectHttpHRHTest02", DetectHttpHRHTest02); + UtRegisterTest("DetectHttpHRHTest03", DetectHttpHRHTest03); + UtRegisterTest("DetectHttpHRHTest04", DetectHttpHRHTest04); + UtRegisterTest("DetectHttpHRHTest05", DetectHttpHRHTest05); + UtRegisterTest("DetectHttpHRHTest06", DetectHttpHRHTest06); + UtRegisterTest("DetectHttpHRHTest07", DetectHttpHRHTest07); + UtRegisterTest("DetectHttpHRHTest08", DetectHttpHRHTest08); + UtRegisterTest("DetectHttpHRHTest09", DetectHttpHRHTest09); + UtRegisterTest("DetectHttpHRHTest10", DetectHttpHRHTest10); + UtRegisterTest("DetectHttpHRHTest11", DetectHttpHRHTest11); + UtRegisterTest("DetectHttpHRHTest12", DetectHttpHRHTest12); + UtRegisterTest("DetectHttpHRHTest13", DetectHttpHRHTest13); + UtRegisterTest("DetectHttpHRHTest14", DetectHttpHRHTest14); + + UtRegisterTest("DetectHttpHRHTest22", DetectHttpHRHTest22); + UtRegisterTest("DetectHttpHRHTest23", DetectHttpHRHTest23); + UtRegisterTest("DetectHttpHRHTest24", DetectHttpHRHTest24); + UtRegisterTest("DetectHttpHRHTest25", DetectHttpHRHTest25); + UtRegisterTest("DetectHttpHRHTest26", DetectHttpHRHTest26); + UtRegisterTest("DetectHttpHRHTest27", DetectHttpHRHTest27); + UtRegisterTest("DetectHttpHRHTest28", DetectHttpHRHTest28); + UtRegisterTest("DetectHttpHRHTest29", DetectHttpHRHTest29); + UtRegisterTest("DetectHttpHRHTest30", DetectHttpHRHTest30); + UtRegisterTest("DetectHttpHRHTest31", DetectHttpHRHTest31); + UtRegisterTest("DetectHttpHRHTest32", DetectHttpHRHTest32); + UtRegisterTest("DetectHttpHRHTest33", DetectHttpHRHTest33); + UtRegisterTest("DetectHttpHRHTest34", DetectHttpHRHTest34); + UtRegisterTest("DetectHttpHRHTest35", DetectHttpHRHTest35); + UtRegisterTest("DetectHttpHRHTest36", DetectHttpHRHTest36); + UtRegisterTest("DetectHttpHRHTest37", DetectHttpHRHTest37); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-method.c b/src/detect-http-method.c index f398de44837a..433c343291ff 100644 --- a/src/detect-http-method.c +++ b/src/detect-http-method.c @@ -57,12 +57,15 @@ #include "app-layer-htp.h" #include "detect-http-method.h" +#include "detect-engine-hmd.h" #include "stream-tcp.h" - +static int g_http_method_buffer_id = 0; static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, char *); void DetectHttpMethodRegisterTests(void); void DetectHttpMethodFree(void *); +static void DetectHttpMethodSetupCallback(Signature *s); +static _Bool DetectHttpMethodValidateCallback(const Signature *s); /** * \brief Registration function for keyword: http_method @@ -71,15 +74,29 @@ void DetectHttpMethodRegister(void) { sigmatch_table[DETECT_AL_HTTP_METHOD].name = "http_method"; sigmatch_table[DETECT_AL_HTTP_METHOD].desc = "content modifier to match only on the HTTP method-buffer"; - sigmatch_table[DETECT_AL_HTTP_METHOD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_method"; + sigmatch_table[DETECT_AL_HTTP_METHOD].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http-method"; sigmatch_table[DETECT_AL_HTTP_METHOD].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_METHOD].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_METHOD].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_METHOD].Setup = DetectHttpMethodSetup; sigmatch_table[DETECT_AL_HTTP_METHOD].Free = DetectHttpMethodFree; sigmatch_table[DETECT_AL_HTTP_METHOD].RegisterTests = DetectHttpMethodRegisterTests; sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_METHOD].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerMpmRegister("http_method", SIG_FLAG_TOSERVER, 4, + PrefilterTxMethodRegister); + + DetectAppLayerInspectEngineRegister("http_method", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpMethod); + + DetectBufferTypeSetDescriptionByName("http_method", + "http request method"); + + DetectBufferTypeRegisterSetupCallback("http_method", + DetectHttpMethodSetupCallback); + DetectBufferTypeRegisterValidateCallback("http_method", + DetectHttpMethodValidateCallback); + + g_http_method_buffer_id = DetectBufferTypeGetByName("http_method"); SCLogDebug("registering http_method rule option"); } @@ -99,9 +116,8 @@ static int DetectHttpMethodSetup(DetectEngineCtx *de_ctx, Signature *s, char *st { return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_METHOD, - DETECT_SM_LIST_HMDMATCH, - ALPROTO_HTTP, - NULL); + g_http_method_buffer_id, + ALPROTO_HTTP); } /** @@ -118,8 +134,45 @@ void DetectHttpMethodFree(void *ptr) SCFree(data); } +static void DetectHttpMethodSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \retval 1 valid + * \retval 0 invalid + */ +static _Bool DetectHttpMethodValidateCallback(const Signature *s) +{ + const SigMatch *sm = s->init_data->smlists[g_http_method_buffer_id]; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + const DetectContentData *cd = (const DetectContentData *)sm->ctx; + if (cd->content && cd->content_len) { + if (cd->content[cd->content_len-1] == 0x20) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing space"); + return FALSE; + } else if (cd->content[0] == 0x20) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading space"); + return FALSE; + } else if (cd->content[cd->content_len-1] == 0x09) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing tab"); + return FALSE; + } else if (cd->content[0] == 0x09) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading tab"); + return FALSE; + } + } + } + return TRUE; +} + #ifdef UNITTESTS /* UNITTESTS */ +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** \test Check a signature with content */ @@ -287,13 +340,13 @@ static int DetectHttpMethodTest12(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HMDMATCH] == NULL: "); + if (de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_method_buffer_id] == NULL: "); goto end; } - DetectContentData *hmd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; - DetectContentData *hmd2 = de_ctx->sig_list->next->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; + DetectContentData *hmd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_method_buffer_id]->ctx; + DetectContentData *hmd2 = (DetectContentData *)de_ctx->sig_list->next->sm_lists_tail[g_http_method_buffer_id]->ctx; if (!(hmd1->flags & DETECT_CONTENT_NOCASE)) { printf("nocase flag not set on sig 1: "); @@ -462,14 +515,15 @@ static int DetectHttpMethodSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -565,14 +619,15 @@ static int DetectHttpMethodSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -649,7 +704,7 @@ static int DetectHttpMethodSigTest03(void) s = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing http_method\"; " - "content:\" \"; " + "content:\"GET\"; " "http_method; sid:1;)"); if (s == NULL) { SCLogDebug("Bad signature"); @@ -659,14 +714,15 @@ static int DetectHttpMethodSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -755,14 +811,15 @@ static int DetectHttpMethodSigTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -803,6 +860,31 @@ static int DetectHttpMethodSigTest04(void) return result; } +static int DetectHttpMethodIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_method; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_method_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** @@ -812,19 +894,23 @@ void DetectHttpMethodRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ SCLogDebug("Registering tests for DetectHttpMethod..."); - UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01, 1); - UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02, 1); - UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03, 1); - UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04, 1); - UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05, 1); - UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", DetectHttpMethodTest12, 1); - UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13, 1); - UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14, 1); - UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15, 1); - UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01, 1); - UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02, 1); - UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03, 1); - UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04, 1); + UtRegisterTest("DetectHttpMethodTest01", DetectHttpMethodTest01); + UtRegisterTest("DetectHttpMethodTest02", DetectHttpMethodTest02); + UtRegisterTest("DetectHttpMethodTest03", DetectHttpMethodTest03); + UtRegisterTest("DetectHttpMethodTest04", DetectHttpMethodTest04); + UtRegisterTest("DetectHttpMethodTest05", DetectHttpMethodTest05); + UtRegisterTest("DetectHttpMethodTest12 -- nocase flag", + DetectHttpMethodTest12); + UtRegisterTest("DetectHttpMethodTest13", DetectHttpMethodTest13); + UtRegisterTest("DetectHttpMethodTest14", DetectHttpMethodTest14); + UtRegisterTest("DetectHttpMethodTest15", DetectHttpMethodTest15); + UtRegisterTest("DetectHttpMethodSigTest01", DetectHttpMethodSigTest01); + UtRegisterTest("DetectHttpMethodSigTest02", DetectHttpMethodSigTest02); + UtRegisterTest("DetectHttpMethodSigTest03", DetectHttpMethodSigTest03); + UtRegisterTest("DetectHttpMethodSigTest04", DetectHttpMethodSigTest04); + + UtRegisterTest("DetectHttpMethodIsdataatParseTest", + DetectHttpMethodIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-http-method.h b/src/detect-http-method.h index 9e6dc4dd95ef..871177b58749 100644 --- a/src/detect-http-method.h +++ b/src/detect-http-method.h @@ -26,8 +26,6 @@ /* prototypes */ void DetectHttpMethodRegister(void); -int DetectHttpMethodDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, - Flow *, uint8_t, void *); #endif /* __DETECT_HTTP_METHOD_H__ */ diff --git a/src/detect-http-protocol.c b/src/detect-http-protocol.c new file mode 100644 index 000000000000..e87b034b5061 --- /dev/null +++ b/src/detect-http-protocol.c @@ -0,0 +1,239 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support http_protocol sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-http-header-common.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#define KEYWORD_NAME "http_protocol" +#define KEYWORD_DOC "http-keywords#http-protocol" +#define BUFFER_NAME "http_protocol" +#define BUFFER_DESC "http protocol" +static int g_buffer_id = 0; + +/** \brief HTTP Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_protocol == NULL) + return; + + uint32_t buffer_len = bstr_size(tx->request_protocol); + const uint8_t *buffer = bstr_ptr(tx->request_protocol); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpRequestProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestProtocol, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief HTTP Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_protocol == NULL) + return; + + uint32_t buffer_len = bstr_size(tx->response_protocol); + const uint8_t *buffer = bstr_ptr(tx->response_protocol); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpResponseProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseProtocol, + ALPROTO_HTTP, HTP_RESPONSE_LINE, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineHttpProtocol(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + bstr *str = NULL; + htp_tx_t *http_tx = tx; + + if (flags & STREAM_TOSERVER) + str = http_tx->request_protocol; + else if (flags & STREAM_TOCLIENT) + str = http_tx->response_protocol; + + if (str == NULL) + goto end; + + uint32_t buffer_len = bstr_size(str); + uint8_t *buffer = bstr_ptr(str); + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +int DetectHttpProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectHttpProtocolSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpProtocolRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].Setup = DetectHttpProtocolSetup; + + sigmatch_table[DETECT_AL_HTTP_PROTOCOL].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestProtocolRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseProtocolRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + InspectEngineHttpProtocol); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + InspectEngineHttpProtocol); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectHttpProtocolSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-http-protocol.h b/src/detect-http-protocol.h new file mode 100644 index 000000000000..88dde2f8c764 --- /dev/null +++ b/src/detect-http-protocol.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_PROTOCOL_H__ +#define __DETECT_HTTP_PROTOCOL_H__ + +void DetectHttpProtocolRegister(void); + +#endif /* __DETECT_HTTP_PROTOCOL_H__ */ diff --git a/src/detect-http-raw-header.c b/src/detect-http-raw-header.c index 61e2f153c16e..18872b7b4483 100644 --- a/src/detect-http-raw-header.c +++ b/src/detect-http-raw-header.c @@ -57,11 +57,15 @@ #include "app-layer-htp.h" #include "detect-http-raw-header.h" +#include "detect-engine-hrhd.h" #include "stream-tcp.h" -int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpRawHeaderRegisterTests(void); -void DetectHttpRawHeaderFree(void *); +static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpRawHeaderRegisterTests(void); +static void DetectHttpRawHeaderFree(void *); +static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s); +static void DetectHttpRawHeaderSetupCallback(Signature *s); +static int g_http_raw_header_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_raw_header" keyword. @@ -70,16 +74,33 @@ void DetectHttpRawHeaderRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].name = "http_raw_header"; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Setup = DetectHttpRawHeaderSetup; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].Free = DetectHttpRawHeaderFree; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].RegisterTests = DetectHttpRawHeaderRegisterTests; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_RAW_HEADER].flags |= SIGMATCH_PAYLOAD; - return; + DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOSERVER, 2, + PrefilterTxRequestHeadersRawRegister); + DetectAppLayerMpmRegister("http_raw_header", SIG_FLAG_TOCLIENT, 2, + PrefilterTxResponseHeadersRawRegister); + + DetectAppLayerInspectEngineRegister("http_raw_header", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpRawHeader); + DetectAppLayerInspectEngineRegister("http_raw_header", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpRawHeader); + + DetectBufferTypeSetDescriptionByName("http_raw_header", + "raw http headers"); + + DetectBufferTypeRegisterValidateCallback("http_raw_header", + DetectHttpRawHeaderValidateCallback); + DetectBufferTypeRegisterSetupCallback("http_raw_header", + DetectHttpRawHeaderSetupCallback); + + g_http_raw_header_buffer_id = DetectBufferTypeGetByName("http_raw_header"); } @@ -118,15 +139,33 @@ int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_HEADER, - DETECT_SM_LIST_HRHDMATCH, - ALPROTO_HTTP, - NULL); + g_http_raw_header_buffer_id, + ALPROTO_HTTP); +} + +static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s) +{ + if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { + SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " + "without a flow direction. Use flow:to_server for " + "inspecting request headers or flow:to_client for " + "inspecting response headers."); + SCReturnInt(FALSE); + } + return TRUE; +} + +static void DetectHttpRawHeaderSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } /************************************Unittests*********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** @@ -154,7 +193,7 @@ static int DetectHttpRawHeaderTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id]; if (sm != NULL) { result &= (sm->type == DETECT_CONTENT); result &= (sm->next == NULL); @@ -351,15 +390,16 @@ static int DetectHttpRawHeaderTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -460,15 +500,16 @@ static int DetectHttpRawHeaderTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -485,15 +526,16 @@ static int DetectHttpRawHeaderTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -587,15 +629,16 @@ static int DetectHttpRawHeaderTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -612,15 +655,16 @@ static int DetectHttpRawHeaderTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -715,15 +759,16 @@ static int DetectHttpRawHeaderTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -740,15 +785,16 @@ static int DetectHttpRawHeaderTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -843,15 +889,16 @@ static int DetectHttpRawHeaderTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -868,15 +915,16 @@ static int DetectHttpRawHeaderTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -963,15 +1011,16 @@ static int DetectHttpRawHeaderTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1064,15 +1113,16 @@ static int DetectHttpRawHeaderTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1166,15 +1216,16 @@ static int DetectHttpRawHeaderTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1231,13 +1282,13 @@ int DetectHttpRawHeaderTest20(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_DISTANCE || @@ -1275,13 +1326,13 @@ int DetectHttpRawHeaderTest21(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - DetectContentData *hrhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hrhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hrhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hrhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (hrhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hrhd1->content, "one", hrhd1->content_len) != 0 || hrhd2->flags != DETECT_CONTENT_WITHIN || @@ -1391,21 +1442,21 @@ int DetectHttpRawHeaderTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_WITHIN || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1442,21 +1493,21 @@ int DetectHttpRawHeaderTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hhd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectContentData *hhd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hhd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hhd1->content, "two", hhd1->content_len) != 0) { @@ -1493,21 +1544,21 @@ int DetectHttpRawHeaderTest27(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRHDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_header_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->prev->ctx; - DetectContentData *hhd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->prev->ctx; + DetectContentData *hhd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_header_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hhd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hhd2->content, "two", hhd2->content_len) != 0) { @@ -1522,32 +1573,61 @@ int DetectHttpRawHeaderTest27(void) return result; } +static int DetectHttpRawHeaderIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "flow:to_server; " + "content:\"one\"; http_raw_header; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_raw_header_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ void DetectHttpRawHeaderRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpRawHeaderTest01", DetectHttpRawHeaderTest01, 1); - UtRegisterTest("DetectHttpRawHeaderTest02", DetectHttpRawHeaderTest02, 1); - UtRegisterTest("DetectHttpRawHeaderTest03", DetectHttpRawHeaderTest03, 1); - UtRegisterTest("DetectHttpRawHeaderTest04", DetectHttpRawHeaderTest04, 1); - UtRegisterTest("DetectHttpRawHeaderTest05", DetectHttpRawHeaderTest05, 1); - UtRegisterTest("DetectHttpRawHeaderTest06", DetectHttpRawHeaderTest06, 1); - UtRegisterTest("DetectHttpRawHeaderTest07", DetectHttpRawHeaderTest07, 1); - UtRegisterTest("DetectHttpRawHeaderTest08", DetectHttpRawHeaderTest08, 1); - UtRegisterTest("DetectHttpRawHeaderTest09", DetectHttpRawHeaderTest09, 1); - UtRegisterTest("DetectHttpRawHeaderTest10", DetectHttpRawHeaderTest10, 1); - UtRegisterTest("DetectHttpRawHeaderTest11", DetectHttpRawHeaderTest11, 1); - UtRegisterTest("DetectHttpRawHeaderTest12", DetectHttpRawHeaderTest12, 1); - UtRegisterTest("DetectHttpRawHeaderTest13", DetectHttpRawHeaderTest13, 1); - UtRegisterTest("DetectHttpRawHeaderTest20", DetectHttpRawHeaderTest20, 1); - UtRegisterTest("DetectHttpRawHeaderTest21", DetectHttpRawHeaderTest21, 1); - UtRegisterTest("DetectHttpRawHeaderTest22", DetectHttpRawHeaderTest22, 1); - UtRegisterTest("DetectHttpRawHeaderTest23", DetectHttpRawHeaderTest23, 1); - UtRegisterTest("DetectHttpRawHeaderTest24", DetectHttpRawHeaderTest24, 1); - UtRegisterTest("DetectHttpRawHeaderTest25", DetectHttpRawHeaderTest25, 1); - UtRegisterTest("DetectHttpRawHeaderTest26", DetectHttpRawHeaderTest26, 1); - UtRegisterTest("DetectHttpRawHeaderTest27", DetectHttpRawHeaderTest27, 1); + UtRegisterTest("DetectHttpRawHeaderTest01", DetectHttpRawHeaderTest01); + UtRegisterTest("DetectHttpRawHeaderTest02", DetectHttpRawHeaderTest02); + UtRegisterTest("DetectHttpRawHeaderTest03", DetectHttpRawHeaderTest03); + UtRegisterTest("DetectHttpRawHeaderTest04", DetectHttpRawHeaderTest04); + UtRegisterTest("DetectHttpRawHeaderTest05", DetectHttpRawHeaderTest05); + UtRegisterTest("DetectHttpRawHeaderTest06", DetectHttpRawHeaderTest06); + UtRegisterTest("DetectHttpRawHeaderTest07", DetectHttpRawHeaderTest07); + UtRegisterTest("DetectHttpRawHeaderTest08", DetectHttpRawHeaderTest08); + UtRegisterTest("DetectHttpRawHeaderTest09", DetectHttpRawHeaderTest09); + UtRegisterTest("DetectHttpRawHeaderTest10", DetectHttpRawHeaderTest10); + UtRegisterTest("DetectHttpRawHeaderTest11", DetectHttpRawHeaderTest11); + UtRegisterTest("DetectHttpRawHeaderTest12", DetectHttpRawHeaderTest12); + UtRegisterTest("DetectHttpRawHeaderTest13", DetectHttpRawHeaderTest13); + UtRegisterTest("DetectHttpRawHeaderTest20", DetectHttpRawHeaderTest20); + UtRegisterTest("DetectHttpRawHeaderTest21", DetectHttpRawHeaderTest21); + UtRegisterTest("DetectHttpRawHeaderTest22", DetectHttpRawHeaderTest22); + UtRegisterTest("DetectHttpRawHeaderTest23", DetectHttpRawHeaderTest23); + UtRegisterTest("DetectHttpRawHeaderTest24", DetectHttpRawHeaderTest24); + UtRegisterTest("DetectHttpRawHeaderTest25", DetectHttpRawHeaderTest25); + UtRegisterTest("DetectHttpRawHeaderTest26", DetectHttpRawHeaderTest26); + UtRegisterTest("DetectHttpRawHeaderTest27", DetectHttpRawHeaderTest27); + + UtRegisterTest("DetectHttpRawHeaderIsdataatParseTest", + DetectHttpRawHeaderIsdataatParseTest); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-raw-uri.c b/src/detect-http-raw-uri.c index 7cedd8927122..51df60d1b9e7 100644 --- a/src/detect-http-raw-uri.c +++ b/src/detect-http-raw-uri.c @@ -52,10 +52,13 @@ #include "app-layer-htp.h" #include "detect-http-raw-uri.h" +#include "detect-engine-hrud.h" #include "stream-tcp.h" static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, char *); static void DetectHttpRawUriRegisterTests(void); +static void DetectHttpRawUriSetupCallback(Signature *s); +static int g_http_raw_uri_buffer_id = 0; /** * \brief Registration function for keyword http_raw_uri. @@ -64,17 +67,27 @@ void DetectHttpRawUriRegister(void) { sigmatch_table[DETECT_AL_HTTP_RAW_URI].name = "http_raw_uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].desc = "content modifier to match on HTTP uri"; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; + sigmatch_table[DETECT_AL_HTTP_RAW_URI].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_uri-and-http_raw-uri"; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Setup = DetectHttpRawUriSetup; sigmatch_table[DETECT_AL_HTTP_RAW_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_RAW_URI].RegisterTests = DetectHttpRawUriRegisterTests; sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_RAW_URI].flags |= SIGMATCH_PAYLOAD; - return; + DetectAppLayerMpmRegister("http_raw_uri", SIG_FLAG_TOSERVER, 2, + PrefilterTxRawUriRegister); + + DetectAppLayerInspectEngineRegister("http_raw_uri", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpRawUri); + + DetectBufferTypeSetDescriptionByName("http_raw_uri", + "raw http uri"); + + DetectBufferTypeRegisterSetupCallback("http_raw_uri", + DetectHttpRawUriSetupCallback); + + g_http_raw_uri_buffer_id = DetectBufferTypeGetByName("http_raw_uri"); } /** @@ -91,11 +104,15 @@ static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *ar { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_RAW_URI, - DETECT_SM_LIST_HRUDMATCH, - ALPROTO_HTTP, - NULL); + g_http_raw_uri_buffer_id, + ALPROTO_HTTP); } +static void DetectHttpRawUriSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} /******************************** UNITESTS **********************************/ @@ -176,7 +193,7 @@ int DetectHttpRawUriTest03(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -248,19 +265,19 @@ int DetectHttpRawUriTest05(void) printf("sig failed to parse\n"); goto end; } - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) + if (s->sm_lists[g_http_raw_uri_buffer_id] == NULL) goto end; - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH]->type != DETECT_CONTENT) { + if (s->sm_lists[g_http_raw_uri_buffer_id]->type != DETECT_CONTENT) { printf("wrong type\n"); goto end; } char *str = "we are testing http_raw_uri keyword"; int uricomp = memcmp((const char *) - ((DetectContentData*)s->sm_lists[DETECT_SM_LIST_HRUDMATCH]->ctx)->content, + ((DetectContentData*)s->sm_lists[g_http_raw_uri_buffer_id]->ctx)->content, str, strlen(str) - 1); - int urilen = ((DetectContentData*)s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx)->content_len; + int urilen = ((DetectContentData*)s->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx)->content_len; if (uricomp != 0 || urilen != strlen("we are testing http_raw_uri keyword")) { printf("sig failed to parse, content not setup properly\n"); @@ -298,15 +315,15 @@ int DetectHttpRawUriTest12(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -345,15 +362,15 @@ int DetectHttpRawUriTest13(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -464,15 +481,15 @@ int DetectHttpRawUriTest17(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -512,15 +529,15 @@ int DetectHttpRawUriTest18(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HRUDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_raw_uri_buffer_id] == NULL\n"); goto end; } DetectContentData *ud1 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->prev->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->prev->ctx; DetectContentData *ud2 = - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH]->ctx; + (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_raw_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -545,18 +562,18 @@ int DetectHttpRawUriTest18(void) static void DetectHttpRawUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpRawUriTest01", DetectHttpRawUriTest01, 1); - UtRegisterTest("DetectHttpRawUriTest02", DetectHttpRawUriTest02, 1); - UtRegisterTest("DetectHttpRawUriTest03", DetectHttpRawUriTest03, 1); - UtRegisterTest("DetectHttpRawUriTest04", DetectHttpRawUriTest04, 1); - UtRegisterTest("DetectHttpRawUriTest05", DetectHttpRawUriTest05, 1); - UtRegisterTest("DetectHttpRawUriTest12", DetectHttpRawUriTest12, 1); - UtRegisterTest("DetectHttpRawUriTest13", DetectHttpRawUriTest13, 1); - UtRegisterTest("DetectHttpRawUriTest14", DetectHttpRawUriTest14, 1); - UtRegisterTest("DetectHttpRawUriTest15", DetectHttpRawUriTest15, 1); - UtRegisterTest("DetectHttpRawUriTest16", DetectHttpRawUriTest16, 1); - UtRegisterTest("DetectHttpRawUriTest17", DetectHttpRawUriTest17, 1); - UtRegisterTest("DetectHttpRawUriTest18", DetectHttpRawUriTest18, 1); + UtRegisterTest("DetectHttpRawUriTest01", DetectHttpRawUriTest01); + UtRegisterTest("DetectHttpRawUriTest02", DetectHttpRawUriTest02); + UtRegisterTest("DetectHttpRawUriTest03", DetectHttpRawUriTest03); + UtRegisterTest("DetectHttpRawUriTest04", DetectHttpRawUriTest04); + UtRegisterTest("DetectHttpRawUriTest05", DetectHttpRawUriTest05); + UtRegisterTest("DetectHttpRawUriTest12", DetectHttpRawUriTest12); + UtRegisterTest("DetectHttpRawUriTest13", DetectHttpRawUriTest13); + UtRegisterTest("DetectHttpRawUriTest14", DetectHttpRawUriTest14); + UtRegisterTest("DetectHttpRawUriTest15", DetectHttpRawUriTest15); + UtRegisterTest("DetectHttpRawUriTest16", DetectHttpRawUriTest16); + UtRegisterTest("DetectHttpRawUriTest17", DetectHttpRawUriTest17); + UtRegisterTest("DetectHttpRawUriTest18", DetectHttpRawUriTest18); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-request-line.c b/src/detect-http-request-line.c new file mode 100644 index 000000000000..3d4d69b05801 --- /dev/null +++ b/src/detect-http-request-line.c @@ -0,0 +1,332 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support for the http_request_line keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "stream-tcp.h" +#include "detect-http-request-line.h" + +static int DetectHttpRequestLineSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpRequestLineRegisterTests(void); +static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +static void DetectHttpRequestLineSetupCallback(Signature *s); +static int g_http_request_line_buffer_id = 0; + +/** + * \brief Registers the keyword handlers for the "http_request_line" keyword. + */ +void DetectHttpRequestLineRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].name = "http_request_line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].desc = "content modifier to match only on the HTTP request line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_request-line"; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].Setup = DetectHttpRequestLineSetup; + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].RegisterTests = DetectHttpRequestLineRegisterTests; + + sigmatch_table[DETECT_AL_HTTP_REQUEST_LINE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("http_request_line", SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestLineRegister); + + DetectAppLayerInspectEngineRegister("http_request_line", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpRequestLine); + + DetectBufferTypeSetDescriptionByName("http_request_line", + "http request line"); + + DetectBufferTypeRegisterSetupCallback("http_request_line", + DetectHttpRequestLineSetupCallback); + + g_http_request_line_buffer_id = DetectBufferTypeGetByName("http_request_line"); +} + +/** + * \brief The setup function for the http_request_line keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectHttpRequestLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_http_request_line_buffer_id; + s->alproto = ALPROTO_HTTP; + return 0; +} + +static void DetectHttpRequestLineSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** \brief HTTP request line Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestLine(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_line == NULL) + return; + + const uint32_t buffer_len = bstr_len(tx->request_line); + const uint8_t *buffer = bstr_ptr(tx->request_line); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpRequestLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestLine, + ALPROTO_HTTP, HTP_REQUEST_LINE, + mpm_ctx, NULL, "http_request_line"); +} + +/** + * \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match. + * \retval 1 match. + * \retval 2 Sig can't match. + */ +static int DetectEngineInspectHttpRequestLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->request_line == NULL) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + det_ctx->discontinue_matching = 0; + det_ctx->buffer_offset = 0; + det_ctx->inspection_recursion_counter = 0; + + /* Inspect all the uricontents fetched on each + * transaction at the app layer */ + int r = DetectEngineContentInspection(de_ctx, det_ctx, + s, smd, + f, + bstr_ptr(tx->request_line), + bstr_len(tx->request_line), + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containting a http_request_line is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpRequestLineTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(http_request_line; content:\"GET /\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + PASS; +} + + +/** + *\test Test that the http_request_line content matches against a http request + * which holds the content. + */ +static int DetectHttpRequestLineTest02(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF_NULL(p); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(http_request_line; content:\"GET /index.html HTTP/1.0\"; " + "sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + + FAIL_IF(!(PacketAlertCheck(p, 1))); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +#endif /* UNITTESTS */ + +static void DetectHttpRequestLineRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectHttpRequestLineTest01", DetectHttpRequestLineTest01); + UtRegisterTest("DetectHttpRequestLineTest02", DetectHttpRequestLineTest02); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-http-request-line.h b/src/detect-http-request-line.h new file mode 100644 index 000000000000..64751b7ee32e --- /dev/null +++ b/src/detect-http-request-line.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_REQUEST_LINE_H__ +#define __DETECT_HTTP_REQUEST_LINE_H__ + +void DetectHttpRequestLineRegister(void); + +#endif /* __DETECT_HTTP_REQUEST_LINE_H__ */ diff --git a/src/detect-http-response-line.c b/src/detect-http-response-line.c new file mode 100644 index 000000000000..cb28358c922f --- /dev/null +++ b/src/detect-http-response-line.c @@ -0,0 +1,348 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support for the http_response_line keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "stream-tcp.h" +#include "detect-http-response-line.h" + +static int DetectHttpResponseLineSetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpResponseLineRegisterTests(void); +static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx); +static int DetectEngineInspectHttpResponseLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id); +static void DetectHttpResponseLineSetupCallback(Signature *s); +static int g_http_response_line_id = 0; + +/** + * \brief Registers the keyword handlers for the "http_response_line" keyword. + */ +void DetectHttpResponseLineRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].name = "http_response_line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].desc = "content modifier to match only on the HTTP response line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_response-line"; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Match = NULL; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].Setup = DetectHttpResponseLineSetup; + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].RegisterTests = DetectHttpResponseLineRegisterTests; + + sigmatch_table[DETECT_AL_HTTP_RESPONSE_LINE].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("http_response_line", SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseLineRegister); + + DetectAppLayerInspectEngineRegister("http_response_line", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpResponseLine); + + DetectBufferTypeSetDescriptionByName("http_response_line", + "http response line"); + + DetectBufferTypeRegisterSetupCallback("http_response_line", + DetectHttpResponseLineSetupCallback); + + g_http_response_line_id = DetectBufferTypeGetByName("http_response_line"); +} + +/** + * \brief The setup function for the http_response_line keyword for a signature. + * + * \param de_ctx Pointer to the detection engine context. + * \param s Pointer to the signature for the current Signature being + * parsed from the rules. + * \param m Pointer to the head of the SigMatch for the current rule + * being parsed. + * \param arg Pointer to the string holding the keyword value. + * + * \retval 0 On success + * \retval -1 On failure + */ +static int DetectHttpResponseLineSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_http_response_line_id; + s->alproto = ALPROTO_HTTP; + return 0; +} + +static void DetectHttpResponseLineSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** \brief HTTP response line Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseLine(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_line == NULL) + return; + + const uint32_t buffer_len = bstr_len(tx->response_line); + const uint8_t *buffer = bstr_ptr(tx->response_line); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpResponseLineRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + return PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseLine, + ALPROTO_HTTP, HTP_RESPONSE_LINE, + mpm_ctx, NULL, "http_response_line"); +} + +/** + * \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match. + * \retval 1 match. + * \retval 2 Sig can't match. + */ +int DetectEngineInspectHttpResponseLine(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id) +{ + htp_tx_t *tx = (htp_tx_t *)txv; + + if (tx->response_line == NULL) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_LINE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + else + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; + } + + det_ctx->discontinue_matching = 0; + det_ctx->buffer_offset = 0; + det_ctx->inspection_recursion_counter = 0; + +#if 0 + PrintRawDataFp(stdout, (uint8_t *)bstr_ptr(tx->response_line), + bstr_len(tx->response_line)); +#endif + + /* run the inspection against the buffer */ + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + bstr_ptr(tx->response_line), + bstr_len(tx->response_line), + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) { + return DETECT_ENGINE_INSPECT_SIG_MATCH; + } else { + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } +} + +/************************************Unittests*********************************/ + +#ifdef UNITTESTS + +#include "stream-tcp-reassemble.h" + +/** + * \test Test that a signature containting a http_response_line is correctly parsed + * and the keyword is registered. + */ +static int DetectHttpResponseLineTest01(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " + "(http_response_line; content:\"200 OK\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + DetectEngineCtxFree(de_ctx); + PASS; +} + + +/** + *\test Test that the http_response_line content matches against a http request + * which holds the content. + */ +static int DetectHttpResponseLineTest02(void) +{ + TcpSession ssn; + Packet *p = NULL; + ThreadVars th_v; + DetectEngineCtx *de_ctx = NULL; + DetectEngineThreadCtx *det_ctx = NULL; + HtpState *http_state = NULL; + Flow f; + uint8_t http_buf[] = + "GET /index.html HTTP/1.0\r\n" + "Host: www.openinfosecfoundation.org\r\n" + "User-Agent: This is dummy message body\r\n" + "Content-Type: text/html\r\n" + "\r\n"; + uint32_t http_len = sizeof(http_buf) - 1; + uint8_t http_buf2[] = + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 7\r\n" + "\r\n" + "message"; + uint32_t http_len2 = sizeof(http_buf2) - 1; + + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + FAIL_IF_NULL(alp_tctx); + + memset(&th_v, 0, sizeof(th_v)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + FAIL_IF_NULL(p); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flowflags |= (FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED); + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " + "(http_response_line; content:\"HTTP/1.0 200 OK\"; " + "sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FAIL_IF(r != 0); + + http_state = f.alstate; + FAIL_IF_NULL(http_state); + + r = AppLayerParserParse(&th_v, alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, http_buf2, http_len2); + FAIL_IF(r != 0); + + /* do detect */ + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(PacketAlertCheck(p, 1)); + + p->flowflags = (FLOW_PKT_TOCLIENT|FLOW_PKT_ESTABLISHED); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + FAIL_IF(!(PacketAlertCheck(p, 1))); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + PASS; +} + +#endif /* UNITTESTS */ + +void DetectHttpResponseLineRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectHttpResponseLineTest01", DetectHttpResponseLineTest01); + UtRegisterTest("DetectHttpResponseLineTest02", DetectHttpResponseLineTest02); +#endif /* UNITTESTS */ + + return; +} +/** + * @} + */ diff --git a/src/detect-http-response-line.h b/src/detect-http-response-line.h new file mode 100644 index 000000000000..0563feaf60b1 --- /dev/null +++ b/src/detect-http-response-line.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_RESPONSE_LINE_H__ +#define __DETECT_HTTP_RESPONSE_LINE_H__ + +void DetectHttpResponseLineRegister(void); + +#endif /* __DETECT_HTTP_RESPONSE_LINE_H__ */ diff --git a/src/detect-http-server-body.c b/src/detect-http-server-body.c index 01a9def8f2fd..145995e83929 100644 --- a/src/detect-http-server-body.c +++ b/src/detect-http-server-body.c @@ -59,9 +59,11 @@ #include "detect-http-server-body.h" #include "stream-tcp.h" -int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpServerBodyRegisterTests(void); -void DetectHttpServerBodyFree(void *); +static int DetectHttpServerBodySetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpServerBodyRegisterTests(void); +static void DetectHttpServerBodyFree(void *); + +static int g_file_data_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_server_body" keyword. @@ -70,24 +72,15 @@ void DetectHttpServerBodyRegister(void) { sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].name = "http_server_body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].desc = "content modifier to match only on the HTTP response-body"; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_server_body"; + sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_server-body"; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Setup = DetectHttpServerBodySetup; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].Free = DetectHttpServerBodyFree; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].RegisterTests = DetectHttpServerBodyRegisterTests; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_SERVER_BODY].flags |= SIGMATCH_PAYLOAD ; -} -static void DetectHttpServerBodySetupCallback(Signature *s) -{ - s->flags |= SIG_FLAG_APPLAYER; - AppLayerHtpEnableResponseBodyCallback(); - - return; + g_file_data_buffer_id = DetectBufferTypeRegister("file_data"); } /** @@ -107,9 +100,8 @@ int DetectHttpServerBodySetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_SERVER_BODY, - DETECT_SM_LIST_HSBDMATCH, - ALPROTO_HTTP, - DetectHttpServerBodySetupCallback); + g_file_data_buffer_id, + ALPROTO_HTTP); } /** @@ -127,7 +119,7 @@ void DetectHttpServerBodyFree(void *ptr) if (hsbd->content != NULL) SCFree(hsbd->content); - BoyerMooreCtxDeInit(hsbd->bm_ctx); + SpmDestroyCtx(hsbd->spm_ctx); SCFree(hsbd); SCReturn; @@ -167,7 +159,7 @@ static int DetectHttpServerBodyTest01(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { goto end; } @@ -366,22 +358,28 @@ static int DetectHttpServerBodyTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -489,21 +487,26 @@ static int DetectHttpServerBodyTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -519,14 +522,16 @@ static int DetectHttpServerBodyTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -626,15 +631,17 @@ static int DetectHttpServerBodyTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -643,15 +650,17 @@ static int DetectHttpServerBodyTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -661,15 +670,17 @@ static int DetectHttpServerBodyTest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -773,15 +784,17 @@ static int DetectHttpServerBodyTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -790,15 +803,17 @@ static int DetectHttpServerBodyTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -808,23 +823,27 @@ static int DetectHttpServerBodyTest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -928,15 +947,17 @@ static int DetectHttpServerBodyTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -945,15 +966,17 @@ static int DetectHttpServerBodyTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -963,23 +986,27 @@ static int DetectHttpServerBodyTest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1079,15 +1106,17 @@ static int DetectHttpServerBodyTest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1096,15 +1125,17 @@ static int DetectHttpServerBodyTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -1114,15 +1145,17 @@ static int DetectHttpServerBodyTest11(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1222,15 +1255,17 @@ static int DetectHttpServerBodyTest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1239,15 +1274,17 @@ static int DetectHttpServerBodyTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -1257,15 +1294,17 @@ static int DetectHttpServerBodyTest12(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1353,22 +1392,28 @@ static int DetectHttpServerBodyTest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1480,23 +1525,26 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 1"); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } SCLogDebug("add chunk 2"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("inspect chunk 1"); @@ -1510,23 +1558,25 @@ static int DetectHttpServerBodyTest14(void) SCLogDebug("add chunk 3"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } SCLogDebug("add chunk 4"); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCLogDebug("inspect chunk 4"); @@ -1646,21 +1696,24 @@ static int DetectHttpServerBodyTest15(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1674,21 +1727,23 @@ static int DetectHttpServerBodyTest15(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1740,7 +1795,7 @@ int DetectHttpServerBodyTest22(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; content:\"two\"; http_server_body; " "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -1753,15 +1808,15 @@ int DetectHttpServerBodyTest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1795,7 +1850,7 @@ int DetectHttpServerBodyTest23(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -1808,15 +1863,15 @@ int DetectHttpServerBodyTest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1849,7 +1904,7 @@ int DetectHttpServerBodyTest24(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; within:15; http_server_body; content:\"four\"; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -1862,15 +1917,15 @@ int DetectHttpServerBodyTest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1903,7 +1958,7 @@ int DetectHttpServerBodyTest25(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; " "content:\"four\"; distance:10; sid:1;)"); @@ -1917,15 +1972,15 @@ int DetectHttpServerBodyTest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1959,7 +2014,7 @@ int DetectHttpServerBodyTest26(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_server_body; pcre:/two/; " "content:\"three\"; distance:10; http_server_body; within:10; " "content:\"four\"; distance:10; sid:1;)"); @@ -1973,15 +2028,15 @@ int DetectHttpServerBodyTest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2016,7 +2071,7 @@ int DetectHttpServerBodyTest27(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; offset:10; http_server_body; pcre:/two/; distance:10; " "content:\"three\"; distance:10; http_server_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); @@ -2042,7 +2097,7 @@ int DetectHttpServerBodyTest28(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; pcre:/two/; " "content:\"three\"; http_server_body; depth:10; " "content:\"four\"; distance:10; sid:1;)"); @@ -2056,15 +2111,15 @@ int DetectHttpServerBodyTest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -2098,7 +2153,7 @@ int DetectHttpServerBodyTest29(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; distance:0; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2111,13 +2166,13 @@ int DetectHttpServerBodyTest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_DISTANCE || @@ -2142,7 +2197,7 @@ int DetectHttpServerBodyTest30(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; " "content:\"two\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2155,13 +2210,13 @@ int DetectHttpServerBodyTest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "one", hsbd1->content_len) != 0 || hsbd2->flags != DETECT_CONTENT_WITHIN || @@ -2186,7 +2241,7 @@ int DetectHttpServerBodyTest31(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2210,7 +2265,7 @@ int DetectHttpServerBodyTest32(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; http_server_body; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2234,7 +2289,7 @@ int DetectHttpServerBodyTest33(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"one\"; within:5; sid:1;)"); if (de_ctx->sig_list == NULL) { printf("de_ctx->sig_list == NULL\n"); @@ -2254,38 +2309,32 @@ int DetectHttpServerBodyTest34(void) DetectEngineCtx *de_ctx = NULL; int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; within:5; http_server_body; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("de_ctx->sig_list == NULL\n"); - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH] != NULL\n"); - goto end; - } + FAIL_IF_NOT_NULL(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_PMATCH]); - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_WITHIN || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { @@ -2309,7 +2358,7 @@ int DetectHttpServerBodyTest35(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(content:\"two\"; http_server_body; " "pcre:/one/QR; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2322,21 +2371,21 @@ int DetectHttpServerBodyTest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *hsbd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectContentData *hsbd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || hsbd1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(hsbd1->content, "two", hsbd1->content_len) != 0) { @@ -2360,7 +2409,7 @@ int DetectHttpServerBodyTest36(void) goto end; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(pcre:/one/Q; " "content:\"two\"; distance:5; http_server_body; sid:1;)"); if (de_ctx->sig_list == NULL) { @@ -2373,21 +2422,21 @@ int DetectHttpServerBodyTest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_file_data_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->prev->ctx; - DetectContentData *hsbd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->prev->ctx; + DetectContentData *hsbd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_file_data_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || hsbd2->flags != DETECT_CONTENT_DISTANCE || memcmp(hsbd2->content, "two", hsbd2->content_len) != 0) { @@ -2428,7 +2477,6 @@ static int DetectHttpServerBodyFileDataTest01(void) "\r\n" "message"; uint32_t http_len2 = sizeof(http_buf2) - 1; - int result = 0; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); @@ -2451,68 +2499,43 @@ static int DetectHttpServerBodyFileDataTest01(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any " "(msg:\"http server body test\"; " "file_data; content:\"message\"; " "sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; + FAIL_IF_NULL(de_ctx->sig_list); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); + FAIL_IF(r != 0); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); + FAIL_IF(r != 0); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: \n"); - result = 0; - goto end; - } + FAIL_IF_NULL(http_state); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - SigCleanSignatures(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /** @@ -2589,23 +2612,28 @@ static int DetectHttpServerBodyFileDataTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2621,14 +2649,16 @@ static int DetectHttpServerBodyFileDataTest02(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -2728,15 +2758,17 @@ static int DetectHttpServerBodyFileDataTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2745,15 +2777,17 @@ static int DetectHttpServerBodyFileDataTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -2763,15 +2797,17 @@ static int DetectHttpServerBodyFileDataTest03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ @@ -2876,15 +2912,17 @@ static int DetectHttpServerBodyFileDataTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -2893,15 +2931,17 @@ static int DetectHttpServerBodyFileDataTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -2911,23 +2951,27 @@ static int DetectHttpServerBodyFileDataTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3031,15 +3075,17 @@ static int DetectHttpServerBodyFileDataTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3048,15 +3094,17 @@ static int DetectHttpServerBodyFileDataTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -3066,23 +3114,27 @@ static int DetectHttpServerBodyFileDataTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf4, http_len4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf4, + http_len4); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3182,15 +3234,17 @@ static int DetectHttpServerBodyFileDataTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3199,15 +3253,17 @@ static int DetectHttpServerBodyFileDataTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -3217,15 +3273,17 @@ static int DetectHttpServerBodyFileDataTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3325,15 +3383,17 @@ static int DetectHttpServerBodyFileDataTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, http_buf1, http_len1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, http_buf1, + http_len1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3342,15 +3402,17 @@ static int DetectHttpServerBodyFileDataTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, http_buf2, http_len2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START, http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); @@ -3360,15 +3422,17 @@ static int DetectHttpServerBodyFileDataTest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, http_buf3, http_len3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, http_buf3, + http_len3); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -3456,22 +3520,28 @@ static int DetectHttpServerBodyFileDataTest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START|STREAM_EOF, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + http_buf, + http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START|STREAM_EOF, http_buf2, http_len2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_START | STREAM_EOF, + http_buf2, + http_len2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -3581,21 +3651,24 @@ static int DetectHttpServerBodyFileDataTest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3605,21 +3678,23 @@ static int DetectHttpServerBodyFileDataTest09(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3737,21 +3812,24 @@ static int DetectHttpServerBodyFileDataTest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3761,21 +3839,23 @@ static int DetectHttpServerBodyFileDataTest10(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_EOF, httpbuf4, httplen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT | STREAM_EOF, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -3823,47 +3903,57 @@ static int DetectHttpServerBodyFileDataTest10(void) void DetectHttpServerBodyRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpServerBodyTest01", DetectHttpServerBodyTest01, 1); - UtRegisterTest("DetectHttpServerBodyTest02", DetectHttpServerBodyTest02, 1); - UtRegisterTest("DetectHttpServerBodyTest03", DetectHttpServerBodyTest03, 1); - UtRegisterTest("DetectHttpServerBodyTest04", DetectHttpServerBodyTest04, 1); - UtRegisterTest("DetectHttpServerBodyTest05", DetectHttpServerBodyTest05, 1); - UtRegisterTest("DetectHttpServerBodyTest06", DetectHttpServerBodyTest06, 1); - UtRegisterTest("DetectHttpServerBodyTest07", DetectHttpServerBodyTest07, 1); - UtRegisterTest("DetectHttpServerBodyTest08", DetectHttpServerBodyTest08, 1); - UtRegisterTest("DetectHttpServerBodyTest09", DetectHttpServerBodyTest09, 1); - UtRegisterTest("DetectHttpServerBodyTest10", DetectHttpServerBodyTest10, 1); - UtRegisterTest("DetectHttpServerBodyTest11", DetectHttpServerBodyTest11, 1); - UtRegisterTest("DetectHttpServerBodyTest12", DetectHttpServerBodyTest12, 1); - UtRegisterTest("DetectHttpServerBodyTest13", DetectHttpServerBodyTest13, 1); - UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14, 1); - UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15, 1); - UtRegisterTest("DetectHttpServerBodyTest22", DetectHttpServerBodyTest22, 1); - UtRegisterTest("DetectHttpServerBodyTest23", DetectHttpServerBodyTest23, 1); - UtRegisterTest("DetectHttpServerBodyTest24", DetectHttpServerBodyTest24, 1); - UtRegisterTest("DetectHttpServerBodyTest25", DetectHttpServerBodyTest25, 1); - UtRegisterTest("DetectHttpServerBodyTest26", DetectHttpServerBodyTest26, 1); - UtRegisterTest("DetectHttpServerBodyTest27", DetectHttpServerBodyTest27, 1); - UtRegisterTest("DetectHttpServerBodyTest28", DetectHttpServerBodyTest28, 1); - UtRegisterTest("DetectHttpServerBodyTest29", DetectHttpServerBodyTest29, 1); - UtRegisterTest("DetectHttpServerBodyTest30", DetectHttpServerBodyTest30, 1); - UtRegisterTest("DetectHttpServerBodyTest31", DetectHttpServerBodyTest31, 1); - UtRegisterTest("DetectHttpServerBodyTest32", DetectHttpServerBodyTest32, 1); - UtRegisterTest("DetectHttpServerBodyTest33", DetectHttpServerBodyTest33, 1); - UtRegisterTest("DetectHttpServerBodyTest34", DetectHttpServerBodyTest34, 1); - UtRegisterTest("DetectHttpServerBodyTest35", DetectHttpServerBodyTest35, 1); - UtRegisterTest("DetectHttpServerBodyTest36", DetectHttpServerBodyTest36, 1); - - UtRegisterTest("DetectHttpServerBodyFileDataTest01", DetectHttpServerBodyFileDataTest01, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest02", DetectHttpServerBodyFileDataTest02, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest03", DetectHttpServerBodyFileDataTest03, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest04", DetectHttpServerBodyFileDataTest04, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest05", DetectHttpServerBodyFileDataTest05, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest06", DetectHttpServerBodyFileDataTest06, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest07", DetectHttpServerBodyFileDataTest07, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest08", DetectHttpServerBodyFileDataTest08, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest09", DetectHttpServerBodyFileDataTest09, 1); - UtRegisterTest("DetectHttpServerBodyFileDataTest10", DetectHttpServerBodyFileDataTest10, 1); + UtRegisterTest("DetectHttpServerBodyTest01", DetectHttpServerBodyTest01); + UtRegisterTest("DetectHttpServerBodyTest02", DetectHttpServerBodyTest02); + UtRegisterTest("DetectHttpServerBodyTest03", DetectHttpServerBodyTest03); + UtRegisterTest("DetectHttpServerBodyTest04", DetectHttpServerBodyTest04); + UtRegisterTest("DetectHttpServerBodyTest05", DetectHttpServerBodyTest05); + UtRegisterTest("DetectHttpServerBodyTest06", DetectHttpServerBodyTest06); + UtRegisterTest("DetectHttpServerBodyTest07", DetectHttpServerBodyTest07); + UtRegisterTest("DetectHttpServerBodyTest08", DetectHttpServerBodyTest08); + UtRegisterTest("DetectHttpServerBodyTest09", DetectHttpServerBodyTest09); + UtRegisterTest("DetectHttpServerBodyTest10", DetectHttpServerBodyTest10); + UtRegisterTest("DetectHttpServerBodyTest11", DetectHttpServerBodyTest11); + UtRegisterTest("DetectHttpServerBodyTest12", DetectHttpServerBodyTest12); + UtRegisterTest("DetectHttpServerBodyTest13", DetectHttpServerBodyTest13); + UtRegisterTest("DetectHttpServerBodyTest14", DetectHttpServerBodyTest14); + UtRegisterTest("DetectHttpServerBodyTest15", DetectHttpServerBodyTest15); + UtRegisterTest("DetectHttpServerBodyTest22", DetectHttpServerBodyTest22); + UtRegisterTest("DetectHttpServerBodyTest23", DetectHttpServerBodyTest23); + UtRegisterTest("DetectHttpServerBodyTest24", DetectHttpServerBodyTest24); + UtRegisterTest("DetectHttpServerBodyTest25", DetectHttpServerBodyTest25); + UtRegisterTest("DetectHttpServerBodyTest26", DetectHttpServerBodyTest26); + UtRegisterTest("DetectHttpServerBodyTest27", DetectHttpServerBodyTest27); + UtRegisterTest("DetectHttpServerBodyTest28", DetectHttpServerBodyTest28); + UtRegisterTest("DetectHttpServerBodyTest29", DetectHttpServerBodyTest29); + UtRegisterTest("DetectHttpServerBodyTest30", DetectHttpServerBodyTest30); + UtRegisterTest("DetectHttpServerBodyTest31", DetectHttpServerBodyTest31); + UtRegisterTest("DetectHttpServerBodyTest32", DetectHttpServerBodyTest32); + UtRegisterTest("DetectHttpServerBodyTest33", DetectHttpServerBodyTest33); + UtRegisterTest("DetectHttpServerBodyTest34", DetectHttpServerBodyTest34); + UtRegisterTest("DetectHttpServerBodyTest35", DetectHttpServerBodyTest35); + UtRegisterTest("DetectHttpServerBodyTest36", DetectHttpServerBodyTest36); + + UtRegisterTest("DetectHttpServerBodyFileDataTest01", + DetectHttpServerBodyFileDataTest01); + UtRegisterTest("DetectHttpServerBodyFileDataTest02", + DetectHttpServerBodyFileDataTest02); + UtRegisterTest("DetectHttpServerBodyFileDataTest03", + DetectHttpServerBodyFileDataTest03); + UtRegisterTest("DetectHttpServerBodyFileDataTest04", + DetectHttpServerBodyFileDataTest04); + UtRegisterTest("DetectHttpServerBodyFileDataTest05", + DetectHttpServerBodyFileDataTest05); + UtRegisterTest("DetectHttpServerBodyFileDataTest06", + DetectHttpServerBodyFileDataTest06); + UtRegisterTest("DetectHttpServerBodyFileDataTest07", + DetectHttpServerBodyFileDataTest07); + UtRegisterTest("DetectHttpServerBodyFileDataTest08", + DetectHttpServerBodyFileDataTest08); + UtRegisterTest("DetectHttpServerBodyFileDataTest09", + DetectHttpServerBodyFileDataTest09); + UtRegisterTest("DetectHttpServerBodyFileDataTest10", + DetectHttpServerBodyFileDataTest10); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-start.c b/src/detect-http-start.c new file mode 100644 index 000000000000..1e5836b77baa --- /dev/null +++ b/src/detect-http-start.c @@ -0,0 +1,336 @@ +/* Copyright (C) 2007-2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup httplayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements http_start + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-http-header-common.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-htp.h" +#include "detect-http-header.h" +#include "stream-tcp.h" + +#include "util-print.h" + +#define KEYWORD_NAME "http_start" +#define KEYWORD_DOC "http-keywords#http-start" +#define BUFFER_NAME "http_start" +#define BUFFER_DESC "http start: request/response line + headers" +static int g_buffer_id = 0; +static int g_keyword_thread_id = 0; + +#define BUFFER_TX_STEP 4 +#define BUFFER_SIZE_STEP 2048 +static HttpHeaderThreadDataConfig g_td_config = { BUFFER_TX_STEP, BUFFER_SIZE_STEP }; + +static uint8_t *GetBufferForTX(htp_tx_t *tx, uint64_t tx_id, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, HtpState *htp_state, uint8_t flags, + uint32_t *buffer_len) +{ + *buffer_len = 0; + + HttpHeaderThreadData *hdr_td = NULL; + HttpHeaderBuffer *buf = HttpHeaderGetBufferSpaceForTXID(det_ctx, f, flags, + tx_id, g_keyword_thread_id, &hdr_td); + if (unlikely(buf == NULL)) { + return NULL; + } else if (buf->len > 0) { + /* already filled buf, reuse */ + *buffer_len = buf->len; + return buf->buffer; + } + + bstr *line = NULL; + htp_table_t *headers; + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_REQUEST_HEADERS) + return NULL; + line = tx->request_line; + headers = tx->request_headers; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= + HTP_RESPONSE_HEADERS) + return NULL; + headers = tx->response_headers; + line = tx->response_line; + } + if (headers == NULL) + return NULL; + + size_t line_size = bstr_len(line) + 2; + if (line_size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, line_size) != 0) { + return NULL; + } + } + memcpy(buf->buffer + buf->len, bstr_ptr(line), bstr_size(line)); + buf->len += bstr_size(line); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + + size_t i = 0; + size_t no_of_headers = htp_table_size(headers); + for (; i < no_of_headers; i++) { + htp_header_t *h = htp_table_get_index(headers, i, NULL); + size_t size1 = bstr_size(h->name); + size_t size2 = bstr_size(h->value); +#if 0 + if (flags & STREAM_TOSERVER) { + if (size1 == 6 && + SCMemcmpLowercase("cookie", bstr_ptr(h->name), 6) == 0) { + continue; + } + } else { + if (size1 == 10 && + SCMemcmpLowercase("set-cookie", bstr_ptr(h->name), 10) == 0) { + continue; + } + } +#endif + size_t size = size1 + size2 + 4; + if (i + 1 == no_of_headers) + size += 2; + if (size + buf->len > buf->size) { + if (HttpHeaderExpandBuffer(hdr_td, buf, size) != 0) { + return NULL; + } + } + + memcpy(buf->buffer + buf->len, bstr_ptr(h->name), bstr_size(h->name)); + buf->len += bstr_size(h->name); + buf->buffer[buf->len++] = ':'; + buf->buffer[buf->len++] = ' '; + memcpy(buf->buffer + buf->len, bstr_ptr(h->value), bstr_size(h->value)); + buf->len += bstr_size(h->value); + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + if (i + 1 == no_of_headers) { + buf->buffer[buf->len++] = '\r'; + buf->buffer[buf->len++] = '\n'; + } + } + + *buffer_len = buf->len; + return buf->buffer; +} + +/** \brief HTTP Start Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpRequestStart(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, + NULL, det_ctx, f, htp_state, + flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpRequestStartRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpRequestStart, + ALPROTO_HTTP, HTP_REQUEST_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief HTTP Start Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxHttpResponseStart(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + htp_tx_t *tx = (htp_tx_t *)txv; + + HtpState *htp_state = f->alstate; + uint32_t buffer_len = 0; + const uint8_t *buffer = GetBufferForTX(tx, idx, NULL, det_ctx, + f, htp_state, flags, &buffer_len); + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxHttpResponseStartRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxHttpResponseStart, + ALPROTO_HTTP, HTP_RESPONSE_HEADERS, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineHttpStart(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)alstate; + uint32_t buffer_len = 0; + uint8_t *buffer = GetBufferForTX(tx, tx_id, + de_ctx, det_ctx, f, htp_state, + flags, &buffer_len); + if (buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (flags & STREAM_TOSERVER) { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } else { + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + } + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectHttpStartSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectHttpStartSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} + +/** + * \brief Registers the keyword handlers for the "http_header" keyword. + */ +void DetectHttpStartRegister(void) +{ + sigmatch_table[DETECT_AL_HTTP_START].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_HTTP_START].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_HTTP_START].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_HTTP_START].Setup = DetectHttpStartSetup; + + sigmatch_table[DETECT_AL_HTTP_START].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxHttpRequestStartRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxHttpResponseStartRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + InspectEngineHttpStart); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + InspectEngineHttpStart); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectHttpStartSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); + + g_keyword_thread_id = DetectRegisterThreadCtxGlobalFuncs(KEYWORD_NAME, + HttpHeaderThreadDataInit, &g_td_config, HttpHeaderThreadDataFree); + + SCLogDebug("keyword %s registered. Thread id %d. " + "Buffer %s registered. Buffer id %d", + KEYWORD_NAME, g_keyword_thread_id, + BUFFER_NAME, g_buffer_id); +} diff --git a/src/detect-http-start.h b/src/detect-http-start.h new file mode 100644 index 000000000000..52cada1c860a --- /dev/null +++ b/src/detect-http-start.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_HTTP_START_H__ +#define __DETECT_HTTP_START_H__ + +void DetectHttpStartRegister(void); + +#endif /* __DETECT_HTTP_START_H__ */ diff --git a/src/detect-http-stat-code.c b/src/detect-http-stat-code.c index 0237009f81c6..80743c92bae1 100644 --- a/src/detect-http-stat-code.c +++ b/src/detect-http-stat-code.c @@ -59,15 +59,14 @@ #include "app-layer-htp.h" #include "detect-http-stat-code.h" +#include "detect-engine-hscd.h" #include "stream-tcp-private.h" #include "stream-tcp.h" -int DetectHttpStatCodeMatch(ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, Signature *, - SigMatch *); static int DetectHttpStatCodeSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpStatCodeRegisterTests(void); -void DetectHttpStatCodeFree(void *); +static void DetectHttpStatCodeRegisterTests(void); +static void DetectHttpStatCodeSetupCallback(Signature *); +static int g_http_stat_code_buffer_id = 0; /** * \brief Registration function for keyword: http_stat_code @@ -76,16 +75,28 @@ void DetectHttpStatCodeRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_CODE].name = "http_stat_code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].desc = "content modifier to match only on HTTP stat-code-buffer"; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_code"; + sigmatch_table[DETECT_AL_HTTP_STAT_CODE].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_stat-code"; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Setup = DetectHttpStatCodeSetup; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].RegisterTests = DetectHttpStatCodeRegisterTests; sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_STAT_CODE].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerMpmRegister("http_stat_code", SIG_FLAG_TOCLIENT, 4, + PrefilterTxHttpStatCodeRegister); + + DetectAppLayerInspectEngineRegister("http_stat_code", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpStatCode); + + DetectBufferTypeSetDescriptionByName("http_stat_code", + "http response status code"); + + DetectBufferTypeRegisterSetupCallback("http_stat_code", + DetectHttpStatCodeSetupCallback); + + g_http_stat_code_buffer_id = DetectBufferTypeGetByName("http_stat_code"); } /** @@ -103,9 +114,14 @@ static int DetectHttpStatCodeSetup(DetectEngineCtx *de_ctx, Signature *s, char * { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_STAT_CODE, - DETECT_SM_LIST_HSCDMATCH, - ALPROTO_HTTP, - NULL); + g_http_stat_code_buffer_id, + ALPROTO_HTTP); +} + +static void DetectHttpStatCodeSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } #ifdef UNITTESTS @@ -148,7 +164,7 @@ int DetectHttpStatCodeTest01(void) printf("sid 3 parse failed: "); goto end; } - if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]->ctx)->flags & + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { goto end; @@ -186,7 +202,7 @@ int DetectHttpStatCodeTest02(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSCDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_code_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -269,21 +285,23 @@ static int DetectHttpStatCodeSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -377,23 +395,25 @@ static int DetectHttpStatCodeSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -493,23 +513,25 @@ static int DetectHttpStatCodeSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -609,23 +631,25 @@ static int DetectHttpStatCodeSigTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -673,12 +697,12 @@ void DetectHttpStatCodeRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01, 1); - UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02, 1); - UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01, 1); - UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02, 1); - UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03, 1); - UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04, 1); + UtRegisterTest("DetectHttpStatCodeTest01", DetectHttpStatCodeTest01); + UtRegisterTest("DetectHttpStatCodeTest02", DetectHttpStatCodeTest02); + UtRegisterTest("DetectHttpStatCodeSigTest01", DetectHttpStatCodeSigTest01); + UtRegisterTest("DetectHttpStatCodeSigTest02", DetectHttpStatCodeSigTest02); + UtRegisterTest("DetectHttpStatCodeSigTest03", DetectHttpStatCodeSigTest03); + UtRegisterTest("DetectHttpStatCodeSigTest04", DetectHttpStatCodeSigTest04); #endif /* UNITTESTS */ } diff --git a/src/detect-http-stat-msg.c b/src/detect-http-stat-msg.c index d2d7685edd0e..5ae19559ecd2 100644 --- a/src/detect-http-stat-msg.c +++ b/src/detect-http-stat-msg.c @@ -59,15 +59,14 @@ #include "app-layer-htp.h" #include "detect-http-stat-msg.h" +#include "detect-engine-hsmd.h" #include "stream-tcp-private.h" #include "stream-tcp.h" -int DetectHttpStatMsgMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, Signature *, - SigMatch *); static int DetectHttpStatMsgSetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpStatMsgRegisterTests(void); -void DetectHttpStatMsgFree(void *); +static void DetectHttpStatMsgRegisterTests(void); +static void DetectHttpStatMsgSetupCallback(Signature *s); +static int g_http_stat_msg_buffer_id = 0; /** * \brief Registration function for keyword: http_stat_msg @@ -76,16 +75,28 @@ void DetectHttpStatMsgRegister (void) { sigmatch_table[DETECT_AL_HTTP_STAT_MSG].name = "http_stat_msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].desc = "content modifier to match on HTTP stat-msg-buffer"; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_stat_msg"; + sigmatch_table[DETECT_AL_HTTP_STAT_MSG].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_stat-msg"; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Setup = DetectHttpStatMsgSetup; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].Free = NULL; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].RegisterTests = DetectHttpStatMsgRegisterTests; sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_STAT_MSG].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerMpmRegister("http_stat_msg", SIG_FLAG_TOCLIENT, 3, + PrefilterTxHttpStatMsgRegister); + + DetectAppLayerInspectEngineRegister("http_stat_msg", + ALPROTO_HTTP, SIG_FLAG_TOCLIENT, + DetectEngineInspectHttpStatMsg); + + DetectBufferTypeSetDescriptionByName("http_stat_msg", + "http response status message"); + + DetectBufferTypeRegisterSetupCallback("http_stat_msg", + DetectHttpStatMsgSetupCallback); + + g_http_stat_msg_buffer_id = DetectBufferTypeGetByName("http_stat_msg"); } /** @@ -103,9 +114,14 @@ static int DetectHttpStatMsgSetup(DetectEngineCtx *de_ctx, Signature *s, char *a { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_STAT_MSG, - DETECT_SM_LIST_HSMDMATCH, - ALPROTO_HTTP, - NULL); + g_http_stat_msg_buffer_id, + ALPROTO_HTTP); +} + +static void DetectHttpStatMsgSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } #ifdef UNITTESTS @@ -140,7 +156,7 @@ int DetectHttpStatMsgTest01(void) "fast_pattern; http_stat_msg; sid:1;)"); if (de_ctx->sig_list == NULL) goto end; - if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]->ctx)->flags & + if (!(((DetectContentData *)de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]->ctx)->flags & DETECT_CONTENT_FAST_PATTERN)) { goto end; @@ -178,7 +194,7 @@ int DetectHttpStatMsgTest02(void) } result = 0; - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSMDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_stat_msg_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -267,23 +283,25 @@ static int DetectHttpStatMsgSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -375,23 +393,25 @@ static int DetectHttpStatMsgSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -487,23 +507,25 @@ static int DetectHttpStatMsgSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf2, httplen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOCLIENT, httpbuf2, httplen2); if (r != 0) { printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -551,11 +573,11 @@ void DetectHttpStatMsgRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpStatMsgTest01", DetectHttpStatMsgTest01, 1); - UtRegisterTest("DetectHttpStatMsgTest02", DetectHttpStatMsgTest02, 1); - UtRegisterTest("DetectHttpStatMsgSigTest01", DetectHttpStatMsgSigTest01, 1); - UtRegisterTest("DetectHttpStatMsgSigTest02", DetectHttpStatMsgSigTest02, 1); - UtRegisterTest("DetectHttpStatMsgSigTest03", DetectHttpStatMsgSigTest03, 1); + UtRegisterTest("DetectHttpStatMsgTest01", DetectHttpStatMsgTest01); + UtRegisterTest("DetectHttpStatMsgTest02", DetectHttpStatMsgTest02); + UtRegisterTest("DetectHttpStatMsgSigTest01", DetectHttpStatMsgSigTest01); + UtRegisterTest("DetectHttpStatMsgSigTest02", DetectHttpStatMsgSigTest02); + UtRegisterTest("DetectHttpStatMsgSigTest03", DetectHttpStatMsgSigTest03); #endif /* UNITTESTS */ } diff --git a/src/detect-http-ua.c b/src/detect-http-ua.c index e335aeb101c4..654e72f05b75 100644 --- a/src/detect-http-ua.c +++ b/src/detect-http-ua.c @@ -57,10 +57,13 @@ #include "app-layer-htp.h" #include "stream-tcp.h" #include "detect-http-ua.h" +#include "detect-engine-hua.h" -int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); -void DetectHttpUARegisterTests(void); -void DetectHttpUAFree(void *); +static int DetectHttpUASetup(DetectEngineCtx *, Signature *, char *); +static void DetectHttpUARegisterTests(void); +static void DetectHttpUAFree(void *); +static void DetectHttpUASetupCallback(Signature *); +static int g_http_ua_buffer_id = 0; /** * \brief Registers the keyword handlers for the "http_user_agent" keyword. @@ -69,18 +72,28 @@ void DetectHttpUARegister(void) { sigmatch_table[DETECT_AL_HTTP_USER_AGENT].name = "http_user_agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].desc = "content modifier to match only on the HTTP User-Agent header"; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_user_agent"; + sigmatch_table[DETECT_AL_HTTP_USER_AGENT].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_user-agent"; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].AppLayerMatch = NULL; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Setup = DetectHttpUASetup; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].Free = DetectHttpUAFree; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].RegisterTests = DetectHttpUARegisterTests; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_USER_AGENT].flags |= SIGMATCH_PAYLOAD ; - return; + DetectAppLayerMpmRegister("http_user_agent", SIG_FLAG_TOSERVER, 2, + PrefilterTxUARegister); + + DetectAppLayerInspectEngineRegister("http_user_agent", + ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpUA); + + DetectBufferTypeSetDescriptionByName("http_user_agent", + "http user agent"); + + DetectBufferTypeRegisterSetupCallback("http_user_agent", + DetectHttpUASetupCallback); + + g_http_ua_buffer_id = DetectBufferTypeGetByName("http_user_agent"); } /** @@ -100,9 +113,14 @@ int DetectHttpUASetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { return DetectEngineContentModifierBufferSetup(de_ctx, s, arg, DETECT_AL_HTTP_USER_AGENT, - DETECT_SM_LIST_HUADMATCH, - ALPROTO_HTTP, - NULL); + g_http_ua_buffer_id, + ALPROTO_HTTP); +} + +static void DetectHttpUASetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; } /** @@ -119,7 +137,7 @@ void DetectHttpUAFree(void *ptr) if (huad->content != NULL) SCFree(huad->content); - BoyerMooreCtxDeInit(huad->bm_ctx); + SpmDestroyCtx(huad->spm_ctx); SCFree(huad); return; @@ -331,15 +349,16 @@ static int DetectHttpUATest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -438,15 +457,16 @@ static int DetectHttpUATest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -462,14 +482,15 @@ static int DetectHttpUATest07(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -561,15 +582,16 @@ static int DetectHttpUATest08(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -586,15 +608,16 @@ static int DetectHttpUATest08(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -691,15 +714,16 @@ static int DetectHttpUATest09(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -716,15 +740,16 @@ static int DetectHttpUATest09(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -821,15 +846,16 @@ static int DetectHttpUATest10(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http1_buf, http1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http1_buf, http1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -846,15 +872,16 @@ static int DetectHttpUATest10(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http2_buf, http2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http2_buf, http2_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: \n", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -940,15 +967,16 @@ static int DetectHttpUATest11(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1039,15 +1067,16 @@ static int DetectHttpUATest12(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1139,15 +1168,16 @@ static int DetectHttpUATest13(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf, http_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf, http_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -1247,14 +1277,15 @@ static int DetectHttpUATest14(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1264,14 +1295,15 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1281,14 +1313,15 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1298,14 +1331,15 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); if (r != 0) { printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1315,14 +1349,15 @@ static int DetectHttpUATest14(void) } p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); if (r != 0) { printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1334,14 +1369,15 @@ static int DetectHttpUATest14(void) SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); if (r != 0) { printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1417,15 +1453,15 @@ int DetectHttpUATest22(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *cd1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (cd1->flags != 0 || memcmp(cd1->content, "one", cd1->content_len) != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1472,15 +1508,15 @@ int DetectHttpUATest23(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1526,15 +1562,15 @@ int DetectHttpUATest24(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != 0 || cd2->flags != 0 || memcmp(cd2->content, "four", cd2->content_len) != 0 || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || @@ -1581,15 +1617,15 @@ int DetectHttpUATest25(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != DETECT_PCRE_RELATIVE_NEXT || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1637,15 +1673,15 @@ int DetectHttpUATest26(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1720,15 +1756,15 @@ int DetectHttpUATest28(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; - DetectContentData *cd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->prev->ctx; + DetectContentData *cd2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || cd2->flags != DETECT_CONTENT_DISTANCE || memcmp(cd2->content, "four", cd2->content_len) != 0 || @@ -1775,13 +1811,13 @@ int DetectHttpUATest29(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_DISTANCE || @@ -1819,13 +1855,13 @@ int DetectHttpUATest30(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "one", huad1->content_len) != 0 || huad2->flags != DETECT_CONTENT_WITHIN || @@ -1935,21 +1971,21 @@ int DetectHttpUATest34(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || huad2->flags != DETECT_CONTENT_WITHIN || memcmp(huad2->content, "two", huad2->content_len) != 0) { @@ -1986,21 +2022,21 @@ int DetectHttpUATest35(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_PCRE || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_CONTENT) { + if (de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->type != DETECT_PCRE || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->type != DETECT_CONTENT) { goto end; } - DetectContentData *huad1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectPcreData *pd2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectContentData *huad1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectPcreData *pd2 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd2->flags != (DETECT_PCRE_RELATIVE) || huad1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(huad1->content, "two", huad1->content_len) != 0) { @@ -2037,21 +2073,21 @@ int DetectHttpUATest36(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HUADMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_ua_buffer_id] == NULL\n"); goto end; } - if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->type != DETECT_CONTENT || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev == NULL || - de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->type != DETECT_PCRE) { + if (de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id] == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->type != DETECT_CONTENT || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev == NULL || + de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->type != DETECT_PCRE) { goto end; } - DetectPcreData *pd1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->prev->ctx; - DetectContentData *huad2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_HUADMATCH]->ctx; + DetectPcreData *pd1 = (DetectPcreData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->prev->ctx; + DetectContentData *huad2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_ua_buffer_id]->ctx; if (pd1->flags != (DETECT_PCRE_RELATIVE_NEXT) || huad2->flags != DETECT_CONTENT_DISTANCE || memcmp(huad2->content, "two", huad2->content_len) != 0) { @@ -2071,36 +2107,36 @@ int DetectHttpUATest36(void) void DetectHttpUARegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01, 1); - UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02, 1); - UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03, 1); - UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04, 1); - UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05, 1); - UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06, 1); - UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07, 1); - UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08, 1); - UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09, 1); - UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10, 1); - UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11, 1); - UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12, 1); - UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13, 1); - UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14, 1); - - UtRegisterTest("DetectHttpUATest22", DetectHttpUATest22, 1); - UtRegisterTest("DetectHttpUATest23", DetectHttpUATest23, 1); - UtRegisterTest("DetectHttpUATest24", DetectHttpUATest24, 1); - UtRegisterTest("DetectHttpUATest25", DetectHttpUATest25, 1); - UtRegisterTest("DetectHttpUATest26", DetectHttpUATest26, 1); - UtRegisterTest("DetectHttpUATest27", DetectHttpUATest27, 1); - UtRegisterTest("DetectHttpUATest28", DetectHttpUATest28, 1); - UtRegisterTest("DetectHttpUATest29", DetectHttpUATest29, 1); - UtRegisterTest("DetectHttpUATest30", DetectHttpUATest30, 1); - UtRegisterTest("DetectHttpUATest31", DetectHttpUATest31, 1); - UtRegisterTest("DetectHttpUATest32", DetectHttpUATest32, 1); - UtRegisterTest("DetectHttpUATest33", DetectHttpUATest33, 1); - UtRegisterTest("DetectHttpUATest34", DetectHttpUATest34, 1); - UtRegisterTest("DetectHttpUATest35", DetectHttpUATest35, 1); - UtRegisterTest("DetectHttpUATest36", DetectHttpUATest36, 1); + UtRegisterTest("DetectHttpUATest01", DetectHttpUATest01); + UtRegisterTest("DetectHttpUATest02", DetectHttpUATest02); + UtRegisterTest("DetectHttpUATest03", DetectHttpUATest03); + UtRegisterTest("DetectHttpUATest04", DetectHttpUATest04); + UtRegisterTest("DetectHttpUATest05", DetectHttpUATest05); + UtRegisterTest("DetectHttpUATest06", DetectHttpUATest06); + UtRegisterTest("DetectHttpUATest07", DetectHttpUATest07); + UtRegisterTest("DetectHttpUATest08", DetectHttpUATest08); + UtRegisterTest("DetectHttpUATest09", DetectHttpUATest09); + UtRegisterTest("DetectHttpUATest10", DetectHttpUATest10); + UtRegisterTest("DetectHttpUATest11", DetectHttpUATest11); + UtRegisterTest("DetectHttpUATest12", DetectHttpUATest12); + UtRegisterTest("DetectHttpUATest13", DetectHttpUATest13); + UtRegisterTest("DetectHttpUATest14", DetectHttpUATest14); + + UtRegisterTest("DetectHttpUATest22", DetectHttpUATest22); + UtRegisterTest("DetectHttpUATest23", DetectHttpUATest23); + UtRegisterTest("DetectHttpUATest24", DetectHttpUATest24); + UtRegisterTest("DetectHttpUATest25", DetectHttpUATest25); + UtRegisterTest("DetectHttpUATest26", DetectHttpUATest26); + UtRegisterTest("DetectHttpUATest27", DetectHttpUATest27); + UtRegisterTest("DetectHttpUATest28", DetectHttpUATest28); + UtRegisterTest("DetectHttpUATest29", DetectHttpUATest29); + UtRegisterTest("DetectHttpUATest30", DetectHttpUATest30); + UtRegisterTest("DetectHttpUATest31", DetectHttpUATest31); + UtRegisterTest("DetectHttpUATest32", DetectHttpUATest32); + UtRegisterTest("DetectHttpUATest33", DetectHttpUATest33); + UtRegisterTest("DetectHttpUATest34", DetectHttpUATest34); + UtRegisterTest("DetectHttpUATest35", DetectHttpUATest35); + UtRegisterTest("DetectHttpUATest36", DetectHttpUATest36); #endif /* UNITTESTS */ return; diff --git a/src/detect-http-uri.c b/src/detect-http-uri.c index a4a4782d7924..64e2c03dd881 100644 --- a/src/detect-http-uri.c +++ b/src/detect-http-uri.c @@ -53,10 +53,13 @@ #include "app-layer-htp.h" #include "detect-http-uri.h" #include "detect-uricontent.h" +#include "detect-engine-uri.h" #include "stream-tcp.h" -int DetectHttpUriSetup (DetectEngineCtx *, Signature *, char *); -void DetectHttpUriRegisterTests(void); +static void DetectHttpUriRegisterTests(void); +static void DetectHttpUriSetupCallback(Signature *s); + +static int g_http_uri_buffer_id = 0; /** * \brief Registration function for keyword: http_uri @@ -65,16 +68,27 @@ void DetectHttpUriRegister (void) { sigmatch_table[DETECT_AL_HTTP_URI].name = "http_uri"; sigmatch_table[DETECT_AL_HTTP_URI].desc = "content modifier to match specifically and only on the HTTP uri-buffer"; - sigmatch_table[DETECT_AL_HTTP_URI].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#http_uri-and-http_raw_uri"; + sigmatch_table[DETECT_AL_HTTP_URI].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#http_uri-and-http_raw-uri"; sigmatch_table[DETECT_AL_HTTP_URI].Match = NULL; - sigmatch_table[DETECT_AL_HTTP_URI].AppLayerMatch = NULL; - sigmatch_table[DETECT_AL_HTTP_URI].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_AL_HTTP_URI].Setup = DetectHttpUriSetup; sigmatch_table[DETECT_AL_HTTP_URI].Free = NULL; sigmatch_table[DETECT_AL_HTTP_URI].RegisterTests = DetectHttpUriRegisterTests; sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_AL_HTTP_URI].flags |= SIGMATCH_PAYLOAD; + + DetectAppLayerMpmRegister("http_uri", SIG_FLAG_TOSERVER, 2, + PrefilterTxUriRegister); + + DetectAppLayerInspectEngineRegister("http_uri", ALPROTO_HTTP, SIG_FLAG_TOSERVER, + DetectEngineInspectHttpUri); + + DetectBufferTypeSetDescriptionByName("http_uri", + "http request uri"); + + DetectBufferTypeRegisterSetupCallback("http_uri", + DetectHttpUriSetupCallback); + + g_http_uri_buffer_id = DetectBufferTypeGetByName("http_uri"); } @@ -93,23 +107,28 @@ int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) { return DetectEngineContentModifierBufferSetup(de_ctx, s, str, DETECT_AL_HTTP_URI, - DETECT_SM_LIST_UMATCH, - ALPROTO_HTTP, - NULL); + g_http_uri_buffer_id, + ALPROTO_HTTP); } +static void DetectHttpUriSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; +} /******************************** UNITESTS **********************************/ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** * \test Checks if a http_uri is registered in a Signature, if content is not * specified in the signature */ -int DetectHttpUriTest01(void) +static int DetectHttpUriTest01(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -133,7 +152,7 @@ int DetectHttpUriTest01(void) * \test Checks if a http_uri is registered in a Signature, if some parameter * is specified with http_uri in the signature */ -int DetectHttpUriTest02(void) +static int DetectHttpUriTest02(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -157,7 +176,7 @@ int DetectHttpUriTest02(void) /** * \test Checks if a http_uri is registered in a Signature */ -int DetectHttpUriTest03(void) +static int DetectHttpUriTest03(void) { SigMatch *sm = NULL; DetectEngineCtx *de_ctx = NULL; @@ -178,7 +197,7 @@ int DetectHttpUriTest03(void) goto end; } - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; + sm = de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]; if (sm == NULL) { printf("no sigmatch(es): "); goto end; @@ -204,7 +223,7 @@ int DetectHttpUriTest03(void) * \test Checks if a http_uri is registered in a Signature, when rawbytes is * also specified in the signature */ -int DetectHttpUriTest04(void) +static int DetectHttpUriTest04(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -229,7 +248,7 @@ int DetectHttpUriTest04(void) * \test Checks if a http_uri is successfully converted to a uricontent * */ -int DetectHttpUriTest05(void) +static int DetectHttpUriTest05(void) { DetectEngineCtx *de_ctx = NULL; Signature *s = NULL; @@ -246,16 +265,16 @@ int DetectHttpUriTest05(void) printf("sig failed to parse\n"); goto end; } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) + if (s->sm_lists[g_http_uri_buffer_id] == NULL) goto end; - if (s->sm_lists[DETECT_SM_LIST_UMATCH]->type != DETECT_CONTENT) { + if (s->sm_lists[g_http_uri_buffer_id]->type != DETECT_CONTENT) { printf("wrong type\n"); goto end; } char *str = "we are testing http_uri keyword"; - int uricomp = memcmp((const char *)((DetectContentData*) s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->content, str, strlen(str)-1); - int urilen = ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->content_len; + int uricomp = memcmp((const char *)((DetectContentData*) s->sm_lists[g_http_uri_buffer_id]->ctx)->content, str, strlen(str)-1); + int urilen = ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->content_len; if (uricomp != 0 || urilen != strlen("we are testing http_uri keyword")) { printf("sig failed to parse, content not setup properly\n"); @@ -269,7 +288,7 @@ int DetectHttpUriTest05(void) return result; } -int DetectHttpUriTest12(void) +static int DetectHttpUriTest12(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -291,13 +310,13 @@ int DetectHttpUriTest12(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -313,7 +332,7 @@ int DetectHttpUriTest12(void) return result; } -int DetectHttpUriTest13(void) +static int DetectHttpUriTest13(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -335,13 +354,13 @@ int DetectHttpUriTest13(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -357,7 +376,7 @@ int DetectHttpUriTest13(void) return result; } -int DetectHttpUriTest14(void) +static int DetectHttpUriTest14(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -381,7 +400,7 @@ int DetectHttpUriTest14(void) return result; } -int DetectHttpUriTest15(void) +static int DetectHttpUriTest15(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -397,12 +416,12 @@ int DetectHttpUriTest15(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *cd = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *cd = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (memcmp(cd->content, "one", cd->content_len) != 0 || cd->flags != DETECT_CONTENT_WITHIN) { goto end; @@ -416,7 +435,7 @@ int DetectHttpUriTest15(void) return result; } -int DetectHttpUriTest16(void) +static int DetectHttpUriTest16(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -440,7 +459,7 @@ int DetectHttpUriTest16(void) return result; } -int DetectHttpUriTest17(void) +static int DetectHttpUriTest17(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -462,13 +481,13 @@ int DetectHttpUriTest17(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_DISTANCE || @@ -484,7 +503,7 @@ int DetectHttpUriTest17(void) return result; } -int DetectHttpUriTest18(void) +static int DetectHttpUriTest18(void) { DetectEngineCtx *de_ctx = NULL; int result = 0; @@ -506,13 +525,13 @@ int DetectHttpUriTest18(void) goto end; } - if (de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL) { - printf("de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL\n"); + if (de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL) { + printf("de_ctx->sig_list->sm_lists[g_http_uri_buffer_id] == NULL\n"); goto end; } - DetectContentData *ud1 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->prev->ctx; - DetectContentData *ud2 = de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + DetectContentData *ud1 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->prev->ctx; + DetectContentData *ud2 = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[g_http_uri_buffer_id]->ctx; if (ud1->flags != DETECT_CONTENT_RELATIVE_NEXT || memcmp(ud1->content, "one", ud1->content_len) != 0 || ud2->flags != DETECT_CONTENT_WITHIN || @@ -528,26 +547,54 @@ int DetectHttpUriTest18(void) return result; } +static int DetectHttpUriIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "content:\"one\"; http_uri; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_uri_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ /** * \brief Register the UNITTESTS for the http_uri keyword */ -void DetectHttpUriRegisterTests (void) +static void DetectHttpUriRegisterTests (void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectHttpUriTest01", DetectHttpUriTest01, 1); - UtRegisterTest("DetectHttpUriTest02", DetectHttpUriTest02, 1); - UtRegisterTest("DetectHttpUriTest03", DetectHttpUriTest03, 1); - UtRegisterTest("DetectHttpUriTest04", DetectHttpUriTest04, 1); - UtRegisterTest("DetectHttpUriTest05", DetectHttpUriTest05, 1); - UtRegisterTest("DetectHttpUriTest12", DetectHttpUriTest12, 1); - UtRegisterTest("DetectHttpUriTest13", DetectHttpUriTest13, 1); - UtRegisterTest("DetectHttpUriTest14", DetectHttpUriTest14, 1); - UtRegisterTest("DetectHttpUriTest15", DetectHttpUriTest15, 1); - UtRegisterTest("DetectHttpUriTest16", DetectHttpUriTest16, 1); - UtRegisterTest("DetectHttpUriTest17", DetectHttpUriTest17, 1); - UtRegisterTest("DetectHttpUriTest18", DetectHttpUriTest18, 1); + UtRegisterTest("DetectHttpUriTest01", DetectHttpUriTest01); + UtRegisterTest("DetectHttpUriTest02", DetectHttpUriTest02); + UtRegisterTest("DetectHttpUriTest03", DetectHttpUriTest03); + UtRegisterTest("DetectHttpUriTest04", DetectHttpUriTest04); + UtRegisterTest("DetectHttpUriTest05", DetectHttpUriTest05); + UtRegisterTest("DetectHttpUriTest12", DetectHttpUriTest12); + UtRegisterTest("DetectHttpUriTest13", DetectHttpUriTest13); + UtRegisterTest("DetectHttpUriTest14", DetectHttpUriTest14); + UtRegisterTest("DetectHttpUriTest15", DetectHttpUriTest15); + UtRegisterTest("DetectHttpUriTest16", DetectHttpUriTest16); + UtRegisterTest("DetectHttpUriTest17", DetectHttpUriTest17); + UtRegisterTest("DetectHttpUriTest18", DetectHttpUriTest18); + + UtRegisterTest("DetectHttpUriIsdataatParseTest", + DetectHttpUriIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-http-uri.h b/src/detect-http-uri.h index cb327804ea0a..b55df07e3318 100644 --- a/src/detect-http-uri.h +++ b/src/detect-http-uri.h @@ -25,10 +25,7 @@ #define _DETECT_HTTP_URI_H /* prototypes */ +int DetectHttpUriSetup (DetectEngineCtx *, Signature *, char *); void DetectHttpUriRegister (void); -int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, char *str); -int DetectHttpUriDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, - SigMatch *sm, Flow *f, uint8_t flags, void *state); - #endif /* _DETECT_HTTP_URI_H */ diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index fefcd025f627..4e9c1f9a41e1 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icmp-id.h" @@ -42,10 +43,13 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpIdRegisterTests(void); void DetectIcmpIdFree(void *); +static int PrefilterSetupIcmpId(SigGroupHead *sgh); +static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: icmp_id @@ -54,52 +58,24 @@ void DetectIcmpIdRegister (void) { sigmatch_table[DETECT_ICMP_ID].name = "icmp_id"; sigmatch_table[DETECT_ICMP_ID].desc = "check for a ICMP id"; - sigmatch_table[DETECT_ICMP_ID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icmp_id"; + sigmatch_table[DETECT_ICMP_ID].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icmp-id"; sigmatch_table[DETECT_ICMP_ID].Match = DetectIcmpIdMatch; sigmatch_table[DETECT_ICMP_ID].Setup = DetectIcmpIdSetup; sigmatch_table[DETECT_ICMP_ID].Free = DetectIcmpIdFree; sigmatch_table[DETECT_ICMP_ID].RegisterTests = DetectIcmpIdRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_ICMP_ID].SupportsPrefilter = PrefilterIcmpIdIsPrefilterable; + sigmatch_table[DETECT_ICMP_ID].SetupPrefilter = PrefilterSetupIcmpId; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \brief This function is used to match icmp_id rule option set on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static inline _Bool GetIcmpId(Packet *p, uint16_t *id) { - uint16_t pid; - DetectIcmpIdData *iid = (DetectIcmpIdData *)m->ctx; - if (PKT_IS_PSEUDOPKT(p)) - return 0; + return FALSE; + uint16_t pid; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ case ICMP_ECHOREPLY: @@ -118,7 +94,7 @@ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, break; default: SCLogDebug("Packet has no id field"); - return 0; + return FALSE; } } else if (PKT_IS_ICMPV6(p)) { switch (ICMPV6_GET_TYPE(p)) { @@ -132,13 +108,37 @@ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, break; default: SCLogDebug("Packet has no id field"); - return 0; + return FALSE; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); - return 0; + return FALSE; } + *id = pid; + return TRUE; +} + +/** + * \brief This function is used to match icmp_id rule option set on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) +{ + uint16_t pid; + + if (GetIcmpId(p, &pid) == FALSE) + return 0; + + const DetectIcmpIdData *iid = (const DetectIcmpIdData *)ctx; if (pid == iid->id) return 1; @@ -240,7 +240,7 @@ static int DetectIcmpIdSetup (DetectEngineCtx *de_ctx, Signature *s, char *icmpi if (sm == NULL) goto error; sm->type = DETECT_ICMP_ID; - sm->ctx = (void *)iid; + sm->ctx = (SigMatchCtx *)iid; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -265,9 +265,61 @@ void DetectIcmpIdFree (void *ptr) SCFree(iid); } -#ifdef UNITTESTS +/* prefilter code */ -#include "detect-parse.h" +static void +PrefilterPacketIcmpIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + uint16_t pid; + if (GetIcmpId(p, &pid) == FALSE) + return; + + if (pid == ctx->v1.u16[0]) + { + SCLogDebug("packet matches ICMP ID %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIcmpIdSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIcmpIdData *a = smctx; + v->u16[0] = a->id; +} + +static _Bool +PrefilterPacketIcmpIdCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIcmpIdData *a = smctx; + if (v.u16[0] == a->id) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIcmpId(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ICMP_ID, + PrefilterPacketIcmpIdSet, + PrefilterPacketIcmpIdCompare, + PrefilterPacketIcmpIdMatch); +} + +static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICMP_ID: + return TRUE; + } + } + return FALSE; +} + +#ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -488,13 +540,13 @@ int DetectIcmpIdMatchTest02 (void) void DetectIcmpIdRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("DetectIcmpIdParseTest01", DetectIcmpIdParseTest01, 1); - UtRegisterTest("DetectIcmpIdParseTest02", DetectIcmpIdParseTest02, 1); - UtRegisterTest("DetectIcmpIdParseTest03", DetectIcmpIdParseTest03, 1); - UtRegisterTest("DetectIcmpIdParseTest04", DetectIcmpIdParseTest04, 1); - UtRegisterTest("DetectIcmpIdParseTest05", DetectIcmpIdParseTest05, 1); - UtRegisterTest("DetectIcmpIdMatchTest01", DetectIcmpIdMatchTest01, 1); - UtRegisterTest("DetectIcmpIdMatchTest02", DetectIcmpIdMatchTest02, 1); + UtRegisterTest("DetectIcmpIdParseTest01", DetectIcmpIdParseTest01); + UtRegisterTest("DetectIcmpIdParseTest02", DetectIcmpIdParseTest02); + UtRegisterTest("DetectIcmpIdParseTest03", DetectIcmpIdParseTest03); + UtRegisterTest("DetectIcmpIdParseTest04", DetectIcmpIdParseTest04); + UtRegisterTest("DetectIcmpIdParseTest05", DetectIcmpIdParseTest05); + UtRegisterTest("DetectIcmpIdMatchTest01", DetectIcmpIdMatchTest01); + UtRegisterTest("DetectIcmpIdMatchTest02", DetectIcmpIdMatchTest02); #endif /* UNITTESTS */ } diff --git a/src/detect-icmp-seq.c b/src/detect-icmp-seq.c index b5bccc0c1cef..8ef19c0512d3 100644 --- a/src/detect-icmp-seq.c +++ b/src/detect-icmp-seq.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icmp-seq.h" @@ -42,10 +43,13 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectIcmpSeqMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIcmpSeqSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpSeqRegisterTests(void); void DetectIcmpSeqFree(void *); +static int PrefilterSetupIcmpSeq(SigGroupHead *sgh); +static _Bool PrefilterIcmpSeqIsPrefilterable(const Signature *s); /** * \brief Registration function for icmp_seq @@ -54,51 +58,24 @@ void DetectIcmpSeqRegister (void) { sigmatch_table[DETECT_ICMP_SEQ].name = "icmp_seq"; sigmatch_table[DETECT_ICMP_SEQ].desc = "check for a ICMP sequence number"; - sigmatch_table[DETECT_ICMP_SEQ].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icmp_seq"; + sigmatch_table[DETECT_ICMP_SEQ].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icmp-seq"; sigmatch_table[DETECT_ICMP_SEQ].Match = DetectIcmpSeqMatch; sigmatch_table[DETECT_ICMP_SEQ].Setup = DetectIcmpSeqSetup; sigmatch_table[DETECT_ICMP_SEQ].Free = DetectIcmpSeqFree; sigmatch_table[DETECT_ICMP_SEQ].RegisterTests = DetectIcmpSeqRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_ICMP_SEQ].SupportsPrefilter = PrefilterIcmpSeqIsPrefilterable; + sigmatch_table[DETECT_ICMP_SEQ].SetupPrefilter = PrefilterSetupIcmpSeq; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE,"pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY,"pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \brief This function is used to match icmp_seq rule option set on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIcmpSeqData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static inline _Bool GetIcmpSeq(Packet *p, uint16_t *seq) { uint16_t seqn; - DetectIcmpSeqData *iseq = (DetectIcmpSeqData *)m->ctx; if (PKT_IS_PSEUDOPKT(p)) - return 0; + return FALSE; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ @@ -118,7 +95,7 @@ int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p break; default: SCLogDebug("Packet has no seq field"); - return 0; + return FALSE; } } else if (PKT_IS_ICMPV6(p)) { @@ -133,13 +110,37 @@ int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p break; default: SCLogDebug("Packet has no seq field"); - return 0; + return FALSE; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); - return 0; + return FALSE; } + *seq = seqn; + return TRUE; +} + +/** + * \brief This function is used to match icmp_seq rule option set on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectIcmpSeqData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectIcmpSeqMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) +{ + uint16_t seqn; + + if (GetIcmpSeq(p, &seqn) == FALSE) + return 0; + + const DetectIcmpSeqData *iseq = (const DetectIcmpSeqData *)ctx; if (seqn == iseq->seq) return 1; @@ -242,7 +243,7 @@ static int DetectIcmpSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *icmp if (sm == NULL) goto error; sm->type = DETECT_ICMP_SEQ; - sm->ctx = (void *)iseq; + sm->ctx = (SigMatchCtx *)iseq; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -266,9 +267,62 @@ void DetectIcmpSeqFree (void *ptr) SCFree(iseq); } -#ifdef UNITTESTS +/* prefilter code */ -#include "detect-parse.h" +static void +PrefilterPacketIcmpSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + uint16_t seqn; + + if (GetIcmpSeq(p, &seqn) == FALSE) + return; + + if (seqn == ctx->v1.u16[0]) + { + SCLogDebug("packet matches ICMP SEQ %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIcmpSeqSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIcmpSeqData *a = smctx; + v->u16[0] = a->seq; +} + +static _Bool +PrefilterPacketIcmpSeqCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIcmpSeqData *a = smctx; + if (v.u16[0] == a->seq) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIcmpSeq(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ICMP_SEQ, + PrefilterPacketIcmpSeqSet, + PrefilterPacketIcmpSeqCompare, + PrefilterPacketIcmpSeqMatch); +} + +static _Bool PrefilterIcmpSeqIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICMP_SEQ: + return TRUE; + } + } + return FALSE; +} + +#ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -310,9 +364,9 @@ int DetectIcmpSeqParseTest03 (void) iseq = DetectIcmpSeqParse("badc"); if (iseq != NULL) { DetectIcmpSeqFree(iseq); - return 1; + return 0; } - return 0; + return 1; } /** @@ -381,10 +435,10 @@ int DetectIcmpSeqMatchTest01 (void) void DetectIcmpSeqRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01, 1); - UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02, 1); - UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03, 0); - UtRegisterTest("DetectIcmpSeqMatchTest01", DetectIcmpSeqMatchTest01, 1); + UtRegisterTest("DetectIcmpSeqParseTest01", DetectIcmpSeqParseTest01); + UtRegisterTest("DetectIcmpSeqParseTest02", DetectIcmpSeqParseTest02); + UtRegisterTest("DetectIcmpSeqParseTest03", DetectIcmpSeqParseTest03); + UtRegisterTest("DetectIcmpSeqMatchTest01", DetectIcmpSeqMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-icode.c b/src/detect-icode.c index ff82274e341c..e832f5bbfa63 100644 --- a/src/detect-icode.c +++ b/src/detect-icode.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icode.h" @@ -45,11 +46,14 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectICodeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectICodeSetup(DetectEngineCtx *, Signature *, char *); void DetectICodeRegisterTests(void); void DetectICodeFree(void *); +static int PrefilterSetupICode(SigGroupHead *sgh); +static _Bool PrefilterICodeIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: keyword @@ -58,33 +62,47 @@ void DetectICodeRegister (void) { sigmatch_table[DETECT_ICODE].name = "icode"; sigmatch_table[DETECT_ICODE].desc = "match on specific ICMP id-value"; - sigmatch_table[DETECT_ICODE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#icode"; + sigmatch_table[DETECT_ICODE].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icode"; sigmatch_table[DETECT_ICODE].Match = DetectICodeMatch; sigmatch_table[DETECT_ICODE].Setup = DetectICodeSetup; sigmatch_table[DETECT_ICODE].Free = DetectICodeFree; sigmatch_table[DETECT_ICODE].RegisterTests = DetectICodeRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_ICODE].SupportsPrefilter = PrefilterICodeIsPrefilterable; + sigmatch_table[DETECT_ICODE].SetupPrefilter = PrefilterSetupICode; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; +#define DETECT_ICODE_EQ PREFILTER_U8HASH_MODE_EQ /**< "equal" operator */ +#define DETECT_ICODE_LT PREFILTER_U8HASH_MODE_LT /**< "less than" operator */ +#define DETECT_ICODE_GT PREFILTER_U8HASH_MODE_GT /**< "greater than" operator */ +#define DETECT_ICODE_RN PREFILTER_U8HASH_MODE_RA /**< "range" operator */ -error: - return; +typedef struct DetectICodeData_ { + uint8_t code1; + uint8_t code2; + + uint8_t mode; +} DetectICodeData; + +static inline int ICodeMatch(const uint8_t pcode, const uint8_t mode, + const uint8_t dcode1, const uint8_t dcode2) +{ + switch (mode) { + case DETECT_ICODE_EQ: + return (pcode == dcode1) ? 1 : 0; + + case DETECT_ICODE_LT: + return (pcode < dcode1) ? 1 : 0; + + case DETECT_ICODE_GT: + return (pcode > dcode1) ? 1 : 0; + + case DETECT_ICODE_RN: + return (pcode > dcode1 && pcode < dcode2) ? 1 : 0; + } + return 0; } /** @@ -98,40 +116,24 @@ void DetectICodeRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectICodeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint8_t picode; - DetectICodeData *icd = (DetectICodeData *)m->ctx; - if (PKT_IS_PSEUDOPKT(p)) return 0; + uint8_t picode; if (PKT_IS_ICMPV4(p)) { picode = ICMPV4_GET_CODE(p); } else if (PKT_IS_ICMPV6(p)) { picode = ICMPV6_GET_CODE(p); } else { /* Packet not ICMPv4 nor ICMPv6 */ - return ret; - } - - switch(icd->mode) { - case DETECT_ICODE_EQ: - ret = (picode == icd->code1) ? 1 : 0; - break; - case DETECT_ICODE_LT: - ret = (picode < icd->code1) ? 1 : 0; - break; - case DETECT_ICODE_GT: - ret = (picode > icd->code1) ? 1 : 0; - break; - case DETECT_ICODE_RN: - ret = (picode >= icd->code1 && picode <= icd->code2) ? 1 : 0; - break; + return 0; } - return ret; + const DetectICodeData *icd = (const DetectICodeData *)ctx; + return ICodeMatch(picode, icd->mode, icd->code1, icd->code2); } /** @@ -259,7 +261,7 @@ static int DetectICodeSetup(DetectEngineCtx *de_ctx, Signature *s, char *icodest if (sm == NULL) goto error; sm->type = DETECT_ICODE; - sm->ctx = (void *)icd; + sm->ctx = (SigMatchCtx *)icd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -283,9 +285,73 @@ void DetectICodeFree(void *ptr) SCFree(icd); } -#ifdef UNITTESTS +/* prefilter code */ -#include "detect-parse.h" +static void PrefilterPacketICodeMatch(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t picode; + if (PKT_IS_ICMPV4(p)) { + picode = ICMPV4_GET_CODE(p); + } else if (PKT_IS_ICMPV6(p)) { + picode = ICMPV6_GET_CODE(p); + } else { + /* Packet not ICMPv4 nor ICMPv6 */ + return; + } + + const PrefilterPacketU8HashCtx *h = pectx; + const SigsArray *sa = h->array[picode]; + if (sa) { + PrefilterAddSids(&det_ctx->pmq, sa->sigs, sa->cnt); + } +} + +static void +PrefilterPacketICodeSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectICodeData *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->code1; + v->u8[2] = a->code2; +} + +static _Bool +PrefilterPacketICodeCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectICodeData *a = smctx; + if (v.u8[0] == a->mode && + v.u8[1] == a->code1 && + v.u8[2] == a->code2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupICode(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeaderU8Hash(sgh, DETECT_ICODE, + PrefilterPacketICodeSet, + PrefilterPacketICodeCompare, + PrefilterPacketICodeMatch); +} + +static _Bool PrefilterICodeIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICODE: + return TRUE; + } + } + return FALSE; +} + +#ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -515,14 +581,14 @@ int DetectICodeMatchTest01(void) void DetectICodeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectICodeParseTest01", DetectICodeParseTest01, 1); - UtRegisterTest("DetectICodeParseTest02", DetectICodeParseTest02, 1); - UtRegisterTest("DetectICodeParseTest03", DetectICodeParseTest03, 1); - UtRegisterTest("DetectICodeParseTest04", DetectICodeParseTest04, 1); - UtRegisterTest("DetectICodeParseTest05", DetectICodeParseTest05, 1); - UtRegisterTest("DetectICodeParseTest06", DetectICodeParseTest06, 1); - UtRegisterTest("DetectICodeParseTest07", DetectICodeParseTest07, 1); - UtRegisterTest("DetectICodeParseTest08", DetectICodeParseTest08, 1); - UtRegisterTest("DetectICodeMatchTest01", DetectICodeMatchTest01, 1); + UtRegisterTest("DetectICodeParseTest01", DetectICodeParseTest01); + UtRegisterTest("DetectICodeParseTest02", DetectICodeParseTest02); + UtRegisterTest("DetectICodeParseTest03", DetectICodeParseTest03); + UtRegisterTest("DetectICodeParseTest04", DetectICodeParseTest04); + UtRegisterTest("DetectICodeParseTest05", DetectICodeParseTest05); + UtRegisterTest("DetectICodeParseTest06", DetectICodeParseTest06); + UtRegisterTest("DetectICodeParseTest07", DetectICodeParseTest07); + UtRegisterTest("DetectICodeParseTest08", DetectICodeParseTest08); + UtRegisterTest("DetectICodeMatchTest01", DetectICodeMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-icode.h b/src/detect-icode.h index 88a4d4814065..9d0a179c2f5e 100644 --- a/src/detect-icode.h +++ b/src/detect-icode.h @@ -26,18 +26,6 @@ #ifndef __DETECT_ICODE_H__ #define __DETECT_ICODE_H__ -#define DETECT_ICODE_EQ 0 /**< "equal" operator */ -#define DETECT_ICODE_LT 1 /**< "less than" operator */ -#define DETECT_ICODE_GT 2 /**< "greater than" operator */ -#define DETECT_ICODE_RN 3 /**< "range" operator */ - -typedef struct DetectICodeData_ { - uint8_t code1; - uint8_t code2; - - uint8_t mode; -}DetectICodeData; - /* prototypes */ void DetectICodeRegister(void); diff --git a/src/detect-id.c b/src/detect-id.c index d9b861c80014..cdc32ebc1a87 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -31,6 +31,7 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-engine-prefilter-common.h" #include "detect-id.h" #include "flow.h" @@ -48,12 +49,15 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); +static int DetectIdMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIdSetup (DetectEngineCtx *, Signature *, char *); void DetectIdRegisterTests(void); void DetectIdFree(void *); +static int PrefilterSetupId(SigGroupHead *sgh); +static _Bool PrefilterIdIsPrefilterable(const Signature *s); + /** * \brief Registration function for keyword: id */ @@ -61,34 +65,16 @@ void DetectIdRegister (void) { sigmatch_table[DETECT_ID].name = "id"; sigmatch_table[DETECT_ID].desc = "match on a specific IP ID value"; - sigmatch_table[DETECT_ID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Id"; + sigmatch_table[DETECT_ID].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#id"; sigmatch_table[DETECT_ID].Match = DetectIdMatch; sigmatch_table[DETECT_ID].Setup = DetectIdSetup; sigmatch_table[DETECT_ID].Free = DetectIdFree; sigmatch_table[DETECT_ID].RegisterTests = DetectIdRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering id rule option"); + sigmatch_table[DETECT_ID].SupportsPrefilter = PrefilterIdIsPrefilterable; + sigmatch_table[DETECT_ID].SetupPrefilter = PrefilterSetupId; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -102,10 +88,10 @@ void DetectIdRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, SigMatch *m) +static int DetectIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - DetectIdData *id_d = (DetectIdData *)m->ctx; + const DetectIdData *id_d = (const DetectIdData *)ctx; /** * To match a ipv4 packet with a "id" rule @@ -139,7 +125,6 @@ DetectIdData *DetectIdParse (char *idstr) int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - ret = pcre_exec(parse_regex, parse_regex_study, idstr, strlen(idstr), 0, 0, ov, MAX_SUBSTRINGS); @@ -152,26 +137,16 @@ DetectIdData *DetectIdParse (char *idstr) if (ret > 1) { - const char *str_ptr; - char *orig; + char copy_str[128] = ""; char *tmp_str; - res = pcre_get_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1, - &str_ptr); + res = pcre_copy_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - /* We have a correct id option */ - id_d = SCMalloc(sizeof(DetectIdData)); - if (unlikely(id_d == NULL)) - goto error; - - orig = SCStrdup((char*)str_ptr); - if (unlikely(orig == NULL)) { - goto error; - } - tmp_str=orig; + tmp_str = copy_str; /* Let's see if we need to scape "'s */ if (tmp_str[0] == '"') @@ -187,13 +162,15 @@ DetectIdData *DetectIdParse (char *idstr) SCLogError(SC_ERR_INVALID_VALUE, "\"id\" option must be in " "the range %u - %u", DETECT_IPID_MIN, DETECT_IPID_MAX); - - SCFree(orig); goto error; } - id_d->id = temp; - SCFree(orig); + /* We have a correct id option */ + id_d = SCMalloc(sizeof(DetectIdData)); + if (unlikely(id_d == NULL)) + goto error; + + id_d->id = temp; SCLogDebug("detect-id: will look for ip_id: %u\n", id_d->id); } @@ -201,7 +178,8 @@ DetectIdData *DetectIdParse (char *idstr) return id_d; error: - if (id_d != NULL) DetectIdFree(id_d); + if (id_d != NULL) + DetectIdFree(id_d); return NULL; } @@ -233,7 +211,7 @@ int DetectIdSetup (DetectEngineCtx *de_ctx, Signature *s, char *idstr) goto error; sm->type = DETECT_ID; - sm->ctx = (void *)id_d; + sm->ctx = (SigMatchCtx *)id_d; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -258,6 +236,63 @@ void DetectIdFree(void *ptr) SCFree(id_d); } +/* prefilter code */ + +static void +PrefilterPacketIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { + return; + } + + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + if (IPV4_GET_IPID(p) == ctx->v1.u16[0]) + { + SCLogDebug("packet matches IP id %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIdSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIdData *a = smctx; + v->u16[0] = a->id; +} + +static _Bool +PrefilterPacketIdCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIdData *a = smctx; + if (v.u16[0] == a->id) + return TRUE; + return FALSE; +} + +static int PrefilterSetupId(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ID, + PrefilterPacketIdSet, + PrefilterPacketIdCompare, + PrefilterPacketIdMatch); +} + +static _Bool PrefilterIdIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ID: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS /* UNITTESTS */ /** @@ -382,11 +417,11 @@ int DetectIdTestMatch01(void) void DetectIdRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectIdTestParse01", DetectIdTestParse01, 1); - UtRegisterTest("DetectIdTestParse02", DetectIdTestParse02, 1); - UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03, 1); - UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04, 1); - UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01, 1); + UtRegisterTest("DetectIdTestParse01", DetectIdTestParse01); + UtRegisterTest("DetectIdTestParse02", DetectIdTestParse02); + UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03); + UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04); + UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01); #endif /* UNITTESTS */ } diff --git a/src/detect-ipopts.c b/src/detect-ipopts.c index a8bfc065b604..33addb855b3b 100644 --- a/src/detect-ipopts.c +++ b/src/detect-ipopts.c @@ -35,9 +35,6 @@ #include "util-debug.h" -/* Need to get the DIpOpts[] array */ -#define DETECT_EVENTS - #include "detect-ipopts.h" #include "util-unittest.h" @@ -46,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectIpOptsMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, char *); void IpOptsRegisterTests(void); void DetectIpOptsFree(void *); @@ -58,35 +56,35 @@ void DetectIpOptsRegister (void) { sigmatch_table[DETECT_IPOPTS].name = "ipopts"; sigmatch_table[DETECT_IPOPTS].desc = "check if a specific IP option is set"; - sigmatch_table[DETECT_IPOPTS].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Ipopts"; + sigmatch_table[DETECT_IPOPTS].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ipopts"; sigmatch_table[DETECT_IPOPTS].Match = DetectIpOptsMatch; sigmatch_table[DETECT_IPOPTS].Setup = DetectIpOptsSetup; sigmatch_table[DETECT_IPOPTS].Free = DetectIpOptsFree; sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} -error: - return; +/** + * \struct DetectIpOptss_ + * DetectIpOptss_ is used to store supported iptops values + */ -} +struct DetectIpOpts_ { + const char *ipopt_name; /**< ip option name */ + uint16_t code; /**< ip option flag value */ +} ipopts[] = { + { "rr", IPV4_OPT_FLAG_RR, }, + { "lsrr", IPV4_OPT_FLAG_LSRR, }, + { "eol", IPV4_OPT_FLAG_EOL, }, + { "nop", IPV4_OPT_FLAG_NOP, }, + { "ts", IPV4_OPT_FLAG_TS, }, + { "sec", IPV4_OPT_FLAG_SEC, }, + { "ssrr", IPV4_OPT_FLAG_SSRR, }, + { "satid", IPV4_OPT_FLAG_SID, }, + { "any", 0xffff, }, + { NULL, 0 }, +}; /** * \internal @@ -101,33 +99,19 @@ void DetectIpOptsRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectIpOptsMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - int ipopt = 0; - DetectIpOptsData *de = (DetectIpOptsData *)m->ctx; + const DetectIpOptsData *de = (const DetectIpOptsData *)ctx; if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) - return ret; - - /* IPV4_OPT_ANY matches on any options */ + return 0; - if (p->IPV4_OPTS_CNT && (de->ipopt == IPV4_OPT_ANY)) { + if (p->ip4vars.opts_set & de->ipopt) { return 1; } - /* Loop through instead of using o_xxx direct access fields so that - * future options do not require any modification here. - */ - - while(ipopt < p->IPV4_OPTS_CNT) { - if (p->IPV4_OPTS[ipopt].type == de->ipopt) { - return 1; - } - ipopt++; - } - - return ret; + return 0; } /** @@ -153,8 +137,8 @@ DetectIpOptsData *DetectIpOptsParse (char *rawstr) goto error; } - for(i = 0; DIpOpts[i].ipopt_name != NULL; i++) { - if((strcasecmp(DIpOpts[i].ipopt_name,rawstr)) == 0) { + for(i = 0; ipopts[i].ipopt_name != NULL; i++) { + if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) { found = 1; break; } @@ -167,7 +151,7 @@ DetectIpOptsData *DetectIpOptsParse (char *rawstr) if (unlikely(de == NULL)) goto error; - de->ipopt = DIpOpts[i].code; + de->ipopt = ipopts[i].code; return de; @@ -201,7 +185,7 @@ static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst goto error; sm->type = DETECT_IPOPTS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -261,10 +245,10 @@ int IpOptsTestParse02 (void) de = DetectIpOptsParse("invalidopt"); if (de) { DetectIpOptsFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -289,9 +273,7 @@ int IpOptsTestParse03 (void) memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; - p->IPV4_OPTS[0].type = IPV4_OPT_RR; - - p->IPV4_OPTS_CNT++; + p->ip4vars.opts_set = IPV4_OPT_FLAG_RR; de = DetectIpOptsParse("rr"); @@ -303,9 +285,9 @@ int IpOptsTestParse03 (void) goto error; sm->type = DETECT_IPOPTS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectIpOptsMatch(&tv,NULL,p,NULL,sm); + ret = DetectIpOptsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { SCFree(p); @@ -341,9 +323,7 @@ int IpOptsTestParse04 (void) memset(&ip4h, 0, sizeof(IPV4Hdr)); p->ip4h = &ip4h; - p->IPV4_OPTS[0].type = IPV4_OPT_RR; - - p->IPV4_OPTS_CNT++; + p->ip4vars.opts_set = IPV4_OPT_FLAG_RR; de = DetectIpOptsParse("lsrr"); @@ -355,20 +335,21 @@ int IpOptsTestParse04 (void) goto error; sm->type = DETECT_IPOPTS; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; - ret = DetectIpOptsMatch(&tv,NULL,p,NULL,sm); + ret = DetectIpOptsMatch(&tv, NULL, p, NULL, sm->ctx); if(ret) { SCFree(p); - return 1; + return 0; } + /* Error expected. */ error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); - return 0; + return 1; } #endif /* UNITTESTS */ @@ -378,9 +359,9 @@ int IpOptsTestParse04 (void) void IpOptsRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01, 1); - UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02, 0); - UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03, 1); - UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04, 0); + UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01); + UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02); + UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03); + UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04); #endif /* UNITTESTS */ } diff --git a/src/detect-ipopts.h b/src/detect-ipopts.h index bd346256171c..2c599d82e2e4 100644 --- a/src/detect-ipopts.h +++ b/src/detect-ipopts.h @@ -38,7 +38,7 @@ */ typedef struct DetectIpOptsData_ { - uint8_t ipopt; /**< Ip option */ + uint16_t ipopt; /**< ip option flag */ } DetectIpOptsData; /** @@ -47,34 +47,5 @@ typedef struct DetectIpOptsData_ { void DetectIpOptsRegister (void); -#ifdef DETECT_EVENTS - -/** - * Used to check ipopts:any - */ - -#define IPV4_OPT_ANY 0xff - -/** - * \struct DetectIpOptss_ - * DetectIpOptss_ is used to store supported iptops values - */ - -struct DetectIpOptss_ { - char *ipopt_name; /**< Ip option name */ - uint8_t code; /**< Ip option value */ -} DIpOpts[] = { - { "rr", IPV4_OPT_RR, }, - { "lsrr", IPV4_OPT_LSRR, }, - { "eol", IPV4_OPT_EOL, }, - { "nop", IPV4_OPT_NOP, }, - { "ts", IPV4_OPT_TS, }, - { "sec", IPV4_OPT_SEC, }, - { "ssrr", IPV4_OPT_SSRR, }, - { "satid", IPV4_OPT_SID, }, - { "any", IPV4_OPT_ANY, }, - { NULL, 0 }, -}; -#endif /* DETECT_EVENTS */ #endif /*__DETECT_IPOPTS_H__ */ diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index a40403681888..944b03817d29 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -61,39 +61,15 @@ static void DetectIPProtoFree(void *); void DetectIPProtoRegister(void) { - const char *eb; - int eo; - int opts = 0; - sigmatch_table[DETECT_IPPROTO].name = "ip_proto"; sigmatch_table[DETECT_IPPROTO].desc = "match on the IP protocol in the packet-header"; - sigmatch_table[DETECT_IPPROTO].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ip_proto"; + sigmatch_table[DETECT_IPPROTO].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ip-proto"; sigmatch_table[DETECT_IPPROTO].Match = NULL; sigmatch_table[DETECT_IPPROTO].Setup = DetectIPProtoSetup; sigmatch_table[DETECT_IPPROTO].Free = DetectIPProtoFree; sigmatch_table[DETECT_IPPROTO].RegisterTests = DetectIPProtoRegisterTests; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - if (parse_regex) - pcre_free(parse_regex); - if (parse_regex_study) - pcre_free_study(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -183,7 +159,7 @@ static DetectIPProtoData *DetectIPProtoParse(const char *optstr) static int DetectIPProtoTypePresentForOP(Signature *s, uint8_t op) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; DetectIPProtoData *data; while (sm != NULL) { @@ -240,7 +216,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst if (s->proto.flags & (DETECT_PROTO_ANY | DETECT_PROTO_IPV6 | DETECT_PROTO_IPV4)) { s->proto.flags &= ~DETECT_PROTO_ANY; memset(s->proto.proto, 0x00, sizeof(s->proto.proto)); - s->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + s->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; } else { /* The ipproto engine has a relationship with the protocol that is * set after the action and also the app protocol(that can also be @@ -248,7 +224,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst * An ip_proto keyword can be used only with alert ip, which if * not true we error out on the sig. And hence the init_flag to * indicate this. */ - if (!(s->init_flags & SIG_FLAG_INIT_FIRST_IPPROTO_SEEN)) { + if (!(s->init_data->init_flags & SIG_FLAG_INIT_FIRST_IPPROTO_SEEN)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature can use " "ip_proto keyword only when we use alert ip, " "in which case the _ANY flag is set on the sig " @@ -286,7 +262,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst s->proto.proto[i] = 0xff; } } else if (lt_set && !not_set) { - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO) { break; @@ -294,7 +270,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - DetectIPProtoData *data_temp = temp_sm->ctx; + DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto <= data->proto) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have " "both gt and lt ipprotos, with the lt being " @@ -328,7 +304,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst } } else { DetectIPProtoData *data_temp; - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_LT) { @@ -337,7 +313,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - data_temp = temp_sm->ctx; + data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto <= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto @@ -405,7 +381,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst } s->proto.proto[data->proto / 8] = ~(0xff << (data->proto % 8)); } else if (gt_set && !not_set) { - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO) { break; @@ -413,7 +389,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - DetectIPProtoData *data_temp = temp_sm->ctx; + DetectIPProtoData *data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto >= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto @@ -448,7 +424,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst } } else { DetectIPProtoData *data_temp; - SigMatch *temp_sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *temp_sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (temp_sm != NULL) { if (temp_sm->type == DETECT_IPPROTO && ((DetectIPProtoData *)temp_sm->ctx)->op == DETECT_IPPROTO_OP_GT) { @@ -457,7 +433,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst temp_sm = temp_sm->next; } if (temp_sm != NULL) { - data_temp = temp_sm->ctx; + data_temp = (DetectIPProtoData *)temp_sm->ctx; if (data_temp->proto >= data->proto) { /* Updated by AS. Please do not remove this unused code. * Need it as we redo this code once we solve ipproto @@ -557,7 +533,7 @@ static int DetectIPProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst void DetectIPProtoRemoveAllSMs(Signature *s) { - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; while (sm != NULL) { if (sm->type != DETECT_IPPROTO) { @@ -584,9 +560,6 @@ static void DetectIPProtoFree(void *ptr) /* UNITTESTS */ #ifdef UNITTESTS -#include "detect-engine.h" -#include "detect-parse.h" - /** * \test DetectIPProtoTestParse01 is a test for an invalid proto number */ @@ -637,7 +610,7 @@ static int DetectIPProtoTestSetup01(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -677,7 +650,7 @@ static int DetectIPProtoTestSetup02(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -714,7 +687,7 @@ static int DetectIPProtoTestSetup03(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -750,7 +723,7 @@ static int DetectIPProtoTestSetup04(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -786,7 +759,7 @@ static int DetectIPProtoTestSetup05(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; DetectIPProtoSetup(NULL, sig, value_str); for (i = 0; i < (value / 8); i++) { @@ -821,7 +794,7 @@ static int DetectIPProtoTestSetup06(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -848,7 +821,7 @@ static int DetectIPProtoTestSetup07(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -875,7 +848,7 @@ static int DetectIPProtoTestSetup08(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -902,7 +875,7 @@ static int DetectIPProtoTestSetup09(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -929,7 +902,7 @@ static int DetectIPProtoTestSetup10(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -956,7 +929,7 @@ static int DetectIPProtoTestSetup11(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -983,7 +956,7 @@ static int DetectIPProtoTestSetup12(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1010,7 +983,7 @@ static int DetectIPProtoTestSetup13(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1034,7 +1007,7 @@ static int DetectIPProtoTestSetup14(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1060,7 +1033,7 @@ static int DetectIPProtoTestSetup15(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1096,7 +1069,7 @@ static int DetectIPProtoTestSetup15(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1141,7 +1114,7 @@ static int DetectIPProtoTestSetup16(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1177,7 +1150,7 @@ static int DetectIPProtoTestSetup16(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1222,7 +1195,7 @@ static int DetectIPProtoTestSetup17(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1258,7 +1231,7 @@ static int DetectIPProtoTestSetup17(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1299,7 +1272,7 @@ static int DetectIPProtoTestSetup18(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1335,7 +1308,7 @@ static int DetectIPProtoTestSetup18(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1377,7 +1350,7 @@ static int DetectIPProtoTestSetup19(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1416,7 +1389,7 @@ static int DetectIPProtoTestSetup19(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1463,7 +1436,7 @@ static int DetectIPProtoTestSetup20(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1500,7 +1473,7 @@ static int DetectIPProtoTestSetup20(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1548,7 +1521,7 @@ static int DetectIPProtoTestSetup21(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1587,7 +1560,7 @@ static int DetectIPProtoTestSetup21(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1635,7 +1608,7 @@ static int DetectIPProtoTestSetup22(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1674,7 +1647,7 @@ static int DetectIPProtoTestSetup22(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -1721,7 +1694,7 @@ static int DetectIPProtoTestSetup23(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1758,7 +1731,7 @@ static int DetectIPProtoTestSetup23(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1806,7 +1779,7 @@ static int DetectIPProtoTestSetup24(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1845,7 +1818,7 @@ static int DetectIPProtoTestSetup24(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -1893,7 +1866,7 @@ static int DetectIPProtoTestSetup25(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1932,7 +1905,7 @@ static int DetectIPProtoTestSetup25(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -1979,7 +1952,7 @@ static int DetectIPProtoTestSetup26(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2015,7 +1988,7 @@ static int DetectIPProtoTestSetup26(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2063,7 +2036,7 @@ static int DetectIPProtoTestSetup27(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2101,7 +2074,7 @@ static int DetectIPProtoTestSetup27(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2149,7 +2122,7 @@ static int DetectIPProtoTestSetup28(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2188,7 +2161,7 @@ static int DetectIPProtoTestSetup28(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2235,7 +2208,7 @@ static int DetectIPProtoTestSetup29(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2272,7 +2245,7 @@ static int DetectIPProtoTestSetup29(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2320,7 +2293,7 @@ static int DetectIPProtoTestSetup30(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2359,7 +2332,7 @@ static int DetectIPProtoTestSetup30(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2407,7 +2380,7 @@ static int DetectIPProtoTestSetup31(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2446,7 +2419,7 @@ static int DetectIPProtoTestSetup31(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2493,7 +2466,7 @@ static int DetectIPProtoTestSetup32(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2530,7 +2503,7 @@ static int DetectIPProtoTestSetup32(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2578,7 +2551,7 @@ static int DetectIPProtoTestSetup33(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2617,7 +2590,7 @@ static int DetectIPProtoTestSetup33(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2666,7 +2639,7 @@ static int DetectIPProtoTestSetup34(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2705,7 +2678,7 @@ static int DetectIPProtoTestSetup34(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -2734,7 +2707,7 @@ static int DetectIPProtoTestSetup35(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2771,7 +2744,7 @@ static int DetectIPProtoTestSetup35(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2819,7 +2792,7 @@ static int DetectIPProtoTestSetup36(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2858,7 +2831,7 @@ static int DetectIPProtoTestSetup36(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -2906,7 +2879,7 @@ static int DetectIPProtoTestSetup37(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2945,7 +2918,7 @@ static int DetectIPProtoTestSetup37(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -2985,7 +2958,7 @@ static int DetectIPProtoTestSetup38(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3022,7 +2995,7 @@ static int DetectIPProtoTestSetup38(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3063,7 +3036,7 @@ static int DetectIPProtoTestSetup39(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3102,7 +3075,7 @@ static int DetectIPProtoTestSetup39(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3144,7 +3117,7 @@ static int DetectIPProtoTestSetup40(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3183,7 +3156,7 @@ static int DetectIPProtoTestSetup40(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3224,7 +3197,7 @@ static int DetectIPProtoTestSetup41(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3261,7 +3234,7 @@ static int DetectIPProtoTestSetup41(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3303,7 +3276,7 @@ static int DetectIPProtoTestSetup42(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3342,7 +3315,7 @@ static int DetectIPProtoTestSetup42(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3384,7 +3357,7 @@ static int DetectIPProtoTestSetup43(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3427,7 +3400,7 @@ static int DetectIPProtoTestSetup43(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3478,7 +3451,7 @@ static int DetectIPProtoTestSetup44(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3518,7 +3491,7 @@ static int DetectIPProtoTestSetup44(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3570,7 +3543,7 @@ static int DetectIPProtoTestSetup45(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3613,7 +3586,7 @@ static int DetectIPProtoTestSetup45(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3663,7 +3636,7 @@ static int DetectIPProtoTestSetup46(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3701,7 +3674,7 @@ static int DetectIPProtoTestSetup46(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -3752,7 +3725,7 @@ static int DetectIPProtoTestSetup47(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3792,7 +3765,7 @@ static int DetectIPProtoTestSetup47(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3842,7 +3815,7 @@ static int DetectIPProtoTestSetup48(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3880,7 +3853,7 @@ static int DetectIPProtoTestSetup48(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -3932,7 +3905,7 @@ static int DetectIPProtoTestSetup49(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -3972,7 +3945,7 @@ static int DetectIPProtoTestSetup49(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4020,7 +3993,7 @@ static int DetectIPProtoTestSetup50(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4060,7 +4033,7 @@ static int DetectIPProtoTestSetup50(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4109,7 +4082,7 @@ static int DetectIPProtoTestSetup51(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4149,7 +4122,7 @@ static int DetectIPProtoTestSetup51(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4196,7 +4169,7 @@ static int DetectIPProtoTestSetup52(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4234,7 +4207,7 @@ static int DetectIPProtoTestSetup52(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4282,7 +4255,7 @@ static int DetectIPProtoTestSetup53(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4322,7 +4295,7 @@ static int DetectIPProtoTestSetup53(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4369,7 +4342,7 @@ static int DetectIPProtoTestSetup54(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4407,7 +4380,7 @@ static int DetectIPProtoTestSetup54(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4454,7 +4427,7 @@ static int DetectIPProtoTestSetup55(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4492,7 +4465,7 @@ static int DetectIPProtoTestSetup55(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4540,7 +4513,7 @@ static int DetectIPProtoTestSetup56(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4580,7 +4553,7 @@ static int DetectIPProtoTestSetup56(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -4627,7 +4600,7 @@ static int DetectIPProtoTestSetup57(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4665,7 +4638,7 @@ static int DetectIPProtoTestSetup57(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4713,7 +4686,7 @@ static int DetectIPProtoTestSetup58(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4753,7 +4726,7 @@ static int DetectIPProtoTestSetup58(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -4801,7 +4774,7 @@ static int DetectIPProtoTestSetup59(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4841,7 +4814,7 @@ static int DetectIPProtoTestSetup59(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4889,7 +4862,7 @@ static int DetectIPProtoTestSetup60(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4929,7 +4902,7 @@ static int DetectIPProtoTestSetup60(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -4976,7 +4949,7 @@ static int DetectIPProtoTestSetup61(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5014,7 +4987,7 @@ static int DetectIPProtoTestSetup61(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5065,7 +5038,7 @@ static int DetectIPProtoTestSetup62(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5105,7 +5078,7 @@ static int DetectIPProtoTestSetup62(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5155,7 +5128,7 @@ static int DetectIPProtoTestSetup63(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5193,7 +5166,7 @@ static int DetectIPProtoTestSetup63(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5245,7 +5218,7 @@ static int DetectIPProtoTestSetup64(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5288,7 +5261,7 @@ static int DetectIPProtoTestSetup64(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5339,7 +5312,7 @@ static int DetectIPProtoTestSetup65(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5379,7 +5352,7 @@ static int DetectIPProtoTestSetup65(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5431,7 +5404,7 @@ static int DetectIPProtoTestSetup66(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5474,7 +5447,7 @@ static int DetectIPProtoTestSetup66(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -5525,7 +5498,7 @@ static int DetectIPProtoTestSetup67(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5570,7 +5543,7 @@ static int DetectIPProtoTestSetup68(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5615,7 +5588,7 @@ static int DetectIPProtoTestSetup69(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5653,7 +5626,7 @@ static int DetectIPProtoTestSetup70(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5691,7 +5664,7 @@ static int DetectIPProtoTestSetup71(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5729,7 +5702,7 @@ static int DetectIPProtoTestSetup72(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5767,7 +5740,7 @@ static int DetectIPProtoTestSetup73(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5812,7 +5785,7 @@ static int DetectIPProtoTestSetup74(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5856,7 +5829,7 @@ static int DetectIPProtoTestSetup75(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5893,7 +5866,7 @@ static int DetectIPProtoTestSetup76(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -5930,7 +5903,7 @@ static int DetectIPProtoTestSetup77(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -5967,7 +5940,7 @@ static int DetectIPProtoTestSetup78(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6005,7 +5978,7 @@ static int DetectIPProtoTestSetup79(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6042,7 +6015,7 @@ static int DetectIPProtoTestSetup80(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6079,7 +6052,7 @@ static int DetectIPProtoTestSetup81(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6117,7 +6090,7 @@ static int DetectIPProtoTestSetup82(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6155,7 +6128,7 @@ static int DetectIPProtoTestSetup83(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6193,7 +6166,7 @@ static int DetectIPProtoTestSetup84(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6231,7 +6204,7 @@ static int DetectIPProtoTestSetup85(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6269,7 +6242,7 @@ static int DetectIPProtoTestSetup86(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6308,7 +6281,7 @@ static int DetectIPProtoTestSetup87(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6356,7 +6329,7 @@ static int DetectIPProtoTestSetup88(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6404,7 +6377,7 @@ static int DetectIPProtoTestSetup89(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6452,7 +6425,7 @@ static int DetectIPProtoTestSetup90(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6500,7 +6473,7 @@ static int DetectIPProtoTestSetup91(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6548,7 +6521,7 @@ static int DetectIPProtoTestSetup92(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6596,7 +6569,7 @@ static int DetectIPProtoTestSetup93(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6641,7 +6614,7 @@ static int DetectIPProtoTestSetup94(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6686,7 +6659,7 @@ static int DetectIPProtoTestSetup95(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6731,7 +6704,7 @@ static int DetectIPProtoTestSetup96(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -6776,7 +6749,7 @@ static int DetectIPProtoTestSetup97(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6821,7 +6794,7 @@ static int DetectIPProtoTestSetup98(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -6867,7 +6840,7 @@ static int DetectIPProtoTestSetup99(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6913,7 +6886,7 @@ static int DetectIPProtoTestSetup100(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -6959,7 +6932,7 @@ static int DetectIPProtoTestSetup101(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7005,7 +6978,7 @@ static int DetectIPProtoTestSetup102(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7051,7 +7024,7 @@ static int DetectIPProtoTestSetup103(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7097,7 +7070,7 @@ static int DetectIPProtoTestSetup104(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7143,7 +7116,7 @@ static int DetectIPProtoTestSetup105(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7192,7 +7165,7 @@ static int DetectIPProtoTestSetup106(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7241,7 +7214,7 @@ static int DetectIPProtoTestSetup107(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7290,7 +7263,7 @@ static int DetectIPProtoTestSetup108(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7339,7 +7312,7 @@ static int DetectIPProtoTestSetup109(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7388,7 +7361,7 @@ static int DetectIPProtoTestSetup110(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7436,7 +7409,7 @@ static int DetectIPProtoTestSetup111(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7484,7 +7457,7 @@ static int DetectIPProtoTestSetup112(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7532,7 +7505,7 @@ static int DetectIPProtoTestSetup113(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7580,7 +7553,7 @@ static int DetectIPProtoTestSetup114(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7628,7 +7601,7 @@ static int DetectIPProtoTestSetup115(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7676,7 +7649,7 @@ static int DetectIPProtoTestSetup116(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7724,7 +7697,7 @@ static int DetectIPProtoTestSetup117(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7772,7 +7745,7 @@ static int DetectIPProtoTestSetup118(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -7820,7 +7793,7 @@ static int DetectIPProtoTestSetup119(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -7868,7 +7841,7 @@ static int DetectIPProtoTestSetup120(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7916,7 +7889,7 @@ static int DetectIPProtoTestSetup121(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -7964,7 +7937,7 @@ static int DetectIPProtoTestSetup122(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -8012,7 +7985,7 @@ static int DetectIPProtoTestSetup123(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8060,7 +8033,7 @@ static int DetectIPProtoTestSetup124(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8108,7 +8081,7 @@ static int DetectIPProtoTestSetup125(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8156,7 +8129,7 @@ static int DetectIPProtoTestSetup126(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8204,7 +8177,7 @@ static int DetectIPProtoTestSetup127(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -8252,7 +8225,7 @@ static int DetectIPProtoTestSetup128(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value3_str) != 0) goto end; @@ -8298,7 +8271,7 @@ static int DetectIPProtoTestSetup129(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8335,7 +8308,7 @@ static int DetectIPProtoTestSetup130(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8372,7 +8345,7 @@ static int DetectIPProtoTestSetup131(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8409,7 +8382,7 @@ static int DetectIPProtoTestSetup132(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8446,7 +8419,7 @@ static int DetectIPProtoTestSetup133(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8484,7 +8457,7 @@ static int DetectIPProtoTestSetup134(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8528,7 +8501,7 @@ static int DetectIPProtoTestSetup135(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -8592,7 +8565,7 @@ static int DetectIPProtoTestSetup136(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value8_str) != 0) goto end; @@ -8656,7 +8629,7 @@ static int DetectIPProtoTestSetup137(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; @@ -8720,7 +8693,7 @@ static int DetectIPProtoTestSetup138(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value2_str) != 0) goto end; @@ -8784,7 +8757,7 @@ static int DetectIPProtoTestSetup139(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value7_str) != 0) goto end; @@ -8848,7 +8821,7 @@ static int DetectIPProtoTestSetup140(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; @@ -8912,7 +8885,7 @@ static int DetectIPProtoTestSetup141(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value6_str) != 0) goto end; @@ -8976,7 +8949,7 @@ static int DetectIPProtoTestSetup142(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value4_str) != 0) goto end; @@ -9042,7 +9015,7 @@ static int DetectIPProtoTestSetup143(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value1_str) != 0) goto end; @@ -9112,7 +9085,7 @@ static int DetectIPProtoTestSetup144(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value10_str) != 0) goto end; @@ -9182,7 +9155,7 @@ static int DetectIPProtoTestSetup145(void) if ((sig = SigAlloc()) == NULL) goto end; - sig->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; + sig->init_data->init_flags |= SIG_FLAG_INIT_FIRST_IPPROTO_SEEN; sig->proto.flags |= DETECT_PROTO_ANY; if (DetectIPProtoSetup(NULL, sig, value5_str) != 0) goto end; @@ -9241,7 +9214,7 @@ static int DetectIPProtoTestSig1(void) uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); if (p == NULL) - goto end; + return 0; char *sigs[4]; sigs[0] = "alert ip any any -> any any " @@ -9268,9 +9241,6 @@ static int DetectIPProtoTestSig1(void) result = UTHGenericTest(&p, 1, sigs, sid, results, 4); UTHFreePacket(p); -end: - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); return result; } @@ -9311,7 +9281,7 @@ static int DetectIPProtoTestSig2(void) goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -9396,7 +9366,7 @@ static int DetectIPProtoTestSig3(void) goto end; } - de_ctx->mpm_matcher = DEFAULT_MPM; + de_ctx->mpm_matcher = mpm_default_matcher; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -9454,156 +9424,156 @@ static int DetectIPProtoTestSig3(void) static void DetectIPProtoRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectIPProtoTestParse01", DetectIPProtoTestParse01, 1); - UtRegisterTest("DetectIPProtoTestParse02", DetectIPProtoTestParse02, 1); - UtRegisterTest("DetectIPProtoTestSetup01", DetectIPProtoTestSetup01, 1); - UtRegisterTest("DetectIPProtoTestSetup02", DetectIPProtoTestSetup02, 1); - UtRegisterTest("DetectIPProtoTestSetup03", DetectIPProtoTestSetup03, 1); - UtRegisterTest("DetectIPProtoTestSetup04", DetectIPProtoTestSetup04, 1); - UtRegisterTest("DetectIPProtoTestSetup05", DetectIPProtoTestSetup05, 1); - UtRegisterTest("DetectIPProtoTestSetup06", DetectIPProtoTestSetup06, 1); - UtRegisterTest("DetectIPProtoTestSetup07", DetectIPProtoTestSetup07, 1); - UtRegisterTest("DetectIPProtoTestSetup08", DetectIPProtoTestSetup08, 1); - UtRegisterTest("DetectIPProtoTestSetup09", DetectIPProtoTestSetup09, 1); - UtRegisterTest("DetectIPProtoTestSetup10", DetectIPProtoTestSetup10, 1); - UtRegisterTest("DetectIPProtoTestSetup11", DetectIPProtoTestSetup11, 1); - UtRegisterTest("DetectIPProtoTestSetup12", DetectIPProtoTestSetup12, 1); - UtRegisterTest("DetectIPProtoTestSetup13", DetectIPProtoTestSetup13, 1); - UtRegisterTest("DetectIPProtoTestSetup14", DetectIPProtoTestSetup14, 1); - UtRegisterTest("DetectIPProtoTestSetup15", DetectIPProtoTestSetup15, 1); - UtRegisterTest("DetectIPProtoTestSetup16", DetectIPProtoTestSetup16, 1); - UtRegisterTest("DetectIPProtoTestSetup17", DetectIPProtoTestSetup17, 1); - UtRegisterTest("DetectIPProtoTestSetup18", DetectIPProtoTestSetup18, 1); - UtRegisterTest("DetectIPProtoTestSetup19", DetectIPProtoTestSetup19, 1); - UtRegisterTest("DetectIPProtoTestSetup20", DetectIPProtoTestSetup20, 1); - UtRegisterTest("DetectIPProtoTestSetup21", DetectIPProtoTestSetup21, 1); - UtRegisterTest("DetectIPProtoTestSetup22", DetectIPProtoTestSetup22, 1); - UtRegisterTest("DetectIPProtoTestSetup23", DetectIPProtoTestSetup23, 1); - UtRegisterTest("DetectIPProtoTestSetup24", DetectIPProtoTestSetup24, 1); - UtRegisterTest("DetectIPProtoTestSetup25", DetectIPProtoTestSetup25, 1); - UtRegisterTest("DetectIPProtoTestSetup26", DetectIPProtoTestSetup26, 1); - UtRegisterTest("DetectIPProtoTestSetup27", DetectIPProtoTestSetup27, 1); - UtRegisterTest("DetectIPProtoTestSetup28", DetectIPProtoTestSetup28, 1); - UtRegisterTest("DetectIPProtoTestSetup29", DetectIPProtoTestSetup29, 1); - UtRegisterTest("DetectIPProtoTestSetup30", DetectIPProtoTestSetup30, 1); - UtRegisterTest("DetectIPProtoTestSetup31", DetectIPProtoTestSetup31, 1); - UtRegisterTest("DetectIPProtoTestSetup32", DetectIPProtoTestSetup32, 1); - UtRegisterTest("DetectIPProtoTestSetup33", DetectIPProtoTestSetup33, 1); - UtRegisterTest("DetectIPProtoTestSetup34", DetectIPProtoTestSetup34, 1); - UtRegisterTest("DetectIPProtoTestSetup35", DetectIPProtoTestSetup35, 1); - UtRegisterTest("DetectIPProtoTestSetup36", DetectIPProtoTestSetup36, 1); - UtRegisterTest("DetectIPProtoTestSetup37", DetectIPProtoTestSetup37, 1); - UtRegisterTest("DetectIPProtoTestSetup38", DetectIPProtoTestSetup38, 1); - UtRegisterTest("DetectIPProtoTestSetup39", DetectIPProtoTestSetup39, 1); - UtRegisterTest("DetectIPProtoTestSetup40", DetectIPProtoTestSetup40, 1); - UtRegisterTest("DetectIPProtoTestSetup41", DetectIPProtoTestSetup41, 1); - UtRegisterTest("DetectIPProtoTestSetup42", DetectIPProtoTestSetup42, 1); - UtRegisterTest("DetectIPProtoTestSetup43", DetectIPProtoTestSetup43, 1); - UtRegisterTest("DetectIPProtoTestSetup44", DetectIPProtoTestSetup44, 1); - UtRegisterTest("DetectIPProtoTestSetup45", DetectIPProtoTestSetup45, 1); - UtRegisterTest("DetectIPProtoTestSetup46", DetectIPProtoTestSetup46, 1); - UtRegisterTest("DetectIPProtoTestSetup47", DetectIPProtoTestSetup47, 1); - UtRegisterTest("DetectIPProtoTestSetup48", DetectIPProtoTestSetup48, 1); - UtRegisterTest("DetectIPProtoTestSetup49", DetectIPProtoTestSetup49, 1); - UtRegisterTest("DetectIPProtoTestSetup50", DetectIPProtoTestSetup50, 1); - UtRegisterTest("DetectIPProtoTestSetup51", DetectIPProtoTestSetup51, 1); - UtRegisterTest("DetectIPProtoTestSetup52", DetectIPProtoTestSetup52, 1); - UtRegisterTest("DetectIPProtoTestSetup53", DetectIPProtoTestSetup53, 1); - UtRegisterTest("DetectIPProtoTestSetup54", DetectIPProtoTestSetup54, 1); - UtRegisterTest("DetectIPProtoTestSetup55", DetectIPProtoTestSetup55, 1); - UtRegisterTest("DetectIPProtoTestSetup56", DetectIPProtoTestSetup56, 1); - UtRegisterTest("DetectIPProtoTestSetup57", DetectIPProtoTestSetup57, 1); - UtRegisterTest("DetectIPProtoTestSetup58", DetectIPProtoTestSetup58, 1); - UtRegisterTest("DetectIPProtoTestSetup59", DetectIPProtoTestSetup59, 1); - UtRegisterTest("DetectIPProtoTestSetup60", DetectIPProtoTestSetup60, 1); - UtRegisterTest("DetectIPProtoTestSetup61", DetectIPProtoTestSetup61, 1); - UtRegisterTest("DetectIPProtoTestSetup62", DetectIPProtoTestSetup62, 1); - UtRegisterTest("DetectIPProtoTestSetup63", DetectIPProtoTestSetup63, 1); - UtRegisterTest("DetectIPProtoTestSetup64", DetectIPProtoTestSetup64, 1); - UtRegisterTest("DetectIPProtoTestSetup65", DetectIPProtoTestSetup65, 1); - UtRegisterTest("DetectIPProtoTestSetup66", DetectIPProtoTestSetup66, 1); - UtRegisterTest("DetectIPProtoTestSetup67", DetectIPProtoTestSetup67, 1); - UtRegisterTest("DetectIPProtoTestSetup68", DetectIPProtoTestSetup68, 1); - UtRegisterTest("DetectIPProtoTestSetup69", DetectIPProtoTestSetup69, 1); - UtRegisterTest("DetectIPProtoTestSetup70", DetectIPProtoTestSetup70, 1); - UtRegisterTest("DetectIPProtoTestSetup71", DetectIPProtoTestSetup71, 1); - UtRegisterTest("DetectIPProtoTestSetup72", DetectIPProtoTestSetup72, 1); - UtRegisterTest("DetectIPProtoTestSetup73", DetectIPProtoTestSetup73, 1); - UtRegisterTest("DetectIPProtoTestSetup74", DetectIPProtoTestSetup74, 1); - UtRegisterTest("DetectIPProtoTestSetup75", DetectIPProtoTestSetup75, 1); - UtRegisterTest("DetectIPProtoTestSetup76", DetectIPProtoTestSetup76, 1); - UtRegisterTest("DetectIPProtoTestSetup77", DetectIPProtoTestSetup77, 1); - UtRegisterTest("DetectIPProtoTestSetup78", DetectIPProtoTestSetup78, 1); - UtRegisterTest("DetectIPProtoTestSetup79", DetectIPProtoTestSetup79, 1); - UtRegisterTest("DetectIPProtoTestSetup80", DetectIPProtoTestSetup80, 1); - UtRegisterTest("DetectIPProtoTestSetup81", DetectIPProtoTestSetup81, 1); - UtRegisterTest("DetectIPProtoTestSetup82", DetectIPProtoTestSetup82, 1); - UtRegisterTest("DetectIPProtoTestSetup83", DetectIPProtoTestSetup83, 1); - UtRegisterTest("DetectIPProtoTestSetup84", DetectIPProtoTestSetup84, 1); - UtRegisterTest("DetectIPProtoTestSetup85", DetectIPProtoTestSetup85, 1); - UtRegisterTest("DetectIPProtoTestSetup86", DetectIPProtoTestSetup86, 1); - UtRegisterTest("DetectIPProtoTestSetup87", DetectIPProtoTestSetup87, 1); - UtRegisterTest("DetectIPProtoTestSetup88", DetectIPProtoTestSetup88, 1); - UtRegisterTest("DetectIPProtoTestSetup89", DetectIPProtoTestSetup89, 1); - UtRegisterTest("DetectIPProtoTestSetup90", DetectIPProtoTestSetup90, 1); - UtRegisterTest("DetectIPProtoTestSetup91", DetectIPProtoTestSetup91, 1); - UtRegisterTest("DetectIPProtoTestSetup92", DetectIPProtoTestSetup92, 1); - UtRegisterTest("DetectIPProtoTestSetup93", DetectIPProtoTestSetup93, 1); - UtRegisterTest("DetectIPProtoTestSetup94", DetectIPProtoTestSetup94, 1); - UtRegisterTest("DetectIPProtoTestSetup95", DetectIPProtoTestSetup95, 1); - UtRegisterTest("DetectIPProtoTestSetup96", DetectIPProtoTestSetup96, 1); - UtRegisterTest("DetectIPProtoTestSetup97", DetectIPProtoTestSetup97, 1); - UtRegisterTest("DetectIPProtoTestSetup98", DetectIPProtoTestSetup98, 1); - UtRegisterTest("DetectIPProtoTestSetup99", DetectIPProtoTestSetup99, 1); - UtRegisterTest("DetectIPProtoTestSetup100", DetectIPProtoTestSetup100, 1); - UtRegisterTest("DetectIPProtoTestSetup101", DetectIPProtoTestSetup101, 1); - UtRegisterTest("DetectIPProtoTestSetup102", DetectIPProtoTestSetup102, 1); - UtRegisterTest("DetectIPProtoTestSetup103", DetectIPProtoTestSetup103, 1); - UtRegisterTest("DetectIPProtoTestSetup104", DetectIPProtoTestSetup104, 1); - UtRegisterTest("DetectIPProtoTestSetup105", DetectIPProtoTestSetup105, 1); - UtRegisterTest("DetectIPProtoTestSetup106", DetectIPProtoTestSetup106, 1); - UtRegisterTest("DetectIPProtoTestSetup107", DetectIPProtoTestSetup107, 1); - UtRegisterTest("DetectIPProtoTestSetup108", DetectIPProtoTestSetup108, 1); - UtRegisterTest("DetectIPProtoTestSetup109", DetectIPProtoTestSetup109, 1); - UtRegisterTest("DetectIPProtoTestSetup110", DetectIPProtoTestSetup110, 1); - UtRegisterTest("DetectIPProtoTestSetup111", DetectIPProtoTestSetup111, 1); - UtRegisterTest("DetectIPProtoTestSetup112", DetectIPProtoTestSetup112, 1); - UtRegisterTest("DetectIPProtoTestSetup113", DetectIPProtoTestSetup113, 1); - UtRegisterTest("DetectIPProtoTestSetup114", DetectIPProtoTestSetup114, 1); - UtRegisterTest("DetectIPProtoTestSetup115", DetectIPProtoTestSetup115, 1); - UtRegisterTest("DetectIPProtoTestSetup116", DetectIPProtoTestSetup116, 1); - UtRegisterTest("DetectIPProtoTestSetup117", DetectIPProtoTestSetup117, 1); - UtRegisterTest("DetectIPProtoTestSetup118", DetectIPProtoTestSetup118, 1); - UtRegisterTest("DetectIPProtoTestSetup119", DetectIPProtoTestSetup119, 1); - UtRegisterTest("DetectIPProtoTestSetup120", DetectIPProtoTestSetup120, 1); - UtRegisterTest("DetectIPProtoTestSetup121", DetectIPProtoTestSetup121, 1); - UtRegisterTest("DetectIPProtoTestSetup122", DetectIPProtoTestSetup122, 1); - UtRegisterTest("DetectIPProtoTestSetup123", DetectIPProtoTestSetup123, 1); - UtRegisterTest("DetectIPProtoTestSetup124", DetectIPProtoTestSetup124, 1); - UtRegisterTest("DetectIPProtoTestSetup125", DetectIPProtoTestSetup125, 1); - UtRegisterTest("DetectIPProtoTestSetup126", DetectIPProtoTestSetup126, 1); - UtRegisterTest("DetectIPProtoTestSetup127", DetectIPProtoTestSetup127, 1); - UtRegisterTest("DetectIPProtoTestSetup128", DetectIPProtoTestSetup128, 1); - UtRegisterTest("DetectIPProtoTestSetup129", DetectIPProtoTestSetup129, 1); - UtRegisterTest("DetectIPProtoTestSetup130", DetectIPProtoTestSetup130, 1); - UtRegisterTest("DetectIPProtoTestSetup131", DetectIPProtoTestSetup131, 1); - UtRegisterTest("DetectIPProtoTestSetup132", DetectIPProtoTestSetup132, 1); - UtRegisterTest("DetectIPProtoTestSetup133", DetectIPProtoTestSetup133, 1); - UtRegisterTest("DetectIPProtoTestSetup134", DetectIPProtoTestSetup134, 1); - UtRegisterTest("DetectIPProtoTestSetup135", DetectIPProtoTestSetup135, 1); - UtRegisterTest("DetectIPProtoTestSetup136", DetectIPProtoTestSetup136, 1); - UtRegisterTest("DetectIPProtoTestSetup137", DetectIPProtoTestSetup137, 1); - UtRegisterTest("DetectIPProtoTestSetup138", DetectIPProtoTestSetup138, 1); - UtRegisterTest("DetectIPProtoTestSetup139", DetectIPProtoTestSetup139, 1); - UtRegisterTest("DetectIPProtoTestSetup140", DetectIPProtoTestSetup140, 1); - UtRegisterTest("DetectIPProtoTestSetup141", DetectIPProtoTestSetup141, 1); - UtRegisterTest("DetectIPProtoTestSetup142", DetectIPProtoTestSetup142, 1); - UtRegisterTest("DetectIPProtoTestSetup143", DetectIPProtoTestSetup143, 1); - UtRegisterTest("DetectIPProtoTestSetup144", DetectIPProtoTestSetup144, 1); - UtRegisterTest("DetectIPProtoTestSetup145", DetectIPProtoTestSetup145, 1); - - UtRegisterTest("DetectIPProtoTestSig1", DetectIPProtoTestSig1, 1); - UtRegisterTest("DetectIPProtoTestSig2", DetectIPProtoTestSig2, 1); - UtRegisterTest("DetectIPProtoTestSig3", DetectIPProtoTestSig3, 1); + UtRegisterTest("DetectIPProtoTestParse01", DetectIPProtoTestParse01); + UtRegisterTest("DetectIPProtoTestParse02", DetectIPProtoTestParse02); + UtRegisterTest("DetectIPProtoTestSetup01", DetectIPProtoTestSetup01); + UtRegisterTest("DetectIPProtoTestSetup02", DetectIPProtoTestSetup02); + UtRegisterTest("DetectIPProtoTestSetup03", DetectIPProtoTestSetup03); + UtRegisterTest("DetectIPProtoTestSetup04", DetectIPProtoTestSetup04); + UtRegisterTest("DetectIPProtoTestSetup05", DetectIPProtoTestSetup05); + UtRegisterTest("DetectIPProtoTestSetup06", DetectIPProtoTestSetup06); + UtRegisterTest("DetectIPProtoTestSetup07", DetectIPProtoTestSetup07); + UtRegisterTest("DetectIPProtoTestSetup08", DetectIPProtoTestSetup08); + UtRegisterTest("DetectIPProtoTestSetup09", DetectIPProtoTestSetup09); + UtRegisterTest("DetectIPProtoTestSetup10", DetectIPProtoTestSetup10); + UtRegisterTest("DetectIPProtoTestSetup11", DetectIPProtoTestSetup11); + UtRegisterTest("DetectIPProtoTestSetup12", DetectIPProtoTestSetup12); + UtRegisterTest("DetectIPProtoTestSetup13", DetectIPProtoTestSetup13); + UtRegisterTest("DetectIPProtoTestSetup14", DetectIPProtoTestSetup14); + UtRegisterTest("DetectIPProtoTestSetup15", DetectIPProtoTestSetup15); + UtRegisterTest("DetectIPProtoTestSetup16", DetectIPProtoTestSetup16); + UtRegisterTest("DetectIPProtoTestSetup17", DetectIPProtoTestSetup17); + UtRegisterTest("DetectIPProtoTestSetup18", DetectIPProtoTestSetup18); + UtRegisterTest("DetectIPProtoTestSetup19", DetectIPProtoTestSetup19); + UtRegisterTest("DetectIPProtoTestSetup20", DetectIPProtoTestSetup20); + UtRegisterTest("DetectIPProtoTestSetup21", DetectIPProtoTestSetup21); + UtRegisterTest("DetectIPProtoTestSetup22", DetectIPProtoTestSetup22); + UtRegisterTest("DetectIPProtoTestSetup23", DetectIPProtoTestSetup23); + UtRegisterTest("DetectIPProtoTestSetup24", DetectIPProtoTestSetup24); + UtRegisterTest("DetectIPProtoTestSetup25", DetectIPProtoTestSetup25); + UtRegisterTest("DetectIPProtoTestSetup26", DetectIPProtoTestSetup26); + UtRegisterTest("DetectIPProtoTestSetup27", DetectIPProtoTestSetup27); + UtRegisterTest("DetectIPProtoTestSetup28", DetectIPProtoTestSetup28); + UtRegisterTest("DetectIPProtoTestSetup29", DetectIPProtoTestSetup29); + UtRegisterTest("DetectIPProtoTestSetup30", DetectIPProtoTestSetup30); + UtRegisterTest("DetectIPProtoTestSetup31", DetectIPProtoTestSetup31); + UtRegisterTest("DetectIPProtoTestSetup32", DetectIPProtoTestSetup32); + UtRegisterTest("DetectIPProtoTestSetup33", DetectIPProtoTestSetup33); + UtRegisterTest("DetectIPProtoTestSetup34", DetectIPProtoTestSetup34); + UtRegisterTest("DetectIPProtoTestSetup35", DetectIPProtoTestSetup35); + UtRegisterTest("DetectIPProtoTestSetup36", DetectIPProtoTestSetup36); + UtRegisterTest("DetectIPProtoTestSetup37", DetectIPProtoTestSetup37); + UtRegisterTest("DetectIPProtoTestSetup38", DetectIPProtoTestSetup38); + UtRegisterTest("DetectIPProtoTestSetup39", DetectIPProtoTestSetup39); + UtRegisterTest("DetectIPProtoTestSetup40", DetectIPProtoTestSetup40); + UtRegisterTest("DetectIPProtoTestSetup41", DetectIPProtoTestSetup41); + UtRegisterTest("DetectIPProtoTestSetup42", DetectIPProtoTestSetup42); + UtRegisterTest("DetectIPProtoTestSetup43", DetectIPProtoTestSetup43); + UtRegisterTest("DetectIPProtoTestSetup44", DetectIPProtoTestSetup44); + UtRegisterTest("DetectIPProtoTestSetup45", DetectIPProtoTestSetup45); + UtRegisterTest("DetectIPProtoTestSetup46", DetectIPProtoTestSetup46); + UtRegisterTest("DetectIPProtoTestSetup47", DetectIPProtoTestSetup47); + UtRegisterTest("DetectIPProtoTestSetup48", DetectIPProtoTestSetup48); + UtRegisterTest("DetectIPProtoTestSetup49", DetectIPProtoTestSetup49); + UtRegisterTest("DetectIPProtoTestSetup50", DetectIPProtoTestSetup50); + UtRegisterTest("DetectIPProtoTestSetup51", DetectIPProtoTestSetup51); + UtRegisterTest("DetectIPProtoTestSetup52", DetectIPProtoTestSetup52); + UtRegisterTest("DetectIPProtoTestSetup53", DetectIPProtoTestSetup53); + UtRegisterTest("DetectIPProtoTestSetup54", DetectIPProtoTestSetup54); + UtRegisterTest("DetectIPProtoTestSetup55", DetectIPProtoTestSetup55); + UtRegisterTest("DetectIPProtoTestSetup56", DetectIPProtoTestSetup56); + UtRegisterTest("DetectIPProtoTestSetup57", DetectIPProtoTestSetup57); + UtRegisterTest("DetectIPProtoTestSetup58", DetectIPProtoTestSetup58); + UtRegisterTest("DetectIPProtoTestSetup59", DetectIPProtoTestSetup59); + UtRegisterTest("DetectIPProtoTestSetup60", DetectIPProtoTestSetup60); + UtRegisterTest("DetectIPProtoTestSetup61", DetectIPProtoTestSetup61); + UtRegisterTest("DetectIPProtoTestSetup62", DetectIPProtoTestSetup62); + UtRegisterTest("DetectIPProtoTestSetup63", DetectIPProtoTestSetup63); + UtRegisterTest("DetectIPProtoTestSetup64", DetectIPProtoTestSetup64); + UtRegisterTest("DetectIPProtoTestSetup65", DetectIPProtoTestSetup65); + UtRegisterTest("DetectIPProtoTestSetup66", DetectIPProtoTestSetup66); + UtRegisterTest("DetectIPProtoTestSetup67", DetectIPProtoTestSetup67); + UtRegisterTest("DetectIPProtoTestSetup68", DetectIPProtoTestSetup68); + UtRegisterTest("DetectIPProtoTestSetup69", DetectIPProtoTestSetup69); + UtRegisterTest("DetectIPProtoTestSetup70", DetectIPProtoTestSetup70); + UtRegisterTest("DetectIPProtoTestSetup71", DetectIPProtoTestSetup71); + UtRegisterTest("DetectIPProtoTestSetup72", DetectIPProtoTestSetup72); + UtRegisterTest("DetectIPProtoTestSetup73", DetectIPProtoTestSetup73); + UtRegisterTest("DetectIPProtoTestSetup74", DetectIPProtoTestSetup74); + UtRegisterTest("DetectIPProtoTestSetup75", DetectIPProtoTestSetup75); + UtRegisterTest("DetectIPProtoTestSetup76", DetectIPProtoTestSetup76); + UtRegisterTest("DetectIPProtoTestSetup77", DetectIPProtoTestSetup77); + UtRegisterTest("DetectIPProtoTestSetup78", DetectIPProtoTestSetup78); + UtRegisterTest("DetectIPProtoTestSetup79", DetectIPProtoTestSetup79); + UtRegisterTest("DetectIPProtoTestSetup80", DetectIPProtoTestSetup80); + UtRegisterTest("DetectIPProtoTestSetup81", DetectIPProtoTestSetup81); + UtRegisterTest("DetectIPProtoTestSetup82", DetectIPProtoTestSetup82); + UtRegisterTest("DetectIPProtoTestSetup83", DetectIPProtoTestSetup83); + UtRegisterTest("DetectIPProtoTestSetup84", DetectIPProtoTestSetup84); + UtRegisterTest("DetectIPProtoTestSetup85", DetectIPProtoTestSetup85); + UtRegisterTest("DetectIPProtoTestSetup86", DetectIPProtoTestSetup86); + UtRegisterTest("DetectIPProtoTestSetup87", DetectIPProtoTestSetup87); + UtRegisterTest("DetectIPProtoTestSetup88", DetectIPProtoTestSetup88); + UtRegisterTest("DetectIPProtoTestSetup89", DetectIPProtoTestSetup89); + UtRegisterTest("DetectIPProtoTestSetup90", DetectIPProtoTestSetup90); + UtRegisterTest("DetectIPProtoTestSetup91", DetectIPProtoTestSetup91); + UtRegisterTest("DetectIPProtoTestSetup92", DetectIPProtoTestSetup92); + UtRegisterTest("DetectIPProtoTestSetup93", DetectIPProtoTestSetup93); + UtRegisterTest("DetectIPProtoTestSetup94", DetectIPProtoTestSetup94); + UtRegisterTest("DetectIPProtoTestSetup95", DetectIPProtoTestSetup95); + UtRegisterTest("DetectIPProtoTestSetup96", DetectIPProtoTestSetup96); + UtRegisterTest("DetectIPProtoTestSetup97", DetectIPProtoTestSetup97); + UtRegisterTest("DetectIPProtoTestSetup98", DetectIPProtoTestSetup98); + UtRegisterTest("DetectIPProtoTestSetup99", DetectIPProtoTestSetup99); + UtRegisterTest("DetectIPProtoTestSetup100", DetectIPProtoTestSetup100); + UtRegisterTest("DetectIPProtoTestSetup101", DetectIPProtoTestSetup101); + UtRegisterTest("DetectIPProtoTestSetup102", DetectIPProtoTestSetup102); + UtRegisterTest("DetectIPProtoTestSetup103", DetectIPProtoTestSetup103); + UtRegisterTest("DetectIPProtoTestSetup104", DetectIPProtoTestSetup104); + UtRegisterTest("DetectIPProtoTestSetup105", DetectIPProtoTestSetup105); + UtRegisterTest("DetectIPProtoTestSetup106", DetectIPProtoTestSetup106); + UtRegisterTest("DetectIPProtoTestSetup107", DetectIPProtoTestSetup107); + UtRegisterTest("DetectIPProtoTestSetup108", DetectIPProtoTestSetup108); + UtRegisterTest("DetectIPProtoTestSetup109", DetectIPProtoTestSetup109); + UtRegisterTest("DetectIPProtoTestSetup110", DetectIPProtoTestSetup110); + UtRegisterTest("DetectIPProtoTestSetup111", DetectIPProtoTestSetup111); + UtRegisterTest("DetectIPProtoTestSetup112", DetectIPProtoTestSetup112); + UtRegisterTest("DetectIPProtoTestSetup113", DetectIPProtoTestSetup113); + UtRegisterTest("DetectIPProtoTestSetup114", DetectIPProtoTestSetup114); + UtRegisterTest("DetectIPProtoTestSetup115", DetectIPProtoTestSetup115); + UtRegisterTest("DetectIPProtoTestSetup116", DetectIPProtoTestSetup116); + UtRegisterTest("DetectIPProtoTestSetup117", DetectIPProtoTestSetup117); + UtRegisterTest("DetectIPProtoTestSetup118", DetectIPProtoTestSetup118); + UtRegisterTest("DetectIPProtoTestSetup119", DetectIPProtoTestSetup119); + UtRegisterTest("DetectIPProtoTestSetup120", DetectIPProtoTestSetup120); + UtRegisterTest("DetectIPProtoTestSetup121", DetectIPProtoTestSetup121); + UtRegisterTest("DetectIPProtoTestSetup122", DetectIPProtoTestSetup122); + UtRegisterTest("DetectIPProtoTestSetup123", DetectIPProtoTestSetup123); + UtRegisterTest("DetectIPProtoTestSetup124", DetectIPProtoTestSetup124); + UtRegisterTest("DetectIPProtoTestSetup125", DetectIPProtoTestSetup125); + UtRegisterTest("DetectIPProtoTestSetup126", DetectIPProtoTestSetup126); + UtRegisterTest("DetectIPProtoTestSetup127", DetectIPProtoTestSetup127); + UtRegisterTest("DetectIPProtoTestSetup128", DetectIPProtoTestSetup128); + UtRegisterTest("DetectIPProtoTestSetup129", DetectIPProtoTestSetup129); + UtRegisterTest("DetectIPProtoTestSetup130", DetectIPProtoTestSetup130); + UtRegisterTest("DetectIPProtoTestSetup131", DetectIPProtoTestSetup131); + UtRegisterTest("DetectIPProtoTestSetup132", DetectIPProtoTestSetup132); + UtRegisterTest("DetectIPProtoTestSetup133", DetectIPProtoTestSetup133); + UtRegisterTest("DetectIPProtoTestSetup134", DetectIPProtoTestSetup134); + UtRegisterTest("DetectIPProtoTestSetup135", DetectIPProtoTestSetup135); + UtRegisterTest("DetectIPProtoTestSetup136", DetectIPProtoTestSetup136); + UtRegisterTest("DetectIPProtoTestSetup137", DetectIPProtoTestSetup137); + UtRegisterTest("DetectIPProtoTestSetup138", DetectIPProtoTestSetup138); + UtRegisterTest("DetectIPProtoTestSetup139", DetectIPProtoTestSetup139); + UtRegisterTest("DetectIPProtoTestSetup140", DetectIPProtoTestSetup140); + UtRegisterTest("DetectIPProtoTestSetup141", DetectIPProtoTestSetup141); + UtRegisterTest("DetectIPProtoTestSetup142", DetectIPProtoTestSetup142); + UtRegisterTest("DetectIPProtoTestSetup143", DetectIPProtoTestSetup143); + UtRegisterTest("DetectIPProtoTestSetup144", DetectIPProtoTestSetup144); + UtRegisterTest("DetectIPProtoTestSetup145", DetectIPProtoTestSetup145); + + UtRegisterTest("DetectIPProtoTestSig1", DetectIPProtoTestSig1); + UtRegisterTest("DetectIPProtoTestSig2", DetectIPProtoTestSig2); + UtRegisterTest("DetectIPProtoTestSig3", DetectIPProtoTestSig3); #endif /* UNITTESTS */ } diff --git a/src/detect-iprep.c b/src/detect-iprep.c index 820bfee3aeaa..7b0dfb78b6a7 100644 --- a/src/detect-iprep.c +++ b/src/detect-iprep.c @@ -41,6 +41,9 @@ #include "detect-engine-state.h" #include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-fmemopen.h" #include "reputation.h" #include "host.h" @@ -49,7 +52,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectIPRepMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectIPRepSetup (DetectEngineCtx *, Signature *, char *); void DetectIPRepFree (void *); void IPRepRegisterTests(void); @@ -64,28 +68,7 @@ void DetectIPRepRegister (void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_IPREP].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } static uint8_t GetHostRepSrc(Packet *p, uint8_t cat, uint32_t version) @@ -184,9 +167,10 @@ static inline int RepMatch(uint8_t op, uint8_t val1, uint8_t val2) * 1: match * -1: error */ -int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - DetectIPRepData *rd = (DetectIPRepData *)m->ctx; + const DetectIPRepData *rd = (const DetectIPRepData *)ctx; if (rd == NULL) return 0; @@ -197,11 +181,15 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, switch(rd->cmd) { case DETECT_IPREP_CMD_ANY: val = GetHostRepSrc(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { if (RepMatch(rd->op, val, rd->val) == 1) return 1; } val = GetHostRepDst(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -210,6 +198,8 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, case DETECT_IPREP_CMD_SRC: val = GetHostRepSrc(p, rd->cat, version); SCLogDebug("checking src -- val %u (looking for cat %u, val %u)", val, rd->cat, rd->val); + if (val == 0) + val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -218,6 +208,8 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, case DETECT_IPREP_CMD_DST: SCLogDebug("checking dst"); val = GetHostRepDst(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -225,9 +217,13 @@ int DetectIPRepMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, case DETECT_IPREP_CMD_BOTH: val = GetHostRepSrc(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepSrc(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val == 0 || RepMatch(rd->op, val, rd->val) == 0) return 0; val = GetHostRepDst(p, rd->cat, version); + if (val == 0) + val = SRepCIDRGetIPRepDst(det_ctx->de_ctx->srepCIDR_ctx, p, rd->cat, version); if (val > 0) { return RepMatch(rd->op, val, rd->val); } @@ -353,7 +349,7 @@ int DetectIPRepSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) goto error; sm->type = DETECT_IPREP; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -382,6 +378,618 @@ void DetectIPRepFree (void *ptr) } #ifdef UNITTESTS +FILE *DetectIPRepGenerateCategoriesDummy() +{ + FILE *fd = NULL; + const char *buffer = "1,BadHosts,Know bad hosts"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +FILE *DetectIPRepGenerateCategoriesDummy2() +{ + FILE *fd = NULL; + const char *buffer = + "1,BadHosts,Know bad hosts\n" + "2,GoodHosts,Know good hosts\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +FILE *DetectIPRepGenerateNetworksDummy() +{ + FILE *fd = NULL; + const char *buffer = "10.0.0.0/24,1,20"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +FILE *DetectIPRepGenerateNetworksDummy2() +{ + FILE *fd = NULL; + const char *buffer = + "0.0.0.0/0,1,10\n" + "192.168.0.0/16,2,127"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen()"); + + return fd; +} + +static int DetectIPRepTest01(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1;rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest02(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:src,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest03(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->dst.addr_data32[0] = UTHSetIPv4Address("10.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:dst,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest04(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("10.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:both,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} + +static int DetectIPRepTest05(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("1.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result == 0; +} + +static int DetectIPRepTest06(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("1.0.0.1"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result == 0; +} + +static int DetectIPRepTest07(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->dst.addr_data32[0] = UTHSetIPv4Address("1.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result == 0; +} + +static int DetectIPRepTest08(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("1.0.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("1.0.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"IPREP High value badhost\"; iprep:any,BadHosts,>,1; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result == 0; +} + +static int DetectIPRepTest09(void) +{ + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + Signature *sig = NULL; + FILE *fd = NULL; + int result = 0, r = 0; + Packet *p = UTHBuildPacket((uint8_t *)"lalala", 6, IPPROTO_TCP); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + HostInitConfig(HOST_QUIET); + memset(&th_v, 0, sizeof(th_v)); + + if (de_ctx == NULL || p == NULL) + goto end; + + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("192.168.0.2"); + de_ctx->flags |= DE_QUIET; + + SRepInit(de_ctx); + SRepResetVersion(); + + fd = DetectIPRepGenerateCategoriesDummy2(); + r = SRepLoadCatFileFromFD(fd); + if (r < 0) { + goto end; + } + + fd = DetectIPRepGenerateNetworksDummy2(); + r = SRepLoadFileFromFD(de_ctx->srepCIDR_ctx, fd); + if (r < 0) { + goto end; + } + + sig = de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"test\"; iprep:src,BadHosts,>,9; sid:1; rev:1;)"); + if (sig == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + p->alerts.cnt = 0; + p->action = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { + goto end; + } + + result = 1; +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + HostShutdown(); + return result; +} #endif /* UNITTESTS */ /** @@ -390,5 +998,14 @@ void DetectIPRepFree (void *ptr) void IPRepRegisterTests(void) { #ifdef UNITTESTS + UtRegisterTest("DetectIPRepTest01", DetectIPRepTest01); + UtRegisterTest("DetectIPRepTest02", DetectIPRepTest02); + UtRegisterTest("DetectIPRepTest03", DetectIPRepTest03); + UtRegisterTest("DetectIPRepTest04", DetectIPRepTest04); + UtRegisterTest("DetectIPRepTest05", DetectIPRepTest05); + UtRegisterTest("DetectIPRepTest06", DetectIPRepTest06); + UtRegisterTest("DetectIPRepTest07", DetectIPRepTest07); + UtRegisterTest("DetectIPRepTest08", DetectIPRepTest08); + UtRegisterTest("DetectIPRepTest09", DetectIPRepTest09); #endif /* UNITTESTS */ } diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index e8e11df1c17c..4d5df7f73811 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -55,7 +55,6 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectIsdataatMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectIsdataatSetup (DetectEngineCtx *, Signature *, char *); void DetectIsdataatRegisterTests(void); void DetectIsdataatFree(void *); @@ -67,65 +66,14 @@ void DetectIsdataatRegister(void) { sigmatch_table[DETECT_ISDATAAT].name = "isdataat"; sigmatch_table[DETECT_ISDATAAT].desc = "check if there is still data at a specific part of the payload"; - sigmatch_table[DETECT_ISDATAAT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Isadataat"; - sigmatch_table[DETECT_ISDATAAT].Match = DetectIsdataatMatch; + sigmatch_table[DETECT_ISDATAAT].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#isadataat"; + /* match is handled in DetectEngineContentInspection() */ + sigmatch_table[DETECT_ISDATAAT].Match = NULL; sigmatch_table[DETECT_ISDATAAT].Setup = DetectIsdataatSetup; sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; - sigmatch_table[DETECT_ISDATAAT].flags |= SIGMATCH_PAYLOAD; - - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; -} - -/** - * \brief This function is used to match isdataat on a packet - * \todo We need to add support for rawbytes - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIsdataatData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIsdataatMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) -{ - DetectIsdataatData *idad = (DetectIsdataatData *)m->ctx; - - SCLogDebug("payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); - - /* Relative to the last matched content is not performed here, returning match (content should take care of this)*/ - if (idad->flags & ISDATAAT_RELATIVE) - return 1; - - /* its not relative and we have more data in the packet than the offset of isdataat */ - if (p->payload_len >= idad->dataat) { - SCLogDebug("matched with payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); - return 1; - } - - return 0; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -260,109 +208,17 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst return -1; int sm_list; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { - AppLayerHtpEnableResponseBodyCallback(); - s->alproto = ALPROTO_HTTP; - } - sm_list = s->list; - s->flags |= SIG_FLAG_APPLAYER; + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + sm_list = s->init_data->list; + if (idad->flags & ISDATAAT_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); } } else if (idad->flags & ISDATAAT_RELATIVE) { - prev_pm = SigMatchGetLastSMFromLists(s, 168, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTETEST, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTEJUMP, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_BYTE_EXTRACT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH], - - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_ISDATAAT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); + prev_pm = DetectGetLastSMFromLists(s, + DETECT_CONTENT, DETECT_PCRE, + DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, + DETECT_ISDATAAT, -1); if (prev_pm == NULL) sm_list = DETECT_SM_LIST_PMATCH; else { @@ -390,7 +246,7 @@ int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, char *isdataatst if (sm == NULL) goto end; sm->type = DETECT_ISDATAAT; - sm->ctx = (void *)idad; + sm->ctx = (SigMatchCtx *)idad; SigMatchAppendSMToList(s, sm, sm_list); if (!(idad->flags & ISDATAAT_RELATIVE)) { @@ -432,6 +288,7 @@ void DetectIsdataatFree(void *ptr) #ifdef UNITTESTS +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectIsdataatTestParse01 is a test to make sure that we return a correct IsdataatData structure @@ -495,14 +352,14 @@ int DetectIsdataatTestParse04(void) s->alproto = ALPROTO_DCERPC; result &= (DetectIsdataatSetup(NULL, s, "30") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); s->alproto = ALPROTO_DCERPC; /* failure since we have no preceding content/pcre/bytejump */ result &= (DetectIsdataatSetup(NULL, s, "30,relative") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + result &= (s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); @@ -535,12 +392,12 @@ int DetectIsdataatTestParse05(void) goto end; } s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_ISDATAAT); + data = (DetectIsdataatData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) ) { result = 0; @@ -558,12 +415,12 @@ int DetectIsdataatTestParse05(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_ISDATAAT); + data = (DetectIsdataatData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || (data->flags & ISDATAAT_RAWBYTES) ) { result = 0; @@ -581,12 +438,12 @@ int DetectIsdataatTestParse05(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL) { result = 0; goto end; } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; + result &= (s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_ISDATAAT); + data = (DetectIsdataatData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; if ( !(data->flags & ISDATAAT_RELATIVE) || !(data->flags & ISDATAAT_RAWBYTES) ) { result = 0; @@ -601,7 +458,7 @@ int DetectIsdataatTestParse05(void) goto end; } s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { + if (s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL) { result = 0; goto end; } @@ -658,461 +515,6 @@ int DetectIsdataatTestParse06(void) return result; } -int DetectIsdataatTestParse07(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "uricontent:\"one\"; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse08(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_uri; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse09(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_client_body; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse10(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_header; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse11(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "flow:to_server; content:\"one\"; http_raw_header; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse12(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_method; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -int DetectIsdataatTestParse13(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing bytejump_body\"; " - "content:\"one\"; http_cookie; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] == NULL) { - goto end; - } - - result = 1; - - result &= (s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->type == DETECT_ISDATAAT); - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - result = 0; - goto end; - } - - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -static int DetectIsdataatTestParse14(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing file_data and isdataat\"; " - "file_data; content:\"one\"; " - "isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("server body list empty: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_ISDATAAT) { - printf("last server body sm not isdataat: "); - goto end; - } - - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - goto end; - } - - result = 1; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \test file_data with isdataat relative to it - */ -static int DetectIsdataatTestParse15(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing file_data and isdataat\"; " - "file_data; isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse: "); - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("server body list empty: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_ISDATAAT) { - printf("last server body sm not isdataat: "); - goto end; - } - - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - goto end; - } - - result = 1; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - -/** - * \test dns_query with isdataat relative to it - */ -static int DetectIsdataatTestParse16(void) -{ - DetectEngineCtx *de_ctx = NULL; - int result = 0; - Signature *s = NULL; - DetectIsdataatData *data = NULL; - - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"Testing dns_query and isdataat\"; " - "dns_query; isdataat:!4,relative; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse: "); - goto end; - } - - s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH] == NULL) { - printf("dns_query list empty: "); - goto end; - } - - if (s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]->type != DETECT_ISDATAAT) { - printf("last dns_query body sm not isdataat: "); - goto end; - } - - data = (DetectIsdataatData *)s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]->ctx; - if ( !(data->flags & ISDATAAT_RELATIVE) || - (data->flags & ISDATAAT_RAWBYTES) || - !(data->flags & ISDATAAT_NEGATED) ) { - goto end; - } - - result = 1; - end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} - /** * \test DetectIsdataatTestPacket01 is a test to check matches of * isdataat, and isdataat relative @@ -1225,25 +627,17 @@ int DetectIsdataatTestPacket03 (void) void DetectIsdataatRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01, 1); - UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02, 1); - UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03, 1); - UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04, 1); - UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05, 1); - UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06, 1); - UtRegisterTest("DetectIsdataatTestParse07", DetectIsdataatTestParse07, 1); - UtRegisterTest("DetectIsdataatTestParse08", DetectIsdataatTestParse08, 1); - UtRegisterTest("DetectIsdataatTestParse09", DetectIsdataatTestParse09, 1); - UtRegisterTest("DetectIsdataatTestParse10", DetectIsdataatTestParse10, 1); - UtRegisterTest("DetectIsdataatTestParse11", DetectIsdataatTestParse11, 1); - UtRegisterTest("DetectIsdataatTestParse12", DetectIsdataatTestParse12, 1); - UtRegisterTest("DetectIsdataatTestParse13", DetectIsdataatTestParse13, 1); - UtRegisterTest("DetectIsdataatTestParse14", DetectIsdataatTestParse14, 1); - UtRegisterTest("DetectIsdataatTestParse15", DetectIsdataatTestParse15, 1); - UtRegisterTest("DetectIsdataatTestParse16", DetectIsdataatTestParse16, 1); - - UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01, 1); - UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02, 1); - UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03, 1); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); + + UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01); + UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02); + UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03); + UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04); + UtRegisterTest("DetectIsdataatTestParse05", DetectIsdataatTestParse05); + UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); + + UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); + UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02); + UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03); #endif } diff --git a/src/detect-itype.c b/src/detect-itype.c index 1828dbc02522..0931972b80f2 100644 --- a/src/detect-itype.c +++ b/src/detect-itype.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-itype.h" @@ -45,11 +46,14 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectITypeMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectITypeSetup(DetectEngineCtx *, Signature *, char *); void DetectITypeRegisterTests(void); void DetectITypeFree(void *); +static int PrefilterSetupIType(SigGroupHead *sgh); +static _Bool PrefilterITypeIsPrefilterable(const Signature *s); /** * \brief Registration function for itype: keyword @@ -58,33 +62,47 @@ void DetectITypeRegister (void) { sigmatch_table[DETECT_ITYPE].name = "itype"; sigmatch_table[DETECT_ITYPE].desc = "matching on a specific ICMP type"; - sigmatch_table[DETECT_ITYPE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#itype"; + sigmatch_table[DETECT_ITYPE].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#itype"; sigmatch_table[DETECT_ITYPE].Match = DetectITypeMatch; sigmatch_table[DETECT_ITYPE].Setup = DetectITypeSetup; sigmatch_table[DETECT_ITYPE].Free = DetectITypeFree; sigmatch_table[DETECT_ITYPE].RegisterTests = DetectITypeRegisterTests; - const char *eb; - int eo; - int opts = 0; + sigmatch_table[DETECT_ITYPE].SupportsPrefilter = PrefilterITypeIsPrefilterable; + sigmatch_table[DETECT_ITYPE].SetupPrefilter = PrefilterSetupIType; - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; +#define DETECT_ITYPE_EQ PREFILTER_U8HASH_MODE_EQ /**< "equal" operator */ +#define DETECT_ITYPE_LT PREFILTER_U8HASH_MODE_LT /**< "less than" operator */ +#define DETECT_ITYPE_GT PREFILTER_U8HASH_MODE_GT /**< "greater than" operator */ +#define DETECT_ITYPE_RN PREFILTER_U8HASH_MODE_RA /**< "range" operator */ -error: - return; +typedef struct DetectITypeData_ { + uint8_t type1; + uint8_t type2; + + uint8_t mode; +} DetectITypeData; + +static inline int ITypeMatch(const uint8_t ptype, const uint8_t mode, + const uint8_t dtype1, const uint8_t dtype2) +{ + switch (mode) { + case DETECT_ITYPE_EQ: + return (ptype == dtype1) ? 1 : 0; + + case DETECT_ITYPE_LT: + return (ptype < dtype1) ? 1 : 0; + + case DETECT_ITYPE_GT: + return (ptype > dtype1) ? 1 : 0; + + case DETECT_ITYPE_RN: + return (ptype > dtype1 && ptype < dtype2) ? 1 : 0; + } + return 0; } /** @@ -98,40 +116,24 @@ void DetectITypeRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectITypeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint8_t pitype; - DetectITypeData *itd = (DetectITypeData *)m->ctx; - if (PKT_IS_PSEUDOPKT(p)) return 0; + uint8_t pitype; if (PKT_IS_ICMPV4(p)) { pitype = ICMPV4_GET_TYPE(p); } else if (PKT_IS_ICMPV6(p)) { pitype = ICMPV6_GET_TYPE(p); } else { /* Packet not ICMPv4 nor ICMPv6 */ - return ret; - } - - switch(itd->mode) { - case DETECT_ITYPE_EQ: - ret = (pitype == itd->type1) ? 1 : 0; - break; - case DETECT_ITYPE_LT: - ret = (pitype < itd->type1) ? 1 : 0; - break; - case DETECT_ITYPE_GT: - ret = (pitype > itd->type1) ? 1 : 0; - break; - case DETECT_ITYPE_RN: - ret = (pitype > itd->type1 && pitype < itd->type2) ? 1 : 0; - break; + return 0; } - return ret; + const DetectITypeData *itd = (const DetectITypeData *)ctx; + return ITypeMatch(pitype, itd->mode, itd->type1, itd->type2); } /** @@ -259,7 +261,7 @@ static int DetectITypeSetup(DetectEngineCtx *de_ctx, Signature *s, char *itypest if (sm == NULL) goto error; sm->type = DETECT_ITYPE; - sm->ctx = (void *)itd; + sm->ctx = (SigMatchCtx *)itd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -283,9 +285,78 @@ void DetectITypeFree(void *ptr) SCFree(itd); } +/* prefilter code + * + * Prefilter uses the U8Hash logic, where we setup a 256 entry array + * for each ICMP type. Each array element has the list of signatures + * that need to be inspected. */ + +static void PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx, + Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t pitype; + if (PKT_IS_ICMPV4(p)) { + pitype = ICMPV4_GET_TYPE(p); + } else if (PKT_IS_ICMPV6(p)) { + pitype = ICMPV6_GET_TYPE(p); + } else { + /* Packet not ICMPv4 nor ICMPv6 */ + return; + } + + const PrefilterPacketU8HashCtx *h = pectx; + const SigsArray *sa = h->array[pitype]; + if (sa) { + PrefilterAddSids(&det_ctx->pmq, sa->sigs, sa->cnt); + } +} + +static void +PrefilterPacketITypeSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectITypeData *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->type1; + v->u8[2] = a->type2; +} + +static _Bool +PrefilterPacketITypeCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectITypeData *a = smctx; + if (v.u8[0] == a->mode && + v.u8[1] == a->type1 && + v.u8[2] == a->type2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIType(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeaderU8Hash(sgh, DETECT_ITYPE, + PrefilterPacketITypeSet, + PrefilterPacketITypeCompare, + PrefilterPacketITypeMatch); +} + +static _Bool PrefilterITypeIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ITYPE: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -516,14 +587,14 @@ int DetectITypeMatchTest01(void) void DetectITypeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectITypeParseTest01", DetectITypeParseTest01, 1); - UtRegisterTest("DetectITypeParseTest02", DetectITypeParseTest02, 1); - UtRegisterTest("DetectITypeParseTest03", DetectITypeParseTest03, 1); - UtRegisterTest("DetectITypeParseTest04", DetectITypeParseTest04, 1); - UtRegisterTest("DetectITypeParseTest05", DetectITypeParseTest05, 1); - UtRegisterTest("DetectITypeParseTest06", DetectITypeParseTest06, 1); - UtRegisterTest("DetectITypeParseTest07", DetectITypeParseTest07, 1); - UtRegisterTest("DetectITypeParseTest08", DetectITypeParseTest08, 1); - UtRegisterTest("DetectITypeMatchTest01", DetectITypeMatchTest01, 1); + UtRegisterTest("DetectITypeParseTest01", DetectITypeParseTest01); + UtRegisterTest("DetectITypeParseTest02", DetectITypeParseTest02); + UtRegisterTest("DetectITypeParseTest03", DetectITypeParseTest03); + UtRegisterTest("DetectITypeParseTest04", DetectITypeParseTest04); + UtRegisterTest("DetectITypeParseTest05", DetectITypeParseTest05); + UtRegisterTest("DetectITypeParseTest06", DetectITypeParseTest06); + UtRegisterTest("DetectITypeParseTest07", DetectITypeParseTest07); + UtRegisterTest("DetectITypeParseTest08", DetectITypeParseTest08); + UtRegisterTest("DetectITypeMatchTest01", DetectITypeMatchTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-itype.h b/src/detect-itype.h index 168e0e7b36b3..c8d1092e6bfc 100644 --- a/src/detect-itype.h +++ b/src/detect-itype.h @@ -24,18 +24,6 @@ #ifndef __DETECT_ITYPE_H__ #define __DETECT_ITYPE_H__ -#define DETECT_ITYPE_EQ 0 /**< "equal" operator */ -#define DETECT_ITYPE_LT 1 /**< "less than" operator */ -#define DETECT_ITYPE_GT 2 /**< "greater than" operator */ -#define DETECT_ITYPE_RN 3 /**< "range" operator */ - -typedef struct DetectITypeData_ { - uint8_t type1; - uint8_t type2; - - uint8_t mode; -} DetectITypeData; - /* prototypes */ void DetectITypeRegister(void); diff --git a/src/detect-l3proto.c b/src/detect-l3proto.c index c67b47c8bb82..fb94a9a0f65f 100644 --- a/src/detect-l3proto.c +++ b/src/detect-l3proto.c @@ -73,12 +73,14 @@ static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst char *str = optstr; char dubbed = 0; - /* strip "'s */ - if (optstr[0] == '\"' && optstr[strlen(optstr) - 1] == '\"') { + /* Strip leading and trailing "s. */ + if (optstr[0] == '\"') { str = SCStrdup(optstr + 1); if (unlikely(str == NULL)) goto error; - str[strlen(optstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } @@ -120,10 +122,6 @@ static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, char *optst #ifdef UNITTESTS -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" - /** * \test DetectL3protoTestSig01 is a test for checking the working of ttl keyword * by setting up the signature and later testing its working by matching @@ -384,8 +382,8 @@ static int DetectL3protoTestSig3(void) void DetectL3protoRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectL3protoTestSig1", DetectL3protoTestSig1, 1); - UtRegisterTest("DetectL3protoTestSig2", DetectL3protoTestSig2, 1); - UtRegisterTest("DetectL3protoTestSig3", DetectL3protoTestSig3, 1); + UtRegisterTest("DetectL3protoTestSig1", DetectL3protoTestSig1); + UtRegisterTest("DetectL3protoTestSig2", DetectL3protoTestSig2); + UtRegisterTest("DetectL3protoTestSig3", DetectL3protoTestSig3); #endif /* UNITTESTS */ } diff --git a/src/detect-lua-extensions.c b/src/detect-lua-extensions.c index 6d63e708e1b9..91d1f071e42d 100644 --- a/src/detect-lua-extensions.c +++ b/src/detect-lua-extensions.c @@ -65,342 +65,350 @@ #include "util-lua.h" #include "util-lua-common.h" #include "util-lua-http.h" - -static const char luaext_key_ld[] = "suricata:luajitdata"; -static const char luaext_key_det_ctx[] = "suricata:det_ctx"; - -static int LuaGetFlowvar(lua_State *luastate) +#include "util-lua-dns.h" +#include "util-lua-tls.h" +#include "util-lua-ssh.h" +#include "util-lua-smtp.h" +#include "util-lua-dnp3.h" + +static const char luaext_key_ld[] = "suricata:luadata"; + +/* hack to please scan-build. Even though LuaCallbackError *always* + * returns 2, scan-build doesn't accept it and and generates false + * positives */ +#define LUA_ERROR(msg) \ + LuaCallbackError(luastate, (msg)); \ + return 2 + +static int GetLuaData(lua_State *luastate, DetectLuaData **ret_ld) { - uint16_t idx; - int id; - Flow *f; - FlowVar *fv; - DetectLuaData *ld; - int flow_lock = 0; + *ret_ld = NULL; - /* need luajit data for id -> idx conversion */ + DetectLuaData *ld; lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); lua_gettable(luastate, LUA_REGISTRYINDEX); ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; + LUA_ERROR("internal error: no ld"); } + *ret_ld = ld; + return 0; +} - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); +static int GetFlow(lua_State *luastate, Flow **ret_f) +{ + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; + LUA_ERROR("no flow"); } + *ret_f = f; + return 0; +} + +static int GetFlowVarById(lua_State *luastate, Flow *f, + FlowVar **ret_fv, _Bool fv_may_be_null, uint32_t *ret_idx) +{ + DetectLuaData *ld = NULL; + if (ret_idx) + *ret_idx = 0; + *ret_fv = NULL; + + /* need lua data for id -> idx conversion */ + int ret = GetLuaData(luastate, &ld); + if (ret != 0) + return ret; - /* need flowvar idx */ if (!lua_isnumber(luastate, 1)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; + LUA_ERROR("flowvar id not a number"); } - id = lua_tonumber(luastate, 1); + int id = lua_tonumber(luastate, 1); if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id out of range"); - return 2; + LUA_ERROR("flowvar id out of range"); } - idx = ld->flowvar[id]; + uint32_t idx = ld->flowvar[id]; if (idx == 0) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id uninitialized"); - return 2; + LUA_ERROR("flowvar id uninitialized"); + } + FlowVar *fv = FlowVarGet(f, idx); + if (!fv_may_be_null && fv == NULL) { + LUA_ERROR("no flow var"); } + *ret_fv = fv; + if (ret_idx) + *ret_idx = idx; + return 0; +} - /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); +static int GetFlowVarByKey(lua_State *luastate, Flow *f, FlowVar **ret_fv) +{ + *ret_fv = NULL; - fv = FlowVarGet(f, idx); - if (fv == NULL) { - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); + if (!lua_isstring(luastate, 1)) { + LUA_ERROR("flowvar key not a string"); + } + const char *keystr = lua_tostring(luastate, 1); + if (keystr == NULL) { + LUA_ERROR("key is null"); + } + if (!lua_isnumber(luastate, 2)) { + LUA_ERROR("key length not specified"); + } + int keylen = lua_tonumber(luastate, 2); + if (keylen < 0 || keylen > 0xff) { + LUA_ERROR("key len out of range: max 256"); + } - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow var"); - return 2; + FlowVar *fv = FlowVarGetByKey(f, (const uint8_t *)keystr, keylen); + if (fv == NULL) { + LUA_ERROR("no flow var"); } + *ret_fv = fv; + return 0; +} - LuaPushStringBuffer(luastate, (const uint8_t *)fv->data.fv_str.value, - (size_t)fv->data.fv_str.value_len); +static int GetFlowIntById(lua_State *luastate, Flow *f, + FlowVar **ret_fv, _Bool fv_may_be_null, uint32_t *ret_idx) +{ + DetectLuaData *ld = NULL; + if (ret_idx) + *ret_idx = 0; + *ret_fv = NULL; - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); + /* need lua data for id -> idx conversion */ + int ret = GetLuaData(luastate, &ld); + if (ret != 0) + return ret; - return 1; + if (!lua_isnumber(luastate, 1)) { + LUA_ERROR("flowvar id not a number"); + } + int id = lua_tonumber(luastate, 1); + if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { + LUA_ERROR("flowvar id out of range"); + } + uint32_t idx = ld->flowint[id]; + if (idx == 0) { + LUA_ERROR("flowvar id uninitialized"); + } + FlowVar *fv = FlowVarGet(f, idx); + if (!fv_may_be_null && fv == NULL) { + LUA_ERROR("no flow var"); + } + *ret_fv = fv; + if (ret_idx) + *ret_idx = idx; + return 0; +} + +static int LuaGetFlowvar(lua_State *luastate) +{ + Flow *f; + FlowVar *fv; + int ret; + + /* need flow */ + ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; + + if (lua_isnumber(luastate, 1)) { + ret = GetFlowVarById(luastate, f, &fv, FALSE, NULL); + if (ret != 0 || fv == NULL) + return ret; + } else if (lua_isstring(luastate, 1)) { + ret = GetFlowVarByKey(luastate, f, &fv); + if (ret != 0 || fv == NULL) + return ret; + } else { + LUA_ERROR("invalid data type as first argument"); + } + LuaPushStringBuffer(luastate, + (const uint8_t *)fv->data.fv_str.value, + (size_t)fv->data.fv_str.value_len); + return 1; } -int LuaSetFlowvar(lua_State *luastate) +static int LuaSetFlowvarById(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx = 0; Flow *f; const char *str; int len; uint8_t *buffer; - DetectEngineThreadCtx *det_ctx; - DetectLuaData *ld; - int flow_lock = 0; + FlowVar *fv = NULL; - /* need luajit data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } - - /* need det_ctx */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_det_ctx); - lua_gettable(luastate, LUA_REGISTRYINDEX); - det_ctx = lua_touserdata(luastate, -1); - SCLogDebug("det_ctx %p", det_ctx); - if (det_ctx == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no det_ctx"); - return 2; - } + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } - - /* need flowvar idx */ - if (!lua_isnumber(luastate, 1)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id out of range"); - return 2; - } + ret = GetFlowVarById(luastate, f, &fv, TRUE, &idx); + if (ret != 0) + return ret; if (!lua_isstring(luastate, 2)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "2nd arg not a string"); - return 2; + LUA_ERROR("buffer not a string"); } str = lua_tostring(luastate, 2); if (str == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "null string"); - return 2; + LUA_ERROR("buffer is null"); } if (!lua_isnumber(luastate, 3)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "3rd arg not a number"); - return 2; + LUA_ERROR("buffer length not specified"); } len = lua_tonumber(luastate, 3); if (len < 0 || len > 0xffff) { - lua_pushnil(luastate); - lua_pushstring(luastate, "len out of range: max 64k"); - return 2; - } - - idx = ld->flowvar[id]; - if (idx == 0) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowvar id uninitialized"); - return 2; + LUA_ERROR("len out of range: max 64k"); } buffer = SCMalloc(len+1); if (unlikely(buffer == NULL)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "out of memory"); - return 2; + LUA_ERROR("out of memory"); } memcpy(buffer, str, len); buffer[len] = '\0'; - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FlowVarAddStr(f, idx, buffer, len); - else - FlowVarAddStrNoLock(f, idx, buffer, len); - - //SCLogInfo("stored:"); - //PrintRawDataFp(stdout,buffer,len); + FlowVarAddIdValue(f, idx, buffer, len); return 0; } -static int LuaGetFlowint(lua_State *luastate) +static int LuaSetFlowvarByKey(lua_State *luastate) { - uint16_t idx; - int id; Flow *f; - FlowVar *fv; - DetectLuaData *ld; - int flow_lock = 0; - uint32_t number; + const char *str; + int len; + uint8_t *buffer; - /* need luajit data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; + + const char *keystr = NULL; + int keylen = 0; + + keystr = lua_tostring(luastate, 1); + if (keystr == NULL) { + LUA_ERROR("key is null"); + } + if (!lua_isnumber(luastate, 2)) { + LUA_ERROR("key length not specified"); + } + keylen = lua_tonumber(luastate, 2); + if (keylen < 0 || keylen > 0xff) { + LUA_ERROR("key len out of range: max 256"); } - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; + if (!lua_isstring(luastate, 3)) { + LUA_ERROR("buffer not a string"); + } + str = lua_tostring(luastate, 3); + if (str == NULL) { + LUA_ERROR("buffer is null"); } - /* need flowint idx */ - if (!lua_isnumber(luastate, 1)) { - SCLogDebug("1st arg not a number"); - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { - SCLogDebug("id %d", id); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; + if (!lua_isnumber(luastate, 4)) { + LUA_ERROR("buffer length not specified"); } - idx = ld->flowint[id]; - if (idx == 0) { - SCLogDebug("idx %u", idx); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; + len = lua_tonumber(luastate, 4); + if (len < 0 || len > 0xffff) { + LUA_ERROR("len out of range: max 64k"); } - /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); + buffer = SCMalloc(len+1); + if (unlikely(buffer == NULL)) { + LUA_ERROR("out of memory"); + } + memcpy(buffer, str, len); + buffer[len] = '\0'; - fv = FlowVarGet(f, idx); - if (fv == NULL) { - SCLogDebug("fv NULL"); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); + uint8_t *keybuf = SCMalloc(keylen+1); + if (unlikely(keybuf == NULL)) { + SCFree(buffer); + LUA_ERROR("out of memory"); + } + memcpy(keybuf, keystr, keylen); + keybuf[keylen] = '\0'; + FlowVarAddKeyValue(f, keybuf, keylen, buffer, len); - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow var"); - return 2; + return 0; +} + +static int LuaSetFlowvar(lua_State *luastate) +{ + if (lua_isnumber(luastate, 1)) { + return LuaSetFlowvarById(luastate); + } else { + return LuaSetFlowvarByKey(luastate); } - number = fv->data.fv_int.value; +} - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); +static int LuaGetFlowint(lua_State *luastate) +{ + Flow *f; + FlowVar *fv; + uint32_t number; + + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; + + ret = GetFlowIntById(luastate, f, &fv, FALSE, NULL); + if (ret != 0) + return ret; + + number = fv->data.fv_int.value; /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); - SCLogDebug("retrieved flow:%p idx:%u value:%u", f, idx, number); - return 1; } -int LuaSetFlowint(lua_State *luastate) +static int LuaSetFlowint(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx; Flow *f; - DetectEngineThreadCtx *det_ctx; DetectLuaData *ld; - int flow_lock = 0; - uint32_t number; - lua_Number luanumber; - /* need luajit data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } + /* need lua data for id -> idx conversion */ + int ret = GetLuaData(luastate, &ld); + if (ret != 0) + return ret; - /* need det_ctx */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_det_ctx); - lua_gettable(luastate, LUA_REGISTRYINDEX); - det_ctx = lua_touserdata(luastate, -1); - SCLogDebug("det_ctx %p", det_ctx); - if (det_ctx == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no det_ctx"); - return 2; - } - - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } + /* need flow */ + ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; /* need flowint idx */ if (!lua_isnumber(luastate, 1)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; + LUA_ERROR("1st arg not a number"); } - id = lua_tonumber(luastate, 1); + int id = lua_tonumber(luastate, 1); if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWVARS) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; + LUA_ERROR("flowint id out of range"); } if (!lua_isnumber(luastate, 2)) { - lua_pushnil(luastate); - lua_pushstring(luastate, "2nd arg not a number"); - return 2; + LUA_ERROR("2nd arg not a number"); } - luanumber = lua_tonumber(luastate, 2); + lua_Number luanumber = lua_tonumber(luastate, 2); if (luanumber < 0 || id > (double)UINT_MAX) { - lua_pushnil(luastate); - lua_pushstring(luastate, "value out of range, value must be unsigned 32bit int"); - return 2; + LUA_ERROR("value out of range, " + "value must be unsigned 32bit int"); } - number = (uint32_t)luanumber; + uint32_t number = (uint32_t)luanumber; idx = ld->flowint[id]; if (idx == 0) { - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; + LUA_ERROR("flowint id uninitialized"); } - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FlowVarAddInt(f, idx, number); - else - FlowVarAddIntNoLock(f, idx, number); + FlowVarAddInt(f, idx, number); SCLogDebug("stored flow:%p idx:%u value:%u", f, idx, number); return 0; @@ -408,60 +416,20 @@ int LuaSetFlowint(lua_State *luastate) static int LuaIncrFlowint(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx; Flow *f; FlowVar *fv; - DetectLuaData *ld; - int flow_lock = 0; uint32_t number; - /* need luajit data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } + ret = GetFlowIntById(luastate, f, &fv, TRUE, &idx); + if (ret != 0) + return ret; - /* need flowint idx */ - if (!lua_isnumber(luastate, 1)) { - SCLogDebug("1st arg not a number"); - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { - SCLogDebug("id %d", id); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; - } - idx = ld->flowint[id]; - if (idx == 0) { - SCLogDebug("idx %u", idx); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; - } - - /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); - - fv = FlowVarGet(f, idx); if (fv == NULL) { number = 1; } else { @@ -471,73 +439,29 @@ static int LuaIncrFlowint(lua_State *luastate) } FlowVarAddIntNoLock(f, idx, number); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("incremented flow:%p idx:%u value:%u", f, idx, number); - return 1; } static int LuaDecrFlowint(lua_State *luastate) { - uint16_t idx; - int id; + uint32_t idx; Flow *f; FlowVar *fv; - DetectLuaData *ld; - int flow_lock = 0; uint32_t number; - /* need luajit data for id -> idx conversion */ - lua_pushlightuserdata(luastate, (void *)&luaext_key_ld); - lua_gettable(luastate, LUA_REGISTRYINDEX); - ld = lua_touserdata(luastate, -1); - SCLogDebug("ld %p", ld); - if (ld == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "internal error: no ld"); - return 2; - } - - /* need flow and lock hint */ - f = LuaStateGetFlow(luastate, &flow_lock); - if (f == NULL) { - lua_pushnil(luastate); - lua_pushstring(luastate, "no flow"); - return 2; - } - - /* need flowint idx */ - if (!lua_isnumber(luastate, 1)) { - SCLogDebug("1st arg not a number"); - lua_pushnil(luastate); - lua_pushstring(luastate, "1st arg not a number"); - return 2; - } - id = lua_tonumber(luastate, 1); - if (id < 0 || id >= DETECT_LUAJIT_MAX_FLOWINTS) { - SCLogDebug("id %d", id); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id out of range"); - return 2; - } - idx = ld->flowint[id]; - if (idx == 0) { - SCLogDebug("idx %u", idx); - lua_pushnil(luastate); - lua_pushstring(luastate, "flowint id uninitialized"); - return 2; - } + /* need flow */ + int ret = GetFlow(luastate, &f); + if (ret != 0) + return ret; - /* lookup var */ - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_RDLOCK(f); + ret = GetFlowIntById(luastate, f, &fv, TRUE, &idx); + if (ret != 0) + return ret; - fv = FlowVarGet(f, idx); if (fv == NULL) { number = 0; } else { @@ -547,35 +471,26 @@ static int LuaDecrFlowint(lua_State *luastate) } FlowVarAddIntNoLock(f, idx, number); - if (flow_lock == LUA_FLOW_NOT_LOCKED_BY_PARENT) - FLOWLOCK_UNLOCK(f); - /* return value through luastate, as a luanumber */ lua_pushnumber(luastate, (lua_Number)number); SCLogDebug("decremented flow:%p idx:%u value:%u", f, idx, number); - return 1; } void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngineThreadCtx *det_ctx, - Flow *f, int flow_locked, Packet *p) + Flow *f, Packet *p, uint8_t flags) { SCLogDebug("det_ctx %p, f %p", det_ctx, f); - /* luajit keyword data */ + /* lua keyword data */ lua_pushlightuserdata(lua_state, (void *)&luaext_key_ld); lua_pushlightuserdata(lua_state, (void *)ld); lua_settable(lua_state, LUA_REGISTRYINDEX); - /* detection engine thread ctx */ - lua_pushlightuserdata(lua_state, (void *)&luaext_key_det_ctx); - lua_pushlightuserdata(lua_state, (void *)det_ctx); - lua_settable(lua_state, LUA_REGISTRYINDEX); + LuaStateSetFlow(lua_state, f); - LuaStateSetFlow(lua_state, f, flow_locked); - - if (det_ctx->tx_id_set && flow_locked == LUA_FLOW_LOCKED_BY_PARENT) { + if (det_ctx->tx_id_set) { if (f && f->alstate) { void *txptr = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, det_ctx->tx_id); if (txptr) { @@ -586,6 +501,8 @@ void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *ld, DetectEngi if (p != NULL) LuaStateSetPacket(lua_state, p); + + LuaStateSetDirection(lua_state, (flags & STREAM_TOSERVER)); } /** @@ -613,6 +530,11 @@ int LuaRegisterExtensions(lua_State *lua_state) LuaRegisterFunctions(lua_state); LuaRegisterHttpFunctions(lua_state); + LuaRegisterDnsFunctions(lua_state); + LuaRegisterTlsFunctions(lua_state); + LuaRegisterSshFunctions(lua_state); + LuaRegisterSmtpFunctions(lua_state); + LuaRegisterDNP3Functions(lua_state); return 0; } diff --git a/src/detect-lua-extensions.h b/src/detect-lua-extensions.h index e2edf9c6f9f3..54a465783e2d 100644 --- a/src/detect-lua-extensions.h +++ b/src/detect-lua-extensions.h @@ -29,7 +29,7 @@ int LuaRegisterExtensions(lua_State *); void LuaExtensionsMatchSetup(lua_State *lua_state, DetectLuaData *, DetectEngineThreadCtx *det_ctx, - Flow *f, int flow_locked, Packet *p); + Flow *f, Packet *p, uint8_t flags); #endif /* HAVE_LUA */ #endif diff --git a/src/detect-lua.c b/src/detect-lua.c index 21a318104c5a..0c00edc8bf0d 100644 --- a/src/detect-lua.c +++ b/src/detect-lua.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -68,7 +68,7 @@ static int DetectLuaSetupNoSupport (DetectEngineCtx *a, Signature *b, char *c) } /** - * \brief Registration function for keyword: luajit + * \brief Registration function for keyword: lua */ void DetectLuaRegister(void) { @@ -85,55 +85,63 @@ void DetectLuaRegister(void) #else /* HAVE_LUA */ -#ifdef HAVE_LUAJIT -#include "util-pool.h" - -/** \brief lua_State pool - * - * Lua requires states to be alloc'd in memory <2GB. For this reason we - * prealloc the states early during engine startup so we have a better chance - * of getting the states. We protect the pool with a lock as the detect - * threads access it during their init and cleanup. - * - * Pool size is automagically determined based on number of keyword occurences, - * cpus/cores and rule reloads being enabled or not. - * - * Alternatively, the "detect-engine.luajit-states" var can be set. - */ -static Pool *luajit_states = NULL; -static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; - -#endif /* HAVE_LUAJIT */ - #include "util-lua.h" static int DetectLuaMatch (ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); -static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m); + Packet *, const Signature *, const SigMatchCtx *); +static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx); static int DetectLuaSetup (DetectEngineCtx *, Signature *, char *); static void DetectLuaRegisterTests(void); static void DetectLuaFree(void *); +static int g_smtp_generic_list_id = 0; + +static int InspectSmtpGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); /** - * \brief Registration function for keyword: luajit + * \brief Registration function for keyword: lua */ void DetectLuaRegister(void) { sigmatch_table[DETECT_LUA].name = "lua"; sigmatch_table[DETECT_LUA].alias = "luajit"; - sigmatch_table[DETECT_LUA].desc = "match via a luajit script"; + sigmatch_table[DETECT_LUA].desc = "match via a lua script"; sigmatch_table[DETECT_LUA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Lua_scripting"; sigmatch_table[DETECT_LUA].Match = DetectLuaMatch; - sigmatch_table[DETECT_LUA].AppLayerMatch = DetectLuaAppMatch; + sigmatch_table[DETECT_LUA].AppLayerTxMatch = DetectLuaAppTxMatch; sigmatch_table[DETECT_LUA].Setup = DetectLuaSetup; sigmatch_table[DETECT_LUA].Free = DetectLuaFree; sigmatch_table[DETECT_LUA].RegisterTests = DetectLuaRegisterTests; - SCLogDebug("registering luajit rule option"); + g_smtp_generic_list_id = DetectBufferTypeRegister("smtp_generic"); + + DetectAppLayerInspectEngineRegister("smtp_generic", + ALPROTO_SMTP, SIG_FLAG_TOSERVER, + InspectSmtpGeneric); + DetectAppLayerInspectEngineRegister("smtp_generic", + ALPROTO_SMTP, SIG_FLAG_TOCLIENT, + InspectSmtpGeneric); + + SCLogDebug("registering lua rule option"); return; } +static int InspectSmtpGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} + #define DATATYPE_PACKET (1<<0) #define DATATYPE_PAYLOAD (1<<1) #define DATATYPE_STREAM (1<<2) @@ -155,87 +163,15 @@ void DetectLuaRegister(void) #define DATATYPE_HTTP_RESPONSE_HEADERS (1<<13) #define DATATYPE_HTTP_RESPONSE_HEADERS_RAW (1<<14) -#ifdef HAVE_LUAJIT -static void *LuaStatePoolAlloc(void) -{ - return luaL_newstate(); -} - -static void LuaStatePoolFree(void *d) -{ - lua_State *s = (lua_State *)d; - if (s != NULL) - lua_close(s); -} - -/** \brief Populate lua states pool - * - * \param num keyword instances - * \param reloads bool indicating we have rule reloads enabled - */ -int DetectLuajitSetupStatesPool(int num, int reloads) -{ - int retval = 0; - pthread_mutex_lock(&luajit_states_lock); - - if (luajit_states == NULL) { - int cnt = 0; - char *conf_val = NULL; - - if ((ConfGet("detect-engine.luajit-states", &conf_val)) == 1) { - cnt = (int)atoi(conf_val); - } else { - int cpus = UtilCpuGetNumProcessorsOnline(); - if (cpus == 0) { - cpus = 10; - } - cnt = num * cpus; - cnt *= 3; /* assume 3 threads per core */ - - /* alloc a bunch extra so reload can add new rules/instances */ - if (reloads) - cnt *= 5; - } - - luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); - if (luajit_states == NULL) { - SCLogError(SC_ERR_LUA_ERROR, "luastate pool init failed, lua/luajit keywords won't work"); - retval = -1; - } - } +#define DATATYPE_DNS_RRNAME (1<<15) +#define DATATYPE_DNS_REQUEST (1<<16) +#define DATATYPE_DNS_RESPONSE (1<<17) - pthread_mutex_unlock(&luajit_states_lock); - return retval; -} -#endif /* HAVE_LUAJIT */ - -static lua_State *DetectLuaGetState(void) -{ - - lua_State *s = NULL; -#ifdef HAVE_LUAJIT - pthread_mutex_lock(&luajit_states_lock); - if (luajit_states != NULL) - s = (lua_State *)PoolGet(luajit_states); - pthread_mutex_unlock(&luajit_states_lock); -#else - s = luaL_newstate(); -#endif - return s; -} +#define DATATYPE_TLS (1<<18) +#define DATATYPE_SSH (1<<19) +#define DATATYPE_SMTP (1<<20) -static void DetectLuaReturnState(lua_State *s) -{ - if (s != NULL) { -#ifdef HAVE_LUAJIT - pthread_mutex_lock(&luajit_states_lock); - PoolReturn(luajit_states, (void *)s); - pthread_mutex_unlock(&luajit_states_lock); -#else - lua_close(s); -#endif - } -} +#define DATATYPE_DNP3 (1<<20) /** \brief dump stack from lua state to screen */ void LuaDumpStack(lua_State *state) @@ -272,9 +208,10 @@ void LuaDumpStack(lua_State *state) } } -int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, +int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, - Flow *f, int flow_lock) + Flow *f) { SCEnter(); int ret = 0; @@ -282,54 +219,53 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch if (buffer == NULL || buffer_len == 0) SCReturnInt(0); - DetectLuaData *luajit = (DetectLuaData *)sm->ctx; - if (luajit == NULL) + DetectLuaData *lua = (DetectLuaData *)smd->ctx; + if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); - if (tluajit == NULL) + DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + if (tlua == NULL) SCReturnInt(0); - /* setup extension data for use in lua c functions */ - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - f, flow_lock, /* no packet in the ctx */NULL); + LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, + f, /* no packet in the ctx */NULL, 0); /* prepare data to pass to script */ - lua_getglobal(tluajit->luastate, "match"); - lua_newtable(tluajit->luastate); /* stack at -1 */ + lua_getglobal(tlua->luastate, "match"); + lua_newtable(tlua->luastate); /* stack at -1 */ - lua_pushliteral (tluajit->luastate, "offset"); /* stack at -2 */ - lua_pushnumber (tluajit->luastate, (int)(offset + 1)); - lua_settable(tluajit->luastate, -3); + lua_pushliteral (tlua->luastate, "offset"); /* stack at -2 */ + lua_pushnumber (tlua->luastate, (int)(offset + 1)); + lua_settable(tlua->luastate, -3); - lua_pushstring (tluajit->luastate, luajit->buffername); /* stack at -2 */ - LuaPushStringBuffer(tluajit->luastate, (const uint8_t *)buffer, (size_t)buffer_len); - lua_settable(tluajit->luastate, -3); + lua_pushstring (tlua->luastate, lua->buffername); /* stack at -2 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)buffer, (size_t)buffer_len); + lua_settable(tlua->luastate, -3); - int retval = lua_pcall(tluajit->luastate, 1, 1, 0); + int retval = lua_pcall(tlua->luastate, 1, 1, 0); if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); + SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1)); } /* process returns from script */ - if (lua_gettop(tluajit->luastate) > 0) { + if (lua_gettop(tlua->luastate) > 0) { /* script returns a number (return 1 or return 0) */ - if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { - double script_ret = lua_tonumber(tluajit->luastate, 1); + if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) { + double script_ret = lua_tonumber(tlua->luastate, 1); SCLogDebug("script_ret %f", script_ret); - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ - } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { - lua_pushnil(tluajit->luastate); + } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { + lua_pushnil(tlua->luastate); const char *k, *v; - while (lua_next(tluajit->luastate, -2)) { - v = lua_tostring(tluajit->luastate, -1); - lua_pop(tluajit->luastate, 1); - k = lua_tostring(tluajit->luastate, -1); + while (lua_next(tlua->luastate, -2)) { + v = lua_tostring(tlua->luastate, -1); + lua_pop(tlua->luastate, 1); + k = lua_tostring(tlua->luastate, -1); if (!k || !v) continue; @@ -345,18 +281,18 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch } /* pop the table */ - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); } } else { SCLogDebug("no stack"); } /* clear the stack */ - while (lua_gettop(tluajit->luastate) > 0) { - lua_pop(tluajit->luastate, 1); + while (lua_gettop(tlua->luastate) > 0) { + lua_pop(tlua->luastate, 1); } - if (luajit->negated) { + if (lua->negated) { if (ret == 1) ret = 0; else @@ -364,11 +300,10 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch } SCReturnInt(ret); - } /** - * \brief match the specified luajit + * \brief match the specified lua script * * \param t thread local vars * \param det_ctx pattern matcher thread local data @@ -380,53 +315,57 @@ int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch * \retval 1 match */ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; - DetectLuaData *luajit = (DetectLuaData *)m->ctx; - if (luajit == NULL) + DetectLuaData *lua = (DetectLuaData *)ctx; + if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); - if (tluajit == NULL) + DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + if (tlua == NULL) SCReturnInt(0); /* setup extension data for use in lua c functions */ - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - p->flow, /* flow not locked */LUA_FLOW_NOT_LOCKED_BY_PARENT, p); + uint8_t flags = 0; + if (p->flowflags & FLOW_PKT_TOSERVER) + flags = STREAM_TOSERVER; + else if (p->flowflags & FLOW_PKT_TOCLIENT) + flags = STREAM_TOCLIENT; - if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) + LuaStateSetThreadVars(tlua->luastate, tv); + + LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, + p->flow, p, flags); + + if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len == 0) SCReturnInt(0); - if ((tluajit->flags & DATATYPE_PACKET) && GET_PKT_LEN(p) == 0) + if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p) == 0) SCReturnInt(0); - if (tluajit->alproto != ALPROTO_UNKNOWN) { + if (tlua->alproto != ALPROTO_UNKNOWN) { if (p->flow == NULL) SCReturnInt(0); - FLOWLOCK_RDLOCK(p->flow); - int alproto = p->flow->alproto; - FLOWLOCK_UNLOCK(p->flow); - - if (tluajit->alproto != alproto) + AppProto alproto = p->flow->alproto; + if (tlua->alproto != alproto) SCReturnInt(0); } - lua_getglobal(tluajit->luastate, "match"); - lua_newtable(tluajit->luastate); /* stack at -1 */ + lua_getglobal(tlua->luastate, "match"); + lua_newtable(tlua->luastate); /* stack at -1 */ - if ((tluajit->flags & DATATYPE_PAYLOAD) && p->payload_len) { - lua_pushliteral(tluajit->luastate, "payload"); /* stack at -2 */ - LuaPushStringBuffer (tluajit->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */ - lua_settable(tluajit->luastate, -3); + if ((tlua->flags & DATATYPE_PAYLOAD) && p->payload_len) { + lua_pushliteral(tlua->luastate, "payload"); /* stack at -2 */ + LuaPushStringBuffer (tlua->luastate, (const uint8_t *)p->payload, (size_t)p->payload_len); /* stack at -3 */ + lua_settable(tlua->luastate, -3); } - if ((tluajit->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) { - lua_pushliteral(tluajit->luastate, "packet"); /* stack at -2 */ - LuaPushStringBuffer (tluajit->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */ - lua_settable(tluajit->luastate, -3); + if ((tlua->flags & DATATYPE_PACKET) && GET_PKT_LEN(p)) { + lua_pushliteral(tlua->luastate, "packet"); /* stack at -2 */ + LuaPushStringBuffer (tlua->luastate, (const uint8_t *)GET_PKT_DATA(p), (size_t)GET_PKT_LEN(p)); /* stack at -3 */ + lua_settable(tlua->luastate, -3); } - if (tluajit->alproto == ALPROTO_HTTP) { - FLOWLOCK_RDLOCK(p->flow); + if (tlua->alproto == ALPROTO_HTTP) { HtpState *htp_state = p->flow->alstate; if (htp_state != NULL && htp_state->connp != NULL) { htp_tx_t *tx = NULL; @@ -438,44 +377,43 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, if (tx == NULL) continue; - if ((tluajit->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && + if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && bstr_len(tx->request_line) > 0) { - lua_pushliteral(tluajit->luastate, "http.request_line"); /* stack at -2 */ - LuaPushStringBuffer(tluajit->luastate, + lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)bstr_ptr(tx->request_line), bstr_len(tx->request_line)); - lua_settable(tluajit->luastate, -3); + lua_settable(tlua->luastate, -3); } } } - FLOWLOCK_UNLOCK(p->flow); } - int retval = lua_pcall(tluajit->luastate, 1, 1, 0); + int retval = lua_pcall(tlua->luastate, 1, 1, 0); if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); + SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1)); } /* process returns from script */ - if (lua_gettop(tluajit->luastate) > 0) { + if (lua_gettop(tlua->luastate) > 0) { /* script returns a number (return 1 or return 0) */ - if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { - double script_ret = lua_tonumber(tluajit->luastate, 1); + if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) { + double script_ret = lua_tonumber(tlua->luastate, 1); SCLogDebug("script_ret %f", script_ret); - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ - } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { - lua_pushnil(tluajit->luastate); + } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { + lua_pushnil(tlua->luastate); const char *k, *v; - while (lua_next(tluajit->luastate, -2)) { - v = lua_tostring(tluajit->luastate, -1); - lua_pop(tluajit->luastate, 1); - k = lua_tostring(tluajit->luastate, -1); + while (lua_next(tlua->luastate, -2)) { + v = lua_tostring(tlua->luastate, -1); + lua_pop(tlua->luastate, 1); + k = lua_tostring(tlua->luastate, -1); if (!k || !v) continue; @@ -491,14 +429,14 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, } /* pop the table */ - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); } } - while (lua_gettop(tluajit->luastate) > 0) { - lua_pop(tluajit->luastate, 1); + while (lua_gettop(tlua->luastate) > 0) { + lua_pop(tlua->luastate, 1); } - if (luajit->negated) { + if (lua->negated) { if (ret == 1) ret = 0; else @@ -508,86 +446,76 @@ static int DetectLuaMatch (ThreadVars *tv, DetectEngineThreadCtx *det_ctx, SCReturnInt(ret); } -/** - * \brief match the specified lua script in AMATCH - * - * \param t thread local vars - * \param det_ctx pattern matcher thread local data - * \param s signature being inspected - * \param m sigmatch that we will cast into DetectLuaData - * - * \retval 0 no match - * \retval 1 match - */ -static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectLuaAppMatchCommon (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + const Signature *s, const SigMatchCtx *ctx) { SCEnter(); int ret = 0; - DetectLuaData *luajit = (DetectLuaData *)m->ctx; - if (luajit == NULL) + DetectLuaData *lua = (DetectLuaData *)ctx; + if (lua == NULL) SCReturnInt(0); - DetectLuaThreadData *tluajit = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, luajit->thread_ctx_id); - if (tluajit == NULL) + DetectLuaThreadData *tlua = (DetectLuaThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, lua->thread_ctx_id); + if (tlua == NULL) SCReturnInt(0); /* setup extension data for use in lua c functions */ - LuaExtensionsMatchSetup(tluajit->luastate, luajit, det_ctx, - f, /* flow is locked */LUA_FLOW_LOCKED_BY_PARENT, NULL); + LuaExtensionsMatchSetup(tlua->luastate, lua, det_ctx, + f, NULL, flags); - if (tluajit->alproto != ALPROTO_UNKNOWN) { + if (tlua->alproto != ALPROTO_UNKNOWN) { int alproto = f->alproto; - if (tluajit->alproto != alproto) + if (tlua->alproto != alproto) SCReturnInt(0); } - lua_getglobal(tluajit->luastate, "match"); - lua_newtable(tluajit->luastate); /* stack at -1 */ + lua_getglobal(tlua->luastate, "match"); + lua_newtable(tlua->luastate); /* stack at -1 */ - if (tluajit->alproto == ALPROTO_HTTP) { + if (tlua->alproto == ALPROTO_HTTP) { HtpState *htp_state = state; if (htp_state != NULL && htp_state->connp != NULL) { htp_tx_t *tx = NULL; tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, det_ctx->tx_id); if (tx != NULL) { - if ((tluajit->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && + if ((tlua->flags & DATATYPE_HTTP_REQUEST_LINE) && tx->request_line != NULL && bstr_len(tx->request_line) > 0) { - lua_pushliteral(tluajit->luastate, "http.request_line"); /* stack at -2 */ - LuaPushStringBuffer(tluajit->luastate, + lua_pushliteral(tlua->luastate, "http.request_line"); /* stack at -2 */ + LuaPushStringBuffer(tlua->luastate, (const uint8_t *)bstr_ptr(tx->request_line), bstr_len(tx->request_line)); - lua_settable(tluajit->luastate, -3); + lua_settable(tlua->luastate, -3); } } } } - int retval = lua_pcall(tluajit->luastate, 1, 1, 0); + int retval = lua_pcall(tlua->luastate, 1, 1, 0); if (retval != 0) { - SCLogInfo("failed to run script: %s", lua_tostring(tluajit->luastate, -1)); + SCLogInfo("failed to run script: %s", lua_tostring(tlua->luastate, -1)); } /* process returns from script */ - if (lua_gettop(tluajit->luastate) > 0) { + if (lua_gettop(tlua->luastate) > 0) { /* script returns a number (return 1 or return 0) */ - if (lua_type(tluajit->luastate, 1) == LUA_TNUMBER) { - double script_ret = lua_tonumber(tluajit->luastate, 1); + if (lua_type(tlua->luastate, 1) == LUA_TNUMBER) { + double script_ret = lua_tonumber(tlua->luastate, 1); SCLogDebug("script_ret %f", script_ret); - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); if (script_ret == 1.0) ret = 1; /* script returns a table */ - } else if (lua_type(tluajit->luastate, 1) == LUA_TTABLE) { - lua_pushnil(tluajit->luastate); + } else if (lua_type(tlua->luastate, 1) == LUA_TTABLE) { + lua_pushnil(tlua->luastate); const char *k, *v; - while (lua_next(tluajit->luastate, -2)) { - v = lua_tostring(tluajit->luastate, -1); - lua_pop(tluajit->luastate, 1); - k = lua_tostring(tluajit->luastate, -1); + while (lua_next(tlua->luastate, -2)) { + v = lua_tostring(tlua->luastate, -1); + lua_pop(tlua->luastate, 1); + k = lua_tostring(tlua->luastate, -1); if (!k || !v) continue; @@ -603,14 +531,14 @@ static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, } /* pop the table */ - lua_pop(tluajit->luastate, 1); + lua_pop(tlua->luastate, 1); } } - while (lua_gettop(tluajit->luastate) > 0) { - lua_pop(tluajit->luastate, 1); + while (lua_gettop(tlua->luastate) > 0) { + lua_pop(tlua->luastate, 1); } - if (luajit->negated) { + if (lua->negated) { if (ret == 1) ret = 0; else @@ -620,8 +548,27 @@ static int DetectLuaAppMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, SCReturnInt(ret); } +/** + * \brief match the specified lua script in a list with a tx + * + * \param t thread local vars + * \param det_ctx pattern matcher thread local data + * \param s signature being inspected + * \param m sigmatch that we will cast into DetectLuaData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectLuaAppTxMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, + void *state, void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + return DetectLuaAppMatchCommon(t, det_ctx, f, flags, state, s, ctx); +} + #ifdef UNITTESTS -/* if this ptr is set the luajit setup functions will use this buffer as the +/* if this ptr is set the lua setup functions will use this buffer as the * lua script instead of calling luaL_loadfile on the filename supplied. */ static const char *ut_script = NULL; #endif @@ -629,8 +576,8 @@ static const char *ut_script = NULL; static void *DetectLuaThreadInit(void *data) { int status; - DetectLuaData *luajit = (DetectLuaData *)data; - BUG_ON(luajit == NULL); + DetectLuaData *lua = (DetectLuaData *)data; + BUG_ON(lua == NULL); DetectLuaThreadData *t = SCMalloc(sizeof(DetectLuaThreadData)); if (unlikely(t == NULL)) { @@ -639,10 +586,10 @@ static void *DetectLuaThreadInit(void *data) } memset(t, 0x00, sizeof(DetectLuaThreadData)); - t->alproto = luajit->alproto; - t->flags = luajit->flags; + t->alproto = lua->alproto; + t->flags = lua->flags; - t->luastate = DetectLuaGetState(); + t->luastate = LuaGetState(); if (t->luastate == NULL) { SCLogError(SC_ERR_LUA_ERROR, "luastate pool depleted"); goto error; @@ -652,11 +599,11 @@ static void *DetectLuaThreadInit(void *data) LuaRegisterExtensions(t->luastate); - lua_pushinteger(t->luastate, (lua_Integer)(luajit->sid)); + lua_pushinteger(t->luastate, (lua_Integer)(lua->sid)); lua_setglobal(t->luastate, "SCRuleSid"); - lua_pushinteger(t->luastate, (lua_Integer)(luajit->rev)); + lua_pushinteger(t->luastate, (lua_Integer)(lua->rev)); lua_setglobal(t->luastate, "SCRuleRev"); - lua_pushinteger(t->luastate, (lua_Integer)(luajit->gid)); + lua_pushinteger(t->luastate, (lua_Integer)(lua->gid)); lua_setglobal(t->luastate, "SCRuleGid"); /* hackish, needed to allow unittests to pass buffers as scripts instead of files */ @@ -669,7 +616,7 @@ static void *DetectLuaThreadInit(void *data) } } else { #endif - status = luaL_loadfile(t->luastate, luajit->filename); + status = luaL_loadfile(t->luastate, lua->filename); if (status) { SCLogError(SC_ERR_LUA_ERROR, "couldn't load file: %s", lua_tostring(t->luastate, -1)); goto error; @@ -688,7 +635,7 @@ static void *DetectLuaThreadInit(void *data) error: if (t->luastate != NULL) - DetectLuaReturnState(t->luastate); + LuaReturnState(t->luastate); SCFree(t); return NULL; } @@ -698,46 +645,46 @@ static void DetectLuaThreadFree(void *ctx) if (ctx != NULL) { DetectLuaThreadData *t = (DetectLuaThreadData *)ctx; if (t->luastate != NULL) - DetectLuaReturnState(t->luastate); + LuaReturnState(t->luastate); SCFree(t); } } /** - * \brief Parse the luajit keyword + * \brief Parse the lua keyword * * \param str Pointer to the user provided option * - * \retval luajit pointer to DetectLuaData on success + * \retval lua pointer to DetectLuaData on success * \retval NULL on failure */ -static DetectLuaData *DetectLuaParse (char *str) +static DetectLuaData *DetectLuaParse (const DetectEngineCtx *de_ctx, char *str) { - DetectLuaData *luajit = NULL; + DetectLuaData *lua = NULL; - /* We have a correct luajit option */ - luajit = SCMalloc(sizeof(DetectLuaData)); - if (unlikely(luajit == NULL)) + /* We have a correct lua option */ + lua = SCMalloc(sizeof(DetectLuaData)); + if (unlikely(lua == NULL)) goto error; - memset(luajit, 0x00, sizeof(DetectLuaData)); + memset(lua, 0x00, sizeof(DetectLuaData)); if (strlen(str) && str[0] == '!') { - luajit->negated = 1; + lua->negated = 1; str++; } /* get full filename */ - luajit->filename = DetectLoadCompleteSigPath(str); - if (luajit->filename == NULL) { + lua->filename = DetectLoadCompleteSigPath(de_ctx, str); + if (lua->filename == NULL) { goto error; } - return luajit; + return lua; error: - if (luajit != NULL) - DetectLuaFree(luajit); + if (lua != NULL) + DetectLuaFree(lua); return NULL; } @@ -747,7 +694,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) lua_State *luastate = luaL_newstate(); if (luastate == NULL) - goto error; + return -1; luaL_openlibs(luastate); /* hackish, needed to allow unittests to pass buffers as scripts instead of files */ @@ -829,7 +776,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) goto error; } - uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, DETECT_FLOWVAR); + uint32_t idx = VarNameStoreSetupAdd((char *)value, VAR_TYPE_FLOW_VAR); ld->flowvar[ld->flowvars++] = idx; SCLogDebug("script uses flowvar %u with script id %u", idx, ld->flowvars - 1); } @@ -851,7 +798,7 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) goto error; } - uint16_t idx = VariableNameGetIdx(de_ctx, (char *)value, DETECT_FLOWINT); + uint32_t idx = VarNameStoreSetupAdd((char *)value, VAR_TYPE_FLOW_INT); ld->flowint[ld->flowints++] = idx; SCLogDebug("script uses flowint %u with script id %u", idx, ld->flowints - 1); } @@ -938,6 +885,49 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) SCLogError(SC_ERR_LUA_ERROR, "alloc error"); goto error; } + } else if (strncmp(k, "dns", 3) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_DNS; + + if (strcmp(k, "dns.rrname") == 0) + ld->flags |= DATATYPE_DNS_RRNAME; + else if (strcmp(k, "dns.request") == 0) + ld->flags |= DATATYPE_DNS_REQUEST; + else if (strcmp(k, "dns.response") == 0) + ld->flags |= DATATYPE_DNS_RESPONSE; + + else { + SCLogError(SC_ERR_LUA_ERROR, "unsupported dns data type %s", k); + goto error; + } + ld->buffername = SCStrdup(k); + if (ld->buffername == NULL) { + SCLogError(SC_ERR_LUA_ERROR, "alloc error"); + goto error; + } + } else if (strncmp(k, "tls", 3) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_TLS; + + ld->flags |= DATATYPE_TLS; + + } else if (strncmp(k, "ssh", 3) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_SSH; + + ld->flags |= DATATYPE_SSH; + + } else if (strncmp(k, "smtp", 4) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_SMTP; + + ld->flags |= DATATYPE_SMTP; + + } else if (strncmp(k, "dnp3", 4) == 0 && strcmp(v, "true") == 0) { + + ld->alproto = ALPROTO_DNP3; + + ld->flags |= DATATYPE_DNP3; } else { SCLogError(SC_ERR_LUA_ERROR, "unsupported data type %s", k); @@ -955,40 +945,40 @@ static int DetectLuaSetupPrime(DetectEngineCtx *de_ctx, DetectLuaData *ld) } /** - * \brief this function is used to parse luajit options + * \brief this function is used to parse lua options * \brief into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature - * \param str pointer to the user provided "luajit" option + * \param str pointer to the user provided "lua" option * * \retval 0 on Success * \retval -1 on Failure */ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { - DetectLuaData *luajit = NULL; + DetectLuaData *lua = NULL; SigMatch *sm = NULL; - luajit = DetectLuaParse(str); - if (luajit == NULL) + lua = DetectLuaParse(de_ctx, str); + if (lua == NULL) goto error; - if (DetectLuaSetupPrime(de_ctx, luajit) == -1) { + if (DetectLuaSetupPrime(de_ctx, lua) == -1) { goto error; } - luajit->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "luajit", - DetectLuaThreadInit, (void *)luajit, + lua->thread_ctx_id = DetectRegisterThreadCtxFuncs(de_ctx, "lua", + DetectLuaThreadInit, (void *)lua, DetectLuaThreadFree, 0); - if (luajit->thread_ctx_id == -1) + if (lua->thread_ctx_id == -1) goto error; - if (luajit->alproto != ALPROTO_UNKNOWN) { - if (s->alproto != ALPROTO_UNKNOWN && luajit->alproto != s->alproto) { + if (lua->alproto != ALPROTO_UNKNOWN) { + if (s->alproto != ALPROTO_UNKNOWN && lua->alproto != s->alproto) { goto error; } - s->alproto = luajit->alproto; + s->alproto = lua->alproto; } /* Okay so far so good, lets get this into a SigMatch @@ -998,46 +988,72 @@ static int DetectLuaSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) goto error; sm->type = DETECT_LUA; - sm->ctx = (void *)luajit; + sm->ctx = (SigMatchCtx *)lua; - if (luajit->alproto == ALPROTO_UNKNOWN) { - if (luajit->flags & DATATYPE_STREAM) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_PMATCH); - else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); - } else if (luajit->alproto == ALPROTO_HTTP) { - if (luajit->flags & DATATYPE_HTTP_RESPONSE_BODY) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HSBDMATCH); - else if (luajit->flags & DATATYPE_HTTP_REQUEST_BODY) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCBDMATCH); - else if (luajit->flags & DATATYPE_HTTP_URI) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); - else if (luajit->flags & DATATYPE_HTTP_URI_RAW) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); - else if (luajit->flags & DATATYPE_HTTP_REQUEST_COOKIE) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); - else if (luajit->flags & DATATYPE_HTTP_REQUEST_UA) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HUADMATCH); - else if (luajit->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HHDMATCH); - else if (luajit->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRHDMATCH); - else if (luajit->flags & DATATYPE_HTTP_RESPONSE_COOKIE) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HCDMATCH); + int list = -1; + if (lua->alproto == ALPROTO_UNKNOWN) { + if (lua->flags & DATATYPE_STREAM) + list = DETECT_SM_LIST_PMATCH; else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + list = DETECT_SM_LIST_MATCH; + + } else if (lua->alproto == ALPROTO_HTTP) { + if (lua->flags & DATATYPE_HTTP_RESPONSE_BODY) { + list = DetectBufferTypeGetByName("file_data"); + } else if (lua->flags & DATATYPE_HTTP_REQUEST_BODY) { + list = DetectBufferTypeGetByName("http_client_body"); + } else if (lua->flags & DATATYPE_HTTP_URI) { + list = DetectBufferTypeGetByName("http_uri"); + } else if (lua->flags & DATATYPE_HTTP_URI_RAW) { + list = DetectBufferTypeGetByName("http_raw_uri"); + } else if (lua->flags & DATATYPE_HTTP_REQUEST_COOKIE || + lua->flags & DATATYPE_HTTP_RESPONSE_COOKIE) + { + list = DetectBufferTypeGetByName("http_cookie"); + } else if (lua->flags & DATATYPE_HTTP_REQUEST_UA) { + list = DetectBufferTypeGetByName("http_user_agent"); + } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS|DATATYPE_HTTP_RESPONSE_HEADERS)) { + list = DetectBufferTypeGetByName("http_header"); + } else if (lua->flags & (DATATYPE_HTTP_REQUEST_HEADERS_RAW|DATATYPE_HTTP_RESPONSE_HEADERS_RAW)) { + list = DetectBufferTypeGetByName("http_raw_header"); + } else { + list = DetectBufferTypeGetByName("http_request_line"); + } + } else if (lua->alproto == ALPROTO_DNS) { + if (lua->flags & DATATYPE_DNS_RRNAME) { + list = DetectBufferTypeGetByName("dns_query"); + } else if (lua->flags & DATATYPE_DNS_REQUEST) { + list = DetectBufferTypeGetByName("dns_request"); + } else if (lua->flags & DATATYPE_DNS_RESPONSE) { + list = DetectBufferTypeGetByName("dns_response"); + } + } else if (lua->alproto == ALPROTO_TLS) { + list = DetectBufferTypeGetByName("tls_generic"); + } else if (lua->alproto == ALPROTO_SSH) { + list = DetectBufferTypeGetByName("ssh_banner"); + } else if (lua->alproto == ALPROTO_SMTP) { + list = g_smtp_generic_list_id; + } else if (lua->alproto == ALPROTO_DNP3) { + list = DetectBufferTypeGetByName("dnp3"); } else { - SCLogError(SC_ERR_LUA_ERROR, "luajit can't be used with protocol %s", - AppLayerGetProtoName(luajit->alproto)); + SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s", + AppLayerGetProtoName(lua->alproto)); + goto error; + } + + if (list == -1) { + SCLogError(SC_ERR_LUA_ERROR, "lua can't be used with protocol %s", + AppLayerGetProtoName(lua->alproto)); goto error; } - de_ctx->detect_luajit_instances++; + SigMatchAppendSMToList(s, sm, list); + return 0; error: - if (luajit != NULL) - DetectLuaFree(luajit); + if (lua != NULL) + DetectLuaFree(lua); if (sm != NULL) SCFree(sm); return -1; @@ -1052,11 +1068,11 @@ void DetectLuaPostSetup(Signature *s) SigMatch *sm; for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - for (sm = s->sm_lists[i]; sm != NULL; sm = sm->next) { + for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) { if (sm->type != DETECT_LUA) continue; - DetectLuaData *ld = sm->ctx; + DetectLuaData *ld = (DetectLuaData *)sm->ctx; ld->sid = s->id; ld->rev = s->rev; ld->gid = s->gid; @@ -1067,19 +1083,19 @@ void DetectLuaPostSetup(Signature *s) /** * \brief this function will free memory associated with DetectLuaData * - * \param luajit pointer to DetectLuaData + * \param ptr pointer to DetectLuaData */ static void DetectLuaFree(void *ptr) { if (ptr != NULL) { - DetectLuaData *luajit = (DetectLuaData *)ptr; + DetectLuaData *lua = (DetectLuaData *)ptr; - if (luajit->buffername) - SCFree(luajit->buffername); - if (luajit->filename) - SCFree(luajit->filename); + if (lua->buffername) + SCFree(lua->buffername); + if (lua->filename) + SCFree(lua->filename); - SCFree(luajit); + SCFree(lua); } } @@ -1115,7 +1131,7 @@ static int LuaMatchTest01(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1176,14 +1192,15 @@ static int LuaMatchTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1199,14 +1216,15 @@ static int LuaMatchTest01(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogDebug("inspecting p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1279,7 +1297,7 @@ static int LuaMatchTest02(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert tcp any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1415,7 +1433,7 @@ static int LuaMatchTest03(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert tcp any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert tcp any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1548,7 +1566,7 @@ static int LuaMatchTest04(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1610,14 +1628,15 @@ static int LuaMatchTest04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1633,14 +1652,15 @@ static int LuaMatchTest04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogInfo("p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1696,7 +1716,7 @@ static int LuaMatchTest05(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1758,14 +1778,15 @@ static int LuaMatchTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1781,14 +1802,15 @@ static int LuaMatchTest05(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogInfo("p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1849,7 +1871,7 @@ static int LuaMatchTest06(void) " return 0\n" "end\n" "return 0\n"; - char sig[] = "alert http any any -> any any (flow:to_server; luajit:unittest; sid:1;)"; + char sig[] = "alert http any any -> any any (flow:to_server; lua:unittest; sid:1;)"; int result = 0; uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n" @@ -1911,14 +1933,15 @@ static int LuaMatchTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; if (http_state == NULL) { printf("no http state: "); @@ -1934,14 +1957,15 @@ static int LuaMatchTest06(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SCLogInfo("p2"); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); @@ -1981,12 +2005,12 @@ static int LuaMatchTest06(void) void DetectLuaRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("LuaMatchTest01", LuaMatchTest01, 1); - UtRegisterTest("LuaMatchTest02", LuaMatchTest02, 1); - UtRegisterTest("LuaMatchTest03", LuaMatchTest03, 1); - UtRegisterTest("LuaMatchTest04", LuaMatchTest04, 1); - UtRegisterTest("LuaMatchTest05", LuaMatchTest05, 1); - UtRegisterTest("LuaMatchTest06", LuaMatchTest06, 1); + UtRegisterTest("LuaMatchTest01", LuaMatchTest01); + UtRegisterTest("LuaMatchTest02", LuaMatchTest02); + UtRegisterTest("LuaMatchTest03", LuaMatchTest03); + UtRegisterTest("LuaMatchTest04", LuaMatchTest04); + UtRegisterTest("LuaMatchTest05", LuaMatchTest05); + UtRegisterTest("LuaMatchTest06", LuaMatchTest06); #endif } diff --git a/src/detect-lua.h b/src/detect-lua.h index f7dc5de41494..224d6225f305 100644 --- a/src/detect-lua.h +++ b/src/detect-lua.h @@ -26,10 +26,6 @@ #ifdef HAVE_LUA -#include -#include -#include - typedef struct DetectLuaThreadData { lua_State *luastate; uint32_t flags; @@ -44,12 +40,12 @@ typedef struct DetectLuaData { int negated; char *filename; uint32_t flags; - int alproto; + AppProto alproto; char *buffername; /* buffer name in case of a single buffer */ - uint16_t flowint[DETECT_LUAJIT_MAX_FLOWINTS]; + uint32_t flowint[DETECT_LUAJIT_MAX_FLOWINTS]; uint16_t flowints; - uint16_t flowvar[DETECT_LUAJIT_MAX_FLOWVARS]; uint16_t flowvars; + uint32_t flowvar[DETECT_LUAJIT_MAX_FLOWVARS]; uint32_t sid; uint32_t rev; uint32_t gid; @@ -59,13 +55,10 @@ typedef struct DetectLuaData { /* prototypes */ void DetectLuaRegister (void); -int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, +int DetectLuaMatchBuffer(DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, uint8_t *buffer, uint32_t buffer_len, uint32_t offset, - Flow *f, int flow_lock); - -#ifdef HAVE_LUAJIT -int DetectLuajitSetupStatesPool(int num, int reloads); -#endif /* HAVE_LUAJIT */ + Flow *f); void DetectLuaPostSetup(Signature *s); diff --git a/src/detect-mark.c b/src/detect-mark.c index d641df6fd2f2..de04203ce881 100644 --- a/src/detect-mark.c +++ b/src/detect-mark.c @@ -43,7 +43,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; static int DetectMarkSetup (DetectEngineCtx *, Signature *, char *); -int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m); +static int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx); void DetectMarkDataFree(void *ptr); /** @@ -58,27 +59,7 @@ void DetectMarkRegister (void) sigmatch_table[DETECT_MARK].Free = DetectMarkDataFree; sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } #ifdef NFQ @@ -219,7 +200,7 @@ static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) } sm->type = DETECT_MARK; - sm->ctx = (void *)data; + sm->ctx = (SigMatchCtx *)data; /* Append it to the list of tags */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TMATCH); @@ -237,14 +218,30 @@ void DetectMarkDataFree(void *ptr) } -int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectMarkPacket(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { #ifdef NFQ - DetectMarkData *nf_data = (DetectMarkData *) m->ctx; + const DetectMarkData *nf_data = (const DetectMarkData *)ctx; if (nf_data->mask) { - p->nfq_v.mark = (nf_data->mark & nf_data->mask) - | (p->nfq_v.mark & ~(nf_data->mask)); - p->flags |= PKT_MARK_MODIFIED; + if (!(IS_TUNNEL_PKT(p))) { + /* coverity[missing_lock] */ + p->nfq_v.mark = (nf_data->mark & nf_data->mask) + | (p->nfq_v.mark & ~(nf_data->mask)); + p->flags |= PKT_MARK_MODIFIED; + } else { + /* real tunnels may have multiple flows inside them, so marking + * might 'mark' too much. Rebuilt packets from IP fragments + * are fine. */ + if (p->flags & PKT_REBUILT_FRAGMENT) { + Packet *tp = p->root ? p->root : p; + SCMutexLock(&tp->tunnel_mutex); + tp->nfq_v.mark = (nf_data->mark & nf_data->mask) + | (tp->nfq_v.mark & ~(nf_data->mask)); + tp->flags |= PKT_MARK_MODIFIED; + SCMutexUnlock(&tp->tunnel_mutex); + } + } } #endif return 1; @@ -288,11 +285,11 @@ static int MarkTestParse02 (void) data = DetectMarkParse("4"); if (data == NULL) { - return 0; + return 1; } DetectMarkDataFree(data); - return 1; + return 0; } /** @@ -328,11 +325,11 @@ static int MarkTestParse04 (void) data = DetectMarkParse("0x1g/0xff"); if (data == NULL) { - return 0; + return 1; } DetectMarkDataFree(data); - return 1; + return 0; } @@ -345,9 +342,9 @@ static int MarkTestParse04 (void) void MarkRegisterTests(void) { #if defined UNITTESTS && defined NFQ - UtRegisterTest("MarkTestParse01", MarkTestParse01, 1); - UtRegisterTest("MarkTestParse02", MarkTestParse02, 0); - UtRegisterTest("MarkTestParse03", MarkTestParse03, 1); - UtRegisterTest("MarkTestParse04", MarkTestParse04, 0); + UtRegisterTest("MarkTestParse01", MarkTestParse01); + UtRegisterTest("MarkTestParse02", MarkTestParse02); + UtRegisterTest("MarkTestParse03", MarkTestParse03); + UtRegisterTest("MarkTestParse04", MarkTestParse04); #endif /* UNITTESTS */ } diff --git a/src/detect-metadata.c b/src/detect-metadata.c index 3055ec78867e..d5b46949d93f 100644 --- a/src/detect-metadata.c +++ b/src/detect-metadata.c @@ -35,7 +35,7 @@ void DetectMetadataRegister (void) { sigmatch_table[DETECT_METADATA].name = "metadata"; sigmatch_table[DETECT_METADATA].desc = "ignored by suricata"; - sigmatch_table[DETECT_METADATA].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Metadata"; + sigmatch_table[DETECT_METADATA].url = DOC_URL DOC_VERSION "/rules/meta.html#metadata"; sigmatch_table[DETECT_METADATA].Match = NULL; sigmatch_table[DETECT_METADATA].Setup = DetectMetadataSetup; sigmatch_table[DETECT_METADATA].Free = NULL; diff --git a/src/detect-modbus.c b/src/detect-modbus.c new file mode 100644 index 000000000000..1c84f5778ebf --- /dev/null +++ b/src/detect-modbus.c @@ -0,0 +1,881 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + * + * Implements the Modbus function and access keywords + * You can specify a: + * - concrete function like Modbus: + * function 8, subfunction 4 (diagnostic: Force Listen Only Mode) + * - data (in primary table) register access (r/w) like Modbus: + * access read coils, address 1000 (.i.e Read coils: at address 1000) + * - write data value at specific address Modbus: + * access write, address 1500<>2000, value >2000 (Write multiple coils/register: + * at address between 1500 and 2000 value greater than 2000) + */ + +#include "suricata-common.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" + +#include "detect-modbus.h" +#include "detect-engine-modbus.h" + +#include "util-debug.h" + +#include "app-layer-modbus.h" + +#include "stream-tcp.h" + +/** + * \brief Regex for parsing the Modbus function string + */ +#define PARSE_REGEX_FUNCTION "^\\s*\"?\\s*function\\s*(!?[A-z0-9]+)(,\\s*subfunction\\s+(\\d+))?\\s*\"?\\s*$" +static pcre *function_parse_regex; +static pcre_extra *function_parse_regex_study; + +/** + * \brief Regex for parsing the Modbus access string + */ +#define PARSE_REGEX_ACCESS "^\\s*\"?\\s*access\\s*(read|write)\\s*(discretes|coils|input|holding)?(,\\s*address\\s+([<>]?\\d+)(<>\\d+)?(,\\s*value\\s+([<>]?\\d+)(<>\\d+)?)?)?\\s*\"?\\s*$" +static pcre *access_parse_regex; +static pcre_extra *access_parse_regex_study; + +static int g_modbus_buffer_id = 0; + +#define MAX_SUBSTRINGS 30 + +void DetectModbusRegisterTests(void); + +/** \internal + * + * \brief this function will free memory associated with DetectModbus + * + * \param ptr pointer to DetectModbus + */ +static void DetectModbusFree(void *ptr) { + SCEnter(); + DetectModbus *modbus = (DetectModbus *) ptr; + + if(modbus) { + if (modbus->subfunction) + SCFree(modbus->subfunction); + + if (modbus->address) + SCFree(modbus->address); + + if (modbus->data) + SCFree(modbus->data); + + SCFree(modbus); + } +} + +/** \internal + * + * \brief This function is used to parse Modbus parameters in access mode + * + * \param str Pointer to the user provided id option + * + * \retval Pointer to DetectModbusData on success or NULL on failure + */ +static DetectModbus *DetectModbusAccessParse(char *str) +{ + SCEnter(); + DetectModbus *modbus = NULL; + + char arg[MAX_SUBSTRINGS]; + int ov[MAX_SUBSTRINGS], ret, res; + + ret = pcre_exec(access_parse_regex, access_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); + + if (ret < 1) + goto error; + + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct Modbus option */ + modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus)); + if (unlikely(modbus == NULL)) + goto error; + + if (strcmp(arg, "read") == 0) + modbus->type = MODBUS_TYP_READ; + else if (strcmp(arg, "write") == 0) + modbus->type = MODBUS_TYP_WRITE; + else + goto error; + + if (ret > 2) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 2, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (*arg != '\0') { + if (strcmp(arg, "discretes") == 0) { + if (modbus->type == MODBUS_TYP_WRITE) + /* Discrete access is only read access. */ + goto error; + + modbus->type |= MODBUS_TYP_DISCRETES; + } + else if (strcmp(arg, "coils") == 0) { + modbus->type |= MODBUS_TYP_COILS; + } + else if (strcmp(arg, "input") == 0) { + if (modbus->type == MODBUS_TYP_WRITE) { + /* Input access is only read access. */ + goto error; + } + + modbus->type |= MODBUS_TYP_INPUT; + } + else if (strcmp(arg, "holding") == 0) { + modbus->type |= MODBUS_TYP_HOLDING; + } + else + goto error; + } + + if (ret > 4) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 4, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct address option */ + modbus->address = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue)); + if (unlikely(modbus->address == NULL)) + goto error; + + if (arg[0] == '>') { + modbus->address->min = atoi((const char*) (arg+1)); + modbus->address->mode = DETECT_MODBUS_GT; + } else if (arg[0] == '<') { + modbus->address->min = atoi((const char*) (arg+1)); + modbus->address->mode = DETECT_MODBUS_LT; + } else { + modbus->address->min = atoi((const char*) arg); + } + SCLogDebug("and min/equal address %d", modbus->address->min); + + if (ret > 5) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 5, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (*arg != '\0') { + modbus->address->max = atoi((const char*) (arg+2)); + modbus->address->mode = DETECT_MODBUS_RA; + SCLogDebug("and max address %d", modbus->address->max); + } + + if (ret > 7) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 7, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (modbus->address->mode != DETECT_MODBUS_EQ) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords (address range and value)."); + goto error; + } + + /* We have a correct address option */ + modbus->data = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue)); + if (unlikely(modbus->data == NULL)) + goto error; + + if (arg[0] == '>') { + modbus->data->min = atoi((const char*) (arg+1)); + modbus->data->mode = DETECT_MODBUS_GT; + } else if (arg[0] == '<') { + modbus->data->min = atoi((const char*) (arg+1)); + modbus->data->mode = DETECT_MODBUS_LT; + } else { + modbus->data->min = atoi((const char*) arg); + } + SCLogDebug("and min/equal value %d", modbus->data->min); + + if (ret > 8) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 8, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (*arg != '\0') { + modbus->data->max = atoi((const char*) (arg+2)); + modbus->data->mode = DETECT_MODBUS_RA; + SCLogDebug("and max value %d", modbus->data->max); + } + } + } + } + } + } + + SCReturnPtr(modbus, "DetectModbusAccess"); + +error: + if (modbus != NULL) + DetectModbusFree(modbus); + + SCReturnPtr(NULL, "DetectModbus"); +} + +/** \internal + * + * \brief This function is used to parse Modbus parameters in function mode + * + * \param str Pointer to the user provided id option + * + * \retval id_d pointer to DetectModbusData on success + * \retval NULL on failure + */ +static DetectModbus *DetectModbusFunctionParse(char *str) +{ + SCEnter(); + DetectModbus *modbus = NULL; + + char arg[MAX_SUBSTRINGS], *ptr = arg; + int ov[MAX_SUBSTRINGS], res, ret; + + ret = pcre_exec(function_parse_regex, function_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS); + + if (ret < 1) + goto error; + + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct Modbus function option */ + modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus)); + if (unlikely(modbus == NULL)) + goto error; + + if (isdigit((unsigned char)ptr[0])) { + modbus->function = atoi((const char*) ptr); + SCLogDebug("will look for modbus function %d", modbus->function); + + if (ret > 2) { + res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 3, arg, MAX_SUBSTRINGS); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* We have a correct address option */ + modbus->subfunction =(uint16_t *) SCCalloc(1, sizeof(uint16_t)); + if (modbus->subfunction == NULL) + goto error; + + *(modbus->subfunction) = atoi((const char*) arg); + SCLogDebug("and subfunction %d", *(modbus->subfunction)); + } + } else { + uint8_t neg = 0; + + if (ptr[0] == '!') { + neg = 1; + ptr++; + } + + if (strcmp("assigned", ptr) == 0) + modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED; + else if (strcmp("unassigned", ptr) == 0) + modbus->category = MODBUS_CAT_PUBLIC_UNASSIGNED; + else if (strcmp("public", ptr) == 0) + modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED | MODBUS_CAT_PUBLIC_UNASSIGNED; + else if (strcmp("user", ptr) == 0) + modbus->category = MODBUS_CAT_USER_DEFINED; + else if (strcmp("reserved", ptr) == 0) + modbus->category = MODBUS_CAT_RESERVED; + else if (strcmp("all", ptr) == 0) + modbus->category = MODBUS_CAT_ALL; + + if (neg) + modbus->category = ~modbus->category; + SCLogDebug("will look for modbus category function %d", modbus->category); + } + + SCReturnPtr(modbus, "DetectModbusFunction"); + +error: + if (modbus != NULL) + DetectModbusFree(modbus); + + SCReturnPtr(NULL, "DetectModbus"); +} + +/** \internal + * + * \brief this function is used to add the parsed "id" option into the current signature + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Current Signature + * \param str Pointer to the user provided "id" option + * + * \retval 0 on Success or -1 on Failure + */ +static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + SCEnter(); + DetectModbus *modbus = NULL; + SigMatch *sm = NULL; + + if (DetectSignatureSetAppProto(s, ALPROTO_MODBUS) != 0) + return -1; + + if ((modbus = DetectModbusFunctionParse(str)) == NULL) { + if ((modbus = DetectModbusAccessParse(str)) == NULL) { + SCLogError(SC_ERR_PCRE_MATCH, "invalid modbus option"); + goto error; + } + } + + /* Okay so far so good, lets get this into a SigMatch and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_AL_MODBUS; + sm->ctx = (void *) modbus; + + SigMatchAppendSMToList(s, sm, g_modbus_buffer_id); + + SCReturnInt(0); + +error: + if (modbus != NULL) + DetectModbusFree(modbus); + if (sm != NULL) + SCFree(sm); + SCReturnInt(-1); +} + +/** + * \brief Registration function for Modbus keyword + */ +void DetectModbusRegister(void) +{ + SCEnter(); + sigmatch_table[DETECT_AL_MODBUS].name = "modbus"; + sigmatch_table[DETECT_AL_MODBUS].Match = NULL; + sigmatch_table[DETECT_AL_MODBUS].Setup = DetectModbusSetup; + sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree; + sigmatch_table[DETECT_AL_MODBUS].RegisterTests = DetectModbusRegisterTests; + + DetectSetupParseRegexes(PARSE_REGEX_FUNCTION, + &function_parse_regex, &function_parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX_ACCESS, + &access_parse_regex, &access_parse_regex_study); + + DetectAppLayerInspectEngineRegister("modbus", + ALPROTO_MODBUS, SIG_FLAG_TOSERVER, + DetectEngineInspectModbus); + DetectAppLayerInspectEngineRegister("modbus", + ALPROTO_MODBUS, SIG_FLAG_TOCLIENT, + DetectEngineInspectModbus); + + g_modbus_buffer_id = DetectBufferTypeGetByName("modbus"); +} + +#ifdef UNITTESTS /* UNITTESTS */ +#include "util-unittest.h" + +/** \test Signature containing a function. */ +static int DetectModbusTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function\"; " + "modbus: function 1; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if (modbus->function != 1) { + printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a function and a subfunction. */ +static int DetectModbusTest02(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function and subfunction\"; " + "modbus: function 8, subfunction 4; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if ((modbus->function != 8) || (*modbus->subfunction != 4)) { + printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function); + printf("expected subfunction %d, got %" PRIu16 ": ", 4, *modbus->subfunction); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a function category. */ +static int DetectModbusTest03(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.function\"; " + "modbus: function reserved; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if (modbus->category != MODBUS_CAT_RESERVED) { + printf("expected function %d, got %" PRIu8 ": ", MODBUS_CAT_RESERVED, modbus->category); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a negative function category. */ +static int DetectModbusTest04(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + uint8_t category = ~MODBUS_CAT_PUBLIC_ASSIGNED; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus function\"; " + "modbus: function !assigned; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if (modbus->category != category) { + printf("expected function %u, got %" PRIu8 ": ", ~MODBUS_CAT_PUBLIC_ASSIGNED, modbus->category); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a access type. */ +static int DetectModbusTest05(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access read; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if (modbus->type != MODBUS_TYP_READ) { + printf("expected function %d, got %" PRIu8 ": ", MODBUS_TYP_READ, modbus->type); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a access function. */ +static int DetectModbusTest06(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + + uint8_t type = (MODBUS_TYP_READ | MODBUS_TYP_DISCRETES); + + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access read discretes; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if (modbus->type != type) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a read access at an address. */ +static int DetectModbusTest07(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + DetectModbusMode mode = DETECT_MODBUS_EQ; + + uint8_t type = MODBUS_TYP_READ; + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access read, address 1000; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if ((modbus->type != type) || + ((*modbus->address).mode != mode) || + ((*modbus->address).min != 1000)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + printf("expected mode %u, got %u: ", mode, (*modbus->address).mode); + printf("expected address %d, got %" PRIu16 ": ", 1000, (*modbus->address).min); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a write access at a range of address. */ +static int DetectModbusTest08(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + DetectModbusMode mode = DETECT_MODBUS_GT; + + uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_COILS); + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access write coils, address >500; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if ((modbus->type != type) || + ((*modbus->address).mode != mode) || + ((*modbus->address).min != 500)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + printf("expected mode %d, got %u: ", mode, (*modbus->address).mode); + printf("expected address %u, got %" PRIu16 ": ", 500, (*modbus->address).min); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** \test Signature containing a write access at a address a range of value. */ +static int DetectModbusTest09(void) +{ + DetectEngineCtx *de_ctx = NULL; + DetectModbus *modbus = NULL; + DetectModbusMode addressMode = DETECT_MODBUS_EQ; + DetectModbusMode valueMode = DETECT_MODBUS_RA; + + uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_HOLDING); + int result = 0; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any " + "(msg:\"Testing modbus.access\"; " + "modbus: access write holding, address 100, value 500<>1000; sid:1;)"); + + if (de_ctx->sig_list == NULL) + goto end; + + if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) || + (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) { + printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); + goto end; + } + + modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx; + + if ((modbus->type != type) || + ((*modbus->address).mode != addressMode) || + ((*modbus->address).min != 100) || + ((*modbus->data).mode != valueMode) || + ((*modbus->data).min != 500) || + ((*modbus->data).max != 1000)) { + printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type); + printf("expected address mode %u, got %u: ", addressMode, (*modbus->address).mode); + printf("expected address %d, got %" PRIu16 ": ", 500, (*modbus->address).min); + printf("expected value mode %u, got %u: ", valueMode, (*modbus->data).mode); + printf("expected min value %d, got %" PRIu16 ": ", 500, (*modbus->data).min); + printf("expected max value %d, got %" PRIu16 ": ", 1000, (*modbus->data).max); + goto end; + } + + result = 1; + + end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectModbus + */ +void DetectModbusRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("DetectModbusTest01 - Testing function", + DetectModbusTest01); + UtRegisterTest("DetectModbusTest02 - Testing function and subfunction", + DetectModbusTest02); + UtRegisterTest("DetectModbusTest03 - Testing category function", + DetectModbusTest03); + UtRegisterTest("DetectModbusTest04 - Testing category function in negative", + DetectModbusTest04); + UtRegisterTest("DetectModbusTest05 - Testing access type", + DetectModbusTest05); + UtRegisterTest("DetectModbusTest06 - Testing access function", + DetectModbusTest06); + UtRegisterTest("DetectModbusTest07 - Testing access at address", + DetectModbusTest07); + UtRegisterTest("DetectModbusTest08 - Testing a range of address", + DetectModbusTest08); + UtRegisterTest("DetectModbusTest09 - Testing write a range of value", + DetectModbusTest09); +#endif /* UNITTESTS */ +} diff --git a/src/detect-modbus.h b/src/detect-modbus.h new file mode 100644 index 000000000000..408fb7aff809 --- /dev/null +++ b/src/detect-modbus.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 ANSSI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * \author David DIALLO + */ + +#ifndef __DETECT_MODBUS_H__ +#define __DETECT_MODBUS_H__ + +#include "app-layer-modbus.h" + +typedef enum { + DETECT_MODBUS_EQ = 0, /** < EQual operator */ + DETECT_MODBUS_LT, /** < "Less Than" operator */ + DETECT_MODBUS_GT, /** < "Greater Than" operator */ + DETECT_MODBUS_RA, /** < RAnge operator */ +} DetectModbusMode; + +typedef struct DetectModbusValue_ { + uint16_t min; /** < Modbus minimum [range] or equal value to match */ + uint16_t max; /** < Modbus maximum value [range] to match */ + DetectModbusMode mode; /** < Modbus operator used in the address/data signature */ +} DetectModbusValue; + +typedef struct DetectModbus_ { + uint8_t category; /** < Modbus function code category to match */ + uint8_t function; /** < Modbus function code to match */ + uint16_t *subfunction; /** < Modbus subfunction to match */ + uint8_t type; /** < Modbus access type to match */ + DetectModbusValue *address; /** < Modbus address to match */ + DetectModbusValue *data; /** < Modbus data to match */ +} DetectModbus; + +/* prototypes */ +void DetectModbusRegister(void); + +#endif /* __DETECT_MODBUS_H__ */ diff --git a/src/detect-msg.c b/src/detect-msg.c index abd861001da0..314a2f21b5f2 100644 --- a/src/detect-msg.c +++ b/src/detect-msg.c @@ -40,7 +40,7 @@ void DetectMsgRegister (void) { sigmatch_table[DETECT_MSG].name = "msg"; sigmatch_table[DETECT_MSG].desc = "information about the rule and the possible alert"; - sigmatch_table[DETECT_MSG].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#msg-message"; + sigmatch_table[DETECT_MSG].url = DOC_URL DOC_VERSION "/rules/meta.html#msg-message"; sigmatch_table[DETECT_MSG].Match = NULL; sigmatch_table[DETECT_MSG].Setup = DetectMsgSetup; sigmatch_table[DETECT_MSG].Free = NULL; @@ -51,23 +51,25 @@ static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr) { char *str = NULL; uint16_t len; + uint16_t pos = 0; + uint16_t slen = 0; - if (strlen(msgstr) == 0) + slen = strlen(msgstr); + if (slen == 0) goto error; - /* strip "'s */ - if (msgstr[0] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { - str = SCStrdup(msgstr+1); - if (unlikely(str == NULL)) - goto error; - str[strlen(msgstr)-2] = '\0'; - } else if (msgstr[1] == '\"' && msgstr[strlen(msgstr)-1] == '\"') { - /* XXX do this parsing in a better way */ - str = SCStrdup(msgstr+2); + /* skip the first spaces */ + while (pos < slen && isspace((unsigned char)msgstr[pos])) + pos++; + + /* Strip leading and trailing "s. */ + if (msgstr[pos] == '\"') { + str = SCStrdup(msgstr + pos + 1); if (unlikely(str == NULL)) goto error; - str[strlen(msgstr)-3] = '\0'; - //printf("DetectMsgSetup: format hack applied: \'%s\'\n", str); + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str)-1] = '\0'; + } } else { SCLogError(SC_ERR_INVALID_VALUE, "format error \'%s\'", msgstr); goto error; @@ -148,9 +150,8 @@ static int DetectMsgParseTest01(void) if (de_ctx == NULL) goto end; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"flow stateless to_server\"; flow:stateless,to_server; content:\"flowstatelesscheck\"; classtype:bad-unknown; sid: 40000002; rev: 1;)"); if(sig == NULL) @@ -197,6 +198,36 @@ static int DetectMsgParseTest02(void) return result; } +static int DetectMsgParseTest03(void) +{ + int result = 0; + Signature *sig = NULL; + char *teststringparsed = "flow stateless to_server"; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); + + sig = SigInit(de_ctx, "alert tcp any any -> any any (msg: \"flow stateless to_server\"; flow:stateless,to_server; content:\"flowstatelesscheck\"; classtype:bad-unknown; sid: 40000002; rev: 1;)"); + if(sig == NULL) + goto end; + + if (strcmp(sig->msg, teststringparsed) != 0) { + printf("got \"%s\", expected: \"%s\": ", sig->msg, teststringparsed); + goto end; + } + + result = 1; +end: + if (sig != NULL) + SigFree(sig); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + #endif /* UNITTESTS */ /** @@ -205,8 +236,9 @@ static int DetectMsgParseTest02(void) void DetectMsgRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectMsgParseTest01", DetectMsgParseTest01, 1); - UtRegisterTest("DetectMsgParseTest02", DetectMsgParseTest02, 1); + UtRegisterTest("DetectMsgParseTest01", DetectMsgParseTest01); + UtRegisterTest("DetectMsgParseTest02", DetectMsgParseTest02); + UtRegisterTest("DetectMsgParseTest03", DetectMsgParseTest03); #endif /* UNITTESTS */ } diff --git a/src/detect-nocase.c b/src/detect-nocase.c index 694613512714..ee0d5bdea0ad 100644 --- a/src/detect-nocase.c +++ b/src/detect-nocase.c @@ -48,14 +48,13 @@ void DetectNocaseRegister(void) { sigmatch_table[DETECT_NOCASE].name = "nocase"; sigmatch_table[DETECT_NOCASE].desc = "modify content match to be case insensitive"; - sigmatch_table[DETECT_NOCASE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Nocase"; + sigmatch_table[DETECT_NOCASE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#nocase"; sigmatch_table[DETECT_NOCASE].Match = NULL; sigmatch_table[DETECT_NOCASE].Setup = DetectNocaseSetup; sigmatch_table[DETECT_NOCASE].Free = NULL; sigmatch_table[DETECT_NOCASE].RegisterTests = NULL; sigmatch_table[DETECT_NOCASE].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_NOCASE].flags |= SIGMATCH_PAYLOAD; } /** @@ -79,37 +78,14 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls goto end; } - /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrive the sm to apply the nocase against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "nocase needs " - "preceding content, uricontent option, http_client_body, " - "http_server_body, http_header option, http_raw_header option, " - "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg, http_stat_code, http_user_agent or " - "file_data/dce_stub_data sticky buffer options"); + "preceding content option"); goto end; } - /* verify other conditions. */ DetectContentData *cd = (DetectContentData *)pm->ctx;; @@ -117,9 +93,21 @@ static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nulls SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple nocase modifiers with the same content"); goto end; } + + /* for consistency in later use (e.g. by MPM construction and hashing), + * coerce the content string to lower-case. */ + for (uint8_t *c = cd->content; c < cd->content + cd->content_len; c++) { + *c = u8_tolower(*c); + } + cd->flags |= DETECT_CONTENT_NOCASE; /* Recreate the context with nocase chars */ - BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); + SpmDestroyCtx(cd->spm_ctx); + cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, + de_ctx->spm_global_thread_ctx); + if (cd->spm_ctx == NULL) { + goto end; + } ret = 0; end: diff --git a/src/detect-offset.c b/src/detect-offset.c index 6797267d0523..f0c84ee838d9 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -45,13 +45,11 @@ void DetectOffsetRegister (void) { sigmatch_table[DETECT_OFFSET].name = "offset"; sigmatch_table[DETECT_OFFSET].desc = "designate from which byte in the payload will be checked to find a match"; - sigmatch_table[DETECT_OFFSET].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Offset"; + sigmatch_table[DETECT_OFFSET].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#offset"; sigmatch_table[DETECT_OFFSET].Match = NULL; sigmatch_table[DETECT_OFFSET].Setup = DetectOffsetSetup; sigmatch_table[DETECT_OFFSET].Free = NULL; sigmatch_table[DETECT_OFFSET].RegisterTests = NULL; - - sigmatch_table[DETECT_OFFSET].flags |= SIGMATCH_PAYLOAD; } int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) @@ -61,46 +59,25 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (offsetstr[0] == '\"' && offsetstr[strlen(offsetstr)-1] == '\"') { + /* Strip leading and trailing "s. */ + if (offsetstr[0] == '\"') { str = SCStrdup(offsetstr+1); if (unlikely(str == NULL)) goto end; - str[strlen(offsetstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } - /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrive the sm to apply the offset against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "offset needs " - "preceding content, uricontent option, http_client_body, " - "http_server_body, http_header option, http_raw_header option, " - "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg, http_stat_code, http_user_agent or " - "file_data/dce_stub_data sticky buffer options"); + "preceding content option"); goto end; } - /* verify other conditions */ DetectContentData *cd = (DetectContentData *)pm->ctx; diff --git a/src/detect-parse.c b/src/detect-parse.c index b19c2b7e3656..f2d34f36a6dd 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -40,9 +40,9 @@ #include "detect-ipproto.h" #include "detect-flow.h" #include "detect-app-layer-protocol.h" -#include "detect-engine-apt-event.h" #include "detect-lua.h" #include "detect-app-layer-event.h" +#include "detect-http-method.h" #include "pkt-var.h" #include "host.h" @@ -67,7 +67,6 @@ #include "detect-parse.h" #include "detect-engine-iponly.h" #include "app-layer-detect-proto.h" -#include "app-layer.h" extern int sc_set_caps; @@ -76,8 +75,9 @@ static pcre *option_pcre = NULL; static pcre_extra *config_pcre_extra = NULL; static pcre_extra *option_pcre_extra = NULL; -static uint32_t dbg_srcportany_cnt = 0; -static uint32_t dbg_dstportany_cnt = 0; +static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, + SigMatch **src_sm_list, SigMatch **src_sm_list_tail, + SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail); /** * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table. @@ -108,11 +108,7 @@ typedef struct SigDuplWrapper_ { ")" /* if enclosed in [], spaces are allowed */ -#define CONFIG_PCRE_PORT "(" \ - "[\\:A-z0-9_\\$\\!,]+"\ - "|"\ - "\\[[\\:A-z0-9_\\$\\!,\\s]+\\]"\ - ")" +#define CONFIG_PCRE_PORT "([\\[\\]\\:A-z0-9_\\$\\!,\\s]+)" /* format: action space(s) protocol spaces(s) src space(s) sp spaces(s) dir spaces(s) dst spaces(s) dp spaces(s) options */ #define CONFIG_PCRE "^([A-z]+)\\s+([A-z0-9\\-]+)\\s+" \ @@ -139,9 +135,41 @@ typedef struct SignatureParser_ { char opts[DETECT_MAX_RULE_SIZE]; } SignatureParser; -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg, - uint8_t sm_type, uint8_t sm_list, - AppProto alproto, void (*CustomCallback)(Signature *s)) +const char *DetectListToHumanString(int list) +{ +#define CASE_CODE_STRING(E, S) case E: return S; break + switch (list) { + CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet"); + CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload"); + CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag"); + CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch"); + CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress"); + CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold"); + CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)"); + } +#undef CASE_CODE_STRING + return "unknown"; +} + +#define CASE_CODE(E) case E: return #E +const char *DetectListToString(int list) +{ + switch (list) { + CASE_CODE(DETECT_SM_LIST_MATCH); + CASE_CODE(DETECT_SM_LIST_PMATCH); + CASE_CODE(DETECT_SM_LIST_TMATCH); + CASE_CODE(DETECT_SM_LIST_POSTMATCH); + CASE_CODE(DETECT_SM_LIST_SUPPRESS); + CASE_CODE(DETECT_SM_LIST_THRESHOLD); + CASE_CODE(DETECT_SM_LIST_MAX); + } + return "unknown"; +} + +/** \param arg NULL or empty string */ +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, + Signature *s, const char *arg, int sm_type, int sm_list, + AppProto alproto) { SigMatch *sm = NULL; int ret = -1; @@ -152,22 +180,21 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s goto end; } - if (s->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword seen " "with a sticky buffer still set. Reset sticky buffer " "with pkt_data before using the modifier.", sigmatch_table[sm_type].name); goto end; } - /* for now let's hardcode it as http */ if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting " "alprotos set"); goto end; } - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1); if (sm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword " "found inside the rule without a content context. " @@ -184,9 +211,8 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s goto end; } if (cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) { - SigMatch *pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, sm->prev, - DETECT_PCRE, sm->prev); + SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; @@ -197,9 +223,8 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s } } - pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, s->sm_lists_tail[sm_list], - DETECT_PCRE, s->sm_lists_tail[sm_list]); + pm = DetectGetLastSMByListId(s, sm_list, + DETECT_CONTENT, DETECT_PCRE, -1); if (pm != NULL) { if (pm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)pm->ctx; @@ -210,33 +235,21 @@ int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s } } } - if (CustomCallback != NULL) - CustomCallback(s); s->alproto = alproto; s->flags |= SIG_FLAG_APPLAYER; - /* transfer the sm from the pmatch list to hcbdmatch list */ + /* transfer the sm from the pmatch list to sm_list */ SigMatchTransferSigMatchAcrossLists(sm, - &s->sm_lists[DETECT_SM_LIST_PMATCH], - &s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - &s->sm_lists[sm_list], - &s->sm_lists_tail[sm_list]); + &s->init_data->smlists[DETECT_SM_LIST_PMATCH], + &s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH], + &s->init_data->smlists[sm_list], + &s->init_data->smlists_tail[sm_list]); ret = 0; end: return ret; } -uint32_t DbgGetSrcPortAnyCnt(void) -{ - return dbg_srcportany_cnt; -} - -uint32_t DbgGetDstPortAnyCnt(void) -{ - return dbg_dstportany_cnt; -} - SigMatch *SigMatchAlloc(void) { SigMatch *sm = SCMalloc(sizeof(SigMatch)); @@ -295,30 +308,30 @@ SigTableElmt *SigTableGet(char *name) */ void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list) { - if (s->sm_lists[list] == NULL) { - s->sm_lists[list] = new; - s->sm_lists_tail[list] = new; + if (s->init_data->smlists[list] == NULL) { + s->init_data->smlists[list] = new; + s->init_data->smlists_tail[list] = new; new->next = NULL; new->prev = NULL; } else { - SigMatch *cur = s->sm_lists_tail[list]; + SigMatch *cur = s->init_data->smlists_tail[list]; cur->next = new; new->prev = cur; new->next = NULL; - s->sm_lists_tail[list] = new; + s->init_data->smlists_tail[list] = new; } - new->idx = s->sm_cnt; - s->sm_cnt++; + new->idx = s->init_data->sm_cnt; + s->init_data->sm_cnt++; } void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) { - if (sm == s->sm_lists[sm_list]) { - s->sm_lists[sm_list] = sm->next; + if (sm == s->init_data->smlists[sm_list]) { + s->init_data->smlists[sm_list] = sm->next; } - if (sm == s->sm_lists_tail[sm_list]) { - s->sm_lists_tail[sm_list] = sm->prev; + if (sm == s->init_data->smlists_tail[sm_list]) { + s->init_data->smlists_tail[sm_list] = sm->prev; } if (sm->prev != NULL) sm->prev->next = sm->next; @@ -337,7 +350,7 @@ void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list) * * \retval match Pointer to the last SigMatch instance of type 'type'. */ -static inline SigMatch *SigMatchGetLastSM(SigMatch *sm, uint8_t type) +static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type) { while (sm != NULL) { if (sm->type == type) { @@ -349,37 +362,108 @@ static inline SigMatch *SigMatchGetLastSM(SigMatch *sm, uint8_t type) return NULL; } +/** \brief get the last SigMatch from lists that support + * MPM. + * \note only supports the lists that are registered through + * DetectBufferTypeSupportsMpm(). + */ +SigMatch *DetectGetLastSMFromMpmLists(const Signature *s) +{ + SigMatch *sm_last = NULL; + SigMatch *sm_new; + int sm_type; + + /* if we have a sticky buffer, use that */ + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { + if (!(DetectBufferTypeSupportsMpmGetById(s->init_data->list))) { + return NULL; + } + + sm_last = DetectGetLastSMByListPtr(s, + s->init_data->smlists_tail[s->init_data->list], + DETECT_CONTENT, -1); + return sm_last; + } + + /* otherwise brute force it */ + const int nlists = DetectBufferTypeMaxId(); + for (sm_type = 0; sm_type < nlists; sm_type++) { + if (!DetectBufferTypeSupportsMpmGetById(sm_type)) + continue; + SigMatch *sm_list = s->init_data->smlists_tail[sm_type]; + sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT); + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + + return sm_last; +} + /** - * \brief Returns the sm with the largest index (added latest) from all the lists. + * \brief Returns the sm with the largest index (added latest) from the lists + * passed to us. * * \retval Pointer to Last sm. */ -SigMatch *SigMatchGetLastSMFromLists(Signature *s, int args, ...) +SigMatch *DetectGetLastSMFromLists(const Signature *s, ...) { - if (args == 0 || args % 2 != 0) { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "You need to send an even no of args " - "(non zero as well) to this function, since we need a " - "SigMatch list for every SigMatch type(send a map of sm_type " - "and sm_list) sent"); - /* as this is a bug we should abort to ease debugging */ - BUG_ON(1); + SigMatch *sm_last = NULL; + SigMatch *sm_new; + + /* otherwise brute force it */ + const int nlists = DetectBufferTypeMaxId(); + for (int buf_type = 0; buf_type < nlists; buf_type++) { + if (s->init_data->smlists[buf_type] == NULL) + continue; + if (s->init_data->list != DETECT_SM_LIST_NOTSET && + buf_type != s->init_data->list) + continue; + + int sm_type; + va_list ap; + va_start(ap, s); + + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) + { + sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type); + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + va_end(ap); } + return sm_last; +} + +/** + * \brief Returns the sm with the largest index (added last) from the list + * passed to us as a pointer. + * + * \param sm_list pointer to the SigMatch we should look before + * \param va_args list of keyword types terminated by -1 + * + * \retval sm_last to last sm. + */ +SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...) +{ SigMatch *sm_last = NULL; SigMatch *sm_new; - int i; + int sm_type; va_list ap; - va_start(ap, args); + va_start(ap, sm_list); - for (i = 0; i < args; i += 2) { - int sm_type = va_arg(ap, int); - SigMatch *sm_list = va_arg(ap, SigMatch *); - sm_new = SigMatchGetLastSM(sm_list, sm_type); + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) + { + sm_new = SigMatchGetLastSMByType(sm_list, sm_type); if (sm_new == NULL) - continue; + continue; if (sm_last == NULL || sm_new->idx > sm_last->idx) - sm_last = sm_new; + sm_last = sm_new; } va_end(ap); @@ -387,9 +471,68 @@ SigMatch *SigMatchGetLastSMFromLists(Signature *s, int args, ...) return sm_last; } -void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, - SigMatch **src_sm_list, SigMatch **src_sm_list_tail, - SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) +/** + * \brief Returns the sm with the largest index (added last) from the list + * passed to us as an id. + * + * \param list_id id of the list to be searched + * \param va_args list of keyword types terminated by -1 + * + * \retval sm_last to last sm. + */ +SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...) +{ + SigMatch *sm_last = NULL; + SigMatch *sm_new; + int sm_type; + + SigMatch *sm_list = s->init_data->smlists_tail[list_id]; + if (sm_list == NULL) + return NULL; + + va_list ap; + va_start(ap, list_id); + + for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) + { + sm_new = SigMatchGetLastSMByType(sm_list, sm_type); + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + + va_end(ap); + + return sm_last; +} + +/** + * \brief Returns the sm with the largest index (added latest) from this sig + * + * \retval sm_last Pointer to last sm + */ +SigMatch *DetectGetLastSM(const Signature *s) +{ + const int nlists = DetectBufferTypeMaxId(); + SigMatch *sm_last = NULL; + SigMatch *sm_new; + int i; + + for (i = 0; i < nlists; i ++) { + sm_new = s->init_data->smlists_tail[i]; + if (sm_new == NULL) + continue; + if (sm_last == NULL || sm_new->idx > sm_last->idx) + sm_last = sm_new; + } + + return sm_last; +} + +static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, + SigMatch **src_sm_list, SigMatch **src_sm_list_tail, + SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail) { /* we won't do any checks for args */ @@ -419,12 +562,13 @@ void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, return; } -int SigMatchListSMBelongsTo(Signature *s, SigMatch *key_sm) +int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm) { + const int nlists = DetectBufferTypeMaxId(); int list = 0; - for (list = 0; list < DETECT_SM_LIST_MAX; list++) { - SigMatch *sm = s->sm_lists[list]; + for (list = 0; list < nlists; list++) { + const SigMatch *sm = s->init_data->smlists[list]; while (sm != NULL) { if (sm == key_sm) return list; @@ -536,6 +680,26 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, } } + /* Validate double quoting, trimming trailing white space along the way. */ + if (strlen(optvalue) > 0) { + size_t ovlen = strlen(optvalue); + if (ovlen && optvalue[0] == '"') { + for (; ovlen > 0; ovlen--) { + if (isblank(optvalue[ovlen - 1])) { + optvalue[ovlen - 1] = '\0'; + } else { + break; + } + } + if (ovlen && optvalue[ovlen - 1] != '"') { + SCLogError(SC_ERR_INVALID_SIGNATURE, + "bad option value formatting (possible missing semicolon) " + "for keyword %s: \'%s\'", optname, optvalue); + goto error; + } + } + } + /* setup may or may not add a new SigMatch to the list */ if (st->Setup(de_ctx, s, strlen(optvalue) ? optvalue : NULL) < 0) { SCLogDebug("\"%s\" failed to setup", st->name); @@ -552,10 +716,12 @@ static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, return -1; } -/* XXX implement this for real +/** \brief Parse address string and update signature * + * \retval 0 ok, -1 error */ -int SigParseAddress(Signature *s, const char *addrstr, char flag) +static int SigParseAddress(DetectEngineCtx *de_ctx, + Signature *s, const char *addrstr, char flag) { SCLogDebug("Address Group \"%s\" to be parsed now", addrstr); @@ -564,13 +730,15 @@ int SigParseAddress(Signature *s, const char *addrstr, char flag) if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_SRC_ANY; - if (DetectAddressParse(&s->src, (char *)addrstr) < 0) + s->init_data->src = DetectParseAddress(de_ctx, addrstr); + if (s->init_data->src == NULL) goto error; } else { if (strcasecmp(addrstr, "any") == 0) s->flags |= SIG_FLAG_DST_ANY; - if (DetectAddressParse(&s->dst, (char *)addrstr) < 0) + s->init_data->dst = DetectParseAddress(de_ctx, addrstr); + if (s->init_data->dst == NULL) goto error; } @@ -600,8 +768,11 @@ int SigParseProto(Signature *s, const char *protostr) if (r < 0) { s->alproto = AppLayerGetProtoByName((char *)protostr); /* indicate that the signature is app-layer */ - if (s->alproto != ALPROTO_UNKNOWN) + if (s->alproto != ALPROTO_UNKNOWN) { s->flags |= SIG_FLAG_APPLAYER; + + AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto); + } else { SCLogError(SC_ERR_UNKNOWN_PROTOCOL, "protocol \"%s\" cannot be used " "in a signature. Either detection for this protocol " @@ -636,7 +807,8 @@ int SigParseProto(Signature *s, const char *protostr) * \retval 0 On success. * \retval -1 On failure. */ -int SigParsePort(Signature *s, const char *portstr, char flag) +static int SigParsePort(const DetectEngineCtx *de_ctx, + Signature *s, const char *portstr, char flag) { int r = 0; @@ -648,12 +820,12 @@ int SigParsePort(Signature *s, const char *portstr, char flag) if (strcasecmp(portstr, "any") == 0) s->flags |= SIG_FLAG_SP_ANY; - r = DetectPortParse(&s->sp, (char *)portstr); + r = DetectPortParse(de_ctx, &s->sp, (char *)portstr); } else if (flag == 1) { if (strcasecmp(portstr, "any") == 0) s->flags |= SIG_FLAG_DP_ANY; - r = DetectPortParse(&s->dp, (char *)portstr); + r = DetectPortParse(de_ctx, &s->dp, (char *)portstr); } if (r < 0) @@ -668,7 +840,7 @@ int SigParsePort(Signature *s, const char *portstr, char flag) static int SigParseActionRejectValidate(const char *action) { #ifdef HAVE_LIBNET11 -#ifdef HAVE_LIBCAP_NG +#if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES if (sc_set_caps == TRUE) { SCLogError(SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, "Libnet 1.1 is " "incompatible with POSIX based capabilities with privs dropping. " @@ -737,7 +909,8 @@ int SigParseAction(Signature *s, const char *action) * \internal * \brief split a signature string into a few blocks for further parsing */ -static int SigParseBasics(Signature *s, char *sigstr, SignatureParser *parser, uint8_t addrs_direction) +static int SigParseBasics(DetectEngineCtx *de_ctx, + Signature *s, const char *sigstr, SignatureParser *parser, uint8_t addrs_direction) { #define MAX_SUBSTRINGS 30 int ov[MAX_SUBSTRINGS]; @@ -781,29 +954,29 @@ static int SigParseBasics(Signature *s, char *sigstr, SignatureParser *parser, u } /* Check if it is bidirectional */ if (strcmp(parser->direction, "<>") == 0) - s->init_flags |= SIG_FLAG_INIT_BIDIREC; + s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC; /* Parse Address & Ports */ - if (SigParseAddress(s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) + if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; - if (SigParseAddress(s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) + if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; /* For IPOnly */ - if (IPOnlySigParseAddress(s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) + if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; - if (IPOnlySigParseAddress(s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) + if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp, * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp * changes that we made sees to it that at this point of time we don't * set the ip proto for the sig. We do it a bit later. */ - if (SigParsePort(s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0) + if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0) goto error; - if (SigParsePort(s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0) + if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0) goto error; return 0; @@ -832,7 +1005,7 @@ int SigParse(DetectEngineCtx *de_ctx, Signature *s, char *sigstr, uint8_t addrs_ s->sig_str = sigstr; - int ret = SigParseBasics(s, sigstr, &parser, addrs_direction); + int ret = SigParseBasics(de_ctx, s, sigstr, &parser, addrs_direction); if (ret < 0) { SCLogDebug("SigParseBasics failed"); SCReturnInt(-1); @@ -871,15 +1044,36 @@ Signature *SigAlloc (void) Signature *sig = SCMalloc(sizeof(Signature)); if (unlikely(sig == NULL)) return NULL; - memset(sig, 0, sizeof(Signature)); + sig->init_data = SCCalloc(1, sizeof(SignatureInitData)); + if (sig->init_data == NULL) { + SCFree(sig); + return NULL; + } + int lists = DetectBufferTypeMaxId(); + SCLogDebug("smlists size %d", lists); + sig->init_data->smlists = SCCalloc(lists, sizeof(SigMatch *)); + if (sig->init_data->smlists == NULL) { + SCFree(sig->init_data); + SCFree(sig); + return NULL; + } + + sig->init_data->smlists_tail = SCCalloc(lists, sizeof(SigMatch *)); + if (sig->init_data->smlists_tail == NULL) { + SCFree(sig->init_data->smlists_tail); + SCFree(sig->init_data); + SCFree(sig); + return NULL; + } + /* assign it to -1, so that we can later check if the value has been * overwritten after the Signature has been parsed, and if it hasn't been * overwritten, we can then assign the default value of 3 */ sig->prio = -1; - sig->list = DETECT_SM_LIST_NOTSET; + sig->init_data->list = DETECT_SM_LIST_NOTSET; return sig; } @@ -913,8 +1107,34 @@ static void SigRefFree (Signature *s) SCReturn; } +static void SigMatchFreeArrays(Signature *s, int ctxs) +{ + if (s != NULL) { + int type; + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + if (s->sm_arrays[type] != NULL) { + if (ctxs) { + SigMatchData *smd = s->sm_arrays[type]; + while(1) { + if (sigmatch_table[smd->type].Free != NULL) { + sigmatch_table[smd->type].Free(smd->ctx); + } + if (smd->is_last) + break; + smd++; + } + } + + SCFree(s->sm_arrays[type]); + } + } + } +} + void SigFree(Signature *s) { + const int nlists = DetectBufferTypeMaxId(); + if (s == NULL) return; @@ -925,17 +1145,23 @@ void SigFree(Signature *s) IPOnlyCIDRListFree(s->CidrSrc); int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - SigMatch *sm = s->sm_lists[i], *nsm; - while (sm != NULL) { - nsm = sm->next; - SigMatchFree(sm); - sm = nsm; + if (s->init_data) { + for (i = 0; i < nlists; i++) { + SigMatch *sm = s->init_data->smlists[i]; + while (sm != NULL) { + SigMatch *nsm = sm->next; + SigMatchFree(sm); + sm = nsm; + } } } - - DetectAddressHeadCleanup(&s->src); - DetectAddressHeadCleanup(&s->dst); + SigMatchFreeArrays(s, (s->init_data == NULL)); + if (s->init_data) { + SCFree(s->init_data->smlists); + SCFree(s->init_data->smlists_tail); + SCFree(s->init_data); + s->init_data = NULL; + } if (s->sp != NULL) { DetectPortCleanupList(s->sp); @@ -962,9 +1188,31 @@ void SigFree(Signature *s) SigRefFree(s); + DetectEngineAppInspectionEngineSignatureFree(s); + SCFree(s); } +int DetectSignatureSetAppProto(Signature *s, AppProto alproto) +{ + if (alproto == ALPROTO_UNKNOWN || + alproto >= ALPROTO_FAILED) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid alproto %u", alproto); + return -1; + } + + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { + SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, + "can't set rule app proto to %s: already set to %s", + AppProtoToString(alproto), AppProtoToString(s->alproto)); + return -1; + } + + s->alproto = alproto; + s->flags |= SIG_FLAG_APPLAYER; + return 0; +} + /** * \internal * \brief build address match array for cache efficient matching @@ -976,7 +1224,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* source addresses */ uint16_t cnt = 0; uint16_t idx = 0; - DetectAddress *da = s->src.ipv4_head; + DetectAddress *da = s->init_data->src->ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -986,7 +1234,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->src.ipv4_head; da != NULL; da = da->next) { + for (da = s->init_data->src->ipv4_head; da != NULL; da = da->next) { s->addr_src_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_src_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; @@ -997,7 +1245,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* destination addresses */ cnt = 0; idx = 0; - da = s->dst.ipv4_head; + da = s->init_data->dst->ipv4_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1007,7 +1255,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->dst.ipv4_head; da != NULL; da = da->next) { + for (da = s->init_data->dst->ipv4_head; da != NULL; da = da->next) { s->addr_dst_match4[idx].ip = ntohl(da->ip.addr_data32[0]); s->addr_dst_match4[idx].ip2 = ntohl(da->ip2.addr_data32[0]); idx++; @@ -1018,7 +1266,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* source addresses IPv6 */ cnt = 0; idx = 0; - da = s->src.ipv6_head; + da = s->init_data->src->ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1028,7 +1276,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->src.ipv6_head; da != NULL; da = da->next) { + for (da = s->init_data->src->ipv6_head; da != NULL; da = da->next) { s->addr_src_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_src_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_src_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); @@ -1045,7 +1293,7 @@ static void SigBuildAddressMatchArray(Signature *s) /* destination addresses IPv6 */ cnt = 0; idx = 0; - da = s->dst.ipv6_head; + da = s->init_data->dst->ipv6_head; for ( ; da != NULL; da = da->next) { cnt++; } @@ -1055,7 +1303,7 @@ static void SigBuildAddressMatchArray(Signature *s) exit(EXIT_FAILURE); } - for (da = s->dst.ipv6_head; da != NULL; da = da->next) { + for (da = s->init_data->dst->ipv6_head; da != NULL; da = da->next) { s->addr_dst_match6[idx].ip[0] = ntohl(da->ip.addr_data32[0]); s->addr_dst_match6[idx].ip[1] = ntohl(da->ip.addr_data32[1]); s->addr_dst_match6[idx].ip[2] = ntohl(da->ip.addr_data32[2]); @@ -1070,6 +1318,42 @@ static void SigBuildAddressMatchArray(Signature *s) } } +static int SigMatchListLen(SigMatch *sm) +{ + int len = 0; + for (; sm != NULL; sm = sm->next) + len++; + + return len; +} + +/** \brief convert SigMatch list to SigMatchData array + * \note ownership of sm->ctx is transfered to smd->ctx + */ +SigMatchData* SigMatchList2DataArray(SigMatch *head) +{ + int len = SigMatchListLen(head); + if (len == 0) + return NULL; + + SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData)); + if (smd == NULL) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } + SigMatchData *out = smd; + + /* Copy sm type and Context into array */ + SigMatch *sm = head; + for (; sm != NULL; sm = sm->next, smd++) { + smd->type = sm->type; + smd->ctx = sm->ctx; + sm->ctx = NULL; // SigMatch no longer owns the ctx + smd->is_last = (sm->next == NULL); + } + return out; +} + /** * \internal * \brief validate a just parsed signature for internal inconsistencies @@ -1081,12 +1365,22 @@ static void SigBuildAddressMatchArray(Signature *s) */ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) { - uint32_t u = 0; uint32_t sig_flags = 0; SigMatch *sm, *pm; + const int nlists = DetectBufferTypeMaxId(); SCEnter(); + /* run buffer type validation callbacks if any */ + int x; + for (x = 0; x < nlists; x++) { + if (s->init_data->smlists[x]) { + if (DetectBufferRunValidateCallback(x, s) == FALSE) { + SCReturnInt(0); + } + } + } + if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && (s->flags & SIG_FLAG_REQUIRE_STREAM)) { SCLogError(SC_ERR_INVALID_SIGNATURE, "can't mix packet keywords with " @@ -1094,55 +1388,24 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_FLOW) { - DetectFlowData *fd = (DetectFlowData *)sm->ctx; - if (fd == NULL) - continue; - - if (fd->flags & FLOW_PKT_TOCLIENT) { - /* check for uricontent + from_server/to_client */ - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use uricontent " - "/http_uri , raw_uri, http_client_body, " - "http_method, http_user_agent keywords " - "with flow:to_client or flow:from_server"); - SCReturnInt(0); - } - } else if (fd->flags & FLOW_PKT_TOSERVER) { - /* check for uricontent + from_server/to_client */ - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use http_" - "server_body, http_stat_msg, http_stat_code " - "with flow:to_server or flow:from_client"); - SCReturnInt(0); - } - } - } - } - - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { +#if 0 // TODO figure out why this is even necessary + if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) || + s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) { sig_flags |= SIG_FLAG_TOSERVER; s->flags |= SIG_FLAG_TOSERVER; s->flags &= ~SIG_FLAG_TOCLIENT; } - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { + if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_HTTP) || + s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL || + s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) { sig_flags |= SIG_FLAG_TOCLIENT; s->flags |= SIG_FLAG_TOCLIENT; s->flags &= ~SIG_FLAG_TOSERVER; } +#endif if ((sig_flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) { SCLogError(SC_ERR_INVALID_SIGNATURE,"You seem to have mixed keywords " "that require inspection in both directions. Atm we only " @@ -1150,45 +1413,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { - SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " - "without a flow direction. Use flow:to_server for " - "inspecting request headers or flow:to_client for " - "inspecting response headers."); - SCReturnInt(0); - } - } - - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - for (sm = s->sm_lists[DETECT_SM_LIST_HHHDMATCH]; - sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_NOCASE) { - SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http_host keyword " - "specified along with \"nocase\". " - "Since the hostname buffer we match against " - "is actually lowercase. So having a " - "nocase is redundant."); - } else { - for (u = 0; u < cd->content_len; u++) { - if (isupper(cd->content[u])) - break; - } - if (u != cd->content_len) { - SCLogWarning(SC_ERR_INVALID_SIGNATURE, "A pattern with " - "uppercase chars detected for http_host. " - "Since the hostname buffer we match against " - "is lowercase only, please specify a " - "lowercase pattern."); - SCReturnInt(0); - } - } - } - } - } - //if (s->alproto != ALPROTO_UNKNOWN) { // if (s->flags & SIG_FLAG_STATE_MATCH) { // if (s->alproto == ALPROTO_DNS) { @@ -1228,21 +1452,8 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) //} if (s->flags & SIG_FLAG_REQUIRE_PACKET) { - pm = SigMatchGetLastSMFromLists(s, 24, - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_REPLACE, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); - if (pm != NULL) { + pm = DetectGetLastSMFromLists(s, DETECT_REPLACE, -1); + if (pm != NULL && SigMatchListSMBelongsTo(s, pm) != DETECT_SM_LIST_PMATCH) { SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature has" " replace keyword linked with a modified content" " keyword (http_*, dce_*). It only supports content on" @@ -1250,46 +1461,27 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) SCReturnInt(0); } - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] || - s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]) - { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " - "specific matches (like dsize, flags, ttl) with stream / " - "state matching by matching on app layer proto (like using " - "http_* keywords)."); - SCReturnInt(0); - } - } + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; - for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_AL_APP_LAYER_PROTOCOL) - continue; - if (((DetectAppLayerProtocolData *)sm->ctx)->negated) - break; - } - if (sm != NULL && s->alproto != ALPROTO_UNKNOWN) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "We can't have " - "the rule match on a fixed alproto and at the same time" - "have an app-layer-protocol keyword set."); - SCReturnInt(0); + if (!(DetectBufferTypeSupportsPacketGetById(i))) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet " + "specific matches (like dsize, flags, ttl) with stream / " + "state matching by matching on app layer proto (like using " + "http_* keywords)."); + SCReturnInt(0); + } + } } /* TCP: pkt vs stream vs depth/offset */ if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) { if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) { s->flags |= SIG_FLAG_REQUIRE_STREAM; - sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; while (sm != NULL) { if (sm->type == DETECT_CONTENT && (((DetectContentData *)(sm->ctx))->flags & @@ -1302,15 +1494,38 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } } + if (s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] != NULL) { + int list; + uint16_t idx = s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA]->idx; + for (list = 0; list < nlists; list++) { + if (list == DETECT_SM_LIST_POSTMATCH || + list == DETECT_SM_LIST_TMATCH || + list == DETECT_SM_LIST_SUPPRESS || + list == DETECT_SM_LIST_THRESHOLD) + { + continue; + } + + if (list != DETECT_SM_LIST_BASE64_DATA && + s->init_data->smlists[list] != NULL) { + if (s->init_data->smlists[list]->idx > idx) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Rule buffer " + "cannot be reset after base64_data."); + SCReturnInt(0); + } + } + } + } + #ifdef HAVE_LUA DetectLuaPostSetup(s); #endif #ifdef DEBUG int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { - if (s->sm_lists[i] != NULL) { - for (sm = s->sm_lists[i]; sm != NULL; sm = sm->next) { + for (i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] != NULL) { + for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) { BUG_ON(sm == sm->prev); BUG_ON(sm == sm->next); } @@ -1318,6 +1533,20 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) } #endif + if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0) { + if (s->alproto != ALPROTO_UNKNOWN && + !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) + { + SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL, "protocol %s doesn't " + "support file matching", AppProtoToString(s->alproto)); + SCReturnInt(0); + } + + if (s->alproto == ALPROTO_HTTP) { + AppLayerHtpNeedFileInspection(); + } + } + SCReturnInt(1); } @@ -1328,7 +1557,6 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, uint8_t dir) { - SigMatch *sm; Signature *sig = SigAlloc(); if (sig == NULL) goto error; @@ -1373,155 +1601,32 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (DetectAppLayerEventPrepare(sig) < 0) goto error; - /* set mpm_content_len */ - - /* determine the length of the longest pattern in the sig */ - if (sig->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { - sig->mpm_content_maxlen = 0; - - for (sm = sig->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd == NULL) - continue; - - if (sig->mpm_content_maxlen == 0) - sig->mpm_content_maxlen = cd->content_len; - if (sig->mpm_content_maxlen < cd->content_len) - sig->mpm_content_maxlen = cd->content_len; - } - } - } - if (sig->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - sig->mpm_uricontent_maxlen = 0; - - for (sm = sig->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) { - if (sm->type == DETECT_CONTENT) { - DetectContentData *ud = (DetectContentData *)sm->ctx; - if (ud == NULL) - continue; - - if (sig->mpm_uricontent_maxlen == 0) - sig->mpm_uricontent_maxlen = ud->content_len; - if (sig->mpm_uricontent_maxlen < ud->content_len) - sig->mpm_uricontent_maxlen = ud->content_len; - } - } - } - /* set the packet and app layer flags, but only if the * app layer flag wasn't already set in which case we * only consider the app layer */ if (!(sig->flags & SIG_FLAG_APPLAYER)) { - if (sig->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { - SigMatch *sm = sig->sm_lists[DETECT_SM_LIST_MATCH]; + if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) { + SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ; sm != NULL; sm = sm->next) { if (sigmatch_table[sm->type].Match != NULL) - sig->init_flags |= SIG_FLAG_INIT_PACKET; + sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; } } else { - sig->init_flags |= SIG_FLAG_INIT_PACKET; + sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET; } } - if (sig->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) - sig->flags |= SIG_FLAG_APPLAYER; - - if (sig->sm_lists[DETECT_SM_LIST_UMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_DMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_AMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HCBDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HSBDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HMDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HCDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRUDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_FILEMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HSMDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HSCDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HUADMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HHHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH]) - sig->flags |= SIG_FLAG_STATE_MATCH; - if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT]) - sig->flags |= SIG_FLAG_STATE_MATCH; - - if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { + if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; sig->flags |= SIG_FLAG_TOCLIENT; } SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s", sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set", - sig->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); + sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set"); SigBuildAddressMatchArray(sig); - if (sig->sm_lists[DETECT_SM_LIST_APP_EVENT] != NULL) { - if (AppLayerParserProtocolIsTxEventAware(IPPROTO_TCP, sig->alproto)) { - if (sig->flags & SIG_FLAG_TOSERVER) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - sig->alproto, - 0, - DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); - } - if (sig->flags & SIG_FLAG_TOCLIENT) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_TCP, - sig->alproto, - 1, - DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); - } - } - if (AppLayerParserProtocolIsTxEventAware(IPPROTO_UDP, sig->alproto)) { - if (sig->flags & SIG_FLAG_TOSERVER) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_UDP, - sig->alproto, - 0, - DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); - } - if (sig->flags & SIG_FLAG_TOCLIENT) { - DetectEngineRegisterAppInspectionEngine(IPPROTO_UDP, - sig->alproto, - 1, - DETECT_SM_LIST_APP_EVENT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DE_STATE_FLAG_APP_EVENT_INSPECT, - DetectEngineAptEventInspect, - app_inspection_engine); - } - } - } - /* validate signature, SigValidate will report the error reason */ if (SigValidate(de_ctx, sig) == 0) { goto error; @@ -1533,12 +1638,6 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, if (sig != NULL) { SigFree(sig); } - - if (de_ctx->failure_fatal == 1) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature parsing failed: " - "\"%s\"", sigstr); - exit(EXIT_FAILURE); - } return NULL; } @@ -1563,7 +1662,7 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) goto error; } - if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED); if (sig->next == NULL) { goto error; @@ -1576,13 +1675,6 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) if (sig != NULL) { SigFree(sig); } - - if (de_ctx->failure_fatal == 1) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature parsing failed: " - "\"%s\"", sigstr); - exit(EXIT_FAILURE); - } - /* if something failed, restore the old signum count * since we didn't install it */ de_ctx->signum = oldsignum; @@ -1753,6 +1845,8 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, * and discard the other one */ if (sw->s->rev <= sw_dup->s->rev) { ret = 1; + SCFree(sw); + sw = NULL; goto end; } @@ -1761,7 +1855,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, if (sw_dup->s_prev == NULL) { SigDuplWrapper sw_temp; memset(&sw_temp, 0, sizeof(SigDuplWrapper)); - if (sw_dup->s->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { sw_temp.s = sw_dup->s->next->next; de_ctx->sig_list = sw_dup->s->next->next; SigFree(sw_dup->s->next); @@ -1779,7 +1873,7 @@ static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx, } else { SigDuplWrapper sw_temp; memset(&sw_temp, 0, sizeof(SigDuplWrapper)); - if (sw_dup->s->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { sw_temp.s = sw_dup->s->next->next; sw_dup->s_prev->next = sw_dup->s->next->next; SigFree(sw_dup->s->next); @@ -1849,7 +1943,7 @@ Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, char *sigstr) sigstr); } - if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) { + if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) { if (sig->next != NULL) { sig->next->next = de_ctx->sig_list; } else { @@ -1875,6 +1969,114 @@ Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, char *sigstr) return NULL; } +typedef struct DetectParseRegex_ { + pcre *regex; + pcre_extra *study; + struct DetectParseRegex_ *next; +} DetectParseRegex; + +static DetectParseRegex *g_detect_parse_regex_list = NULL; + +void DetectParseFreeRegexes(void) +{ + DetectParseRegex *r = g_detect_parse_regex_list; + while (r) { + DetectParseRegex *next = r->next; + + if (r->regex) { + pcre_free(r->regex); + } + if (r->study) { + pcre_free_study(r->study); + } + SCFree(r); + r = next; + } + g_detect_parse_regex_list = NULL; +} + +/** \brief add regex and/or study to at exit free list + */ +void DetectParseRegexAddToFreeList(pcre *regex, pcre_extra *study) +{ + DetectParseRegex *r = SCCalloc(1, sizeof(*r)); + if (r == NULL) { + FatalError(SC_ERR_MEM_ALLOC, "failed to alloc memory for pcre free list"); + } + r->regex = regex; + r->study = study; + r->next = g_detect_parse_regex_list; + g_detect_parse_regex_list = r; +} + +void DetectSetupParseRegexes(const char *parse_str, + pcre **parse_regex, + pcre_extra **parse_regex_study) +{ + const char *eb; + int eo; + int opts = 0; + + *parse_regex = pcre_compile(parse_str, opts, &eb, &eo, NULL); + if (*parse_regex == NULL) { + FatalError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " + "offset %" PRId32 ": %s", parse_str, eo, eb); + } + + *parse_regex_study = pcre_study(*parse_regex, 0, &eb); + if (eb != NULL) { + FatalError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + } + + DetectParseRegexAddToFreeList(*parse_regex, *parse_regex_study); + return; +} + +#ifdef AFLFUZZ_RULES +#include "util-reference-config.h" +int RuleParseDataFromFile(char *filename) +{ + char buffer[65536]; + + SigTableSetup(); + SigParsePrepare(); + SCReferenceConfInit(); + SCClassConfInit(); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + return 0; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(10000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + if (result < sizeof(buffer)) { + buffer[result] = '\0'; + Signature *s = SigInit(de_ctx, buffer); + if (s != NULL) { + SigFree(s); + } + } + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + DetectEngineCtxFree(de_ctx); + SCClassConfDeinit(); + SCReferenceConfDeinit(); + return 0; +} +#endif /* AFLFUZZ_RULES */ + /* * TESTS */ @@ -1910,16 +2112,15 @@ int SigParseTest02 (void) if (de_ctx == NULL) goto end; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (sig == NULL) { goto end; } - int r = DetectPortParse(&port, "0:20"); + int r = DetectPortParse(de_ctx, &port, "0:20"); if (r < 0) goto end; @@ -2688,7 +2889,7 @@ int SigTestBidirec01 (void) goto end; if (sig->next != NULL) goto end; - if (sig->init_flags & SIG_FLAG_INIT_BIDIREC) + if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) goto end; if (de_ctx->signum != 1) goto end; @@ -2722,7 +2923,7 @@ int SigTestBidirec02 (void) goto end; if (de_ctx->sig_list != sig) goto end; - if (!(sig->init_flags & SIG_FLAG_INIT_BIDIREC)) + if (!(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; if (sig->next == NULL) goto end; @@ -2731,7 +2932,7 @@ int SigTestBidirec02 (void) copy = sig->next; if (copy->next != NULL) goto end; - if (!(copy->init_flags & SIG_FLAG_INIT_BIDIREC)) + if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; result = 1; @@ -2889,7 +3090,7 @@ int SigTestBidirec04 (void) sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)"); if (sig == NULL) goto end; - if ( !(sig->init_flags & SIG_FLAG_INIT_BIDIREC)) + if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)) goto end; if (sig->next == NULL) goto end; @@ -2990,7 +3191,6 @@ int SigTestBidirec04 (void) with source 192.168.1.1 80, all the sids should match */ SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, MPM_B2G); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */ @@ -3003,7 +3203,6 @@ int SigTestBidirec04 (void) PACKET_RECYCLE(p); } FlowShutdown(); - //PatternMatchDestroy(mpm_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: @@ -3246,21 +3445,11 @@ int SigParseTestMpm01 (void) goto end; } - if (sig->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { printf("sig doesn't have content list: "); goto end; } - if (sig->mpm_content_maxlen != 4) { - printf("mpm content max len %"PRIu16", expected 4: ", sig->mpm_content_maxlen); - goto end; - } - - if (sig->mpm_uricontent_maxlen != 0) { - printf("mpm uricontent max len %"PRIu16", expected 0: ", sig->mpm_uricontent_maxlen); - goto end; - } - result = 1; end: if (sig != NULL) @@ -3287,21 +3476,11 @@ int SigParseTestMpm02 (void) goto end; } - if (sig->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) { printf("sig doesn't have content list: "); goto end; } - if (sig->mpm_content_maxlen != 6) { - printf("mpm content max len %"PRIu16", expected 6: ", sig->mpm_content_maxlen); - goto end; - } - - if (sig->mpm_uricontent_maxlen != 0) { - printf("mpm uricontent max len %"PRIu16", expected 0: ", sig->mpm_uricontent_maxlen); - goto end; - } - result = 1; end: if (sig != NULL) @@ -3406,59 +3585,76 @@ static int SigParseTestAppLayerTLS03(void) return result; } +static int SigParseTestUnblanacedQuotes01(void) +{ + DetectEngineCtx *de_ctx; + Signature *s; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + s = SigInit(de_ctx, "alert http any any -> any any (msg:\"SigParseTestUnblanacedQuotes01\"; pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)"); + FAIL_IF_NOT_NULL(s); + + PASS; +} + #endif /* UNITTESTS */ void SigParseRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SigParseTest01", SigParseTest01, 1); - UtRegisterTest("SigParseTest02", SigParseTest02, 1); - UtRegisterTest("SigParseTest03", SigParseTest03, 1); - UtRegisterTest("SigParseTest04", SigParseTest04, 1); - UtRegisterTest("SigParseTest05", SigParseTest05, 1); - UtRegisterTest("SigParseTest06", SigParseTest06, 1); - UtRegisterTest("SigParseTest07", SigParseTest07, 1); - UtRegisterTest("SigParseTest08", SigParseTest08, 1); - UtRegisterTest("SigParseTest09", SigParseTest09, 1); - UtRegisterTest("SigParseTest10", SigParseTest10, 1); - UtRegisterTest("SigParseTest11", SigParseTest11, 1); - UtRegisterTest("SigParseTest12", SigParseTest12, 1); - UtRegisterTest("SigParseTest13", SigParseTest13, 1); - UtRegisterTest("SigParseTest14", SigParseTest14, 1); - UtRegisterTest("SigParseTest15", SigParseTest15, 1); - UtRegisterTest("SigParseTest16", SigParseTest16, 1); - UtRegisterTest("SigParseTest17", SigParseTest17, 1); - UtRegisterTest("SigParseTest18", SigParseTest18, 1); - UtRegisterTest("SigParseTest19", SigParseTest19, 1); - UtRegisterTest("SigParseTest20", SigParseTest20, 1); - UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21, 1); - UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22, 1); - - UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06, 1); - UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07, 1); - UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08, 1); - UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09, 1); - UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10, 1); - UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11, 1); - UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12, 1); - UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13, 1); - UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14, 1); - UtRegisterTest("SigTestBidirec01", SigTestBidirec01, 1); - UtRegisterTest("SigTestBidirec02", SigTestBidirec02, 1); - UtRegisterTest("SigTestBidirec03", SigTestBidirec03, 1); - UtRegisterTest("SigTestBidirec04", SigTestBidirec04, 1); - UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01, 1); - UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02, 1); - UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03, 1); - UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04, 1); - UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05, 1); - UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06, 1); - UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07, 1); - UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08, 1); - UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01, 1); - UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02, 1); - UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01, 1); - UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02, 1); - UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03, 1); + UtRegisterTest("SigParseTest01", SigParseTest01); + UtRegisterTest("SigParseTest02", SigParseTest02); + UtRegisterTest("SigParseTest03", SigParseTest03); + UtRegisterTest("SigParseTest04", SigParseTest04); + UtRegisterTest("SigParseTest05", SigParseTest05); + UtRegisterTest("SigParseTest06", SigParseTest06); + UtRegisterTest("SigParseTest07", SigParseTest07); + UtRegisterTest("SigParseTest08", SigParseTest08); + UtRegisterTest("SigParseTest09", SigParseTest09); + UtRegisterTest("SigParseTest10", SigParseTest10); + UtRegisterTest("SigParseTest11", SigParseTest11); + UtRegisterTest("SigParseTest12", SigParseTest12); + UtRegisterTest("SigParseTest13", SigParseTest13); + UtRegisterTest("SigParseTest14", SigParseTest14); + UtRegisterTest("SigParseTest15", SigParseTest15); + UtRegisterTest("SigParseTest16", SigParseTest16); + UtRegisterTest("SigParseTest17", SigParseTest17); + UtRegisterTest("SigParseTest18", SigParseTest18); + UtRegisterTest("SigParseTest19", SigParseTest19); + UtRegisterTest("SigParseTest20", SigParseTest20); + UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21); + UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22); + + UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06); + UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07); + UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08); + UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09); + UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10); + UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11); + UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12); + UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13); + UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14); + UtRegisterTest("SigTestBidirec01", SigTestBidirec01); + UtRegisterTest("SigTestBidirec02", SigTestBidirec02); + UtRegisterTest("SigTestBidirec03", SigTestBidirec03); + UtRegisterTest("SigTestBidirec04", SigTestBidirec04); + UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01); + UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02); + UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03); + UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04); + UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05); + UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06); + UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07); + UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08); + UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01); + UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02); + UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01); + UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02); + UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03); + UtRegisterTest("SigParseTestUnblanacedQuotes01", + SigParseTestUnblanacedQuotes01); #endif /* UNITTESTS */ } diff --git a/src/detect-parse.h b/src/detect-parse.h index c90560a916cf..456ef66a03f8 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -45,24 +45,44 @@ Signature *SigAlloc(void); void SigFree(Signature *s); Signature *SigInit(DetectEngineCtx *,char *sigstr); Signature *SigInitReal(DetectEngineCtx *, char *); -SigMatch *SigMatchGetLastSMFromLists(Signature *, int, ...); -void SigMatchTransferSigMatchAcrossLists(SigMatch *sm, - SigMatch **, SigMatch **s, - SigMatch **, SigMatch **); +SigMatchData* SigMatchList2DataArray(SigMatch *head); void SigParsePrepare(void); void SigParseRegisterTests(void); Signature *DetectEngineAppendSig(DetectEngineCtx *, char *); void SigMatchAppendSMToList(Signature *, SigMatch *, int); void SigMatchRemoveSMFromList(Signature *, SigMatch *, int); -int SigMatchListSMBelongsTo(Signature *, SigMatch *); +int SigMatchListSMBelongsTo(const Signature *, const SigMatch *); int DetectParseDupSigHashInit(DetectEngineCtx *); void DetectParseDupSigHashFree(DetectEngineCtx *); -int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg, - uint8_t sm_type, uint8_t sm_list, - AppProto alproto, void (*CustomCallback)(Signature *s)); +int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, + Signature *s, const char *arg, int sm_type, int sm_list, + AppProto alproto); + +const char *DetectListToHumanString(int list); +const char *DetectListToString(int list); + +SigMatch *DetectGetLastSM(const Signature *); +SigMatch *DetectGetLastSMFromMpmLists(const Signature *s); +SigMatch *DetectGetLastSMFromLists(const Signature *s, ...); +SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...); +SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...); + +int DetectSignatureSetAppProto(Signature *s, AppProto alproto); + +/* parse regex setup and free util funcs */ + +void DetectSetupParseRegexes(const char *parse_str, + pcre **parse_regex, + pcre_extra **parse_regex_study); +void DetectParseRegexAddToFreeList(pcre *regex, pcre_extra *study); +void DetectParseFreeRegexes(void); + +#ifdef AFLFUZZ_RULES +int RuleParseDataFromFile(char *filename); +#endif #endif /* __DETECT_PARSE_H__ */ diff --git a/src/detect-pcre.c b/src/detect-pcre.c index d87bc5cb0555..661a254a3e1d 100644 --- a/src/detect-pcre.c +++ b/src/detect-pcre.c @@ -57,11 +57,10 @@ #include "stream-tcp-reassemble.h" #include "app-layer-protos.h" #include "app-layer-parser.h" -#include "app-layer-htp.h" - -#include "stream.h" - +#include "util-pages.h" +/* pcre named substring capture supports only 32byte names, A-z0-9 plus _ + * and needs to start with non-numeric. */ #define PARSE_CAPTURE_REGEX "\\(\\?P\\<([A-z]+)\\_([A-z0-9_]+)\\>" #define PARSE_REGEX "(?ctx; + DetectPcreData *pe = (DetectPcreData *)smd->ctx; if (pe->flags & DETECT_PCRE_RELATIVE) { ptr = payload + det_ctx->buffer_offset; @@ -227,26 +215,50 @@ int DetectPcrePayloadMatch(DetectEngineThreadCtx *det_ctx, Signature *s, /* regex matched and we're not negated, * considering it a match */ - SCLogDebug("ret %d capidx %u", ret, pe->capidx); + SCLogDebug("ret %d pe->idx %u", ret, pe->idx); /* see if we need to do substring capturing. */ - if (ret > 1 && pe->capidx != 0) { - SCLogDebug("capturing"); - const char *str_ptr; - ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr); - if (ret) { - if (pe->flags & DETECT_PCRE_CAPTURE_PKT) { - if (p != NULL) { - PktVarAdd(p, pe->capname, (uint8_t *)str_ptr, ret); - } - } else if (pe->flags & DETECT_PCRE_CAPTURE_FLOW) { - if (f != NULL) { - /* store max 64k. Errors are ignored */ - capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; - (void)DetectFlowvarStoreMatch(det_ctx, pe->capidx, - (uint8_t *)str_ptr, capture_len, - DETECT_FLOWVAR_TYPE_POSTMATCH); + if (ret > 1 && pe->idx != 0) { + uint8_t x; + for (x = 0; x < pe->idx; x++) { + SCLogDebug("capturing %u", x); + const char *str_ptr; + ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+1, &str_ptr); + if (unlikely(ret == 0)) + continue; + + SCLogDebug("data %p/%u, type %u id %u p %p", + str_ptr, ret, pe->captypes[x], pe->capids[x], p); + + if (pe->captypes[x] == VAR_TYPE_PKT_VAR_KV) { + /* get the value, as first capture is the key */ + const char *str_ptr2; + int ret2 = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, x+2, &str_ptr2); + if (unlikely(ret2 == 0)) { + break; } + /* key length is limited to 256 chars */ + uint16_t key_len = (ret < 0xff) ? (uint16_t)ret : 0xff; + capture_len = (ret2 < 0xffff) ? (uint16_t)ret2 : 0xffff; + + (void)DetectVarStoreMatchKeyValue(det_ctx, + (uint8_t *)str_ptr, key_len, + (uint8_t *)str_ptr2, capture_len, + DETECT_VAR_TYPE_PKT_POSTMATCH); + + } else if (pe->captypes[x] == VAR_TYPE_PKT_VAR) { + /* store max 64k. Errors are ignored */ + capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; + (void)DetectVarStoreMatch(det_ctx, pe->capids[x], + (uint8_t *)str_ptr, capture_len, + DETECT_VAR_TYPE_PKT_POSTMATCH); + + } else if (pe->captypes[x] == VAR_TYPE_FLOW_VAR && f != NULL) { + /* store max 64k. Errors are ignored */ + capture_len = (ret < 0xffff) ? (uint16_t)ret : 0xffff; + (void)DetectVarStoreMatch(det_ctx, pe->capids[x], + (uint8_t *)str_ptr, capture_len, + DETECT_VAR_TYPE_FLOW_POSTMATCH); } } } @@ -274,7 +286,28 @@ static int DetectPcreSetList(int list, int set) return set; } -static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int *sm_list) +static int DetectPcreHasUpperCase(const char *re) +{ + size_t len = strlen(re); + int is_meta = 0; + + for (size_t i = 0; i < len; i++) { + if (is_meta) { + is_meta = 0; + } + else if (re[i] == '\\') { + is_meta = 1; + } + else if (isupper((unsigned char)re[i])) { + return 1; + } + } + + return 0; +} + +static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, int *sm_list, + char *capture_names, size_t capture_names_size) { int ec; const char *eb; @@ -285,31 +318,69 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; + int check_host_header = 0; - size_t slen = strlen(regexstr); - char re[slen], op_str[64] = ""; - uint16_t pos = 0; + char op_str[64] = ""; uint8_t negate = 0; - uint16_t re_len = 0; - uint32_t u = 0; - while (pos < slen && isspace((unsigned char)regexstr[pos])) { - pos++; + while (*regexstr != '\0' && isspace((unsigned char)*regexstr)) { + regexstr++; } - if (regexstr[pos] == '!') { + if (*regexstr == '!') { negate = 1; - pos++; + regexstr++; + } + + int cut_capture = 0; + char *fcap = strstr(regexstr, "flow:"); + char *pcap = strstr(regexstr, "pkt:"); + /* take the size of the whole input as buffer size for the regex we will + * extract below. Add 1 to please Coverity's alloc_strlen test. */ + size_t slen = strlen(regexstr) + 1; + if (fcap || pcap) { + SCLogDebug("regexstr %s", regexstr); + + if (fcap && !pcap) + cut_capture = fcap - regexstr; + else if (pcap && !fcap) + cut_capture = pcap - regexstr; + else + cut_capture = MIN((pcap - regexstr), (fcap - regexstr)); + + SCLogDebug("cut_capture %d", cut_capture); + + if (cut_capture > 1) { + int offset = cut_capture - 1; + while (offset) { + SCLogDebug("regexstr[offset] %c", regexstr[offset]); + if (regexstr[offset] == ',' || regexstr[offset] == ' ') { + offset--; + } + else + break; + } + + if (cut_capture == (offset + 1)) { + SCLogDebug("missing separators, assume it's part of the regex"); + } else { + slen = offset + 1; + strlcpy(capture_names, regexstr+cut_capture, capture_names_size); + if (capture_names[strlen(capture_names)-1] == '"') + capture_names[strlen(capture_names)-1] = '\0'; + } + } } - ret = pcre_exec(parse_regex, parse_regex_study, regexstr + pos, slen-pos, + char re[slen]; + ret = pcre_exec(parse_regex, parse_regex_study, regexstr, slen, 0, 0, ov, MAX_SUBSTRINGS); if (ret <= 0) { SCLogError(SC_ERR_PCRE_MATCH, "pcre parse error: %s", regexstr); goto error; } - res = pcre_copy_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS, + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, re, slen); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); @@ -317,7 +388,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, } if (ret > 2) { - res = pcre_copy_substring((char *)regexstr + pos, ov, MAX_SUBSTRINGS, + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, op_str, sizeof(op_str)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); @@ -381,81 +452,107 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, /* buffer selection */ - case 'U': /* snort's option */ + case 'U': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'U' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_UMATCH); + int list = DetectBufferTypeGetByName("http_uri"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'V': + } + case 'V': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'V' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HUADMATCH); + int list = DetectBufferTypeGetByName("http_user_agent"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'W': + } + case 'W': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'W' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HHHDMATCH); + int list = DetectBufferTypeGetByName("http_host"); + *sm_list = DetectPcreSetList(*sm_list, list); + check_host_header = 1; break; - case 'Z': + } + case 'Z': { if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'Z' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRHHDMATCH); + int list = DetectBufferTypeGetByName("http_raw_host"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'H': /* snort's option */ + } + case 'H': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'H' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HHDMATCH); + int list = DetectBufferTypeGetByName("http_header"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'I': /* snort's option */ + } case 'I': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'I' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRUDMATCH); + int list = DetectBufferTypeGetByName("http_raw_uri"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'D': /* snort's option */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HRHDMATCH); + } + case 'D': { /* snort's option */ + int list = DetectBufferTypeGetByName("http_raw_header"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'M': /* snort's option */ + } + case 'M': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'M' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HMDMATCH); + int list = DetectBufferTypeGetByName("http_method"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'C': /* snort's option */ + } + case 'C': { /* snort's option */ if (pd->flags & DETECT_PCRE_RAWBYTES) { SCLogError(SC_ERR_INVALID_SIGNATURE, "regex modifier 'C' inconsistent with 'B'"); goto error; } - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HCDMATCH); + int list = DetectBufferTypeGetByName("http_cookie"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'P': + } + case 'P': { /* snort's option (http request body inspection) */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HCBDMATCH); + int list = DetectBufferTypeGetByName("http_client_body"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'Q': + } + case 'Q': { + int list = DetectBufferTypeGetByName("file_data"); /* suricata extension (http response body inspection) */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSBDMATCH); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'Y': + } + case 'Y': { /* snort's option */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSMDMATCH); + int list = DetectBufferTypeGetByName("http_stat_msg"); + *sm_list = DetectPcreSetList(*sm_list, list); break; - case 'S': + } + case 'S': { /* snort's option */ - *sm_list = DetectPcreSetList(*sm_list, DETECT_SM_LIST_HSCDMATCH); + int list = DetectBufferTypeGetByName("http_stat_code"); + *sm_list = DetectPcreSetList(*sm_list, list); break; + } default: SCLogError(SC_ERR_UNKNOWN_REGEX_MOD, "unknown regex modifier '%c'", *op); goto error; @@ -469,25 +566,21 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, SCLogDebug("DetectPcreParse: \"%s\"", re); /* host header */ - if (*sm_list == DETECT_SM_LIST_HHHDMATCH) { + if (check_host_header) { if (pd->flags & DETECT_PCRE_CASELESS) { SCLogWarning(SC_ERR_INVALID_SIGNATURE, "http host pcre(\"W\") " "specified along with \"i(caseless)\" modifier. " "Since the hostname buffer we match against " "is actually lowercase, having a " "nocase is redundant."); - } else { - re_len = strlen(re); - for (u = 0; u < re_len; u++) { - if (isupper((unsigned char)re[u])) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre host(\"W\") " - "specified has an uppercase char. " - "Since the hostname buffer we match against " - "is actually lowercase, please specify an " - "all lowercase based pcre."); - goto error; - } - } + } + else if (DetectPcreHasUpperCase(re)) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre host(\"W\") " + "specified has an uppercase char. " + "Since the hostname buffer we match against " + "is actually lowercase, please specify an " + "all lowercase based pcre."); + goto error; } } @@ -496,22 +589,33 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, * If we fail because a capture group is later referenced (e.g., \1), * PCRE will let us know. */ - pd->re = pcre_compile2(re, opts | PCRE_NO_AUTO_CAPTURE, &ec, &eb, &eo, NULL); + if (capture_names == NULL || strlen(capture_names) == 0) + opts |= PCRE_NO_AUTO_CAPTURE; + + pd->re = pcre_compile2(re, opts, &ec, &eb, &eo, NULL); if (pd->re == NULL && ec == 15) { // reference to non-existent subpattern + opts &= ~PCRE_NO_AUTO_CAPTURE; pd->re = pcre_compile(re, opts, &eb, &eo, NULL); } - if(pd->re == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", regexstr, eo, eb); + if (pd->re == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed " + "at offset %" PRId32 ": %s", regexstr, eo, eb); goto error; } + + int options = 0; #ifdef PCRE_HAVE_JIT - pd->sd = pcre_study(pd->re, PCRE_STUDY_JIT_COMPILE, &eb); + if (pcre_use_jit) + options |= PCRE_STUDY_JIT_COMPILE; +#endif + pd->sd = pcre_study(pd->re, options, &eb); if(eb != NULL) { SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); goto error; } +#ifdef PCRE_HAVE_JIT int jit = 0; ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_JIT, &jit); if (ret != 0 || jit != 1) { @@ -522,12 +626,6 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, "Falling back to regular PCRE handling (%s:%d)", regexstr, de_ctx->rule_file, de_ctx->rule_line); } -#else - pd->sd = pcre_study(pd->re, 0, &eb); - if(eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed : %s", eb); - goto error; - } #endif /*PCRE_HAVE_JIT*/ if (pd->sd == NULL) @@ -563,7 +661,7 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, if (pd != NULL && pd->re != NULL) pcre_free(pd->re); if (pd != NULL && pd->sd != NULL) - pcre_free(pd->sd); + pcre_free_study(pd->sd); if (pd) SCFree(pd); return NULL; @@ -572,67 +670,135 @@ static DetectPcreData *DetectPcreParse (DetectEngineCtx *de_ctx, char *regexstr, /** \internal * \brief check if we need to extract capture settings and set them up if needed */ -static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd) +static int DetectPcreParseCapture(char *regexstr, DetectEngineCtx *de_ctx, DetectPcreData *pd, + char *capture_names) { int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; + memset(&ov, 0, sizeof(ov)); char type_str[16] = ""; - size_t cap_buffer_len = strlen(regexstr); + char *orig_right_edge = regexstr + strlen(regexstr); + char *name_array[DETECT_PCRE_CAPTURE_MAX] = { NULL }; + int name_idx = 0; + int capture_cnt = 0; + int key = 0; + + SCLogDebug("regexstr %s, pd %p", regexstr, pd); + + ret = pcre_fullinfo(pd->re, pd->sd, PCRE_INFO_CAPTURECOUNT, &capture_cnt); + SCLogDebug("ret %d capture_cnt %d", ret, capture_cnt); + if (ret == 0 && capture_cnt && strlen(capture_names) > 0) + { + char *ptr = NULL; + while ((name_array[name_idx] = strtok_r(name_idx == 0 ? capture_names : NULL, " ,", &ptr))){ + if (name_idx > capture_cnt) { + SCLogError(SC_ERR_VAR_LIMIT, "more pkt/flow " + "var capture names than capturing substrings"); + return -1; + } + SCLogDebug("name '%s'", name_array[name_idx]); + + if (strcmp(name_array[name_idx], "pkt:key") == 0) { + key = 1; + SCLogDebug("key-value/key"); + + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR_KV; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + + } else if (key == 1 && strcmp(name_array[name_idx], "pkt:value") == 0) { + SCLogDebug("key-value/value"); + key = 0; + + /* kv error conditions */ + } else if (key == 0 && strcmp(name_array[name_idx], "pkt:value") == 0) { + return -1; + } else if (key == 1) { + return -1; + + } else if (strncmp(name_array[name_idx], "flow:", 5) == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+5, VAR_TYPE_FLOW_VAR); + pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; + pd->idx++; + + } else if (strncmp(name_array[name_idx], "pkt:", 4) == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd(name_array[name_idx]+4, VAR_TYPE_PKT_VAR); + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + + } else { + SCLogError(SC_ERR_VAR_LIMIT, " pkt/flow " + "var capture names must start with 'pkt:' or 'flow:'"); + return -1; + } + + name_idx++; + if (name_idx >= DETECT_PCRE_CAPTURE_MAX) + break; + } + } + + /* take the size of the whole input as buffer size for the string we will + * extract below. Add 1 to please Coverity's alloc_strlen test. */ + size_t cap_buffer_len = strlen(regexstr) + 1; char capture_str[cap_buffer_len]; memset(capture_str, 0x00, cap_buffer_len); if (de_ctx == NULL) goto error; - SCLogDebug("\'%s\'", regexstr); + while (1) { + SCLogDebug("\'%s\'", regexstr); - ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 3) { - return 0; - } + ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 3) { + return 0; + } - res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str)); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; - } - res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len); - if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); - goto error; - } - if (strlen(capture_str) == 0 || strlen(type_str) == 0) { - goto error; - } + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, type_str, sizeof(type_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + res = pcre_copy_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, capture_str, cap_buffer_len); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + if (strlen(capture_str) == 0 || strlen(type_str) == 0) { + goto error; + } - SCLogDebug("type \'%s\'", type_str); - SCLogDebug("capture \'%s\'", capture_str); + SCLogDebug("type \'%s\'", type_str); + SCLogDebug("capture \'%s\'", capture_str); - pd->capname = SCStrdup(capture_str); - if (unlikely(pd->capname == NULL)) - goto error; + if (pd->idx >= DETECT_PCRE_CAPTURE_MAX) { + SCLogError(SC_ERR_VAR_LIMIT, "rule can have maximally %d pkt/flow " + "var captures", DETECT_PCRE_CAPTURE_MAX); + return -1; + } - if (strcmp(type_str, "pkt") == 0) { - pd->flags |= DETECT_PCRE_CAPTURE_PKT; - } else if (strcmp(type_str, "flow") == 0) { - pd->flags |= DETECT_PCRE_CAPTURE_FLOW; - SCLogDebug("flow capture"); - } - if (pd->capname != NULL) { - if (pd->flags & DETECT_PCRE_CAPTURE_PKT) - pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, DETECT_PKTVAR); - else if (pd->flags & DETECT_PCRE_CAPTURE_FLOW) - pd->capidx = VariableNameGetIdx(de_ctx, (char *)pd->capname, DETECT_FLOWVAR); - } + if (strcmp(type_str, "pkt") == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_PKT_VAR); + pd->captypes[pd->idx] = VAR_TYPE_PKT_VAR; + SCLogDebug("id %u type %u", pd->capids[pd->idx], pd->captypes[pd->idx]); + pd->idx++; + } else if (strcmp(type_str, "flow") == 0) { + pd->capids[pd->idx] = VarNameStoreSetupAdd((char *)capture_str, VAR_TYPE_FLOW_VAR); + pd->captypes[pd->idx] = VAR_TYPE_FLOW_VAR; + pd->idx++; + } + + //SCLogNotice("pd->capname %s", pd->capname); + regexstr += ov[1]; - SCLogDebug("pd->capname %s", pd->capname); + if (regexstr >= orig_right_edge) + break; + } return 0; error: - if (pd->capname != NULL) { - SCFree(pd->capname); - pd->capname = NULL; - } return -1; } @@ -643,88 +809,26 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SigMatch *sm = NULL; int ret = -1; int parsed_sm_list = DETECT_SM_LIST_NOTSET; + char capture_names[1024] = ""; - pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list); + pd = DetectPcreParse(de_ctx, regexstr, &parsed_sm_list, capture_names, sizeof(capture_names)); if (pd == NULL) goto error; - if (DetectPcreParseCapture(regexstr, de_ctx, pd) < 0) + if (DetectPcreParseCapture(regexstr, de_ctx, pd, capture_names) < 0) goto error; - if (parsed_sm_list == DETECT_SM_LIST_UMATCH || - parsed_sm_list == DETECT_SM_LIST_HRUDMATCH || - parsed_sm_list == DETECT_SM_LIST_HCBDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSBDMATCH || - parsed_sm_list == DETECT_SM_LIST_HHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HRHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSMDMATCH || - parsed_sm_list == DETECT_SM_LIST_HSCDMATCH || - parsed_sm_list == DETECT_SM_LIST_HHHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HRHHDMATCH || - parsed_sm_list == DETECT_SM_LIST_HMDMATCH || - parsed_sm_list == DETECT_SM_LIST_HCDMATCH || - parsed_sm_list == DETECT_SM_LIST_HUADMATCH) - { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Invalid option. " - "Conflicting alprotos detected for this rule. Http " - "pcre modifier found along with a different protocol " - "for the rule."); - goto error; - } - if (s->list != DETECT_SM_LIST_NOTSET) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre found with http " - "modifier set, with file_data/dce_stub_data sticky " - "option set."); - goto error; - } - } - int sm_list = -1; - if (s->list != DETECT_SM_LIST_NOTSET) { - if (s->list == DETECT_SM_LIST_HSBDMATCH) { - SCLogDebug("adding to http server body list because of file data"); - AppLayerHtpEnableResponseBodyCallback(); - } else if (s->list == DETECT_SM_LIST_DMATCH) { - SCLogDebug("adding to dmatch list because of dce_stub_data"); - } else if (s->list == DETECT_SM_LIST_DNSQUERY_MATCH) { - SCLogDebug("adding to DETECT_SM_LIST_DNSQUERY_MATCH list because of dns_query"); - } + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { s->flags |= SIG_FLAG_APPLAYER; - sm_list = s->list; + sm_list = s->init_data->list; } else { switch(parsed_sm_list) { - case DETECT_SM_LIST_HCBDMATCH: - AppLayerHtpEnableRequestBodyCallback(); - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - sm_list = parsed_sm_list; - break; - - case DETECT_SM_LIST_HSBDMATCH: - AppLayerHtpEnableResponseBodyCallback(); - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - sm_list = parsed_sm_list; - break; - - case DETECT_SM_LIST_UMATCH: - case DETECT_SM_LIST_HRUDMATCH: - case DETECT_SM_LIST_HHDMATCH: - case DETECT_SM_LIST_HRHDMATCH: - case DETECT_SM_LIST_HHHDMATCH: - case DETECT_SM_LIST_HRHHDMATCH: - case DETECT_SM_LIST_HSMDMATCH: - case DETECT_SM_LIST_HSCDMATCH: - case DETECT_SM_LIST_HCDMATCH: - case DETECT_SM_LIST_HMDMATCH: - case DETECT_SM_LIST_HUADMATCH: - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; - sm_list = parsed_sm_list; - break; case DETECT_SM_LIST_NOTSET: sm_list = DETECT_SM_LIST_PMATCH; break; + default: + sm_list = parsed_sm_list; + break; } } if (sm_list == -1) @@ -737,15 +841,20 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst sm->ctx = (void *)pd; SigMatchAppendSMToList(s, sm, sm_list); + uint8_t x; + for (x = 0; x < pd->idx; x++) { + if (DetectFlowvarPostMatchSetup(s, pd->capids[x]) < 0) + goto error_nofree; + } + if (!(pd->flags & DETECT_PCRE_RELATIVE)) goto okay; /* errors below shouldn't free pd */ - SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, sm->prev, - DETECT_PCRE, sm->prev); - if (s->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, sm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); + if (s->init_data->list == DETECT_SM_LIST_NOTSET && prev_pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "pcre with /R (relative) needs " "preceeding match in the same buffer"); goto error_nofree; @@ -760,11 +869,6 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst tmp->flags |= DETECT_PCRE_RELATIVE_NEXT; } - if (pd->capidx != 0) { - if (DetectFlowvarPostMatchSetup(s, pd->capidx) < 0) - goto error_nofree; - } - okay: ret = 0; SCReturnInt(ret); @@ -774,25 +878,26 @@ static int DetectPcreSetup (DetectEngineCtx *de_ctx, Signature *s, char *regexst SCReturnInt(ret); } -void DetectPcreFree(void *ptr) +static void DetectPcreFree(void *ptr) { if (ptr == NULL) return; DetectPcreData *pd = (DetectPcreData *)ptr; - if (pd->capname != NULL) - SCFree(pd->capname); if (pd->re != NULL) pcre_free(pd->re); if (pd->sd != NULL) - pcre_free(pd->sd); + pcre_free_study(pd->sd); SCFree(pd); return; } #ifdef UNITTESTS /* UNITTESTS */ +static int g_file_data_buffer_id = 0; +static int g_http_header_buffer_id = 0; +static int g_dce_stub_data_buffer_id = 0; /** * \test DetectPcreParseTest01 make sure we don't allow invalid opts 7. @@ -804,15 +909,10 @@ static int DetectPcreParseTest01 (void) char *teststring = "/blah/7"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd != NULL) { - printf("expected NULL: got %p", pd); - result = 0; - DetectPcreFree(pd); - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NOT_NULL(pd); DetectEngineCtxFree(de_ctx); return result; @@ -828,15 +928,11 @@ static int DetectPcreParseTest02 (void) char *teststring = "/blah/Ui$"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); + + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NOT_NULL(pd); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd != NULL) { - printf("expected NULL: got %p", pd); - result = 0; - DetectPcreFree(pd); - } DetectEngineCtxFree(de_ctx); return result; } @@ -851,15 +947,11 @@ static int DetectPcreParseTest03 (void) char *teststring = "/blah/UNi"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); + + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NOT_NULL(pd); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd != NULL) { - printf("expected NULL: got %p", pd); - result = 0; - DetectPcreFree(pd); - } DetectEngineCtxFree(de_ctx); return result; } @@ -874,14 +966,10 @@ static int DetectPcreParseTest04 (void) char *teststring = "/b\\\"lah/i"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -898,14 +986,10 @@ static int DetectPcreParseTest05 (void) char *teststring = "/b(l|a)h/"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -922,14 +1006,10 @@ static int DetectPcreParseTest06 (void) char *teststring = "/b(l|a)h/smi"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -946,14 +1026,10 @@ static int DetectPcreParseTest07 (void) char *teststring = "/blah/Ui"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -970,14 +1046,10 @@ static int DetectPcreParseTest08 (void) char *teststring = "/b(l|a)h/O"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); @@ -990,23 +1062,18 @@ static int DetectPcreParseTest08 (void) */ static int DetectPcreParseTest09 (void) { - int result = 1; DetectPcreData *pd = NULL; char *teststring = "/lala\\\\/"; int list = DETECT_SM_LIST_NOTSET; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return 0; + FAIL_IF_NULL(de_ctx); - pd = DetectPcreParse(de_ctx, teststring, &list); - if (pd == NULL) { - printf("expected %p: got NULL", pd); - result = 0; - } + pd = DetectPcreParse(de_ctx, teststring, &list, NULL, 0); + FAIL_IF_NULL(pd); DetectPcreFree(pd); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1015,30 +1082,27 @@ static int DetectPcreParseTest09 (void) int DetectPcreParseTest10(void) { Signature *s = SigAlloc(); - int result = 1; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result = 0; - goto end; - } + FAIL_IF_NULL(de_ctx); s->alproto = ALPROTO_DCERPC; - result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); + FAIL_IF_NOT(s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); SigFree(s); s = SigAlloc(); + FAIL_IF_NULL(s); + /* failure since we have no preceding content/pcre/bytejump */ - result &= (DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); - result &= (s->sm_lists[DETECT_SM_LIST_DMATCH] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); + FAIL_IF_NOT(DetectPcreSetup(de_ctx, s, "/bamboo/") == 0); + FAIL_IF_NOT(s->sm_lists[g_dce_stub_data_buffer_id] == NULL && s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL); - end: SigFree(s); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1047,13 +1111,11 @@ int DetectPcreParseTest10(void) int DetectPcreParseTest11(void) { DetectEngineCtx *de_ctx = NULL; - int result = 1; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " @@ -1061,86 +1123,52 @@ int DetectPcreParseTest11(void) "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); + data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/R; sid:1;)"); - if (s->next == NULL) { - result = 0; - goto end; - } + FAIL_IF_NULL(s->next); s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); + data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "dce_iface:3919286a-b10c-11d0-9ba8-00c04fd92ef5; " "dce_stub_data; " "pcre:/bamboo/RB; sid:1;)"); - if (s->next == NULL) { - result = 0; - goto end; - } + FAIL_IF(s->next == NULL); s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] == NULL) { - result = 0; - goto end; - } - result &= (s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->type == DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_DMATCH]->ctx; - if (!(data->flags & DETECT_PCRE_RAWBYTES) || - !(data->flags & DETECT_PCRE_RELATIVE)) { - result = 0; - goto end; - } + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] == NULL); + FAIL_IF_NOT(s->sm_lists_tail[g_dce_stub_data_buffer_id]->type == DETECT_PCRE); + data = (DetectPcreData *)s->sm_lists_tail[g_dce_stub_data_buffer_id]->ctx; + FAIL_IF(!(data->flags & DETECT_PCRE_RAWBYTES) || + !(data->flags & DETECT_PCRE_RELATIVE)); s->next = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing bytejump_body\"; " "content:\"one\"; pcre:/bamboo/; sid:1;)"); - if (s->next == NULL) { - result = 0; - goto end; - } + FAIL_IF(s->next == NULL); s = s->next; - if (s->sm_lists_tail[DETECT_SM_LIST_DMATCH] != NULL) { - result = 0; - goto end; - } + FAIL_IF(s->sm_lists_tail[g_dce_stub_data_buffer_id] != NULL); - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1150,47 +1178,31 @@ int DetectPcreParseTest11(void) static int DetectPcreParseTest12(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/abc/R; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF (de_ctx->sig_list == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("empty server body list: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { - printf("last sm not pcre: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - printf("flags not right: "); - goto end; - } + data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); - result = 1; - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1199,47 +1211,31 @@ static int DetectPcreParseTest12(void) static int DetectPcreParseTest13(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; content:\"abc\"; pcre:/def/R; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("empty server body list: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { - printf("last sm not pcre: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - !(data->flags & DETECT_PCRE_RELATIVE)) { - printf("flags not right: "); - goto end; - } + data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + !(data->flags & DETECT_PCRE_RELATIVE)); - result = 1; - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1248,57 +1244,39 @@ static int DetectPcreParseTest13(void) static int DetectPcreParseTest14(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Signature *s = NULL; DetectPcreData *data = NULL; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(file_data; pcre:/def/; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); s = de_ctx->sig_list; - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH] == NULL) { - printf("empty server body list: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id] == NULL); - if (s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->type != DETECT_PCRE) { - printf("last sm not pcre: "); - goto end; - } + FAIL_IF(s->sm_lists_tail[g_file_data_buffer_id]->type != DETECT_PCRE); - data = (DetectPcreData *)s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH]->ctx; - if (data->flags & DETECT_PCRE_RAWBYTES || - data->flags & DETECT_PCRE_RELATIVE) { - printf("flags not right: "); - goto end; - } + data = (DetectPcreData *)s->sm_lists_tail[g_file_data_buffer_id]->ctx; + FAIL_IF(data->flags & DETECT_PCRE_RAWBYTES || + data->flags & DETECT_PCRE_RELATIVE); - result = 1; - end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative method */ int DetectPcreParseTest15(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1306,19 +1284,13 @@ int DetectPcreParseTest15(void) "(msg:\"Testing pcre relative http_method\"; " "content:\"GET\"; " "http_method; pcre:\"/abc/RM\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } @@ -1326,10 +1298,8 @@ int DetectPcreParseTest15(void) int DetectPcreParseTest16(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1337,29 +1307,21 @@ int DetectPcreParseTest16(void) "(msg:\"Testing pcre relative http_cookie\"; " "content:\"test\"; " "http_cookie; pcre:\"/abc/RC\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative raw header */ int DetectPcreParseTest17(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1367,29 +1329,21 @@ int DetectPcreParseTest17(void) "(msg:\"Testing pcre relative http_raw_header\"; " "flow:to_server; content:\"test\"; " "http_raw_header; pcre:\"/abc/RD\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative header */ int DetectPcreParseTest18(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1397,29 +1351,21 @@ int DetectPcreParseTest18(void) "(msg:\"Testing pcre relative http_header\"; " "content:\"test\"; " "http_header; pcre:\"/abc/RH\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative client-body */ int DetectPcreParseTest19(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1427,29 +1373,21 @@ int DetectPcreParseTest19(void) "(msg:\"Testing pcre relativie http_client_body\"; " "content:\"test\"; " "http_client_body; pcre:\"/abc/RP\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative raw uri */ int DetectPcreParseTest20(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1457,29 +1395,21 @@ int DetectPcreParseTest20(void) "(msg:\"Testing http_raw_uri\"; " "content:\"test\"; " "http_raw_uri; pcre:\"/abc/RI\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative uricontent */ int DetectPcreParseTest21(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1487,29 +1417,21 @@ int DetectPcreParseTest21(void) "(msg:\"Testing pcre relative uricontent\"; " "uricontent:\"test\"; " "pcre:\"/abc/RU\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with pcre relative http_uri */ int DetectPcreParseTest22(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1517,29 +1439,21 @@ int DetectPcreParseTest22(void) "(msg:\"Testing pcre relative http_uri\"; " "content:\"test\"; " "http_uri; pcre:\"/abc/RU\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); - if (de_ctx->sig_list != NULL) { - result = 1; - } else { - printf("sig parse failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre relative */ int DetectPcreParseTest23(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -1547,137 +1461,99 @@ int DetectPcreParseTest23(void) "(msg:\"Testing inconsistent pcre relative\"; " "content:\"GET\"; " "http_cookie; pcre:\"/abc/RM\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse shouldn't have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest24(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/UI\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre modifiers */ int DetectPcreParseTest25(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/DH\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Check a signature with inconsistent pcre modifiers */ static int DetectPcreParseTest26(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " "(msg:\"Testing inconsistent pcre modifiers\"; " "pcre:\"/abc/F\"; sid:1;)"); + FAIL_IF_NOT_NULL(de_ctx->sig_list); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test Bug 1098 */ static int DetectPcreParseTest27(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; - if ( (de_ctx = DetectEngineCtxInit()) == NULL) - goto end; + FAIL_IF( (de_ctx = DetectEngineCtxInit()) == NULL); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any 80 " "(content:\"baduricontent\"; http_raw_uri; " "pcre:\"/^[a-z]{5}\\.html/R\"; sid:2; rev:2;)"); + FAIL_IF_NOT(de_ctx->sig_list == NULL); - if (de_ctx->sig_list == NULL) { - result = 1; - } else { - printf("sig parse should have failed: "); - } - - end: if (de_ctx != NULL) SigCleanSignatures(de_ctx); if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + PASS; } -static int DetectPcreTestSig01Real(int mpm_type) +static int DetectPcreTestSig01(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1691,7 +1567,6 @@ static int DetectPcreTestSig01Real(int mpm_type) Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; Flow f; AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -1714,37 +1589,24 @@ static int DetectPcreTestSig01Real(int mpm_type) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/^gEt/i\"; pcre:\"/\\/two\\//U\"; pcre:\"/GET \\/two\\//\"; pcre:\"/\\s+HTTP/R\"; sid:1;)"); + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, buf, buflen); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) == 1) { - result = 1; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1) == 1); -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); @@ -1758,22 +1620,10 @@ static int DetectPcreTestSig01Real(int mpm_type) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; -} -static int DetectPcreTestSig01B2g (void) -{ - return DetectPcreTestSig01Real(MPM_B2G); -} -static int DetectPcreTestSig01B3g (void) -{ - return DetectPcreTestSig01Real(MPM_B3G); -} -static int DetectPcreTestSig01Wm (void) -{ - return DetectPcreTestSig01Real(MPM_WUMANBER); + PASS; } -static int DetectPcreTestSig02Real(int mpm_type) +static int DetectPcreTestSig02(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1787,7 +1637,6 @@ static int DetectPcreTestSig02Real(int mpm_type) Flow f; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(&f, 0, sizeof(f)); @@ -1802,26 +1651,18 @@ static int DetectPcreTestSig02Real(int mpm_type) pcre_match_limit_recursion = 100; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; pcre:\"/two/O\"; sid:2;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 2) == 1) { - result = 1; - } + FAIL_IF_NOT(PacketAlertCheck(p, 2) == 1); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -1829,27 +1670,15 @@ static int DetectPcreTestSig02Real(int mpm_type) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FLOW_DESTROY(&f); -end: + UTHFreePackets(&p, 1); - return result; -} -static int DetectPcreTestSig02B2g (void) -{ - return DetectPcreTestSig02Real(MPM_B2G); -} -static int DetectPcreTestSig02B3g (void) -{ - return DetectPcreTestSig02Real(MPM_B3G); -} -static int DetectPcreTestSig02Wm (void) -{ - return DetectPcreTestSig02Real(MPM_WUMANBER); + PASS; } /** * \test DetectPcreTestSig03Real negation test ! outside of "" this sig should not match */ -static int DetectPcreTestSig03Real(int mpm_type) +static int DetectPcreTestSig03(void) { uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" @@ -1862,56 +1691,32 @@ static int DetectPcreTestSig03Real(int mpm_type) Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 1; memset(&th_v, 0, sizeof(th_v)); p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx == NULL); - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"GET\"; pcre:!\"/two/\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)){ - printf("sid 1 matched even though it shouldn't have:"); - result = 0; - } + FAIL_IF(PacketAlertCheck(p, 1)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: - UTHFreePackets(&p, 1); - return result; -} -static int DetectPcreTestSig03B2g (void) -{ - return DetectPcreTestSig03Real(MPM_B2G); -} -static int DetectPcreTestSig03B3g (void) -{ - return DetectPcreTestSig03Real(MPM_B3G); -} -static int DetectPcreTestSig03Wm (void) -{ - return DetectPcreTestSig03Real(MPM_WUMANBER); + UTHFreePackets(&p, 1); + PASS; } /** @@ -1919,7 +1724,6 @@ static int DetectPcreTestSig03Wm (void) */ static int DetectPcreModifPTest04(void) { - int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" @@ -1975,59 +1779,37 @@ static int DetectPcreModifPTest04(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOCTYPE/P\"; " "sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF(s == NULL); s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/blah/P\"; sid:2;)"); - if (s->next == NULL) { - goto end; - } + FAIL_IF(s->next == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sid 1 didn't match but should have: "); - goto end; - } - if (PacketAlertCheck(p, 2)) { - printf("sid 2 matched but shouldn't: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); + FAIL_IF(PacketAlertCheck(p, 2)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); @@ -2037,7 +1819,7 @@ static int DetectPcreModifPTest04(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; } /** @@ -2046,7 +1828,6 @@ static int DetectPcreModifPTest04(void) */ static int DetectPcreModifPTest05(void) { - int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" @@ -2110,85 +1891,51 @@ static int DetectPcreModifPTest05(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"Pcre modifier P\"; pcre:\"/DOC/P\"; " "sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF(s == NULL); s->next = SigInit(de_ctx,"alert http any any -> any any (msg:\"" "Pcre modifier P (no match)\"; pcre:\"/DOCTYPE/P\"; sid:2;)"); - if (s->next == NULL) { - goto end; - } + FAIL_IF(s->next == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(http_state == NULL); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 didn't match on p1 but should have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p1, 1)); - if (PacketAlertCheck(p1, 2)) { - printf("sid 2 did match on p1 but shouldn't have: "); - /* It's a partial match over 2 chunks*/ - goto end; - } + FAIL_IF(PacketAlertCheck(p1, 2)); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect for p2 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 1))) { - printf("sid 1 did match on p2 but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p2, 1))); - if (!(PacketAlertCheck(p2, 2))) { - printf("sid 2 didn't match on p2 but should have: "); - /* It's a partial match over 2 chunks*/ - goto end; - } + FAIL_IF(!(PacketAlertCheck(p2, 2))); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) SigGroupCleanup(de_ctx); @@ -2199,7 +1946,7 @@ static int DetectPcreModifPTest05(void) FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); - return result; + PASS; } int DetectPcreTestSig06() @@ -2229,18 +1976,13 @@ int DetectPcreTestSig07() "lalala\n"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; - if (UTHPacketMatchSig(p, sig) == 0) { - result = 0; - goto end; - } - result = 1; -end: + FAIL_IF(UTHPacketMatchSig(p, sig) == 0); + if (p != NULL) UTHFreePacket(p); - return result; + PASS; } /** \test anchored pcre */ @@ -2251,18 +1993,13 @@ int DetectPcreTestSig08() "lalala"; uint16_t buflen = strlen((char *)buf); Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - int result = 0; char sig[] = "alert tcp any any -> any any (msg:\"pcre with an ending slash\"; pcre:\"/^(la)+$/\"; sid:1;)"; - if (UTHPacketMatchSig(p, sig) == 0) { - result = 0; - goto end; - } - result = 1; -end: + FAIL_IF(UTHPacketMatchSig(p, sig) == 0); + if (p != NULL) UTHFreePacket(p); - return result; + PASS; } /** \test Check the signature working to alert when cookie modifier is @@ -2270,7 +2007,6 @@ int DetectPcreTestSig08() */ static int DetectPcreTestSig09(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; @@ -2304,48 +2040,32 @@ static int DetectPcreTestSig09(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:\"/dummy/C\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2358,7 +2078,7 @@ static int DetectPcreTestSig09(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when cookie modifier is @@ -2366,7 +2086,6 @@ static int DetectPcreTestSig09(void) */ static int DetectPcreTestSig10(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; @@ -2400,48 +2119,32 @@ static int DetectPcreTestSig10(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP cookie\"; pcre:!\"/dummy/C\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 should match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2454,7 +2157,7 @@ static int DetectPcreTestSig10(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when method modifier is @@ -2462,7 +2165,6 @@ static int DetectPcreTestSig10(void) */ static int DetectPcreTestSig11(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; @@ -2496,48 +2198,32 @@ static int DetectPcreTestSig11(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:\"/POST/M\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2550,7 +2236,7 @@ static int DetectPcreTestSig11(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when method modifier is @@ -2558,7 +2244,6 @@ static int DetectPcreTestSig11(void) */ static int DetectPcreTestSig12(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; @@ -2592,48 +2277,32 @@ static int DetectPcreTestSig12(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP method\"; pcre:!\"/POST/M\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 should match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2646,7 +2315,7 @@ static int DetectPcreTestSig12(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when header modifier is @@ -2654,7 +2323,6 @@ static int DetectPcreTestSig12(void) */ static int DetectPcreTestSig13(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy\r\n\r\n"; @@ -2688,48 +2356,32 @@ static int DetectPcreTestSig13(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:\"/User[-_]Agent[:]?\\sMozilla/H\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2742,7 +2394,7 @@ static int DetectPcreTestSig13(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when header modifier is @@ -2750,7 +2402,6 @@ static int DetectPcreTestSig13(void) */ static int DetectPcreTestSig14(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "GET / HTTP/1.0\r\nUser-Agent: IEXPLORER/1.0\r\n" "Cookie: dummoOOooooO\r\n\r\n"; @@ -2784,48 +2435,32 @@ static int DetectPcreTestSig14(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" "\"HTTP header\"; pcre:!\"/User-Agent[:]?\\s+Mozilla/H\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 should match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2838,7 +2473,7 @@ static int DetectPcreTestSig14(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when cookie and relative modifiers are @@ -2846,7 +2481,6 @@ static int DetectPcreTestSig14(void) */ static int DetectPcreTestSig15(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; @@ -2880,9 +2514,7 @@ static int DetectPcreTestSig15(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; @@ -2890,39 +2522,25 @@ static int DetectPcreTestSig15(void) "\"pcre relative HTTP cookie\"; content:\"dummy\";" " http_cookie; pcre:\"/1234/RC\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -2935,7 +2553,7 @@ static int DetectPcreTestSig15(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Check the signature working to alert when method and relative modifiers are @@ -2943,7 +2561,6 @@ static int DetectPcreTestSig15(void) */ static int DetectPcreTestSig16(void) { - int result = 0; Flow f; uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Mozilla/1.0\r\n" "Cookie: dummy 1234\r\n\r\n"; @@ -2977,9 +2594,7 @@ static int DetectPcreTestSig16(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; @@ -2987,39 +2602,25 @@ static int DetectPcreTestSig16(void) "\"pcre relative HTTP method\"; content:\"PO\";" " http_method; pcre:\"/ST/RM\"; " " sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - printf("sig 1 failed to match: "); - goto end; - } + FAIL_IF(!PacketAlertCheck(p, 1)); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -3032,14 +2633,13 @@ static int DetectPcreTestSig16(void) StreamTcpFreeConfig(TRUE); UTHFreePackets(&p, 1); - return result; + PASS; } /** \test Test tracking of body chunks per transactions (on requests) */ static int DetectPcreTxBodyChunksTest01(void) { - int result = 0; Flow f; TcpSession ssn; Packet *p = NULL; @@ -3079,115 +2679,75 @@ static int DetectPcreTxBodyChunksTest01(void) AppLayerHtpEnableRequestBodyCallback(); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START, httpbuf1, + httplen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); + FAIL_IF(r != 0); /* Now we should have 2 transactions, each with it's own list * of request body chunks (let's test it) */ HtpState *htp_state = f.alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(htp_state == NULL); /* hardcoded check of the transactions and it's client body chunks */ - if (AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2) { - printf("The http app layer doesn't have 2 transactions, but it should: "); - goto end; - } + FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 1); HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); - if (htud == NULL) { - printf("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud == NULL); HtpBodyChunk *cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); - - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } /** \test test pcre P modifier with multiple pipelined http transactions */ static int DetectPcreTxBodyChunksTest02(void) { - int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; @@ -3230,160 +2790,102 @@ static int DetectPcreTxBodyChunksTest02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); - if (s == NULL) { - printf("sig2 parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (2): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("signature matched, but shouldn't have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (5): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { - printf("sig 1 alerted (request 2, chunk 6): "); - goto end; - } + FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 2))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; HtpState *htp_state = f.alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(htp_state == NULL); /* hardcoded check of the transactions and it's client body chunks */ - if (AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2) { - printf("The http app layer doesn't have 2 transactions, but it should: "); - goto end; - } + FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); htp_tx_t *t1 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 0); htp_tx_t *t2 = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, 1); @@ -3391,31 +2893,17 @@ static int DetectPcreTxBodyChunksTest02(void) HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(t1); HtpBodyChunk *cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body one!!", 10) != 1); htud = (HtpTxUserData *) htp_tx_get_user_data(t2); cur = htud->request_body.first; - if (htud->request_body.first == NULL) { - SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): "); - goto end; - } + FAIL_IF(htud->request_body.first == NULL); - if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) { - SCLogDebug("Body data in t1 is not correctly set: "); - goto end; - } + FAIL_IF(StreamingBufferSegmentCompareRawData(htud->request_body.sb, &cur->sbseg, (uint8_t *)"Body two!!", 10) != 1); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -3429,13 +2917,12 @@ static int DetectPcreTxBodyChunksTest02(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } /** \test multiple http transactions and body chunks of request handling */ static int DetectPcreTxBodyChunksTest03(void) { - int result = 0; Signature *s = NULL; DetectEngineThreadCtx *det_ctx = NULL; ThreadVars th_v; @@ -3478,162 +2965,102 @@ static int DetectPcreTxBodyChunksTest03(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)"); - if (s == NULL) { - printf("sig2 parse failed: "); - goto end; - } + FAIL_IF(s == NULL); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (2): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf3, httplen3); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("signature matched, but shouldn't have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf4, httplen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 1))); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5); - if (r != 0) { - printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf5, httplen5); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) { - printf("sig 1 alerted (5): "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); p->alerts.cnt = 0; - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6); - if (r != 0) { - printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf6, httplen6); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) { - printf("sig 1 alerted (request 2, chunk 6): "); - goto end; - } + FAIL_IF((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))); p->alerts.cnt = 0; SCLogDebug("sending data chunk 7"); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7); - if (r != 0) { - printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf7, httplen7); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 2))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p, 2))); p->alerts.cnt = 0; HtpState *htp_state = f.alstate; - if (htp_state == NULL) { - printf("no http state: "); - result = 0; - goto end; - } + FAIL_IF(htp_state == NULL); - if (AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2) { - printf("The http app layer doesn't have 2 transactions, but it should: "); - goto end; - } + FAIL_IF(AppLayerParserGetTxCnt(IPPROTO_TCP, ALPROTO_HTTP, htp_state) != 2); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (det_ctx != NULL) { @@ -3647,7 +3074,7 @@ static int DetectPcreTxBodyChunksTest03(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePacket(p); - return result; + PASS; } /** @@ -3655,7 +3082,6 @@ static int DetectPcreTxBodyChunksTest03(void) */ static int DetectPcreFlowvarCapture01(void) { - int result = 0; uint8_t uabuf1[] = "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.0.13) Gecko/2009080315 Ubuntu/8.10 (intrepid) Firefox/3.0.13"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ @@ -3700,71 +3126,47 @@ static int DetectPcreFlowvarCapture01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } - DetectPcreData *pd = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match on p1 but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p1, 1))); - FlowVar *fv = FlowVarGet(&f, pd->capidx); - if (fv == NULL) { - printf("no flowvar: "); - goto end; - } + FlowVar *fv = FlowVarGet(&f, pd->capids[0]); + FAIL_IF(fv == NULL); - if (fv->data.fv_str.value_len != ualen1) { - printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); - goto end; - } + FAIL_IF(fv->data.fv_str.value_len != ualen1); if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); - goto end; + FAIL; } - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -3773,7 +3175,7 @@ static int DetectPcreFlowvarCapture01(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); - return result; + PASS; } /** @@ -3781,7 +3183,6 @@ static int DetectPcreFlowvarCapture01(void) */ static int DetectPcreFlowvarCapture02(void) { - int result = 0; uint8_t uabuf1[] = "Apache"; uint32_t ualen1 = sizeof(uabuf1) - 1; /* minus the \0 */ @@ -3826,41 +3227,26 @@ static int DetectPcreFlowvarCapture02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:1; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } - DetectPcreData *pd1 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; priority:3; sid:2;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } - DetectPcreData *pd2 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; - if (pd1->capidx != pd2->capidx) { - printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); - goto end; - } + FAIL_IF(pd1->capids[0] != pd2->capids[0]); SCSigRegisterSignatureOrderingFuncs(de_ctx); SCSigOrderSignatures(de_ctx); @@ -3868,40 +3254,28 @@ static int DetectPcreFlowvarCapture02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match on p1 but should have: "); - goto end; - } + FAIL_IF(!(PacketAlertCheck(p1, 1))); - FlowVar *fv = FlowVarGet(&f, pd1->capidx); - if (fv == NULL) { - printf("no flowvar: "); - goto end; - } + FlowVar *fv = FlowVarGet(&f, pd1->capids[0]); + FAIL_IF(fv == NULL); if (fv->data.fv_str.value_len != ualen1) { PrintRawDataFp(stdout, fv->data.fv_str.value, fv->data.fv_str.value_len); PrintRawDataFp(stdout, uabuf1, ualen1); printf("%u != %u: ", fv->data.fv_str.value_len, ualen1); - goto end; + FAIL; } if (memcmp(fv->data.fv_str.value, uabuf1, ualen1) != 0) { @@ -3909,11 +3283,9 @@ static int DetectPcreFlowvarCapture02(void) PrintRawDataFp(stdout, uabuf1, ualen1); printf("buffer mismatch: "); - goto end; + FAIL; } - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -3922,7 +3294,7 @@ static int DetectPcreFlowvarCapture02(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); - return result; + PASS; } /** @@ -3930,7 +3302,6 @@ static int DetectPcreFlowvarCapture02(void) */ static int DetectPcreFlowvarCapture03(void) { - int result = 0; uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n" "Host: www.emergingthreats.net\r\n" @@ -3972,76 +3343,47 @@ static int DetectPcreFlowvarCapture03(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF(de_ctx == NULL); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"User-Agent: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:1; sid:1;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } - DetectPcreData *pd1 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd1 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any (content:\"Server: \"; http_header; pcre:\"/(?P.*)\\r\\n/HR\"; content:\"xyz\"; http_header; priority:3; sid:2;)"); - if (s == NULL) { - printf("sig parse failed: "); - goto end; - } + FAIL_IF(s == NULL); - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next == NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->type != DETECT_PCRE) { - goto end; - } - DetectPcreData *pd2 = s->sm_lists[DETECT_SM_LIST_HHDMATCH]->next->ctx; + FAIL_IF(s->sm_lists[g_http_header_buffer_id] == NULL || + s->sm_lists[g_http_header_buffer_id]->next == NULL || + s->sm_lists[g_http_header_buffer_id]->next->type != DETECT_PCRE); + DetectPcreData *pd2 = (DetectPcreData *)s->sm_lists[g_http_header_buffer_id]->next->ctx; - if (pd1->capidx != pd2->capidx) { - printf("capidx mismatch, %u != %u: ", pd1->capidx, pd2->capidx); - goto end; - } + FAIL_IF(pd1->capids[0] != pd2->capids[0]); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); HtpState *http_state = f.alstate; - if (http_state == NULL) { - printf("no http state: "); - goto end; - } + FAIL_IF(http_state == NULL); /* do detect for p1 */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 matched on p1 but shouldn't have: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p1, 1)); - FlowVar *fv = FlowVarGet(&f, pd1->capidx); - if (fv != NULL) { - printf("flowvar, shouldn't have one: "); - goto end; - } + FlowVar *fv = FlowVarGet(&f, pd1->capids[0]); + FAIL_IF(fv != NULL); - result = 1; -end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); if (de_ctx != NULL) @@ -4050,7 +3392,71 @@ static int DetectPcreFlowvarCapture03(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p1, 1); - return result; + PASS; +} + +/** + * \brief Test parsing of pcre's with the W modifier set. + */ +static int DetectPcreParseHttpHost(void) +{ + DetectPcreData *pd = NULL; + int list = DETECT_SM_LIST_NOTSET; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + + FAIL_IF(de_ctx == NULL); + + pd = DetectPcreParse(de_ctx, "/domain\\.com/W", &list, NULL, 0); + FAIL_IF(pd == NULL); + DetectPcreFree(pd); + + list = DETECT_SM_LIST_NOTSET; + pd = DetectPcreParse(de_ctx, "/dOmain\\.com/W", &list, NULL, 0); + FAIL_IF(pd != NULL); + + /* Uppercase meta characters are valid. */ + list = DETECT_SM_LIST_NOTSET; + pd = DetectPcreParse(de_ctx, "/domain\\D+\\.com/W", &list, NULL, 0); + FAIL_IF(pd == NULL); + DetectPcreFree(pd); + + /* This should not parse as the first \ escapes the second \, then + * we have a D. */ + list = DETECT_SM_LIST_NOTSET; + pd = DetectPcreParse(de_ctx, "/\\\\Ddomain\\.com/W", &list, NULL, 0); + FAIL_IF(pd != NULL); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \brief Test parsing of capture extension + */ +static int DetectPcreParseCaptureTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF(de_ctx == NULL); + + Signature *s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/(.*)\\r\\n/HR, flow:somecapture\"; content:\"xyz\"; http_header; sid:1;)"); + FAIL_IF(s == NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/(flow:.*)\\r\\n/HR\"; content:\"xyz\"; http_header; sid:2;)"); + FAIL_IF(s == NULL); + s = DetectEngineAppendSig(de_ctx, "alert http any any -> any any " + "(content:\"Server: \"; http_header; pcre:\"/([a-z]+)([0-9]+)\\r\\n/HR, flow:somecapture, pkt:anothercap\"; content:\"xyz\"; http_header; sid:3;)"); + FAIL_IF(s == NULL); + + SigGroupBuild(de_ctx); + + uint32_t capid = VarNameStoreLookupByName("somecapture", VAR_TYPE_FLOW_VAR); + FAIL_IF (capid != 1); + capid = VarNameStoreLookupByName("anothercap", VAR_TYPE_PKT_VAR); + FAIL_IF (capid != 2); + + DetectEngineCtxFree(de_ctx); + PASS; } #endif /* UNITTESTS */ @@ -4058,68 +3464,88 @@ static int DetectPcreFlowvarCapture03(void) /** * \brief this function registers unit tests for DetectPcre */ -void DetectPcreRegisterTests(void) +static void DetectPcreRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01, 1); - UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02, 1); - UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03, 1); - UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04, 1); - UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05, 1); - UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06, 1); - UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07, 1); - UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08, 1); - UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09, 1); - UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10, 1); - UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11, 1); - UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12, 1); - UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13, 1); - UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14, 1); - UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15, 1); - UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16, 1); - UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17, 1); - UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18, 1); - UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19, 1); - UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20, 1); - UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21, 1); - UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22, 1); - UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23, 1); - UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24, 1); - UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25, 1); - UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26, 1); - UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27, 1); - - UtRegisterTest("DetectPcreTestSig01B2g -- pcre test", DetectPcreTestSig01B2g, 1); - UtRegisterTest("DetectPcreTestSig01B3g -- pcre test", DetectPcreTestSig01B3g, 1); - UtRegisterTest("DetectPcreTestSig01Wm -- pcre test", DetectPcreTestSig01Wm, 1); - UtRegisterTest("DetectPcreTestSig02B2g -- pcre test", DetectPcreTestSig02B2g, 1); - UtRegisterTest("DetectPcreTestSig02B3g -- pcre test", DetectPcreTestSig02B3g, 1); - UtRegisterTest("DetectPcreTestSig02Wm -- pcre test", DetectPcreTestSig02Wm, 1); - UtRegisterTest("DetectPcreTestSig03B2g -- negated pcre test", DetectPcreTestSig03B2g, 1); - UtRegisterTest("DetectPcreTestSig03B3g -- negated pcre test", DetectPcreTestSig03B3g, 1); - UtRegisterTest("DetectPcreTestSig03Wm -- negated pcre test", DetectPcreTestSig03Wm, 1); - - UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", DetectPcreModifPTest04, 1); - UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", DetectPcreModifPTest05, 1); - UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06, 1); - UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", DetectPcreTestSig07, 1); - UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", DetectPcreTestSig08, 1); - UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", DetectPcreTestSig09, 1); - UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", DetectPcreTestSig10, 1); - UtRegisterTest("DetectPcreTestSig11 -- Method modifier", DetectPcreTestSig11, 1); - UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12, 1); - UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13, 1); - UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14, 1); - UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", DetectPcreTestSig15, 1); - UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", DetectPcreTestSig16, 1); - - UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01, 1); - UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02, 1); - UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03, 1); - - UtRegisterTest("DetectPcreFlowvarCapture01 -- capture for http_header", DetectPcreFlowvarCapture01, 1); - UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", DetectPcreFlowvarCapture02, 1); - UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", DetectPcreFlowvarCapture03, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + g_http_header_buffer_id = DetectBufferTypeGetByName("http_header"); + g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); + + UtRegisterTest("DetectPcreParseTest01", DetectPcreParseTest01); + UtRegisterTest("DetectPcreParseTest02", DetectPcreParseTest02); + UtRegisterTest("DetectPcreParseTest03", DetectPcreParseTest03); + UtRegisterTest("DetectPcreParseTest04", DetectPcreParseTest04); + UtRegisterTest("DetectPcreParseTest05", DetectPcreParseTest05); + UtRegisterTest("DetectPcreParseTest06", DetectPcreParseTest06); + UtRegisterTest("DetectPcreParseTest07", DetectPcreParseTest07); + UtRegisterTest("DetectPcreParseTest08", DetectPcreParseTest08); + UtRegisterTest("DetectPcreParseTest09", DetectPcreParseTest09); + UtRegisterTest("DetectPcreParseTest10", DetectPcreParseTest10); + UtRegisterTest("DetectPcreParseTest11", DetectPcreParseTest11); + UtRegisterTest("DetectPcreParseTest12", DetectPcreParseTest12); + UtRegisterTest("DetectPcreParseTest13", DetectPcreParseTest13); + UtRegisterTest("DetectPcreParseTest14", DetectPcreParseTest14); + UtRegisterTest("DetectPcreParseTest15", DetectPcreParseTest15); + UtRegisterTest("DetectPcreParseTest16", DetectPcreParseTest16); + UtRegisterTest("DetectPcreParseTest17", DetectPcreParseTest17); + UtRegisterTest("DetectPcreParseTest18", DetectPcreParseTest18); + UtRegisterTest("DetectPcreParseTest19", DetectPcreParseTest19); + UtRegisterTest("DetectPcreParseTest20", DetectPcreParseTest20); + UtRegisterTest("DetectPcreParseTest21", DetectPcreParseTest21); + UtRegisterTest("DetectPcreParseTest22", DetectPcreParseTest22); + UtRegisterTest("DetectPcreParseTest23", DetectPcreParseTest23); + UtRegisterTest("DetectPcreParseTest24", DetectPcreParseTest24); + UtRegisterTest("DetectPcreParseTest25", DetectPcreParseTest25); + UtRegisterTest("DetectPcreParseTest26", DetectPcreParseTest26); + UtRegisterTest("DetectPcreParseTest27", DetectPcreParseTest27); + + UtRegisterTest("DetectPcreTestSig01 -- pcre test", DetectPcreTestSig01); + UtRegisterTest("DetectPcreTestSig02 -- pcre test", DetectPcreTestSig02); + UtRegisterTest("DetectPcreTestSig03 -- negated pcre test", + DetectPcreTestSig03); + + UtRegisterTest("DetectPcreModifPTest04 -- Modifier P", + DetectPcreModifPTest04); + UtRegisterTest("DetectPcreModifPTest05 -- Modifier P fragmented", + DetectPcreModifPTest05); + UtRegisterTest("DetectPcreTestSig06", DetectPcreTestSig06); + UtRegisterTest("DetectPcreTestSig07 -- anchored pcre", + DetectPcreTestSig07); + UtRegisterTest("DetectPcreTestSig08 -- anchored pcre", + DetectPcreTestSig08); + UtRegisterTest("DetectPcreTestSig09 -- Cookie modifier", + DetectPcreTestSig09); + UtRegisterTest("DetectPcreTestSig10 -- negated Cookie modifier", + DetectPcreTestSig10); + UtRegisterTest("DetectPcreTestSig11 -- Method modifier", + DetectPcreTestSig11); + UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", + DetectPcreTestSig12); + UtRegisterTest("DetectPcreTestSig13 -- Header modifier", + DetectPcreTestSig13); + UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", + DetectPcreTestSig14); + UtRegisterTest("DetectPcreTestSig15 -- relative Cookie modifier", + DetectPcreTestSig15); + UtRegisterTest("DetectPcreTestSig16 -- relative Method modifier", + DetectPcreTestSig16); + + UtRegisterTest("DetectPcreTxBodyChunksTest01", + DetectPcreTxBodyChunksTest01); + UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", + DetectPcreTxBodyChunksTest02); + UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", + DetectPcreTxBodyChunksTest03); + + UtRegisterTest("DetectPcreFlowvarCapture01 -- capture for http_header", + DetectPcreFlowvarCapture01); + UtRegisterTest("DetectPcreFlowvarCapture02 -- capture for http_header", + DetectPcreFlowvarCapture02); + UtRegisterTest("DetectPcreFlowvarCapture03 -- capture for http_header", + DetectPcreFlowvarCapture03); + + UtRegisterTest("DetectPcreParseHttpHost", DetectPcreParseHttpHost); + UtRegisterTest("DetectPcreParseCaptureTest", DetectPcreParseCaptureTest); #endif /* UNITTESTS */ } diff --git a/src/detect-pcre.h b/src/detect-pcre.h index e0098cb1c024..14360c1eefeb 100644 --- a/src/detect-pcre.h +++ b/src/detect-pcre.h @@ -27,24 +27,30 @@ #define DETECT_PCRE_RELATIVE 0x00001 #define DETECT_PCRE_RAWBYTES 0x00002 #define DETECT_PCRE_CASELESS 0x00004 -#define DETECT_PCRE_CAPTURE_PKT 0x00008 -#define DETECT_PCRE_CAPTURE_FLOW 0x00010 + #define DETECT_PCRE_MATCH_LIMIT 0x00020 #define DETECT_PCRE_RELATIVE_NEXT 0x00040 #define DETECT_PCRE_NEGATE 0x00080 +#define DETECT_PCRE_CAPTURE_MAX 8 + typedef struct DetectPcreData_ { /* pcre options */ pcre *re; pcre_extra *sd; int opts; uint16_t flags; - uint16_t capidx; - char *capname; + uint8_t idx; + uint8_t captypes[DETECT_PCRE_CAPTURE_MAX]; + uint32_t capids[DETECT_PCRE_CAPTURE_MAX]; } DetectPcreData; /* prototypes */ -int DetectPcrePayloadMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, Flow *, uint8_t *, uint32_t); + +int DetectPcrePayloadMatch(DetectEngineThreadCtx *, + const Signature *, const SigMatchData *, + Packet *, Flow *, uint8_t *, uint32_t); + int DetectPcrePacketPayloadMatch(DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); int DetectPcrePayloadDoMatch(DetectEngineThreadCtx *, Signature *, SigMatch *, Packet *, uint8_t *, uint16_t); diff --git a/src/detect-pkt-data.c b/src/detect-pkt-data.c index 332ac4ccdce6..4bdc3b331541 100644 --- a/src/detect-pkt-data.c +++ b/src/detect-pkt-data.c @@ -53,8 +53,6 @@ void DetectPktDataRegister(void) { sigmatch_table[DETECT_PKT_DATA].name = "pkt_data"; sigmatch_table[DETECT_PKT_DATA].Match = NULL; - sigmatch_table[DETECT_PKT_DATA].AppLayerMatch = NULL; - sigmatch_table[DETECT_PKT_DATA].alproto = ALPROTO_HTTP; sigmatch_table[DETECT_PKT_DATA].Setup = DetectPktDataSetup; sigmatch_table[DETECT_PKT_DATA].Free = NULL; sigmatch_table[DETECT_PKT_DATA].RegisterTests = DetectPktDataTestRegister; @@ -75,7 +73,7 @@ void DetectPktDataRegister(void) static int DetectPktDataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) { SCEnter(); - s->list = DETECT_SM_LIST_NOTSET; + s->init_data->list = DETECT_SM_LIST_NOTSET; return 0; } @@ -83,6 +81,7 @@ static int DetectPktDataSetup (DetectEngineCtx *de_ctx, Signature *s, char *str) #ifdef UNITTESTS /************************************Unittests*********************************/ +static int g_file_data_buffer_id = 0; static int DetectPktDataTest01(void) { @@ -106,9 +105,9 @@ static int DetectPktDataTest01(void) } /* sm should be in the MATCH list */ - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_HSBDMATCH]; + sm = de_ctx->sig_list->sm_lists[g_file_data_buffer_id]; if (sm == NULL) { - printf("sm not in DETECT_SM_LIST_HSBDMATCH: "); + printf("sm not in g_file_data_buffer_id: "); goto end; } @@ -128,7 +127,7 @@ static int DetectPktDataTest01(void) } - if (sig->list != DETECT_SM_LIST_NOTSET) { + if (sig->init_data->list != DETECT_SM_LIST_NOTSET) { printf("sticky buffer set: "); goto end; } @@ -146,7 +145,9 @@ static int DetectPktDataTest01(void) static void DetectPktDataTestRegister(void) { #ifdef UNITTESTS - UtRegisterTest("DetectPktDataTest01", DetectPktDataTest01, 1); + g_file_data_buffer_id = DetectBufferTypeGetByName("file_data"); + + UtRegisterTest("DetectPktDataTest01", DetectPktDataTest01); #endif } diff --git a/src/detect-pktvar.c b/src/detect-pktvar.c index 813c20ed3005..7a720839d7bf 100644 --- a/src/detect-pktvar.c +++ b/src/detect-pktvar.c @@ -39,7 +39,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectPktvarMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectPktvarSetup (DetectEngineCtx *, Signature *, char *); void DetectPktvarRegister (void) @@ -50,30 +51,7 @@ void DetectPktvarRegister (void) sigmatch_table[DETECT_PKTVAR].Free = NULL; sigmatch_table[DETECT_PKTVAR].RegisterTests = NULL; - sigmatch_table[DETECT_PKTVAR].flags |= SIGMATCH_PAYLOAD; - - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /* @@ -82,12 +60,13 @@ void DetectPktvarRegister (void) * -1: error */ -int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectPktvarMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; - DetectPktvarData *pd = (DetectPktvarData *)m->ctx; + const DetectPktvarData *pd = (const DetectPktvarData *)ctx; - PktVar *pv = PktVarGet(p, pd->name); + PktVar *pv = PktVarGet(p, pd->id); if (pv != NULL) { uint8_t *ptr = SpmSearch(pv->value, pv->value_len, pd->content, pd->content_len); if (ptr != NULL) @@ -113,7 +92,6 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst if (ret != 3) { SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for pktvar.", rawstr); return -1; - } const char *str_ptr; @@ -211,6 +189,8 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst len = x; } + /* coverity[alloc_strlen : FALSE] + * not an actual string, but a byte array */ cd->content = SCMalloc(len); if (cd->content == NULL) { SCFree(cd); @@ -218,12 +198,7 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst return -1; } - cd->name = SCStrdup(varname); - if (cd->name == NULL) { - SCFree(cd); - if (dubbed) SCFree(str); - return -1; - } + cd->id = VarNameStoreSetupAdd(varname, VAR_TYPE_PKT_VAR); memcpy(cd->content, str, len); cd->content_len = len; @@ -236,7 +211,7 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst goto error; sm->type = DETECT_PKTVAR; - sm->ctx = (void *)cd; + sm->ctx = (SigMatchCtx *)cd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -247,8 +222,6 @@ static int DetectPktvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawst if (dubbed) SCFree(str); if (cd) { - if (cd->name) - SCFree(cd->name); SCFree(cd); } if (sm) diff --git a/src/detect-pktvar.h b/src/detect-pktvar.h index e5d1d3a6a116..e6e5211dd6ea 100644 --- a/src/detect-pktvar.h +++ b/src/detect-pktvar.h @@ -25,10 +25,10 @@ #define __DETECT_PKTVAR_H__ typedef struct DetectPktvarData_ { - char *name; - uint8_t *content; + uint32_t id; uint8_t content_len; uint8_t flags; + uint8_t *content; } DetectPktvarData; /* prototypes */ diff --git a/src/detect-prefilter.c b/src/detect-prefilter.c new file mode 100644 index 000000000000..fe50e39ac0ee --- /dev/null +++ b/src/detect-prefilter.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements the prefilter keyword + */ + +#include "suricata-common.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-content.h" + +#include "util-debug.h" + +static int DetectPrefilterSetup (DetectEngineCtx *, Signature *, char *); + +void DetectPrefilterRegister(void) +{ + sigmatch_table[DETECT_PREFILTER].name = "prefilter"; + sigmatch_table[DETECT_PREFILTER].desc = "force a condition to be used as prefilter"; + sigmatch_table[DETECT_PREFILTER].Match = NULL; + sigmatch_table[DETECT_PREFILTER].Setup = DetectPrefilterSetup; + sigmatch_table[DETECT_PREFILTER].Free = NULL; + sigmatch_table[DETECT_PREFILTER].RegisterTests = NULL; + + sigmatch_table[DETECT_PREFILTER].flags |= SIGMATCH_NOOPT; +} + +/** + * \internal + * \brief Apply the prefilter keyword to the last match + * \param det_ctx detection engine ctx + * \param s signature + * \param nullstr should be null + * \retval 0 ok + * \retval -1 failure + */ +static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) +{ + SCEnter(); + + SigMatch *sm = NULL; + int ret = -1; + + if (nullstr != NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "prefilter has value"); + goto end; + } + + if (s->flags & SIG_FLAG_PREFILTER) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter already set"); + goto end; + } + + sm = DetectGetLastSM(s); + if (sm == NULL) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter needs preceding match"); + goto end; + } + + s->init_data->prefilter_sm = sm; + s->flags |= SIG_FLAG_PREFILTER; + + /* if the sig match is content, prefilter should act like + * 'fast_pattern' w/o options. */ + if (sm->type == DETECT_CONTENT) { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if ((cd->flags & DETECT_CONTENT_NEGATED) && + ((cd->flags & DETECT_CONTENT_DISTANCE) || + (cd->flags & DETECT_CONTENT_WITHIN) || + (cd->flags & DETECT_CONTENT_OFFSET) || + (cd->flags & DETECT_CONTENT_DEPTH))) + { + SCLogError(SC_ERR_INVALID_SIGNATURE, "prefilter; cannot be " + "used with negated content, along with relative modifiers"); + goto end; + } + cd->flags |= DETECT_CONTENT_FAST_PATTERN; + } + + ret = 0; + end: + SCReturnInt(ret); +} diff --git a/src/detect-prefilter.h b/src/detect-prefilter.h new file mode 100644 index 000000000000..afc64db43f8f --- /dev/null +++ b/src/detect-prefilter.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_PREFILTER_H__ +#define __DETECT_PREFILTER_H__ + +/* prototypes */ +void DetectPrefilterRegister (void); + +#endif /* __DETECT_PREFILTER_H__ */ diff --git a/src/detect-priority.c b/src/detect-priority.c index 6db84b28b949..e4b10740ecae 100644 --- a/src/detect-priority.c +++ b/src/detect-priority.c @@ -33,7 +33,7 @@ #include "util-debug.h" #include "util-unittest.h" -#define DETECT_PRIORITY_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$" +#define PARSE_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -46,38 +46,20 @@ void SCPriorityRegisterTests(void); */ void DetectPriorityRegister (void) { - const char *eb = NULL; - int eo; - int opts = 0; - sigmatch_table[DETECT_PRIORITY].name = "priority"; sigmatch_table[DETECT_PRIORITY].desc = "rules with a higher priority will be examined first"; - sigmatch_table[DETECT_PRIORITY].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Priority"; + sigmatch_table[DETECT_PRIORITY].url = DOC_URL DOC_VERSION "/rules/meta.html#priority"; sigmatch_table[DETECT_PRIORITY].Match = NULL; sigmatch_table[DETECT_PRIORITY].Setup = DetectPrioritySetup; sigmatch_table[DETECT_PRIORITY].Free = NULL; sigmatch_table[DETECT_PRIORITY].RegisterTests = SCPriorityRegisterTests; - regex = pcre_compile(DETECT_PRIORITY_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_PRIORITY_REGEX, eo, eb); - goto end; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto end; - } - - end: - return; + DetectSetupParseRegexes(PARSE_REGEX, ®ex, ®ex_study); } static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) { - const char *prio_str = NULL; + char copy_str[128] = ""; #define MAX_SUBSTRINGS 30 int ret = 0; @@ -90,26 +72,24 @@ static int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, char *raw return -1; } - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &prio_str); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, copy_str, sizeof(copy_str)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); return -1; } long prio = 0; char *endptr = NULL; - prio = strtol(rawstr, &endptr, 10); + prio = strtol(copy_str, &endptr, 10); if (endptr == NULL || *endptr != '\0') { SCLogError(SC_ERR_INVALID_SIGNATURE, "Saw an invalid character as arg " "to priority keyword"); - goto error; + return -1; } /* if we have reached here, we have had a valid priority. Assign it */ s->prio = prio; return 0; - error: - return -1; } /*------------------------------Unittests-------------------------------------*/ @@ -215,8 +195,8 @@ void SCPriorityRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("DetectPriorityTest01", DetectPriorityTest01, 1); - UtRegisterTest("DetectPriorityTest02", DetectPriorityTest02, 1); + UtRegisterTest("DetectPriorityTest01", DetectPriorityTest01); + UtRegisterTest("DetectPriorityTest02", DetectPriorityTest02); #endif /* UNITTESTS */ diff --git a/src/detect-rawbytes.c b/src/detect-rawbytes.c index 872a71a07216..52c53b7f6a1a 100644 --- a/src/detect-rawbytes.c +++ b/src/detect-rawbytes.c @@ -48,7 +48,6 @@ void DetectRawbytesRegister (void) sigmatch_table[DETECT_RAWBYTES].RegisterTests = NULL; sigmatch_table[DETECT_RAWBYTES].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_RAWBYTES].flags |= SIGMATCH_PAYLOAD; } static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr) @@ -60,13 +59,13 @@ static int DetectRawbytesSetup (DetectEngineCtx *de_ctx, Signature *s, char *nul return -1; } - if (s->list != DETECT_SM_LIST_NOTSET) { + if (s->init_data->list != DETECT_SM_LIST_NOTSET) { SCLogError(SC_ERR_RAWBYTES_FILE_DATA, "\"rawbytes\" cannot be combined with \"file_data\""); SCReturnInt(-1); } - SigMatch *pm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + SigMatch *pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, + DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_RAWBYTES_MISSING_CONTENT, "\"rawbytes\" needs a preceding content option"); SCReturnInt(-1); diff --git a/src/detect-reference.c b/src/detect-reference.c index 55d33d2f6d5c..d1a82dfed55b 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -57,33 +57,13 @@ void DetectReferenceRegister(void) { sigmatch_table[DETECT_REFERENCE].name = "reference"; sigmatch_table[DETECT_REFERENCE].desc = "direct to places where information about the rule can be found"; - sigmatch_table[DETECT_REFERENCE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Reference"; + sigmatch_table[DETECT_REFERENCE].url = DOC_URL DOC_VERSION "/rules/meta.html#reference"; sigmatch_table[DETECT_REFERENCE].Match = NULL; sigmatch_table[DETECT_REFERENCE].Setup = DetectReferenceSetup; sigmatch_table[DETECT_REFERENCE].Free = NULL; sigmatch_table[DETECT_REFERENCE].RegisterTests = ReferenceRegisterTests; - const char *eb; - int opts = 0; - int eo; - - opts |= PCRE_CASELESS; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -242,9 +222,8 @@ static int DetectReferenceParseTest01(void) } de_ctx->flags |= DE_QUIET; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"One reference\"; reference:one,001-2010; sid:2;)"); @@ -289,9 +268,8 @@ static int DetectReferenceParseTest02(void) } de_ctx->flags |= DE_QUIET; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"Two references\"; " @@ -344,9 +322,8 @@ static int DetectReferenceParseTest03(void) } de_ctx->flags |= DE_QUIET; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd =SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " "(msg:\"invalid ref\"; " @@ -370,9 +347,9 @@ static int DetectReferenceParseTest03(void) void ReferenceRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectReferenceParseTest01", DetectReferenceParseTest01, 1); - UtRegisterTest("DetectReferenceParseTest02", DetectReferenceParseTest02, 1); - UtRegisterTest("DetectReferenceParseTest03", DetectReferenceParseTest03, 1); + UtRegisterTest("DetectReferenceParseTest01", DetectReferenceParseTest01); + UtRegisterTest("DetectReferenceParseTest02", DetectReferenceParseTest02); + UtRegisterTest("DetectReferenceParseTest03", DetectReferenceParseTest03); #endif /* UNITTESTS */ return; diff --git a/src/detect-replace.c b/src/detect-replace.c index 6031c31184f6..17f056150588 100644 --- a/src/detect-replace.c +++ b/src/detect-replace.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2013 Open Information Security Foundation +/* Copyright (C) 2011-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -59,7 +59,7 @@ extern int run_mode; #include "host.h" #include "util-profiling.h" -static int DetectReplaceSetup (DetectEngineCtx *, Signature *, char *); +static int DetectReplaceSetup(DetectEngineCtx *, Signature *, char *); void DetectReplaceRegisterTests(void); void DetectReplaceRegister (void) @@ -69,8 +69,6 @@ void DetectReplaceRegister (void) sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup; sigmatch_table[DETECT_REPLACE].Free = NULL; sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests; - - sigmatch_table[DETECT_REPLACE].flags |= SIGMATCH_PAYLOAD; } int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) @@ -103,9 +101,9 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) return 0; } - /* add to the latest "content" keyword from either dmatch or pmatch */ - pm = SigMatchGetLastSMFromLists(s, 2, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]); + /* add to the latest "content" keyword from pmatch */ + pm = DetectGetLastSMByListId(s, DETECT_SM_LIST_PMATCH, + DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_WITHIN_MISSING_CONTENT, "replace needs" "preceding content option for raw sig"); @@ -151,7 +149,17 @@ int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, char *replacestr) return -1; } -DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, DetectContentData *cd) +/* Add to the head of the replace-list. + * + * The first to add to the replace-list has the highest priority. So, + * adding the the head of the list results in the newest modifications + * of content being applied first, so later changes can over ride + * earlier changes. Thus the highest priority modifications should be + * applied last. + */ +DetectReplaceList *DetectReplaceAddToList(DetectReplaceList *replist, + uint8_t *found, + DetectContentData *cd) { DetectReplaceList *newlist; @@ -161,16 +169,13 @@ DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t * newlist = SCMalloc(sizeof(DetectReplaceList)); if (unlikely(newlist == NULL)) - return NULL; + return replist; newlist->found = found; newlist->cd = cd; - newlist->next = NULL; + /* Push new value onto the front of the list. */ + newlist->next = replist; - if (replist) { - replist->next = newlist; - return replist; - } else - return newlist; + return newlist; } @@ -179,7 +184,7 @@ void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist) DetectReplaceList *tlist = NULL; SCLogDebug("replace: Executing match"); - while(replist) { + while (replist) { memcpy(replist->found, replist->cd->replace, replist->cd->replace_len); SCLogDebug("replace: injecting '%s'", replist->cd->replace); p->flags |= PKT_STREAM_MODIFIED; @@ -194,8 +199,8 @@ void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist) void DetectReplaceFreeInternal(DetectReplaceList *replist) { DetectReplaceList *tlist = NULL; - while(replist) { - SCLogDebug("replace: Freing match"); + while (replist) { + SCLogDebug("replace: Freeing match"); tlist = replist; replist = replist->next; SCFree(tlist); @@ -213,8 +218,10 @@ void DetectReplaceFreeInternal(DetectReplaceList *replist) * \retval return 1 if match * \retval return 0 if not */ -int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, char *sig, - uint32_t sid, uint8_t *pp, uint16_t *len) +static +int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, + char *sig, uint32_t sid, uint8_t *pp, + uint16_t *len) { int result = 0; @@ -261,9 +268,11 @@ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, ch } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineAddToMaster(de_ctx); + DetectEngineThreadCtxInit(&th_v, NULL, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + DetectEngineMoveToFreeList(de_ctx); if (PacketAlertCheck(p, sid) != 1) { SCLogDebug("replace: no alert on sig %d", sid); @@ -281,14 +290,9 @@ int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize, ch end: if (dtv.app_tctx != NULL) AppLayerDestroyCtxThread(dtv.app_tctx); - if (de_ctx != NULL) - { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEnginePruneFreeList(); PACKET_RECYCLE(p); FlowShutdown(); SCFree(p); @@ -383,7 +387,7 @@ int DetectReplaceLongPatternMatchTestUDPWrp(char *sig, uint32_t sid, char *sig_r /** * \test Check if replace is working */ -int DetectReplaceMatchTest01() +static int DetectReplaceMatchTest01(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; sid:1;)"; @@ -395,7 +399,7 @@ int DetectReplaceMatchTest01() /** * \test Check if replace is working with offset */ -int DetectReplaceMatchTest02() +static int DetectReplaceMatchTest02(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)"; @@ -407,7 +411,7 @@ int DetectReplaceMatchTest02() /** * \test Check if replace is working with offset and keyword inversion */ -int DetectReplaceMatchTest03() +static int DetectReplaceMatchTest03(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)"; @@ -419,7 +423,7 @@ int DetectReplaceMatchTest03() /** * \test Check if replace is working with second content */ -int DetectReplaceMatchTest04() +static int DetectReplaceMatchTest04(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)"; @@ -431,32 +435,32 @@ int DetectReplaceMatchTest04() /** * \test Check if replace is not done when second content don't match */ -int DetectReplaceMatchTest05() +static int DetectReplaceMatchTest05(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"TH\"; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is not done when second content match and not * first */ -int DetectReplaceMatchTest06() +static int DetectReplaceMatchTest06(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"commode\"; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working when nocase used */ -int DetectReplaceMatchTest07() +static int DetectReplaceMatchTest07(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)"; @@ -468,7 +472,7 @@ int DetectReplaceMatchTest07() /** * \test Check if replace is working when depth is used */ -int DetectReplaceMatchTest08() +static int DetectReplaceMatchTest08(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)"; @@ -480,19 +484,19 @@ int DetectReplaceMatchTest08() /** * \test Check if replace is working when depth block match used */ -int DetectReplaceMatchTest09() +static int DetectReplaceMatchTest09(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"this is a pig test\"; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working when depth block match used */ -int DetectReplaceMatchTest10() +static int DetectReplaceMatchTest10(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)"; @@ -504,7 +508,7 @@ int DetectReplaceMatchTest10() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest11() +static int DetectReplaceMatchTest11(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)"; @@ -516,19 +520,19 @@ int DetectReplaceMatchTest11() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest12() +static int DetectReplaceMatchTest12(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest13() +static int DetectReplaceMatchTest13(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)"; @@ -540,19 +544,19 @@ int DetectReplaceMatchTest13() /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest14() +static int DetectReplaceMatchTest14(void) { char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";" " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)"; char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";" " content:\"pig\"; depth:17; offset:14; sid:2;)"; - return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); + return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2); } /** * \test Check if replace is working with within */ -int DetectReplaceMatchTest15() +static int DetectReplaceMatchTest15(void) { char *sig = "alert udp any any -> any any (msg:\"Nothing..\";" " content:\"com\"; replace:\"org\"; sid:1;)"; @@ -565,7 +569,7 @@ int DetectReplaceMatchTest15() /** * \test Parsing test */ -int DetectReplaceParseTest01(void) +static int DetectReplaceParseTest01(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -599,7 +603,7 @@ int DetectReplaceParseTest01(void) /** * \test Parsing test: non valid because of http protocol */ -int DetectReplaceParseTest02(void) +static int DetectReplaceParseTest02(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -634,7 +638,7 @@ int DetectReplaceParseTest02(void) * \test Parsing test: non valid because of http_header on same content * as replace keyword */ -int DetectReplaceParseTest03(void) +static int DetectReplaceParseTest03(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -668,7 +672,7 @@ int DetectReplaceParseTest03(void) /** * \test Parsing test no content */ -int DetectReplaceParseTest04(void) +static int DetectReplaceParseTest04(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -702,7 +706,7 @@ int DetectReplaceParseTest04(void) /** * \test Parsing test content after replace */ -int DetectReplaceParseTest05(void) +static int DetectReplaceParseTest05(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -736,7 +740,7 @@ int DetectReplaceParseTest05(void) /** * \test Parsing test content and replace length differ */ -int DetectReplaceParseTest06(void) +static int DetectReplaceParseTest06(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -770,7 +774,7 @@ int DetectReplaceParseTest06(void) /** * \test Parsing test content and replace length differ */ -int DetectReplaceParseTest07(void) +static int DetectReplaceParseTest07(void) { int run_mode_backup = run_mode; run_mode = RUNMODE_NFQ; @@ -812,28 +816,28 @@ void DetectReplaceRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ /* matching */ - UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01, 1); - UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02, 1); - UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03, 1); - UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04, 1); - UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05, 0); - UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06, 0); - UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07, 1); - UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08, 1); - UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09, 0); - UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10, 1); - UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11, 1); - UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12, 0); - UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13, 1); - UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14, 0); - UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15, 1); + UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01); + UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02); + UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03); + UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04); + UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05); + UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06); + UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07); + UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08); + UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09); + UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10); + UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11); + UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12); + UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13); + UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14); + UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15); /* parsing */ - UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01, 1); - UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02, 1); - UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03, 1); - UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04, 1); - UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05, 1); - UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06, 1); - UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07, 1); + UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01); + UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02); + UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03); + UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04); + UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05); + UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06); + UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07); #endif /* UNITTESTS */ } diff --git a/src/detect-rev.c b/src/detect-rev.c index 6306f6cc7d1e..1c1bc401da5a 100644 --- a/src/detect-rev.c +++ b/src/detect-rev.c @@ -34,7 +34,7 @@ void DetectRevRegister (void) { sigmatch_table[DETECT_REV].name = "rev"; sigmatch_table[DETECT_REV].desc = "set version of the rule"; - sigmatch_table[DETECT_REV].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Rev-Revision"; + sigmatch_table[DETECT_REV].url = DOC_URL DOC_VERSION "/rules/meta.html#rev-revision"; sigmatch_table[DETECT_REV].Match = NULL; sigmatch_table[DETECT_REV].Setup = DetectRevSetup; sigmatch_table[DETECT_REV].Free = NULL; @@ -46,13 +46,14 @@ static int DetectRevSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) char *str = rawstr; char dubbed = 0; - /* strip "'s */ - if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') { + /* Strip leading and trailing "s. */ + if (rawstr[0] == '\"') { str = SCStrdup(rawstr+1); if (unlikely(str == NULL)) return -1; - - str[strlen(rawstr)-2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(rawstr)-1] = '\0'; + } dubbed = 1; } diff --git a/src/detect-rpc.c b/src/detect-rpc.c index ba7b426c1730..b559ad6f07eb 100644 --- a/src/detect-rpc.c +++ b/src/detect-rpc.c @@ -48,8 +48,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -int DetectRpcSetup (DetectEngineCtx *, Signature *, char *); +static int DetectRpcMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); +static int DetectRpcSetup (DetectEngineCtx *, Signature *, char *); void DetectRpcRegisterTests(void); void DetectRpcFree(void *); @@ -60,34 +61,13 @@ void DetectRpcRegister (void) { sigmatch_table[DETECT_RPC].name = "rpc"; sigmatch_table[DETECT_RPC].desc = "match RPC procedure numbers and RPC version"; - sigmatch_table[DETECT_RPC].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#rpc"; + sigmatch_table[DETECT_RPC].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#rpc"; sigmatch_table[DETECT_RPC].Match = DetectRpcMatch; sigmatch_table[DETECT_RPC].Setup = DetectRpcSetup; sigmatch_table[DETECT_RPC].Free = DetectRpcFree; sigmatch_table[DETECT_RPC].RegisterTests = DetectRpcRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /* @@ -107,10 +87,11 @@ void DetectRpcRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectRpcMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { /* PrintRawDataFp(stdout, p->payload, p->payload_len); */ - DetectRpcData *rd = (DetectRpcData *)m->ctx; + const DetectRpcData *rd = (const DetectRpcData *)ctx; char *rpcmsg = (char *)p->payload; if (PKT_IS_TCP(p)) { @@ -286,7 +267,7 @@ int DetectRpcSetup (DetectEngineCtx *de_ctx, Signature *s, char *rpcstr) goto error; sm->type = DETECT_RPC; - sm->ctx = (void *)rd; + sm->ctx = (SigMatchCtx *)rd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -585,8 +566,6 @@ static int DetectRpcTestSig01(void) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); UTHFreePackets(&p, 1); end: return result; @@ -599,11 +578,11 @@ static int DetectRpcTestSig01(void) void DetectRpcRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectRpcTestParse01", DetectRpcTestParse01, 1); - UtRegisterTest("DetectRpcTestParse02", DetectRpcTestParse02, 1); - UtRegisterTest("DetectRpcTestParse03", DetectRpcTestParse03, 1); - UtRegisterTest("DetectRpcTestParse04", DetectRpcTestParse04, 1); - UtRegisterTest("DetectRpcTestParse05", DetectRpcTestParse05, 1); - UtRegisterTest("DetectRpcTestSig01", DetectRpcTestSig01, 1); + UtRegisterTest("DetectRpcTestParse01", DetectRpcTestParse01); + UtRegisterTest("DetectRpcTestParse02", DetectRpcTestParse02); + UtRegisterTest("DetectRpcTestParse03", DetectRpcTestParse03); + UtRegisterTest("DetectRpcTestParse04", DetectRpcTestParse04); + UtRegisterTest("DetectRpcTestParse05", DetectRpcTestParse05); + UtRegisterTest("DetectRpcTestSig01", DetectRpcTestSig01); #endif /* UNITTESTS */ } diff --git a/src/detect-sameip.c b/src/detect-sameip.c index db17e21599e4..780832b8fef4 100644 --- a/src/detect-sameip.c +++ b/src/detect-sameip.c @@ -38,7 +38,7 @@ #include "util-unittest-helper.h" static int DetectSameipMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + const Signature *, const SigMatchCtx *); static int DetectSameipSetup(DetectEngineCtx *, Signature *, char *); static void DetectSameipRegisterTests(void); @@ -50,7 +50,7 @@ void DetectSameipRegister(void) { sigmatch_table[DETECT_SAMEIP].name = "sameip"; sigmatch_table[DETECT_SAMEIP].desc = "check if the IP address of the source is the same as the IP address of the destination"; - sigmatch_table[DETECT_SAMEIP].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#sameip"; + sigmatch_table[DETECT_SAMEIP].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#sameip"; sigmatch_table[DETECT_SAMEIP].Match = DetectSameipMatch; sigmatch_table[DETECT_SAMEIP].Setup = DetectSameipSetup; sigmatch_table[DETECT_SAMEIP].Free = NULL; @@ -71,7 +71,7 @@ void DetectSameipRegister(void) * \retval 1 match */ static int DetectSameipMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { return CMP_ADDR(&p->src, &p->dst) ? 1 : 0; } @@ -119,7 +119,7 @@ static int DetectSameipSetup(DetectEngineCtx *de_ctx, Signature *s, char *optstr * \internal * \brief This test tests sameip success and failure. */ -static int DetectSameipSigTest01Real(int mpm_type) +static int DetectSameipSigTest01(void) { uint8_t *buf = (uint8_t *) "GET / HTTP/1.0\r\n" @@ -144,7 +144,6 @@ static int DetectSameipSigTest01Real(int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, @@ -182,30 +181,6 @@ static int DetectSameipSigTest01Real(int mpm_type) return result; } -/** - * \test DetectSameipSigTest01B2g tests sameip under B2g MPM - */ -static int DetectSameipSigTest01B2g(void) -{ - return DetectSameipSigTest01Real(MPM_B2G); -} - -/** - * \test DetectSameipSigTest01B2g tests sameip under B3g MPM - */ -static int DetectSameipSigTest01B3g(void) -{ - return DetectSameipSigTest01Real(MPM_B3G); -} - -/** - * \test DetectSameipSigTest01B2g tests sameip under WuManber MPM - */ -static int DetectSameipSigTest01Wm(void) -{ - return DetectSameipSigTest01Real(MPM_WUMANBER); -} - #endif /* UNITTESTS */ /** @@ -215,8 +190,6 @@ static int DetectSameipSigTest01Wm(void) static void DetectSameipRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSameipSigTest01B2g", DetectSameipSigTest01B2g, 1); - UtRegisterTest("DetectSameipSigTest01B3g", DetectSameipSigTest01B3g, 1); - UtRegisterTest("DetectSameipSigTest01Wm", DetectSameipSigTest01Wm, 1); + UtRegisterTest("DetectSameipSigTest01", DetectSameipSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-seq.c b/src/detect-seq.c index b78fa567de0c..6c3bd90531cc 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -30,7 +30,8 @@ #include "detect-parse.h" #include "detect-engine.h" -#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" #include "detect-seq.h" @@ -41,20 +42,24 @@ static int DetectSeqSetup(DetectEngineCtx *, Signature *, char *); static int DetectSeqMatch(ThreadVars *, DetectEngineThreadCtx *, - Packet *, Signature *, SigMatch *); + Packet *, const Signature *, const SigMatchCtx *); static void DetectSeqRegisterTests(void); static void DetectSeqFree(void *); - +static int PrefilterSetupTcpSeq(SigGroupHead *sgh); +static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s); void DetectSeqRegister(void) { sigmatch_table[DETECT_SEQ].name = "seq"; sigmatch_table[DETECT_SEQ].desc = "check for a specific TCP sequence number"; - sigmatch_table[DETECT_SEQ].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#seq"; + sigmatch_table[DETECT_SEQ].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#seq"; sigmatch_table[DETECT_SEQ].Match = DetectSeqMatch; sigmatch_table[DETECT_SEQ].Setup = DetectSeqSetup; sigmatch_table[DETECT_SEQ].Free = DetectSeqFree; sigmatch_table[DETECT_SEQ].RegisterTests = DetectSeqRegisterTests; + + sigmatch_table[DETECT_SEQ].SupportsPrefilter = PrefilterTcpSeqIsPrefilterable; + sigmatch_table[DETECT_SEQ].SetupPrefilter = PrefilterSetupTcpSeq; } /** @@ -70,9 +75,9 @@ void DetectSeqRegister(void) * \retval 1 match */ static int DetectSeqMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Packet *p, Signature *s, SigMatch *m) + Packet *p, const Signature *s, const SigMatchCtx *ctx) { - DetectSeqData *data = (DetectSeqData *)m->ctx; + const DetectSeqData *data = (const DetectSeqData *)ctx; /* This is only needed on TCP packets */ if (!(PKT_IS_TCP(p)) || PKT_IS_PSEUDOPKT(p)) { @@ -111,7 +116,7 @@ static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *optstr) if (-1 == ByteExtractStringUint32(&data->seq, 10, 0, optstr)) { goto error; } - sm->ctx = data; + sm->ctx = (SigMatchCtx*)data; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -139,6 +144,60 @@ static void DetectSeqFree(void *ptr) SCFree(data); } +/* prefilter code */ + +static void +PrefilterPacketSeqMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + if ((p->proto) == IPPROTO_TCP && !(PKT_IS_PSEUDOPKT(p)) && + (p->tcph != NULL) && (TCP_GET_SEQ(p) == ctx->v1.u32[0])) + { + SCLogDebug("packet matches TCP seq %u", ctx->v1.u32[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketSeqSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectSeqData *a = smctx; + v->u32[0] = a->seq; +} + +static _Bool +PrefilterPacketSeqCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectSeqData *a = smctx; + if (v.u32[0] == a->seq) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTcpSeq(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_SEQ, + PrefilterPacketSeqSet, + PrefilterPacketSeqCompare, + PrefilterPacketSeqMatch); +} + +static _Bool PrefilterTcpSeqIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_SEQ: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS @@ -236,8 +295,8 @@ static int DetectSeqSigTest02(void) static void DetectSeqRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01, 1); - UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02, 1); + UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01); + UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02); #endif /* UNITTESTS */ } diff --git a/src/detect-sid.c b/src/detect-sid.c index 1c7666bb17d2..d148a3dd0728 100644 --- a/src/detect-sid.c +++ b/src/detect-sid.c @@ -25,35 +25,41 @@ #include "suricata-common.h" #include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" #include "util-debug.h" #include "util-error.h" +#include "util-unittest.h" static int DetectSidSetup (DetectEngineCtx *, Signature *, char *); +static void DetectSidRegisterTests(void); void DetectSidRegister (void) { sigmatch_table[DETECT_SID].name = "sid"; sigmatch_table[DETECT_SID].desc = "set rule id"; - sigmatch_table[DETECT_SID].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Meta-settings#Sid-signature-id"; + sigmatch_table[DETECT_SID].url = DOC_URL DOC_VERSION "/rules/meta.html#sid-signature-id"; sigmatch_table[DETECT_SID].Match = NULL; sigmatch_table[DETECT_SID].Setup = DetectSidSetup; sigmatch_table[DETECT_SID].Free = NULL; - sigmatch_table[DETECT_SID].RegisterTests = NULL; + sigmatch_table[DETECT_SID].RegisterTests = DetectSidRegisterTests; } static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) { char *str = sidstr; - char dubbed = 0; + char duped = 0; - /* strip "'s */ - if (sidstr[0] == '\"' && sidstr[strlen(sidstr)-1] == '\"') { - str = SCStrdup(sidstr+1); - if (unlikely(str == NULL)) + /* Strip leading and trailing "s. */ + if (sidstr[0] == '\"') { + str = SCStrdup(sidstr + 1); + if (unlikely(str == NULL)) { return -1; - - str[strlen(sidstr)-2] = '\0'; - dubbed = 1; + } + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } + duped = 1; } unsigned long id = 0; @@ -71,13 +77,89 @@ static int DetectSidSetup (DetectEngineCtx *de_ctx, Signature *s, char *sidstr) s->id = (uint32_t)id; - if (dubbed) + if (duped) SCFree(str); return 0; error: - if (dubbed) + if (duped) SCFree(str); return -1; } +#ifdef UNITTESTS + +static int SidTestParse01(void) +{ + int result = 0; + Signature *s = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + s = DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> any any (sid:1; gid:1;)"); + if (s == NULL || s->id != 1) + goto end; + + result = 1; + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SidTestParse02(void) +{ + int result = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + if (DetectEngineAppendSig(de_ctx, + "alert tcp 1.2.3.4 any -> any any (sid:a; gid:1;)") != NULL) + goto end; + + result = 1; + +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SidTestParse03(void) +{ + int result = 0; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + if (DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (content:\"ABC\"; sid:\";)") != NULL) + goto end; + + result = 1; +end: + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + +#endif + +/** + * \brief Register DetectSid unit tests. + */ +static void DetectSidRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SidTestParse01", SidTestParse01); + UtRegisterTest("SidTestParse02", SidTestParse02); + UtRegisterTest("SidTestParse03", SidTestParse03); +#endif /* UNITTESTS */ +} diff --git a/src/detect-simd.c b/src/detect-simd.c deleted file mode 100644 index 0773bc964ca5..000000000000 --- a/src/detect-simd.c +++ /dev/null @@ -1,575 +0,0 @@ -/* Copyright (C) 2013 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Basic detection engine - */ - -#include "suricata-common.h" -#include "detect.h" - -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-vector.h" - -/* Included into detect.c */ - -#if defined(__SSE3__) - -/** - * \brief SIMD implementation of mask prefiltering. - * - * Mass mask matching is done creating a bitmap of signatures that need - * futher inspection. - * - * On 32 bit systems we inspect in 32 sig batches, creating a u32 with flags. - * On 64 bit systems we inspect in 64 sig batches, creating a u64 with flags. - * The size of a register is leading here. - */ -void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureMask mask, AppProto alproto) -{ - uint32_t u; - SigIntId x; - int bitno = 0; -#if __WORDSIZE == 32 - register uint32_t bm; /* bit mask, 32 bits used */ - - Vector pm, sm, r1, r2; - /* load the packet mask into each byte of the vector */ - pm.v = _mm_set1_epi8(mask); - - /* reset previous run */ - det_ctx->match_array_cnt = 0; - - for (u = 0; u < det_ctx->sgh->sig_cnt; u += 32) { - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm = ((uint32_t) _mm_movemask_epi8(r2.v)); - - SCLogDebug("bm1 %08x", bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+16]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint32_t) _mm_movemask_epi8(r2.v) << 16); - - SCLogDebug("bm2 %08x", bm); - - if (bm == 0) { - continue; - } - - /* Check each bit in the bit map. Little endian is assumed (SSE is x86), - * so the bits are in memory backwards, 0 is on the right edge, - * 31 on the left edge. This is why above we store the output of the - * _mm_movemask_epi8 in this order as well */ - bitno = 0; - for (x = u; x < det_ctx->sgh->sig_cnt && bitno < 32; x++, bitno++) { - if (bm & (1 << bitno)) { - SignatureHeader *s = &det_ctx->sgh->head_array[x]; - - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; - det_ctx->match_array_cnt++; - } - } - } - } -#elif __WORDSIZE == 64 - register uint64_t bm; /* bit mask, 64 bits used */ - - Vector pm, sm, r1, r2; - /* load the packet mask into each byte of the vector */ - pm.v = _mm_set1_epi8(mask); - - /* reset previous run */ - det_ctx->match_array_cnt = 0; - - for (u = 0; u < det_ctx->sgh->sig_cnt; u += 64) { - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm = ((uint64_t) _mm_movemask_epi8(r2.v)); - - SCLogDebug("bm1 %08"PRIx64, bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+16]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+32]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&det_ctx->sgh->mask_array[u+48]); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 48; - - SCLogDebug("bm2 %08"PRIx64, bm); - - if (bm == 0) { - continue; - } - - /* Check each bit in the bit map. Little endian is assumed (SSE is x86-64), - * so the bits are in memory backwards, 0 is on the right edge, - * 63 on the left edge. This is why above we store the output of the - * _mm_movemask_epi8 in this order as well */ - bitno = 0; - for (x = u; x < det_ctx->sgh->sig_cnt && bitno < 64; x++, bitno++) { - if (bm & ((uint64_t)1 << bitno)) { - SignatureHeader *s = &det_ctx->sgh->head_array[x]; - - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; - det_ctx->match_array_cnt++; - } - } - } - } -#else -#error Wordsize (__WORDSIZE) neither 32 or 64. -#endif -} - /* end defined(__SSE3__) */ -#elif defined(__tile__) - -/** - * \brief SIMD implementation of mask prefiltering for TILE-Gx - * - * Mass mask matching is done creating a bitmap of signatures that need - * futher inspection. - */ -void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureMask mask, AppProto alproto) -{ - uint32_t u; - register uint64_t bm; /* bit mask, 64 bits used */ - - /* Keep local copies of variables that don't change during this function. */ - uint64_t *mask_vector = (uint64_t*)det_ctx->sgh->mask_array; - uint32_t sig_cnt = det_ctx->sgh->sig_cnt; - SignatureHeader *head_array = det_ctx->sgh->head_array; - - Signature **match_array = det_ctx->match_array; - uint32_t match_count = 0; - - /* Replicate the packet mask into each byte of the vector. */ - uint64_t pm = __insn_shufflebytes(mask, 0, 0); - - /* u is the signature index. */ - for (u = 0; u < sig_cnt; u += 8) { - /* Load 8 masks */ - uint64_t sm = *mask_vector++; - /* Binary AND 8 masks with the packet's mask */ - uint64_t r1 = pm & sm; - /* Compare the result with the original mask - * Result if equal puts a 1 in LSB of bytes that match. - */ - bm = __insn_v1cmpeq(sm, r1); - - /* Check the LSB bit of each byte in the bit map. Little endian is assumed, - * so the LSB byte is index 0. Uses count trailing zeros to find least - * significant bit that is set. */ - while (bm) { - /* Find first bit set starting from LSB. */ - unsigned int first_bit = __insn_ctz(bm); - unsigned int first_byte = first_bit >> 3; - unsigned int x = u + first_byte; - if (x >= sig_cnt) - break; - SignatureHeader *s = &head_array[x]; - - /* Clear the first bit set, so it is not found again. */ - bm -= (1UL << first_bit); - - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - *match_array++ = s->full_sig; - match_count++; - } - } - } - det_ctx->match_array_cnt = match_count; -} -#endif /* defined(__tile__) */ - - -#ifdef UNITTESTS -#include "flow-util.h" -#include "stream-tcp-reassemble.h" -#include "util-var-name.h" - -/// SCLogInfo("%s %u %u %u %u", #v, (v).dw[0], (v).dw[1], (v).dw[2], (v).dw[3]); -#define VECTOR_SCLogInfo(v) { \ - SCLogInfo("%s %08X %08X %08X %08X", #v, (v).dw[0], (v).dw[1], (v).dw[2], (v).dw[3]); \ -} - -/** - * \test Test 32 bit SIMD code. - */ -static int SigTestSIMDMask01(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint32_t bm = 0; - - uint8_t *mask = SCMallocAligned(32, 16); - memset(mask, 0xEF, 32); - mask[31] = 0xFF; - printf("\n"); - pm.v = _mm_set1_epi8(0xEF); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint32_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm %08x", bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint32_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm %08x", bm); - - int b = 0; - for ( ; b < 32; b++){ - if (bm & (1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if (!(bm & (1 << 31))) { - return 1; - } - return 0; -#else - return 1; -#endif -} - -/** - * \test Test 32 bit SIMD code. - */ -static int SigTestSIMDMask02(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint32_t bm = 0; - - uint8_t *mask = SCMallocAligned(32, 16); - memset(mask, 0x01, 32); - mask[31] = 0; - pm.v = _mm_set1_epi8(0x02); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint32_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm %08x", bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint32_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm %08x", bm); - - int b = 0; - for ( ; b < 32; b++){ - if (bm & (1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if (bm & (1 << 31)) { - return 1; - } - return 0; -#else - return 1; -#endif -} - -/** - * \test Test 64 bit SIMD code. - */ -static int SigTestSIMDMask03(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint64_t bm = 0; - uint8_t *mask = SCMallocAligned(64, 16); - memset(mask, 0xEF, 64); - mask[31] = 0xFF; - mask[62] = 0xFF; - printf("\n"); - pm.v = _mm_set1_epi8(0xEF); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint64_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm1 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm2 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[32]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; - - SCLogInfo("bm3 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[48]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 48; - - SCLogInfo("bm4 %"PRIxMAX, (uintmax_t)bm); - - int b = 0; - for ( ; b < 64; b++){ - if (bm & ((uint64_t)1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if (!(bm & ((uint64_t)1 << 31)) && !(bm & ((uint64_t)1 << 62))) { - return 1; - } - return 0; -#else - return 1; -#endif -} - -/** - * \test Test 64 bit SIMD code. - */ -static int SigTestSIMDMask04(void) -{ -#if defined (__SSE3__) - Vector pm, sm, r1, r2; - uint64_t bm = 0; - - uint8_t *mask = SCMallocAligned(64, 16); - memset(mask, 0x01, 64); - mask[31] = 0; - mask[62] = 0; - pm.v = _mm_set1_epi8(0x02); - VECTOR_SCLogInfo(pm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[0]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm = ((uint64_t) _mm_movemask_epi8(r2.v)); - - SCLogInfo("bm1 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[16]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 16; - - SCLogInfo("bm2 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[32]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= ((uint64_t) _mm_movemask_epi8(r2.v)) << 32; - - SCLogInfo("bm3 %"PRIxMAX, (uintmax_t)bm); - - /* load a batch of masks */ - sm.v = _mm_load_si128((const __m128i *)&mask[48]); - VECTOR_SCLogInfo(sm); - /* logical AND them with the packet's mask */ - r1.v = _mm_and_si128(pm.v, sm.v); - VECTOR_SCLogInfo(r1); - /* compare the result with the original mask */ - r2.v = _mm_cmpeq_epi8(sm.v, r1.v); - VECTOR_SCLogInfo(r2); - /* convert into a bitarray */ - bm |= (((uint64_t) _mm_movemask_epi8(r2.v)) << 48); - - SCLogInfo("bm4-total %"PRIxMAX, (uintmax_t)bm); - - int b = 0; - for ( ; b < 64; b++){ - if (bm & ((uint64_t)1 << b)) { - SCLogInfo("b %02d, set", b); - } else { - SCLogInfo("b %02d, not set", b); - - } - } - - if ((bm & ((uint64_t)1 << 31)) && (bm & ((uint64_t)1 << 62))) { - return 1; - } - return 0; -#else - return 1; -#endif -} -#endif /* UNITTESTS */ - -void DetectSimdRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("SigTestSIMDMask01", SigTestSIMDMask01, 1); - UtRegisterTest("SigTestSIMDMask02", SigTestSIMDMask02, 1); - UtRegisterTest("SigTestSIMDMask03", SigTestSIMDMask03, 1); - UtRegisterTest("SigTestSIMDMask04", SigTestSIMDMask04, 1); -#endif /* UNITTESTS */ -} diff --git a/src/detect-ssh-proto-version.c b/src/detect-ssh-proto-version.c index 96a8b6763050..db2371485280 100644 --- a/src/detect-ssh-proto-version.c +++ b/src/detect-ssh-proto-version.c @@ -62,10 +62,13 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectSshVersionMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSshVersionSetup (DetectEngineCtx *, Signature *, char *); -void DetectSshVersionRegisterTests(void); -void DetectSshVersionFree(void *); +static void DetectSshVersionRegisterTests(void); +static void DetectSshVersionFree(void *); +static int g_ssh_banner_list_id = 0; /** * \brief Registration function for keyword: ssh.protoversion @@ -73,35 +76,14 @@ void DetectSshVersionFree(void *); void DetectSshVersionRegister(void) { sigmatch_table[DETECT_AL_SSH_PROTOVERSION].name = "ssh.protoversion"; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Match = NULL; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerMatch = DetectSshVersionMatch; - sigmatch_table[DETECT_AL_SSH_PROTOVERSION].alproto = ALPROTO_SSH; + sigmatch_table[DETECT_AL_SSH_PROTOVERSION].AppLayerTxMatch = DetectSshVersionMatch; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Setup = DetectSshVersionSetup; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].Free = DetectSshVersionFree; sigmatch_table[DETECT_AL_SSH_PROTOVERSION].RegisterTests = DetectSshVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - SCLogDebug("registering ssh.protoversion rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); } /** @@ -115,11 +97,13 @@ void DetectSshVersionRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectSshVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectSshVersionData *ssh = (DetectSshVersionData *)m->ctx; + DetectSshVersionData *ssh = (DetectSshVersionData *)m; SshState *ssh_state = (SshState *)state; if (ssh_state == NULL) { SCLogDebug("no ssh state, no match"); @@ -233,6 +217,9 @@ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectSshVersionData *ssh = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) + return -1; + ssh = DetectSshVersionParse(str); if (ssh == NULL) goto error; @@ -243,18 +230,10 @@ static int DetectSshVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_SSH_PROTOVERSION; sm->ctx = (void *)ssh; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_SSH; + SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); return 0; error: @@ -378,6 +357,7 @@ static int DetectSshVersionTestDetect01(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -396,35 +376,39 @@ static int DetectSshVersionTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -491,6 +475,7 @@ static int DetectSshVersionTestDetect02(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -509,34 +494,38 @@ static int DetectSshVersionTestDetect02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -602,6 +591,7 @@ static int DetectSshVersionTestDetect03(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -620,35 +610,39 @@ static int DetectSshVersionTestDetect03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -689,12 +683,15 @@ static int DetectSshVersionTestDetect03(void) void DetectSshVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01, 1); - UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02, 1); - UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03, 1); - UtRegisterTest("DetectSshVersionTestDetect01", DetectSshVersionTestDetect01, 1); - UtRegisterTest("DetectSshVersionTestDetect02", DetectSshVersionTestDetect02, 1); - UtRegisterTest("DetectSshVersionTestDetect03", DetectSshVersionTestDetect03, 1); + UtRegisterTest("DetectSshVersionTestParse01", DetectSshVersionTestParse01); + UtRegisterTest("DetectSshVersionTestParse02", DetectSshVersionTestParse02); + UtRegisterTest("DetectSshVersionTestParse03", DetectSshVersionTestParse03); + UtRegisterTest("DetectSshVersionTestDetect01", + DetectSshVersionTestDetect01); + UtRegisterTest("DetectSshVersionTestDetect02", + DetectSshVersionTestDetect02); + UtRegisterTest("DetectSshVersionTestDetect03", + DetectSshVersionTestDetect03); #endif /* UNITTESTS */ } diff --git a/src/detect-ssh-proto.c b/src/detect-ssh-proto.c new file mode 100644 index 000000000000..ac1757388cab --- /dev/null +++ b/src/detect-ssh-proto.c @@ -0,0 +1,211 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup sshlayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support ssh_proto sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssh.h" + +#define KEYWORD_NAME "ssh_proto" +#define KEYWORD_DOC "ssh-keywords#ssh-protocol" +#define BUFFER_NAME "ssh_protocol" +#define BUFFER_DESC "ssh protocol field" +static int g_buffer_id = 0; + +/** \brief SSH Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshRequestProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->cli_hdr.proto_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->cli_hdr.proto_version); + const uint8_t *buffer = ssh_state->cli_hdr.proto_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshRequestProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshRequestProtocol, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief SSH Protocol Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshResponseProtocol(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->srv_hdr.proto_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->srv_hdr.proto_version); + const uint8_t *buffer = ssh_state->srv_hdr.proto_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshResponseProtocolRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshResponseProtocol, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineSshProtocol(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + uint8_t *protocol = NULL; + SshState *ssh_state = alstate; + + if (flags & STREAM_TOSERVER) + protocol = ssh_state->cli_hdr.proto_version; + else if (flags & STREAM_TOCLIENT) + protocol = ssh_state->srv_hdr.proto_version; + if (protocol == NULL) + goto end; + + uint32_t buffer_len = strlen((char *)protocol); + uint8_t *buffer = protocol; + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectSshProtocolSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectSshProtocolSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_SSH_STATE; +} + +void DetectSshProtocolRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_PROTOCOL].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].Setup = DetectSshProtocolSetup; + sigmatch_table[DETECT_AL_SSH_PROTOCOL].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxSshRequestProtocolRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxSshResponseProtocolRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOSERVER, + InspectEngineSshProtocol); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOCLIENT, + InspectEngineSshProtocol); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectSshProtocolSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-ssh-proto.h b/src/detect-ssh-proto.h new file mode 100644 index 000000000000..b04476e3c874 --- /dev/null +++ b/src/detect-ssh-proto.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_SSH_PROTOCOL_H__ +#define __DETECT_SSH_PROTOCOL_H__ + +void DetectSshProtocolRegister(void); + +#endif /* __DETECT_SSH_PROTOCOL_H__ */ diff --git a/src/detect-ssh-software-version.c b/src/detect-ssh-software-version.c index f2df5a538350..da5cc5190b88 100644 --- a/src/detect-ssh-software-version.c +++ b/src/detect-ssh-software-version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -61,16 +61,28 @@ /** * \brief Regex for parsing the softwareversion string */ -#define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" +#define PARSE_REGEX "^\\s*\"?\\s*?([0-9a-zA-Z\\:\\.\\-\\_\\+\\s+]+)\\s*\"?\\s*$" static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectSshSoftwareVersionMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSshSoftwareVersionSetup (DetectEngineCtx *, Signature *, char *); -void DetectSshSoftwareVersionRegisterTests(void); -void DetectSshSoftwareVersionFree(void *); -void DetectSshSoftwareVersionRegister(void); +static void DetectSshSoftwareVersionRegisterTests(void); +static void DetectSshSoftwareVersionFree(void *); +static int g_ssh_banner_list_id = 0; + +static int InspectSshBanner(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} /** * \brief Registration function for keyword: ssh.softwareversion @@ -78,35 +90,19 @@ void DetectSshSoftwareVersionRegister(void); void DetectSshSoftwareVersionRegister(void) { sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].name = "ssh.softwareversion"; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Match = NULL; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerMatch = DetectSshSoftwareVersionMatch; - sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].alproto = ALPROTO_SSH; + sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].AppLayerTxMatch = DetectSshSoftwareVersionMatch; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Setup = DetectSshSoftwareVersionSetup; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].Free = DetectSshSoftwareVersionFree; sigmatch_table[DETECT_AL_SSH_SOFTWAREVERSION].RegisterTests = DetectSshSoftwareVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering ssh.softwareversion rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; + g_ssh_banner_list_id = DetectBufferTypeRegister("ssh_banner"); -error: - return; + DetectAppLayerInspectEngineRegister("ssh_banner", + ALPROTO_SSH, SIG_FLAG_TOSERVER, InspectSshBanner); + DetectAppLayerInspectEngineRegister("ssh_banner", + ALPROTO_SSH, SIG_FLAG_TOCLIENT, InspectSshBanner); } /** @@ -120,11 +116,13 @@ void DetectSshSoftwareVersionRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectSshSoftwareVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m->ctx; + DetectSshSoftwareVersionData *ssh = (DetectSshSoftwareVersionData *)m; SshState *ssh_state = (SshState *)state; if (ssh_state == NULL) { SCLogDebug("no ssh state, no match"); @@ -214,6 +212,9 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, DetectSshSoftwareVersionData *ssh = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_SSH) != 0) + return -1; + ssh = DetectSshSoftwareVersionParse(str); if (ssh == NULL) goto error; @@ -224,19 +225,10 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_SSH) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_SSH_SOFTWAREVERSION; sm->ctx = (void *)ssh; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_SSH; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - + SigMatchAppendSMToList(s, sm, g_ssh_banner_list_id); return 0; error: @@ -253,7 +245,7 @@ static int DetectSshSoftwareVersionSetup (DetectEngineCtx *de_ctx, Signature *s, * * \param id_d pointer to DetectSshSoftwareVersionData */ -void DetectSshSoftwareVersionFree(void *ptr) +static void DetectSshSoftwareVersionFree(void *ptr) { if (ptr == NULL) return; @@ -270,7 +262,7 @@ void DetectSshSoftwareVersionFree(void *ptr) * \test DetectSshSoftwareVersionTestParse01 is a test to make sure that we parse * a software version correctly */ -int DetectSshSoftwareVersionTestParse01 (void) +static int DetectSshSoftwareVersionTestParse01 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse("PuTTY_1.0"); @@ -286,7 +278,7 @@ int DetectSshSoftwareVersionTestParse01 (void) * \test DetectSshSoftwareVersionTestParse02 is a test to make sure that we parse * the software version correctly */ -int DetectSshSoftwareVersionTestParse02 (void) +static int DetectSshSoftwareVersionTestParse02 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse("\"SecureCRT-4.0\""); @@ -302,7 +294,7 @@ int DetectSshSoftwareVersionTestParse02 (void) * \test DetectSshSoftwareVersionTestParse03 is a test to make sure that we * don't return a ssh_data with an empty value specified */ -int DetectSshSoftwareVersionTestParse03 (void) +static int DetectSshSoftwareVersionTestParse03 (void) { DetectSshSoftwareVersionData *ssh = NULL; ssh = DetectSshSoftwareVersionParse(""); @@ -350,6 +342,7 @@ static int DetectSshSoftwareVersionTestDetect01(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -368,35 +361,39 @@ static int DetectSshSoftwareVersionTestDetect01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -463,6 +460,7 @@ static int DetectSshSoftwareVersionTestDetect02(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -481,35 +479,39 @@ static int DetectSshSoftwareVersionTestDetect02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -575,6 +577,7 @@ static int DetectSshSoftwareVersionTestDetect03(void) p->flowflags |= FLOW_PKT_ESTABLISHED; p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; f.alproto = ALPROTO_SSH; + f.proto = IPPROTO_TCP; StreamTcpInitConfig(TRUE); @@ -593,35 +596,39 @@ static int DetectSshSoftwareVersionTestDetect03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf1, sshlen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, + STREAM_TOSERVER, sshbuf1, sshlen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf2, sshlen2); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf2, sshlen2); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf3, sshlen3); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf3, sshlen3); if (r != 0) { printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, sshbuf4, sshlen4); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SSH, STREAM_TOSERVER, + sshbuf4, sshlen4); if (r != 0) { printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SshState *ssh_state = f.alstate; if (ssh_state == NULL) { @@ -659,15 +666,21 @@ static int DetectSshSoftwareVersionTestDetect03(void) /** * \brief this function registers unit tests for DetectSshSoftwareVersion */ -void DetectSshSoftwareVersionRegisterTests(void) +static void DetectSshSoftwareVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectSshSoftwareVersionTestParse01", DetectSshSoftwareVersionTestParse01, 1); - UtRegisterTest("DetectSshSoftwareVersionTestParse02", DetectSshSoftwareVersionTestParse02, 1); - UtRegisterTest("DetectSshSoftwareVersionTestParse03", DetectSshSoftwareVersionTestParse03, 1); - UtRegisterTest("DetectSshSoftwareVersionTestDetect01", DetectSshSoftwareVersionTestDetect01, 1); - UtRegisterTest("DetectSshSoftwareVersionTestDetect02", DetectSshSoftwareVersionTestDetect02, 1); - UtRegisterTest("DetectSshSoftwareVersionTestDetect03", DetectSshSoftwareVersionTestDetect03, 1); + UtRegisterTest("DetectSshSoftwareVersionTestParse01", + DetectSshSoftwareVersionTestParse01); + UtRegisterTest("DetectSshSoftwareVersionTestParse02", + DetectSshSoftwareVersionTestParse02); + UtRegisterTest("DetectSshSoftwareVersionTestParse03", + DetectSshSoftwareVersionTestParse03); + UtRegisterTest("DetectSshSoftwareVersionTestDetect01", + DetectSshSoftwareVersionTestDetect01); + UtRegisterTest("DetectSshSoftwareVersionTestDetect02", + DetectSshSoftwareVersionTestDetect02); + UtRegisterTest("DetectSshSoftwareVersionTestDetect03", + DetectSshSoftwareVersionTestDetect03); #endif /* UNITTESTS */ } diff --git a/src/detect-ssh-software-version.h b/src/detect-ssh-software-version.h index 70c37c745f91..7cf311167731 100644 --- a/src/detect-ssh-software-version.h +++ b/src/detect-ssh-software-version.h @@ -31,7 +31,6 @@ typedef struct DetectSshSoftwareVersionData_ { /* prototypes */ void DetectSshSoftwareVersionRegister(void); -void DetectSshSoftwareVersionRegisterTests(void); #endif /* __DETECT_SSH_SOFTWARE_VERSION_H__ */ diff --git a/src/detect-ssh-software.c b/src/detect-ssh-software.c new file mode 100644 index 000000000000..bf2a7e187643 --- /dev/null +++ b/src/detect-ssh-software.c @@ -0,0 +1,211 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup sshlayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + * + * Implements support ssh_software sticky buffer + */ + +#include "suricata-common.h" +#include "threads.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-content-inspection.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssh.h" + +#define KEYWORD_NAME "ssh_software" +#define KEYWORD_DOC "ssh-keywords#ssh-software" +#define BUFFER_NAME "ssh_software" +#define BUFFER_DESC "ssh software" +static int g_buffer_id = 0; + +/** \brief SSH Software Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshRequestSoftware(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->cli_hdr.software_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->cli_hdr.software_version); + const uint8_t *buffer = ssh_state->cli_hdr.software_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshRequestSoftwareRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshRequestSoftware, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (request)"); + return r; +} + +/** \brief SSH Software Mpm prefilter callback + * + * \param det_ctx detection engine thread ctx + * \param p packet to inspect + * \param f flow to inspect + * \param txv tx to inspect + * \param pectx inspection context + */ +static void PrefilterTxSshResponseSoftware(DetectEngineThreadCtx *det_ctx, + const void *pectx, + Packet *p, Flow *f, void *txv, + const uint64_t idx, const uint8_t flags) +{ + SCEnter(); + + const MpmCtx *mpm_ctx = (MpmCtx *)pectx; + const SshState *ssh_state = txv; + + if (ssh_state->srv_hdr.software_version == NULL) + return; + + uint32_t buffer_len = strlen((char *)ssh_state->srv_hdr.software_version); + const uint8_t *buffer = ssh_state->srv_hdr.software_version; + + if (buffer_len >= mpm_ctx->minlen) { + (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx, + &det_ctx->mtcu, &det_ctx->pmq, buffer, buffer_len); + } +} + +static int PrefilterTxSshResponseSoftwareRegister(SigGroupHead *sgh, MpmCtx *mpm_ctx) +{ + SCEnter(); + + int r = PrefilterAppendTxEngine(sgh, PrefilterTxSshResponseSoftware, + ALPROTO_SSH, SSH_STATE_BANNER_DONE, + mpm_ctx, NULL, KEYWORD_NAME " (response)"); + return r; +} + +static int InspectEngineSshSoftware(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, void *tx, uint64_t tx_id) +{ + uint8_t *software = NULL; + SshState *ssh_state = alstate; + + if (flags & STREAM_TOSERVER) + software = ssh_state->cli_hdr.software_version; + else if (flags & STREAM_TOCLIENT) + software = ssh_state->srv_hdr.software_version; + if (software == NULL) + goto end; + + uint32_t buffer_len = strlen((char *)software); + uint8_t *buffer = software; + if (buffer == NULL ||buffer_len == 0) + goto end; + + det_ctx->buffer_offset = 0; + det_ctx->discontinue_matching = 0; + det_ctx->inspection_recursion_counter = 0; + int r = DetectEngineContentInspection(de_ctx, det_ctx, s, smd, + f, + buffer, buffer_len, + 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL); + if (r == 1) + return DETECT_ENGINE_INSPECT_SIG_MATCH; + + end: + if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_SSH, tx, flags) >= SSH_STATE_BANNER_DONE) + return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH; + return DETECT_ENGINE_INSPECT_SIG_NO_MATCH; +} + +static int DetectSshSoftwareSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +{ + s->init_data->list = g_buffer_id; + return 0; +} + +static void DetectSshSoftwareSetupCallback(Signature *s) +{ + SCLogDebug("callback invoked by %u", s->id); + s->mask |= SIG_MASK_REQUIRE_SSH_STATE; +} + +void DetectSshSoftwareRegister(void) +{ + sigmatch_table[DETECT_AL_SSH_SOFTWARE].name = KEYWORD_NAME; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].desc = BUFFER_NAME " sticky buffer"; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].url = DOC_URL DOC_VERSION "/rules/" KEYWORD_DOC; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].Setup = DetectSshSoftwareSetup; + sigmatch_table[DETECT_AL_SSH_SOFTWARE].flags |= SIGMATCH_NOOPT ; + + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, + PrefilterTxSshRequestSoftwareRegister); + DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOCLIENT, 2, + PrefilterTxSshResponseSoftwareRegister); + + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOSERVER, + InspectEngineSshSoftware); + DetectAppLayerInspectEngineRegister(BUFFER_NAME, + ALPROTO_SSH, SIG_FLAG_TOCLIENT, + InspectEngineSshSoftware); + + DetectBufferTypeSetDescriptionByName(BUFFER_NAME, + BUFFER_DESC); + + DetectBufferTypeRegisterSetupCallback(BUFFER_NAME, + DetectSshSoftwareSetupCallback); + + g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME); +} diff --git a/src/detect-ssh-software.h b/src/detect-ssh-software.h new file mode 100644 index 000000000000..a741b87316a3 --- /dev/null +++ b/src/detect-ssh-software.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_SSH_SOFTWARE_H__ +#define __DETECT_SSH_SOFTWARE_H__ + +void DetectSshSoftwareRegister(void); + +#endif /* __DETECT_SSH_SOFTWARE_H__ */ diff --git a/src/detect-ssl-state.c b/src/detect-ssl-state.c index ade64358784f..841558818849 100644 --- a/src/detect-ssl-state.c +++ b/src/detect-ssl-state.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -51,19 +51,28 @@ #include "stream-tcp.h" #include "app-layer-ssl.h" -#define PARSE_REGEX1 "^\\s*([_a-zA-Z0-9]+)(.*)$" +#define PARSE_REGEX1 "^\\s*(!?)([_a-zA-Z0-9]+)(.*)$" static pcre *parse_regex1; static pcre_extra *parse_regex1_study; -#define PARSE_REGEX2 "^(?:\\s*[|]\\s*([_a-zA-Z0-9]+))(.*)$" +#define PARSE_REGEX2 "^(?:\\s*[|,]\\s*(!?)([_a-zA-Z0-9]+))(.*)$" static pcre *parse_regex2; static pcre_extra *parse_regex2_study; -int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); -int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); -void DetectSslStateRegisterTests(void); -void DetectSslStateFree(void *); +static int DetectSslStateMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); +static int DetectSslStateSetup(DetectEngineCtx *, Signature *, char *); +static void DetectSslStateRegisterTests(void); +static void DetectSslStateFree(void *); + +static int InspectTlsGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id); + +static int g_tls_generic_list_id = 0; /** * \brief Registers the keyword handlers for the "ssl_state" keyword. @@ -71,49 +80,35 @@ void DetectSslStateFree(void *); void DetectSslStateRegister(void) { sigmatch_table[DETECT_AL_SSL_STATE].name = "ssl_state"; - sigmatch_table[DETECT_AL_SSL_STATE].Match = NULL; - sigmatch_table[DETECT_AL_SSL_STATE].AppLayerMatch = DetectSslStateMatch; - sigmatch_table[DETECT_AL_SSL_STATE].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_SSL_STATE].AppLayerTxMatch = DetectSslStateMatch; sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup; sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree; sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests; - const char *eb; - int eo; - int opts = 0; + DetectSetupParseRegexes(PARSE_REGEX1, &parse_regex1, &parse_regex1_study); + DetectSetupParseRegexes(PARSE_REGEX2, &parse_regex2, &parse_regex2_study); - SCLogDebug("registering ssl_state rule option"); + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); - /* PARSE_REGEX1 */ - parse_regex1 = pcre_compile(PARSE_REGEX1, opts, &eb, &eo, NULL); - if (parse_regex1 == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX1, eo, eb); - goto error; - } - - parse_regex1_study = pcre_study(parse_regex1, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } + DetectBufferTypeSetDescriptionByName("tls_generic", + "generic ssl/tls inspection"); - /* PARSE_REGEX2 */ - parse_regex2 = pcre_compile(PARSE_REGEX2, opts, &eb, &eo, NULL); - if (parse_regex2 == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX2, eo, eb); - goto error; - } - - parse_regex2_study = pcre_study(parse_regex2, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } + DetectAppLayerInspectEngineRegister("tls_generic", + ALPROTO_TLS, SIG_FLAG_TOSERVER, + InspectTlsGeneric); + DetectAppLayerInspectEngineRegister("tls_generic", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + InspectTlsGeneric); +} -error: - return; +static int InspectTlsGeneric(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); } /** @@ -130,41 +125,24 @@ void DetectSslStateRegister(void) * \retval 1 Match. * \retval 0 No match. */ -int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *alstate, Signature *s, - SigMatch *m) +static int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *alstate, void *txv, + const Signature *s, const SigMatchCtx *m) { - int result = 1; - DetectSslStateData *ssd = (DetectSslStateData *)m->ctx; + const DetectSslStateData *ssd = (const DetectSslStateData *)m; SSLState *ssl_state = (SSLState *)alstate; if (ssl_state == NULL) { SCLogDebug("no app state, no match"); return 0; } - if ((ssd->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_HELLO)) { - result = 0; - goto end; - } - if ((ssd->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO)) { - result = 0; - goto end; - } - if ((ssd->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_CLIENT_KEYX)) { - result = 0; - goto end; - } - if ((ssd->flags & SSL_AL_FLAG_STATE_SERVER_KEYX) && - !(ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_KEYX)) { - result = 0; - goto end; + uint32_t ssl_flags = ssl_state->current_flags; + + if ((ssd->flags & ssl_flags) ^ ssd->mask) { + return 1; } - end: - return result; + return 0; } /** @@ -176,7 +154,7 @@ int DetectSslStateMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval ssd Pointer to DetectSslStateData on succese. * \retval NULL On failure. */ -DetectSslStateData *DetectSslStateParse(char *arg) +static DetectSslStateData *DetectSslStateParse(char *arg) { #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; @@ -184,7 +162,8 @@ DetectSslStateData *DetectSslStateParse(char *arg) int ov2[MAX_SUBSTRINGS]; const char *str1; const char *str2; - uint32_t flags = 0; + int negate = 0; + uint32_t flags = 0, mask = 0; DetectSslStateData *ssd = NULL; ret = pcre_exec(parse_regex1, parse_regex1_study, arg, strlen(arg), 0, 0, @@ -194,22 +173,41 @@ DetectSslStateData *DetectSslStateParse(char *arg) "ssl_state keyword.", arg); goto error; } + res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 1, &str1); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } + negate = !strcmp("!", str1); + pcre_free_substring(str1); + + res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 2, &str1); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } if (strcmp("client_hello", str1) == 0) { flags |= DETECT_SSL_STATE_CLIENT_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_HELLO; } else if (strcmp("server_hello", str1) == 0) { flags |= DETECT_SSL_STATE_SERVER_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_HELLO; } else if (strcmp("client_keyx", str1) == 0) { flags |= DETECT_SSL_STATE_CLIENT_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_KEYX; } else if (strcmp("server_keyx", str1) == 0) { flags |= DETECT_SSL_STATE_SERVER_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_KEYX; } else if (strcmp("unknown", str1) == 0) { flags |= DETECT_SSL_STATE_UNKNOWN; + if (negate) + mask |= DETECT_SSL_STATE_UNKNOWN; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" " "in ssl_state keyword.", str1); @@ -218,7 +216,7 @@ DetectSslStateData *DetectSslStateParse(char *arg) pcre_free_substring(str1); - res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 2, &str1); + res = pcre_get_substring((char *)arg, ov1, MAX_SUBSTRINGS, 3, &str1); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -231,28 +229,47 @@ DetectSslStateData *DetectSslStateParse(char *arg) "ssl_state keyword.", arg); goto error; } + res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 1, &str2); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + negate = !strcmp("!", str2); + pcre_free_substring(str2); + + res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 2, &str2); if (res <= 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } if (strcmp("client_hello", str2) == 0) { flags |= DETECT_SSL_STATE_CLIENT_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_HELLO; } else if (strcmp("server_hello", str2) == 0) { flags |= DETECT_SSL_STATE_SERVER_HELLO; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_HELLO; } else if (strcmp("client_keyx", str2) == 0) { flags |= DETECT_SSL_STATE_CLIENT_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_CLIENT_KEYX; } else if (strcmp("server_keyx", str2) == 0) { flags |= DETECT_SSL_STATE_SERVER_KEYX; + if (negate) + mask |= DETECT_SSL_STATE_SERVER_KEYX; } else if (strcmp("unknown", str2) == 0) { flags |= DETECT_SSL_STATE_UNKNOWN; + if (negate) + mask |= DETECT_SSL_STATE_UNKNOWN; } else { SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" " "in ssl_state keyword.", str2); goto error; } - res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 2, &str2); + res = pcre_get_substring((char *)str1, ov2, MAX_SUBSTRINGS, 3, &str2); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; @@ -261,17 +278,17 @@ DetectSslStateData *DetectSslStateParse(char *arg) pcre_free_substring(str1); str1 = str2; } + pcre_free_substring(str1); if ( (ssd = SCMalloc(sizeof(DetectSslStateData))) == NULL) { goto error; } ssd->flags = flags; + ssd->mask = mask; return ssd; error: - if (ssd != NULL) - DetectSslStateFree(ssd); return NULL; } @@ -286,11 +303,14 @@ DetectSslStateData *DetectSslStateParse(char *arg) * \retval 0 On success. * \retval -1 On failure. */ -int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) +static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { DetectSslStateData *ssd = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + ssd = DetectSslStateParse(arg); if (ssd == NULL) goto error; @@ -300,18 +320,9 @@ int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) goto error; sm->type = DETECT_AL_SSL_STATE; - sm->ctx = ssd; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, - "Rule contains conflicting keywords. Have non-tls alproto " - "set for a rule containing \"ssl_state\" keyword"); - goto error; - } - s->alproto = ALPROTO_TLS; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + sm->ctx = (SigMatchCtx*)ssd; + SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); return 0; error: @@ -327,7 +338,7 @@ int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) * * \param ptr pointer to the data to be freed. */ -void DetectSslStateFree(void *ptr) +static void DetectSslStateFree(void *ptr) { if (ptr != NULL) SCFree(ptr); @@ -339,103 +350,69 @@ void DetectSslStateFree(void *ptr) #ifdef UNITTESTS -int DetectSslStateTest01(void) +static int DetectSslStateTest01(void) { DetectSslStateData *ssd = DetectSslStateParse("client_hello"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == DETECT_SSL_STATE_CLIENT_HELLO) { - SCFree(ssd); - return 1; - } - - return 0; + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == DETECT_SSL_STATE_CLIENT_HELLO); + SCFree(ssd); + PASS; } -int DetectSslStateTest02(void) +static int DetectSslStateTest02(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_hello"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | - DETECT_SSL_STATE_CLIENT_HELLO)) { - SCFree(ssd); - return 1; - } - - return 0; + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_hello"); + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + DETECT_SSL_STATE_CLIENT_HELLO)); + SCFree(ssd); + PASS; } -int DetectSslStateTest03(void) +static int DetectSslStateTest03(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " "client_hello"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | - DETECT_SSL_STATE_CLIENT_HELLO)) { - SCFree(ssd); - return 1; - } - - return 0; + DETECT_SSL_STATE_CLIENT_HELLO)); + SCFree(ssd); + PASS; } -int DetectSslStateTest04(void) +static int DetectSslStateTest04(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " - "client_hello | server_keyx | " + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " + "client_hello , server_keyx , " "unknown"); - if (ssd == NULL) { - printf("ssd == NULL\n"); - return 0; - } - if (ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | DETECT_SSL_STATE_CLIENT_KEYX | DETECT_SSL_STATE_CLIENT_HELLO | DETECT_SSL_STATE_SERVER_KEYX | - DETECT_SSL_STATE_UNKNOWN)) { - SCFree(ssd); - return 1; - } - - return 0; + DETECT_SSL_STATE_UNKNOWN)); + SCFree(ssd); + PASS; } -int DetectSslStateTest05(void) +static int DetectSslStateTest05(void) { - DetectSslStateData *ssd = DetectSslStateParse("| server_hello | client_keyx | " - "client_hello | server_keyx | " + DetectSslStateData *ssd = DetectSslStateParse(", server_hello , client_keyx , " + "client_hello , server_keyx , " "unknown"); - if (ssd != NULL) { - printf("ssd != NULL - failure\n"); - SCFree(ssd); - return 0; - } - - return 1; + FAIL_IF_NOT_NULL(ssd); + PASS; } -int DetectSslStateTest06(void) +static int DetectSslStateTest06(void) { - DetectSslStateData *ssd = DetectSslStateParse("server_hello | client_keyx | " - "client_hello | server_keyx | " - "unknown | "); - if (ssd != NULL) { - printf("ssd != NULL - failure\n"); - SCFree(ssd); - return 0; - } - - return 1; + DetectSslStateData *ssd = DetectSslStateParse("server_hello , client_keyx , " + "client_hello , server_keyx , " + "unknown , "); + FAIL_IF_NOT_NULL(ssd); + PASS; } /** @@ -688,7 +665,6 @@ static int DetectSslStateTest07(void) }; uint32_t toserver_app_data_buf_len = sizeof(toserver_app_data_buf); - int result = 0; Signature *s = NULL; ThreadVars th_v; Packet *p = NULL; @@ -719,168 +695,127 @@ static int DetectSslStateTest07(void) StreamTcpInitConfig(TRUE); de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; ssl_state:client_hello; " "sid:1;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " - "ssl_state:client_hello | server_hello; " + "ssl_state:server_hello; " "sid:2;)"); - if (s == NULL) - goto end; + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(msg:\"ssl state\"; " + "ssl_state:client_keyx; " + "sid:3;)"); + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " - "ssl_state:client_hello | server_hello | " - "client_keyx; sid:3;)"); - if (s == NULL) - goto end; + "ssl_state:server_keyx; " + "sid:4;)"); + FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"ssl state\"; " - "ssl_state:client_hello | server_hello | " - "client_keyx | server_keyx; sid:4;)"); - if (s == NULL) - goto end; + "ssl_state:!client_hello; " + "sid:5;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER | STREAM_START, chello_buf, + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER | STREAM_START, chello_buf, chello_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF(ssl_state == NULL); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, shello_buf, - shello_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + FAIL_IF(PacketAlertCheck(p, 5)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + shello_buf, shello_buf_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; + p->flowflags = (FLOW_PKT_TOCLIENT | FLOW_PKT_ESTABLISHED); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (!PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, client_change_cipher_spec_buf, + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(!PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + FAIL_IF(!PacketAlertCheck(p, 5)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_change_cipher_spec_buf, client_change_cipher_spec_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (!PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, server_change_cipher_spec_buf, + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(!PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_change_cipher_spec_buf, server_change_cipher_spec_buf_len); - if (r != 0) { - printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, toserver_app_data_buf, - toserver_app_data_buf_len); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + toserver_app_data_buf, toserver_app_data_buf_len); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); /* do detect */ p->alerts.cnt = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - goto end; - if (PacketAlertCheck(p, 2)) - goto end; - if (PacketAlertCheck(p, 3)) - goto end; - if (PacketAlertCheck(p, 4)) - goto end; - - result = 1; + FAIL_IF(PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + FAIL_IF(PacketAlertCheck(p, 3)); + FAIL_IF(PacketAlertCheck(p, 4)); - end: if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); @@ -892,22 +827,58 @@ static int DetectSslStateTest07(void) StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + PASS; +} + +/** + * \brief Test that the "|" character still works as a separate for + * compatibility with older Suricata rules. + */ +static int DetectSslStateTest08(void) +{ + DetectSslStateData *ssd = DetectSslStateParse("server_hello|client_hello"); + FAIL_IF_NULL(ssd); + FAIL_IF_NOT(ssd->flags == (DETECT_SSL_STATE_SERVER_HELLO | + DETECT_SSL_STATE_CLIENT_HELLO)); + SCFree(ssd); + PASS; +} + +/** + * \test Test parsing of negated states. + */ +static int DetectSslStateTestParseNegate(void) +{ + DetectSslStateData *ssd = DetectSslStateParse("!client_hello"); + FAIL_IF_NULL(ssd); + uint32_t expected = DETECT_SSL_STATE_CLIENT_HELLO; + FAIL_IF(ssd->flags != expected || ssd->mask != expected); + SCFree(ssd); + + ssd = DetectSslStateParse("!client_hello,!server_hello"); + FAIL_IF_NULL(ssd); + expected = DETECT_SSL_STATE_CLIENT_HELLO | DETECT_SSL_STATE_SERVER_HELLO; + FAIL_IF(ssd->flags != expected || ssd->mask != expected); + SCFree(ssd); + + PASS; } #endif /* UNITTESTS */ -void DetectSslStateRegisterTests(void) +static void DetectSslStateRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSslStateTest01", DetectSslStateTest01, 1); - UtRegisterTest("DetectSslStateTest02", DetectSslStateTest02, 1); - UtRegisterTest("DetectSslStateTest03", DetectSslStateTest03, 1); - UtRegisterTest("DetectSslStateTest04", DetectSslStateTest04, 1); - UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05, 1); - UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06, 1); - UtRegisterTest("DetectSslStateTest07", DetectSslStateTest07, 1); + UtRegisterTest("DetectSslStateTest01", DetectSslStateTest01); + UtRegisterTest("DetectSslStateTest02", DetectSslStateTest02); + UtRegisterTest("DetectSslStateTest03", DetectSslStateTest03); + UtRegisterTest("DetectSslStateTest04", DetectSslStateTest04); + UtRegisterTest("DetectSslStateTest05", DetectSslStateTest05); + UtRegisterTest("DetectSslStateTest06", DetectSslStateTest06); + UtRegisterTest("DetectSslStateTest07", DetectSslStateTest07); + UtRegisterTest("DetectSslStateTest08", DetectSslStateTest08); + UtRegisterTest("DetectSslStateTestParseNegate", + DetectSslStateTestParseNegate); #endif - return; } diff --git a/src/detect-ssl-state.h b/src/detect-ssl-state.h index a9c69a158b56..9246d8f34767 100644 --- a/src/detect-ssl-state.h +++ b/src/detect-ssl-state.h @@ -35,6 +35,7 @@ typedef struct DetectSslStateData_ { uint32_t flags; + uint32_t mask; } DetectSslStateData; void DetectSslStateRegister(void); diff --git a/src/detect-ssl-version.c b/src/detect-ssl-version.c index 599d26b87764..82ac3632eb8e 100644 --- a/src/detect-ssl-version.c +++ b/src/detect-ssl-version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -60,11 +60,13 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, Flow *, - uint8_t, void *, Signature *, SigMatch *); +static int DetectSslVersionMatch(ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, char *); -void DetectSslVersionRegisterTests(void); -void DetectSslVersionFree(void *); +static void DetectSslVersionRegisterTests(void); +static void DetectSslVersionFree(void *); +static int g_tls_generic_list_id = 0; /** * \brief Registration function for keyword: ssl_version @@ -72,36 +74,14 @@ void DetectSslVersionFree(void *); void DetectSslVersionRegister(void) { sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version"; - sigmatch_table[DETECT_AL_SSL_VERSION].Match = NULL; - sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerMatch = DetectSslVersionMatch; - sigmatch_table[DETECT_AL_SSL_VERSION].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch; sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup; sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree; sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - SCLogDebug("registering ssl_version rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); } /** @@ -115,8 +95,9 @@ void DetectSslVersionRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); @@ -124,7 +105,7 @@ int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, uint16_t ver = 0; uint8_t sig_ver = TLS_UNKNOWN; - DetectSslVersionData *ssl = (DetectSslVersionData *)m->ctx; + const DetectSslVersionData *ssl = (const DetectSslVersionData *)m; SSLState *app_state = (SSLState *)state; if (app_state == NULL) { SCLogDebug("no app state, no match"); @@ -184,7 +165,7 @@ int DetectSslVersionMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, * \retval ssl pointer to DetectSslVersionData on success * \retval NULL on failure */ -DetectSslVersionData *DetectSslVersionParse(char *str) +static DetectSslVersionData *DetectSslVersionParse(char *str) { DetectSslVersionData *ssl = NULL; #define MAX_SUBSTRINGS 30 @@ -200,7 +181,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) } if (ret > 1) { - const char *str_ptr[5]; + const char *str_ptr; char *orig; uint8_t found = 0, neg = 0; char *tmp_str; @@ -212,7 +193,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) int i; for (i = 1; i < ret; i++) { - res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr[i]); + res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); if (found == 0) @@ -220,7 +201,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) break; } - orig = SCStrdup((char*) str_ptr[i]); + orig = SCStrdup((char*) str_ptr); if (unlikely(orig == NULL)) { goto error; } @@ -272,6 +253,7 @@ DetectSslVersionData *DetectSslVersionParse(char *str) found = 1; neg = 0; SCFree(orig); + pcre_free_substring(str_ptr); } } @@ -300,6 +282,9 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectSslVersionData *ssl = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + ssl = DetectSslVersionParse(str); if (ssl == NULL) goto error; @@ -313,14 +298,7 @@ static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_SSL_VERSION; sm->ctx = (void *)ssl; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - - s->alproto = ALPROTO_TLS; + SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); return 0; error: @@ -350,16 +328,14 @@ void DetectSslVersionFree(void *ptr) * \test DetectSslVersionTestParse01 is a test to make sure that we parse the * "ssl_version" option correctly when given valid ssl_version option */ -int DetectSslVersionTestParse01(void) +static int DetectSslVersionTestParse01(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3"); - if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3) { - DetectSslVersionFree(ssl); - return 1; - } - - return 0; + FAIL_IF_NULL(ssl); + FAIL_IF_NOT(ssl->data[SSLv3].ver == SSL_VERSION_3); + DetectSslVersionFree(ssl); + PASS; } /** @@ -367,36 +343,30 @@ int DetectSslVersionTestParse01(void) * "ssl_version" option correctly when given an invalid ssl_version option * it should return ssl = NULL */ -int DetectSslVersionTestParse02(void) +static int DetectSslVersionTestParse02(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("2.5"); - if (ssl == NULL) { - DetectSslVersionFree(ssl); - return 1; - } - - return 0; + FAIL_IF_NOT_NULL(ssl); + DetectSslVersionFree(ssl); + PASS; } /** * \test DetectSslVersionTestParse03 is a test to make sure that we parse the * "ssl_version" options correctly when given valid ssl_version options */ -int DetectSslVersionTestParse03(void) +static int DetectSslVersionTestParse03(void) { DetectSslVersionData *ssl = NULL; ssl = DetectSslVersionParse("SSlv3,tls1.0, !tls1.2"); - if (ssl != NULL && ssl->data[SSLv3].ver == SSL_VERSION_3 && - ssl->data[TLS10].ver == TLS_VERSION_10 && - ssl->data[TLS12].ver == TLS_VERSION_12 && - ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED) - { - DetectSslVersionFree(ssl); - return 1; - } - - return 0; + FAIL_IF_NULL(ssl); + FAIL_IF_NOT(ssl->data[SSLv3].ver == SSL_VERSION_3); + FAIL_IF_NOT(ssl->data[TLS10].ver == TLS_VERSION_10); + FAIL_IF_NOT(ssl->data[TLS12].ver == TLS_VERSION_12); + FAIL_IF_NOT(ssl->data[TLS12].flags & DETECT_SSL_VERSION_NEGATED); + DetectSslVersionFree(ssl); + PASS; } #include "stream-tcp-reassemble.h" @@ -404,7 +374,6 @@ int DetectSslVersionTestParse03(void) /** \test Send a get request in three chunks + more data. */ static int DetectSslVersionTestDetect01(void) { - int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); @@ -439,65 +408,40 @@ static int DetectSslVersionTestDetect01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, sslbuf1, ssllen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf2, ssllen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf3, ssllen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf4, ssllen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != 0x16); - if (app_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != TLS_VERSION_10); SCLogDebug("app_state is at %p, app_state->server_connp.version 0x%02X app_state->client_connp.version 0x%02X", app_state, app_state->server_connp.version, app_state->client_connp.version); @@ -505,18 +449,9 @@ static int DetectSslVersionTestDetect01(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - goto end; - } - - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + AppLayerParserThreadCtxFree(alp_tctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); @@ -524,12 +459,12 @@ static int DetectSslVersionTestDetect01(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectSslVersionTestDetect02(void) { - int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); @@ -564,93 +499,59 @@ static int DetectSslVersionTestDetect02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, sslbuf1, ssllen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf2, ssllen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf3, ssllen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf4, ssllen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != 0x16); - if (app_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } - - result = 1; + FAIL_IF_NOT(PacketAlertCheck(p, 1)); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + AppLayerParserThreadCtxFree(alp_tctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectSslVersionTestDetect03(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Flow f; uint8_t sslbuf1[] = { 0x16 }; uint32_t ssllen1 = sizeof(sslbuf1); @@ -686,10 +587,7 @@ static int DetectSslVersionTestDetect03(void) StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); - if (stream_msg == NULL) { - printf("no stream_msg: "); - goto end; - } + FAIL_IF_NULL(stream_msg); memcpy(stream_msg->data, sslbuf4, ssllen4); stream_msg->data_len = ssllen4; @@ -698,90 +596,55 @@ static int DetectSslVersionTestDetect03(void) ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; ssl_version:tls1.0; content:\"|01 00 00 AD|\"; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf1, ssllen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, sslbuf1, ssllen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf2, ssllen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf2, ssllen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf3, ssllen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf3, ssllen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, sslbuf4, ssllen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + sslbuf4, ssllen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SSLState *app_state = f.alstate; - if (app_state == NULL) { - printf("no ssl state: "); - goto end; - } + FAIL_IF_NULL(app_state); - if (app_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", 0x16, app_state->client_connp.content_type); - goto end; - } + FAIL_IF(app_state->client_connp.content_type != 0x16); - if (app_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", TLS_VERSION_10, app_state->client_connp.version); - goto end; - } + FAIL_IF(app_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } - - result = 1; + FAIL_IF_NOT(PacketAlertCheck(p, 1)); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } #endif /* UNITTESTS */ @@ -789,15 +652,18 @@ static int DetectSslVersionTestDetect03(void) /** * \brief this function registers unit tests for DetectSslVersion */ -void DetectSslVersionRegisterTests(void) +static void DetectSslVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01, 1); - UtRegisterTest("DetectSslVersionTestParse02", DetectSslVersionTestParse02, 1); - UtRegisterTest("DetectSslVersionTestParse03", DetectSslVersionTestParse03, 1); - UtRegisterTest("DetectSslVersionTestDetect01", DetectSslVersionTestDetect01, 1); - UtRegisterTest("DetectSslVersionTestDetect02", DetectSslVersionTestDetect02, 1); - UtRegisterTest("DetectSslVersionTestDetect03", DetectSslVersionTestDetect03, 1); + UtRegisterTest("DetectSslVersionTestParse01", DetectSslVersionTestParse01); + UtRegisterTest("DetectSslVersionTestParse02", DetectSslVersionTestParse02); + UtRegisterTest("DetectSslVersionTestParse03", DetectSslVersionTestParse03); + UtRegisterTest("DetectSslVersionTestDetect01", + DetectSslVersionTestDetect01); + UtRegisterTest("DetectSslVersionTestDetect02", + DetectSslVersionTestDetect02); + UtRegisterTest("DetectSslVersionTestDetect03", + DetectSslVersionTestDetect03); #endif /* UNITTESTS */ return; diff --git a/src/detect-stream_size.c b/src/detect-stream_size.c index 200ce76b5a91..529139d5c83d 100644 --- a/src/detect-stream_size.c +++ b/src/detect-stream_size.c @@ -44,7 +44,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ -int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectStreamSizeMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectStreamSizeSetup (DetectEngineCtx *, Signature *, char *); void DetectStreamSizeFree(void *); void DetectStreamSizeRegisterTests(void); @@ -57,33 +58,13 @@ void DetectStreamSizeRegister(void) { sigmatch_table[DETECT_STREAM_SIZE].name = "stream_size"; sigmatch_table[DETECT_STREAM_SIZE].desc = "match on amount of bytes of a stream"; - sigmatch_table[DETECT_STREAM_SIZE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Flow-keywords#stream_size"; + sigmatch_table[DETECT_STREAM_SIZE].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#stream-size"; sigmatch_table[DETECT_STREAM_SIZE].Match = DetectStreamSizeMatch; sigmatch_table[DETECT_STREAM_SIZE].Setup = DetectStreamSizeSetup; sigmatch_table[DETECT_STREAM_SIZE].Free = DetectStreamSizeFree; sigmatch_table[DETECT_STREAM_SIZE].RegisterTests = DetectStreamSizeRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) SCFree(parse_regex); - if (parse_regex_study != NULL) SCFree(parse_regex_study); - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -141,11 +122,12 @@ static int DetectStreamSizeCompare (uint32_t diff, uint32_t stream_size, uint8_t * \retval 0 no match * \retval 1 match */ -int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectStreamSizeMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { int ret = 0; - DetectStreamSizeData *sd = (DetectStreamSizeData *) m->ctx; + const DetectStreamSizeData *sd = (const DetectStreamSizeData *)ctx; if (!(PKT_IS_TCP(p))) return ret; @@ -244,19 +226,19 @@ DetectStreamSizeData *DetectStreamSizeParse (char *streamstr) if (strlen(mode) == 0) goto error; - if (mode[0] == '<') + if (mode[0] == '=') { + sd->mode = DETECTSSIZE_EQ; + } else if (mode[0] == '<') { sd->mode = DETECTSSIZE_LT; - else if (strcmp("<=", mode) == 0) - sd->mode = DETECTSSIZE_LEQ; - else if (mode[0] == '>') + if (strcmp("<=", mode) == 0) + sd->mode = DETECTSSIZE_LEQ; + } else if (mode[0] == '>') { sd->mode = DETECTSSIZE_GT; - else if (strcmp(">=", mode) == 0) - sd->mode = DETECTSSIZE_GEQ; - else if (strcmp("!=", mode) == 0) + if (strcmp(">=", mode) == 0) + sd->mode = DETECTSSIZE_GEQ; + } else if (strcmp("!=", mode) == 0) { sd->mode = DETECTSSIZE_NEQ; - else if (mode[0] == '=') - sd->mode = DETECTSSIZE_EQ; - else { + } else { SCLogError(SC_ERR_INVALID_OPERATOR, "Invalid operator"); goto error; } @@ -320,7 +302,7 @@ static int DetectStreamSizeSetup (DetectEngineCtx *de_ctx, Signature *s, char *s goto error; sm->type = DETECT_STREAM_SIZE; - sm->ctx = (void *)sd; + sm->ctx = (SigMatchCtx *)sd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); @@ -374,7 +356,7 @@ static int DetectStreamSizeParseTest02 (void) DetectStreamSizeData *sd = NULL; sd = DetectStreamSizeParse("invalidoption,<,6"); if (sd != NULL) { - printf("expected: NULL got 0x%02X %" PRId16 ": ",sd->flags, sd->ssize); + printf("expected: NULL got 0x%02X %" PRIu32 ": ",sd->flags, sd->ssize); result = 0; DetectStreamSizeFree(sd); } @@ -447,9 +429,9 @@ static int DetectStreamSizeParseTest03 (void) f.protoctx = &ssn; p->flow = &f; p->tcph = &tcph; - sm.ctx = sd; + sm.ctx = (SigMatchCtx*)sd; - result = DetectStreamSizeMatch(&tv, &dtx, p, &s, &sm); + result = DetectStreamSizeMatch(&tv, &dtx, p, &s, sm.ctx); if (result == 0) { printf("result 0 != 1: "); } @@ -507,9 +489,9 @@ static int DetectStreamSizeParseTest04 (void) f.protoctx = &ssn; p->flow = &f; p->ip4h = &ip4h; - sm.ctx = sd; + sm.ctx = (SigMatchCtx*)sd; - if (!DetectStreamSizeMatch(&tv, &dtx, p, &s, &sm)) + if (!DetectStreamSizeMatch(&tv, &dtx, p, &s, sm.ctx)) result = 1; SCFree(p); @@ -523,10 +505,10 @@ static int DetectStreamSizeParseTest04 (void) void DetectStreamSizeRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01, 1); - UtRegisterTest("DetectStreamSizeParseTest02", DetectStreamSizeParseTest02, 1); - UtRegisterTest("DetectStreamSizeParseTest03", DetectStreamSizeParseTest03, 1); - UtRegisterTest("DetectStreamSizeParseTest04", DetectStreamSizeParseTest04, 1); + UtRegisterTest("DetectStreamSizeParseTest01", DetectStreamSizeParseTest01); + UtRegisterTest("DetectStreamSizeParseTest02", DetectStreamSizeParseTest02); + UtRegisterTest("DetectStreamSizeParseTest03", DetectStreamSizeParseTest03); + UtRegisterTest("DetectStreamSizeParseTest04", DetectStreamSizeParseTest04); #endif /* UNITTESTS */ } diff --git a/src/detect-tag.c b/src/detect-tag.c index 5e0f85ffe81a..b844deb7eefd 100644 --- a/src/detect-tag.c +++ b/src/detect-tag.c @@ -57,7 +57,8 @@ SC_ATOMIC_EXTERN(unsigned int, num_tags); static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectTagMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectTagMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectTagSetup(DetectEngineCtx *, Signature *, char *); void DetectTagRegisterTests(void); void DetectTagDataFree(void *); @@ -74,28 +75,7 @@ void DetectTagRegister(void) sigmatch_table[DETECT_TAG].RegisterTests = DetectTagRegisterTests; sigmatch_table[DETECT_TAG].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -109,9 +89,10 @@ void DetectTagRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTagMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectTagMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - DetectTagData *td = (DetectTagData *) m->ctx; + const DetectTagData *td = (const DetectTagData *)ctx; DetectTagDataEntry tde; memset(&tde, 0, sizeof(DetectTagDataEntry)); @@ -313,7 +294,7 @@ int DetectTagSetup(DetectEngineCtx *de_ctx, Signature *s, char *tagstr) goto error; sm->type = DETECT_TAG; - sm->ctx = (void *)td; + sm->ctx = (SigMatchCtx *)td; /* Append it to the list of tags */ SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_TMATCH); @@ -477,11 +458,11 @@ static int DetectTagTestParse05(void) void DetectTagRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTagTestParse01", DetectTagTestParse01, 1); - UtRegisterTest("DetectTagTestParse02", DetectTagTestParse02, 1); - UtRegisterTest("DetectTagTestParse03", DetectTagTestParse03, 1); - UtRegisterTest("DetectTagTestParse04", DetectTagTestParse04, 1); - UtRegisterTest("DetectTagTestParse05", DetectTagTestParse05, 1); + UtRegisterTest("DetectTagTestParse01", DetectTagTestParse01); + UtRegisterTest("DetectTagTestParse02", DetectTagTestParse02); + UtRegisterTest("DetectTagTestParse03", DetectTagTestParse03); + UtRegisterTest("DetectTagTestParse04", DetectTagTestParse04); + UtRegisterTest("DetectTagTestParse05", DetectTagTestParse05); DetectEngineTagRegisterTests(); #endif /* UNITTESTS */ diff --git a/src/detect-template-buffer.c b/src/detect-template-buffer.c new file mode 100644 index 000000000000..aba807cbe24d --- /dev/null +++ b/src/detect-template-buffer.c @@ -0,0 +1,176 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * TODO: Update the \author in this file and detect-template-buffer.h. + * TODO: Update description in the \file section below. + * TODO: Remove SCLogNotice statements or convert to debug. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Set up of the "template_buffer" keyword to allow content + * inspections on the decoded template application layer buffers. + */ + +#include "suricata-common.h" +#include "conf.h" +#include "detect.h" +#include "detect-engine.h" +#include "app-layer-template.h" +#include "detect-engine-template.h" + +static int DetectTemplateBufferSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTemplateBufferRegisterTests(void); +static int g_template_buffer_id = 0; + +void DetectTemplateBufferRegister(void) +{ + /* TEMPLATE_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + /* TEMPLATE_END_REMOVE */ + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template_buffer"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc = + "Template content modififier to match on the template buffers"; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateBufferSetup; + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = + DetectTemplateBufferRegisterTests; + + sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT; + + /* register inspect engines */ + DetectAppLayerInspectEngineRegister("template_buffer", + ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, + DetectEngineInspectTemplateBuffer); + DetectAppLayerInspectEngineRegister("template_buffer", + ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, + DetectEngineInspectTemplateBuffer); + + g_template_buffer_id = DetectBufferTypeGetByName("template_buffer"); + + SCLogNotice("Template application layer detect registered."); +} + +static int DetectTemplateBufferSetup(DetectEngineCtx *de_ctx, Signature *s, + char *str) +{ + s->init_data->list = g_template_buffer_id; + s->alproto = ALPROTO_TEMPLATE; + return 0; +} + +#ifdef UNITTESTS + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "app-layer-parser.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "flow-util.h" +#include "stream-tcp.h" + +static int DetectTemplateBufferTest(void) +{ + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + Flow f; + Packet *p; + TcpSession tcp; + ThreadVars tv; + Signature *s; + + uint8_t request[] = "Hello World!"; + + /* Setup flow. */ + memset(&f, 0, sizeof(Flow)); + memset(&tcp, 0, sizeof(TcpSession)); + memset(&tv, 0, sizeof(ThreadVars)); + p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP); + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_TEMPLATE; + f.protoctx = (void *)&tcp; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + /* This rule should match. */ + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"World!\"; " + "sid:1; rev:1;)"); + FAIL_IF_NULL(s); + + /* This rule should not match. */ + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "msg:\"TEMPLATE Test Rule\"; " + "template_buffer; content:\"W0rld!\"; " + "sid:2; rev:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TEMPLATE, + STREAM_TOSERVER, request, sizeof(request)); + FLOWLOCK_UNLOCK(&f); + + /* Check that we have app-layer state. */ + FAIL_IF_NULL(f.alstate); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + FAIL_IF(!PacketAlertCheck(p, 1)); + FAIL_IF(PacketAlertCheck(p, 2)); + + /* Cleanup. */ + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + PASS; +} + +#endif + +static void DetectTemplateBufferRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTemplateBufferTest", DetectTemplateBufferTest); +#endif /* UNITTESTS */ +} diff --git a/src/detect-template-buffer.h b/src/detect-template-buffer.h new file mode 100644 index 000000000000..4385e443082c --- /dev/null +++ b/src/detect-template-buffer.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author FirstName LastName + */ + +#ifndef __DETECT_TEMPLATE_BUFFER_H__ +#define __DETECT_TEMPLATE_BUFFER_H__ + +#include "app-layer-template.h" + +void DetectTemplateBufferRegister(void); + +#endif /* __DETECT_TEMPLATE_BUFFER_H__ */ diff --git a/src/detect-template.c b/src/detect-template.c new file mode 100644 index 000000000000..b3aff67bde3e --- /dev/null +++ b/src/detect-template.c @@ -0,0 +1,264 @@ +/* Copyright (C) 2015-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author XXX Yourname + * + * XXX Short description of the purpose of this keyword + */ + +#include "suricata-common.h" +#include "util-unittest.h" + +#include "detect-parse.h" +#include "detect-engine.h" + +#include "detect-template.h" + +/** + * \brief Regex for parsing our keyword options + */ +#define PARSE_REGEX "^\\s*([0-9]+)?\\s*,s*([0-9]+)?\\s*$" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +/* Prototypes of functions registered in DetectTemplateRegister below */ +static int DetectTemplateMatch (ThreadVars *, DetectEngineThreadCtx *, + Packet *, const Signature *, const SigMatchCtx *); +static int DetectTemplateSetup (DetectEngineCtx *, Signature *, char *); +static void DetectTemplateFree (void *); +static void DetectTemplateRegisterTests (void); + +/** + * \brief Registration function for template: keyword + * + * This function is called once in the 'lifetime' of the engine. + */ +void DetectTemplateRegister(void) { + /* keyword name: this is how the keyword is used in a rule */ + sigmatch_table[DETECT_TEMPLATE].name = "template"; + /* description: listed in "suricata --list-keywords=all" */ + sigmatch_table[DETECT_TEMPLATE].desc = "give an introduction into how a detection module works"; + /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ + sigmatch_table[DETECT_TEMPLATE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Developers_Guide"; + /* match function is called when the signature is inspected on a packet */ + sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch; + /* setup function is called during signature parsing, when the template + * keyword is encountered in the rule */ + sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup; + /* free function is called when the detect engine is freed. Normally at + * shutdown, but also during rule reloads. */ + sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree; + /* registers unittests into the system */ + sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; + + /* set up the PCRE for keyword parsing */ + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} + +/** + * \brief This function is used to match TEMPLATE rule option on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch with context that we will cast into DetectTemplateData + * + * \retval 0 no match + * \retval 1 match + */ +static int DetectTemplateMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) +{ + int ret = 0; + const DetectTemplateData *templated = (const DetectTemplateData *) ctx; +#if 0 + if (PKT_IS_PSEUDOPKT(p)) { + /* fake pkt */ + } + + if (PKT_IS_IPV4(p)) { + /* ipv4 pkt */ + } else if (PKT_IS_IPV6(p)) { + /* ipv6 pkt */ + } else { + SCLogDebug("packet is of not IPv4 or IPv6"); + return ret; + } +#endif + /* packet payload access */ + if (p->payload != NULL && p->payload_len > 0) { + if (templated->arg1 == p->payload[0] && + templated->arg2 == p->payload[p->payload_len - 1]) + { + ret = 1; + } + } + + return ret; +} + +/** + * \brief This function is used to parse template options passed via template: keyword + * + * \param templatestr Pointer to the user provided template options + * + * \retval templated pointer to DetectTemplateData on success + * \retval NULL on failure + */ +static DetectTemplateData *DetectTemplateParse (const char *templatestr) +{ + DetectTemplateData *templated = NULL; + char arg1[4] = ""; + char arg2[4] = ""; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + + ret = pcre_exec(parse_regex, parse_regex_study, + templatestr, strlen(templatestr), + 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 3) { + SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); + goto error; + } + + res = pcre_copy_substring((char *) templatestr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("Arg1 \"%s\"", arg1); + + if (ret >= 3) { + res = pcre_copy_substring((char *) templatestr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("Arg2 \"%s\"", arg2); + + } + + templated = SCMalloc(sizeof (DetectTemplateData)); + if (unlikely(templated == NULL)) + goto error; + templated->arg1 = (uint8_t)atoi(arg1); + templated->arg2 = (uint8_t)atoi(arg2); + + return templated; + +error: + if (templated) + SCFree(templated); + return NULL; +} + +/** + * \brief parse the options from the 'template' keyword in the rule into + * the Signature data structure. + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param templatestr pointer to the user provided template options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, char *templatestr) +{ + DetectTemplateData *templated = NULL; + SigMatch *sm = NULL; + + templated = DetectTemplateParse(templatestr); + if (templated == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_TEMPLATE; + sm->ctx = (void *)templated; + + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + s->flags |= SIG_FLAG_REQUIRE_PACKET; + + return 0; + +error: + if (templated != NULL) + DetectTemplateFree(templated); + if (sm != NULL) + SCFree(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectTemplateData + * + * \param ptr pointer to DetectTemplateData + */ +static void DetectTemplateFree(void *ptr) { + DetectTemplateData *templated = (DetectTemplateData *)ptr; + + /* do more specific cleanup here, if needed */ + + SCFree(templated); +} + +#ifdef UNITTESTS + +/** + * \test description of the test + */ + +static int DetectTemplateParseTest01 (void) +{ + DetectTemplateData *templated = DetectTemplateParse("1,10"); + FAIL_IF_NULL(templated); + FAIL_IF(!(templated->arg1 == 1 && templated->arg2 == 10)); + DetectTemplateFree(templated); + PASS; +} + +static int DetectTemplateSignatureTest01 (void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (template:1,10; sid:1; rev:1;)"); + FAIL_IF_NULL(sig); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for DetectTemplate + */ +void DetectTemplateRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("DetectTemplateParseTest01", DetectTemplateParseTest01); + UtRegisterTest("DetectTemplateSignatureTest01", + DetectTemplateSignatureTest01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-template.h b/src/detect-template.h new file mode 100644 index 000000000000..6b2b4435ef80 --- /dev/null +++ b/src/detect-template.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2015-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author XXX Yourname + */ + +#ifndef __DETECT_TEMPLATE_H__ +#define __DETECT_TEMPLATE_H__ + +/** Per keyword data. This is set up by the DetectTemplateSetup() function. + * Each signature will have an instance of DetectTemplateData per occurence + * of the keyword. + * The structure should be considered static/readonly after initialization. + */ +typedef struct DetectTemplateData_ { + uint8_t arg1; + uint8_t arg2; +} DetectTemplateData; + +/** \brief registers the keyword into the engine. Called from + * detect.c::SigTableSetup() */ +void DetectTemplateRegister(void); + +#endif /* __DETECT_TEMPLATE_H__ */ diff --git a/src/detect-threshold.c b/src/detect-threshold.c index 08eadbebda47..3632d4d4d187 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -48,7 +48,6 @@ #include "detect-threshold.h" #include "detect-engine-threshold.h" -#include "detect-parse.h" #include "detect-engine-address.h" #include "util-unittest.h" @@ -65,7 +64,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -static int DetectThresholdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectThresholdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectThresholdSetup(DetectEngineCtx *, Signature *, char *); static void DetectThresholdFree(void *); @@ -77,7 +77,7 @@ void DetectThresholdRegister(void) { sigmatch_table[DETECT_THRESHOLD].name = "threshold"; sigmatch_table[DETECT_THRESHOLD].desc = "control the rule's alert frequency"; - sigmatch_table[DETECT_THRESHOLD].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Rule-Thresholding#threshold"; + sigmatch_table[DETECT_THRESHOLD].url = DOC_URL DOC_VERSION "/rules/thresholding.html#threshold"; sigmatch_table[DETECT_THRESHOLD].Match = DetectThresholdMatch; sigmatch_table[DETECT_THRESHOLD].Setup = DetectThresholdSetup; sigmatch_table[DETECT_THRESHOLD].Free = DetectThresholdFree; @@ -85,30 +85,11 @@ void DetectThresholdRegister(void) /* this is compatible to ip-only signatures */ sigmatch_table[DETECT_THRESHOLD].flags |= SIGMATCH_IPONLY_COMPAT; - const char *eb; - int opts = 0; - int eo; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - -error: - return; - + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm) +static int DetectThresholdMatch(ThreadVars *thv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { return 1; } @@ -142,8 +123,11 @@ static DetectThresholdData *DetectThresholdParse(char *rawstr) goto error; } - for(pos = 0, threshold_opt = strtok(copy_str,","); pos < strlen(copy_str) && threshold_opt != NULL; pos++, threshold_opt = strtok(NULL,",")) { - + char *saveptr = NULL; + for (pos = 0, threshold_opt = strtok_r(copy_str,",", &saveptr); + pos < strlen(copy_str) && threshold_opt != NULL; + pos++, threshold_opt = strtok_r(NULL,"," , &saveptr)) + { if(strstr(threshold_opt,"count")) count_found++; if(strstr(threshold_opt,"second")) @@ -245,10 +229,10 @@ static int DetectThresholdSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw SigMatch *tmpm = NULL; /* checks if there is a previous instance of detection_filter */ - tmpm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_MATCH]); + tmpm = DetectGetLastSMFromLists(s, DETECT_DETECTION_FILTER, -1); if (tmpm != NULL) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and \"threshold\" are not allowed in the same rule"); + SCLogError(SC_ERR_INVALID_SIGNATURE, "\"detection_filter\" and " + "\"threshold\" are not allowed in the same rule"); SCReturnInt(-1); } @@ -261,7 +245,7 @@ static int DetectThresholdSetup(DetectEngineCtx *de_ctx, Signature *s, char *raw goto error; sm->type = DETECT_THRESHOLD; - sm->ctx = (void *)de; + sm->ctx = (SigMatchCtx *)de; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); @@ -283,7 +267,7 @@ static void DetectThresholdFree(void *de_ptr) { DetectThresholdData *de = (DetectThresholdData *)de_ptr; if (de) { - DetectAddressFree(de->addr); + DetectAddressHeadCleanup(&de->addrs); SCFree(de); } } @@ -292,11 +276,8 @@ static void DetectThresholdFree(void *de_ptr) * ONLY TESTS BELOW THIS COMMENT */ #ifdef UNITTESTS - -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" -#include "detect-engine-threshold.h" #include "util-time.h" #include "util-hashlist.h" @@ -330,10 +311,10 @@ static int ThresholdTestParse02(void) de = DetectThresholdParse("type any,track by_dst,count 10,seconds 60"); if (de && (de->type == TYPE_LIMIT) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -367,10 +348,10 @@ static int ThresholdTestParse04(void) de = DetectThresholdParse("count 10, track by_dst, seconds 60, type both, count 10"); if (de && (de->type == TYPE_BOTH) && (de->track == TRACK_DST) && (de->count == 10) && (de->seconds == 60)) { DetectThresholdFree(de); - return 1; + return 0; } - return 0; + return 1; } /** @@ -1484,7 +1465,7 @@ static int DetectThresholdTestSig12(void) SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void*)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); @@ -1497,23 +1478,24 @@ static int DetectThresholdTestSig12(void) void ThresholdRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01, 1); - UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02, 0); - UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03, 1); - UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04, 0); - UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05, 1); - UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1, 1); - UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2, 1); - UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3, 1); - UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4, 1); - UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5, 1); - UtRegisterTest("DetectThresholdTestSig6Ticks", DetectThresholdTestSig6Ticks, 1); - UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7, 1); - UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8, 1); - UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9, 1); - UtRegisterTest("DetectThresholdTestSig10", DetectThresholdTestSig10, 1); - UtRegisterTest("DetectThresholdTestSig11", DetectThresholdTestSig11, 1); - UtRegisterTest("DetectThresholdTestSig12", DetectThresholdTestSig12, 1); + UtRegisterTest("ThresholdTestParse01", ThresholdTestParse01); + UtRegisterTest("ThresholdTestParse02", ThresholdTestParse02); + UtRegisterTest("ThresholdTestParse03", ThresholdTestParse03); + UtRegisterTest("ThresholdTestParse04", ThresholdTestParse04); + UtRegisterTest("ThresholdTestParse05", ThresholdTestParse05); + UtRegisterTest("DetectThresholdTestSig1", DetectThresholdTestSig1); + UtRegisterTest("DetectThresholdTestSig2", DetectThresholdTestSig2); + UtRegisterTest("DetectThresholdTestSig3", DetectThresholdTestSig3); + UtRegisterTest("DetectThresholdTestSig4", DetectThresholdTestSig4); + UtRegisterTest("DetectThresholdTestSig5", DetectThresholdTestSig5); + UtRegisterTest("DetectThresholdTestSig6Ticks", + DetectThresholdTestSig6Ticks); + UtRegisterTest("DetectThresholdTestSig7", DetectThresholdTestSig7); + UtRegisterTest("DetectThresholdTestSig8", DetectThresholdTestSig8); + UtRegisterTest("DetectThresholdTestSig9", DetectThresholdTestSig9); + UtRegisterTest("DetectThresholdTestSig10", DetectThresholdTestSig10); + UtRegisterTest("DetectThresholdTestSig11", DetectThresholdTestSig11); + UtRegisterTest("DetectThresholdTestSig12", DetectThresholdTestSig12); #endif /* UNITTESTS */ } diff --git a/src/detect-threshold.h b/src/detect-threshold.h index 3306094bee74..50e1d2704857 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -38,6 +38,7 @@ #define TRACK_DST 1 #define TRACK_SRC 2 #define TRACK_RULE 3 +#define TRACK_EITHER 4 /**< either src or dst: only used by suppress */ /* Get the new action to take */ #define TH_ACTION_ALERT 0x01 @@ -60,7 +61,7 @@ typedef struct DetectThresholdData_ { uint8_t new_action; /**< new_action alert|drop|pass|log|sdrop|reject */ uint32_t timeout; /**< timeout */ uint32_t flags; /**< flags used to set option */ - DetectAddress* addr; /**< address group used by suppress keyword */ + DetectAddressHead addrs; } DetectThresholdData; typedef struct DetectThresholdEntry_ { diff --git a/src/detect-tls-cert-issuer.c b/src/detect-tls-cert-issuer.c new file mode 100644 index 000000000000..dc4c8b621e33 --- /dev/null +++ b/src/detect-tls-cert-issuer.c @@ -0,0 +1,466 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls_cert_issuer keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-tls.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsIssuerSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsIssuerRegisterTests(void); +static int g_tls_cert_issuer_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls_cert_issuer + */ +void DetectTlsIssuerRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].name = "tls_cert_issuer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].desc = "content modifier to match specifically and only on the TLS cert issuer buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-issuer"; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Match = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Setup = DetectTlsIssuerSetup; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].Free = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].RegisterTests = DetectTlsIssuerRegisterTests; + + sigmatch_table[DETECT_AL_TLS_CERT_ISSUER].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("tls_cert_issuer", SIG_FLAG_TOCLIENT, 2, + PrefilterTxTlsIssuerRegister); + + DetectAppLayerInspectEngineRegister("tls_cert_issuer", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + DetectEngineInspectTlsIssuer); + + g_tls_cert_issuer_buffer_id = DetectBufferTypeGetByName("tls_cert_issuer"); +} + + +/** + * \brief this function setup the tls_cert_issuer modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsIssuerSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->init_data->list = g_tls_cert_issuer_buffer_id; + s->alproto = ALPROTO_TLS; + return 0; +} + +#ifdef UNITTESTS + +/** + * \test Test that a signature containing a tls_cert_issuer is correctly parsed + * and that the keyword is registered. + */ +static int DetectTlsIssuerTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tls any any -> any any " + "(msg:\"Testing tls_cert_issuer\"; " + "tls_cert_issuer; content:\"test\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + sm = de_ctx->sig_list->sm_lists[g_tls_cert_issuer_buffer_id]; + FAIL_IF_NULL(sm); + + FAIL_IF(sm->type != DETECT_CONTENT); + FAIL_IF_NOT_NULL(sm->next); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Test matching for google in the issuer of a certificate + * + */ +static int DetectTlsIssuerTest02(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_issuer\"; " + "tls_cert_issuer; content:\"google\"; nocase; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +#endif + +static void DetectTlsIssuerRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTlsIssuerTest01", DetectTlsIssuerTest01); + UtRegisterTest("DetectTlsIssuerTest02", DetectTlsIssuerTest02); +#endif +} diff --git a/src/detect-tls-cert-issuer.h b/src/detect-tls-cert-issuer.h new file mode 100644 index 000000000000..8e26cb75965c --- /dev/null +++ b/src/detect-tls-cert-issuer.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_ISSUER_H__ +#define __DETECT_TLS_ISSUER_H__ + +#include "app-layer-ssl.h" + +void DetectTlsIssuerRegister(void); + +#endif /* __DETECT_TLS_ISSUER_H__ */ diff --git a/src/detect-tls-cert-serial.c b/src/detect-tls-cert-serial.c new file mode 100644 index 000000000000..4d0a8e4da888 --- /dev/null +++ b/src/detect-tls-cert-serial.c @@ -0,0 +1,467 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls_cert_serial keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-tls.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsSerialSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsSerialRegisterTests(void); +static int g_tls_cert_serial_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls_cert_serial + */ +void DetectTlsSerialRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].name = "tls_cert_serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].desc = "content modifier to match the TLS cert serial buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-serial"; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Match = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Setup = DetectTlsSerialSetup; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].Free = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].RegisterTests = DetectTlsSerialRegisterTests; + + sigmatch_table[DETECT_AL_TLS_CERT_SERIAL].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("tls_cert_serial", SIG_FLAG_TOCLIENT, 2, + PrefilterTxTlsSerialRegister); + + DetectAppLayerInspectEngineRegister("tls_cert_serial", ALPROTO_TLS, + SIG_FLAG_TOCLIENT, DetectEngineInspectTlsSerial); + + g_tls_cert_serial_buffer_id = DetectBufferTypeGetByName("tls_cert_serial"); +} + +/** + * \brief this function setup the tls_cert_serial modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsSerialSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->init_data->list = g_tls_cert_serial_buffer_id; + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + return 0; +} + +#ifdef UNITTESTS + +/** + * \test Test that a signature containing tls_cert_serial is correctly parsed + * and that the keyword is registered. + */ +static int DetectTlsSerialTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tls any any -> any any " + "(msg:\"Testing tls_cert_serial\"; " + "tls_cert_serial; content:\"XX:XX:XX\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + sm = de_ctx->sig_list->sm_lists[g_tls_cert_serial_buffer_id]; + FAIL_IF_NULL(sm); + + FAIL_IF(sm->type != DETECT_CONTENT); + FAIL_IF_NOT_NULL(sm->next); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Test matching for serial in a certificate. + */ +static int DetectTlsSerialTest02(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_serial\"; " + "tls_cert_serial; " + "content:\"5C:19:B7:B1:32:3B:1C:A1\"; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +#endif /* UNITTESTS */ + +static void DetectTlsSerialRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTlsSerialTest01", DetectTlsSerialTest01); + UtRegisterTest("DetectTlsSerialTest02", DetectTlsSerialTest02); +#endif /* UNITTESTS */ +} diff --git a/src/detect-tls-cert-serial.h b/src/detect-tls-cert-serial.h new file mode 100644 index 000000000000..9fe018e90872 --- /dev/null +++ b/src/detect-tls-cert-serial.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2017 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_CERT_SERIAL_H__ +#define __DETECT_TLS_CERT_SERIAL_H__ + +/* prototypes */ +void DetectTlsSerialRegister (void); + +#endif /* __DETECT_TLS_CERT_SERIAL_H__ */ diff --git a/src/detect-tls-cert-subject.c b/src/detect-tls-cert-subject.c new file mode 100644 index 000000000000..d6581fca4cb5 --- /dev/null +++ b/src/detect-tls-cert-subject.c @@ -0,0 +1,465 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls_cert_subject keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-tls.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsSubjectSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsSubjectRegisterTests(void); +static int g_tls_cert_subject_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls_cert_issuer + */ +void DetectTlsSubjectRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].name = "tls_cert_subject"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].desc = "content modifier to match specifically and only on the TLS cert subject buffer"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-cert-subject"; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Match = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Setup = DetectTlsSubjectSetup; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].Free = NULL; + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; + + sigmatch_table[DETECT_AL_TLS_CERT_SUBJECT].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("tls_cert_subject", SIG_FLAG_TOCLIENT, 2, + PrefilterTxTlsSubjectRegister); + + DetectAppLayerInspectEngineRegister("tls_cert_subject", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + DetectEngineInspectTlsSubject); + + g_tls_cert_subject_buffer_id = DetectBufferTypeGetByName("tls_cert_subject"); +} + +/** + * \brief this function setup the tls_cert_subject modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsSubjectSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->init_data->list = g_tls_cert_subject_buffer_id; + s->alproto = ALPROTO_TLS; + return 0; +} + +#ifdef UNITTESTS + +/** + * \test Test that a signature containing a tls_cert_subject is correctly parsed + * and that the keyword is registered. + */ +static int DetectTlsSubjectTest01(void) +{ + DetectEngineCtx *de_ctx = NULL; + SigMatch *sm = NULL; + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert tls any any -> any any " + "(msg:\"Testing tls_cert_subject\"; " + "tls_cert_subject; content:\"test\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + /* sm should not be in the MATCH list */ + sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_MATCH]; + FAIL_IF_NOT_NULL(sm); + + sm = de_ctx->sig_list->sm_lists[g_tls_cert_subject_buffer_id]; + FAIL_IF_NULL(sm); + + FAIL_IF(sm->type != DETECT_CONTENT); + FAIL_IF_NOT_NULL(sm->next); + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + + PASS; +} + +/** + * \test Test matching for google in the subject of a certificate + * + */ +static int DetectTlsSubjectTest02(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_subject\"; " + "tls_cert_subject; content:\"google\"; nocase; " + "sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + FLOWLOCK_UNLOCK(&f); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +#endif + +static void DetectTlsSubjectRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTlsSubjectTest01", DetectTlsSubjectTest01); + UtRegisterTest("DetectTlsSubjectTest02", DetectTlsSubjectTest02); +#endif +} diff --git a/src/detect-tls-cert-subject.h b/src/detect-tls-cert-subject.h new file mode 100644 index 000000000000..8d037275e34b --- /dev/null +++ b/src/detect-tls-cert-subject.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_SUBJECT_H__ +#define __DETECT_TLS_SUBJECT_H__ + +#include "app-layer-ssl.h" + +void DetectTlsSubjectRegister(void); + +#endif /* __DETECT_TLS_SUBJECT_H__ */ diff --git a/src/detect-tls-cert-validity.c b/src/detect-tls-cert-validity.c new file mode 100644 index 000000000000..17e4b32df7c8 --- /dev/null +++ b/src/detect-tls-cert-validity.c @@ -0,0 +1,1986 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements tls certificate validity keywords + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" +#include "detect-tls-cert-validity.h" +#include "detect-engine-tls.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" + +#include "util-time.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +/** + * [tls_notbefore|tls_notafter]:[<|>][<>]; + */ +#define PARSE_REGEX "^\\s*(<|>)?\\s*([ -:TW0-9]+)\\s*(?:(<>)\\s*([ -:TW0-9]+))?\\s*$" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +static int DetectTlsValidityMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t, void *, void *, const Signature *, + const SigMatchCtx *); + +static time_t DateStringToEpoch (char *); +static DetectTlsValidityData *DetectTlsValidityParse (char *); +static int DetectTlsExpiredSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsValidSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsNotBeforeSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsNotAfterSetup (DetectEngineCtx *, Signature *s, char *str); +static int DetectTlsValiditySetup (DetectEngineCtx *, Signature *s, char *str, uint8_t); +static void TlsNotBeforeRegisterTests(void); +static void TlsNotAfterRegisterTests(void); +static void TlsExpiredRegisterTests(void); +static void TlsValidRegisterTests(void); +static void DetectTlsValidityFree(void *); +static int g_tls_validity_buffer_id = 0; + +/** + * \brief Registration function for tls validity keywords. + */ +void DetectTlsValidityRegister (void) +{ + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].name = "tls_cert_notbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].desc = "match TLS certificate notBefore field"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsnotbefore"; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Match = NULL; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Setup = DetectTlsNotBeforeSetup; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_NOTBEFORE].RegisterTests = TlsNotBeforeRegisterTests; + + sigmatch_table[DETECT_AL_TLS_NOTAFTER].name = "tls_cert_notafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].desc = "match TLS certificate notAfter field"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsnotafter"; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Match = NULL; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Setup = DetectTlsNotAfterSetup; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_NOTAFTER].RegisterTests = TlsNotAfterRegisterTests; + + sigmatch_table[DETECT_AL_TLS_EXPIRED].name = "tls_cert_expired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].desc = "match expired TLS certificates"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsexpired"; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Match = NULL; + sigmatch_table[DETECT_AL_TLS_EXPIRED].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Setup = DetectTlsExpiredSetup; + sigmatch_table[DETECT_AL_TLS_EXPIRED].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_EXPIRED].RegisterTests = TlsExpiredRegisterTests; + sigmatch_table[DETECT_AL_TLS_EXPIRED].flags = SIGMATCH_NOOPT; + + sigmatch_table[DETECT_AL_TLS_VALID].name = "tls_cert_valid"; + sigmatch_table[DETECT_AL_TLS_VALID].desc = "match valid TLS certificates"; + sigmatch_table[DETECT_AL_TLS_VALID].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsvalid"; + sigmatch_table[DETECT_AL_TLS_VALID].Match = NULL; + sigmatch_table[DETECT_AL_TLS_VALID].AppLayerTxMatch = DetectTlsValidityMatch; + sigmatch_table[DETECT_AL_TLS_VALID].Setup = DetectTlsValidSetup; + sigmatch_table[DETECT_AL_TLS_VALID].Free = DetectTlsValidityFree; + sigmatch_table[DETECT_AL_TLS_VALID].RegisterTests = TlsValidRegisterTests; + sigmatch_table[DETECT_AL_TLS_VALID].flags = SIGMATCH_NOOPT; + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); + + DetectAppLayerInspectEngineRegister("tls_validity", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + DetectEngineInspectTlsValidity); + + g_tls_validity_buffer_id = DetectBufferTypeGetByName("tls_validity"); +} + +/** + * \internal + * \brief Function to match validity field in a tls certificate. + * + * \param t Pointer to thread vars. + * \param det_ctx Pointer to the pattern matcher thread. + * \param f Pointer to the current flow. + * \param flags Flags. + * \param state App layer state. + * \param s Pointer to the Signature. + * \param m Pointer to the sigmatch that we will cast into + * DetectTlsValidityData. + * + * \retval 0 no match. + * \retval 1 match. + */ +static int DetectTlsValidityMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, + void *txv, const Signature *s, + const SigMatchCtx *ctx) +{ + SCEnter(); + + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, no match"); + SCReturnInt(0); + } + + int ret = 0; + + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) + connp = &ssl_state->client_connp; + else + connp = &ssl_state->server_connp; + + const DetectTlsValidityData *dd = (const DetectTlsValidityData *)ctx; + + time_t cert_epoch = 0; + if (dd->type == DETECT_TLS_TYPE_NOTBEFORE) + cert_epoch = connp->cert0_not_before; + else if (dd->type == DETECT_TLS_TYPE_NOTAFTER) + cert_epoch = connp->cert0_not_after; + + if (cert_epoch == 0) + SCReturnInt(0); + + if ((dd->mode & DETECT_TLS_VALIDITY_EQ) && cert_epoch == dd->epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_LT) && cert_epoch <= dd->epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_GT) && cert_epoch >= dd->epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_RA) && + cert_epoch >= dd->epoch && cert_epoch <= dd->epoch2) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_EX) && + f->lastts.tv_sec > cert_epoch) + ret = 1; + else if ((dd->mode & DETECT_TLS_VALIDITY_VA) && + f->lastts.tv_sec <= cert_epoch) + ret = 1; + + SCReturnInt(ret); +} + +/** + * \internal + * \brief Function to check if string is epoch. + * + * \param string Date string. + * + * \retval epoch time on success. + * \retval 0 on failure. + */ +static time_t StringIsEpoch (char *string) +{ + if (strlen(string) == 0) + return -1; + + /* We assume that the date string is epoch if it consists of only + digits. */ + char *sp = string; + while (*sp) { + if (isdigit(*sp++) == 0) + return -1; + } + + return strtol(string, NULL, 10); +} + +/** + * \internal + * \brief Function to convert date string to epoch. + * + * \param string Date string. + * + * \retval epoch on success. + * \retval 0 on failure. + */ +static time_t DateStringToEpoch (char *string) +{ + int r = 0; + struct tm tm; + char *patterns[] = { + /* ISO 8601 */ + "%Y-%m", + "%Y-%m-%d", + "%Y-%m-%d %H", + "%Y-%m-%d %H:%M", + "%Y-%m-%d %H:%M:%S", + "%Y-%m-%dT%H", + "%Y-%m-%dT%H:%M", + "%Y-%m-%dT%H:%M:%S", + "%H:%M", + "%H:%M:%S", + }; + + /* Skip leading whitespace. */ + while (isspace(*string)) + string++; + + size_t inlen, oldlen; + + oldlen = inlen = strlen(string); + + /* Skip trailing whitespace */ + while (inlen > 0 && isspace(string[inlen - 1])) + inlen--; + + char tmp[inlen + 1]; + + if (inlen < oldlen) { + strlcpy(tmp, string, inlen + 1); + string = tmp; + } + + time_t epoch = StringIsEpoch(string); + if (epoch != -1) { + return epoch;; + } + + r = SCStringPatternToTime(string, patterns, 10, &tm); + + if (r != 0) + return -1; + + return SCMkTimeUtc(&tm); +} + +/** + * \internal + * \brief Function to parse options passed via tls validity keywords. + * + * \param rawstr Pointer to the user provided options. + * + * \retval dd pointer to DetectTlsValidityData on success. + * \retval NULL on failure. + */ +static DetectTlsValidityData *DetectTlsValidityParse (char *rawstr) +{ + DetectTlsValidityData *dd = NULL; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char mode[2] = ""; + char value1[20] = ""; + char value2[20] = ""; + char range[3] = ""; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, + 0, ov, MAX_SUBSTRINGS); + if (ret < 3 || ret > 5) { + SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", rawstr); + goto error; + } + + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, mode, + sizeof(mode)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("mode \"%s\"", mode); + + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, value1, + sizeof(value1)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("value1 \"%s\"", value1); + + if (ret > 3) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, + range, sizeof(range)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("range \"%s\"", range); + + if (ret > 4) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, + value2, sizeof(value2)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, + "pcre_copy_substring failed"); + goto error; + } + SCLogDebug("value2 \"%s\"", value2); + } + } + + dd = SCMalloc(sizeof(DetectTlsValidityData)); + if (unlikely(dd == NULL)) + goto error; + + dd->epoch = 0; + dd->epoch2 = 0; + dd->mode = 0; + + if (strlen(mode) > 0) { + if (mode[0] == '<') + dd->mode |= DETECT_TLS_VALIDITY_LT; + else if (mode[0] == '>') + dd->mode |= DETECT_TLS_VALIDITY_GT; + } + + if (strlen(range) > 0) { + if (strcmp("<>", range) == 0) + dd->mode |= DETECT_TLS_VALIDITY_RA; + } + + if (strlen(range) != 0 && strlen(mode) != 0) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Range specified but mode also set"); + goto error; + } + + if (dd->mode == 0) { + dd->mode |= DETECT_TLS_VALIDITY_EQ; + } + + /* set the first value */ + dd->epoch = DateStringToEpoch(value1); + if (dd->epoch == -1) + goto error; + + /* set the second value if specified */ + if (strlen(value2) > 0) { + if (!(dd->mode & DETECT_TLS_VALIDITY_RA)) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Multiple tls validity values specified but mode is not range"); + goto error; + } + + dd->epoch2 = DateStringToEpoch(value2); + if (dd->epoch2 == -1) + goto error; + + if (dd->epoch2 <= dd->epoch) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Second value in range must not be smaller than the first"); + goto error; + } + } + return dd; + +error: + if (dd) + SCFree(dd); + return NULL; +} + +/** + * \brief Function to add the parsed tls_cert_expired into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsExpiredSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + SigMatch *sm = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); + if (dd == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + dd->mode = DETECT_TLS_VALIDITY_EX; + dd->type = DETECT_TLS_TYPE_NOTAFTER; + dd->epoch = 0; + dd->epoch2 = 0; + + sm->type = DETECT_AL_TLS_EXPIRED; + sm->ctx = (void *)dd; + + SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); + return 0; + +error: + DetectTlsValidityFree(dd); + if (sm) + SCFree(sm); + return -1; +} + +/** + * \brief Function to add the parsed tls_cert_valid into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsValidSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + DetectTlsValidityData *dd = NULL; + SigMatch *sm = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + dd = SCCalloc(1, sizeof(DetectTlsValidityData)); + if (dd == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"Allocation \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + dd->mode = DETECT_TLS_VALIDITY_VA; + dd->type = DETECT_TLS_TYPE_NOTAFTER; + dd->epoch = 0; + dd->epoch2 = 0; + + sm->type = DETECT_AL_TLS_VALID; + sm->ctx = (void *)dd; + + SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); + return 0; + +error: + DetectTlsValidityFree(dd); + if (sm) + SCFree(sm); + return -1; +} + +/** + * \brief Function to add the parsed tls_notbefore into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsNotBeforeSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + uint8_t type = DETECT_TLS_TYPE_NOTBEFORE; + int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); + + SCReturnInt(r); +} + +/** + * \brief Function to add the parsed tls_notafter into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsNotAfterSetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr) +{ + uint8_t type = DETECT_TLS_TYPE_NOTAFTER; + int r = DetectTlsValiditySetup(de_ctx, s, rawstr, type); + + SCReturnInt(r); +} + +/** + * \brief Function to add the parsed tls validity field into the current signature. + * + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Current Signature. + * \param rawstr Pointer to the user provided flags options. + * \param type Defines if this is notBefore or notAfter. + * + * \retval 0 on Success. + * \retval -1 on Failure. + */ +static int DetectTlsValiditySetup (DetectEngineCtx *de_ctx, Signature *s, + char *rawstr, uint8_t type) +{ + DetectTlsValidityData *dd = NULL; + SigMatch *sm = NULL; + + SCLogDebug("\'%s\'", rawstr); + + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + + dd = DetectTlsValidityParse(rawstr); + if (dd == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT,"Parsing \'%s\' failed", rawstr); + goto error; + } + + /* okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + if (type == DETECT_TLS_TYPE_NOTBEFORE) { + dd->type = DETECT_TLS_TYPE_NOTBEFORE; + sm->type = DETECT_AL_TLS_NOTBEFORE; + } + else if (type == DETECT_TLS_TYPE_NOTAFTER) { + dd->type = DETECT_TLS_TYPE_NOTAFTER; + sm->type = DETECT_AL_TLS_NOTAFTER; + } + else { + goto error; + } + + sm->ctx = (void *)dd; + + SigMatchAppendSMToList(s, sm, g_tls_validity_buffer_id); + return 0; + +error: + DetectTlsValidityFree(dd); + if (sm) + SCFree(sm); + return -1; +} + +/** + * \internal + * \brief Function to free memory associated with DetectTlsValidityData. + * + * \param de_ptr Pointer to DetectTlsValidityData. + */ +void DetectTlsValidityFree(void *de_ptr) +{ + DetectTlsValidityData *dd = (DetectTlsValidityData *)de_ptr; + if (dd) + SCFree(dd); +} + +#ifdef UNITTESTS + +/** + * \test This is a test for a valid value 1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse01 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value >1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse02 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(">1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_GT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value <1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse03 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("<1430000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_LT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1430000000<>1470000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse04 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000<>1470000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->epoch2 == 1470000000 && + dd->mode == DETECT_TLS_VALIDITY_RA); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a invalid value A. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse05 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("A"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value >1430000000<>1470000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse06 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(">1430000000<>1470000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value 1430000000<>. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse07 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000<>"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value <>1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse08 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("<>1430000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value "". + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse09 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(""); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value " ". + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse10 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(" "); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a invalid value 1490000000<>1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse11 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1490000000<>1430000000"); + FAIL_IF_NOT_NULL(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1430000000 <> 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse12 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("1430000000 <> 1490000000"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->epoch2 == 1490000000 && + dd->mode == DETECT_TLS_VALIDITY_RA); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value > 1430000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse13 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("> 1430000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1430000000 && dd->mode == DETECT_TLS_VALIDITY_GT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value < 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse14 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("< 1490000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1490000000 && dd->mode == DETECT_TLS_VALIDITY_LT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 1490000000. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse15 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(" 1490000000 "); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1490000000 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse16 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1443657600 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value >2015-10-22. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse17 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse(">2015-10-22"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445472000 && dd->mode == DETECT_TLS_VALIDITY_GT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value <2015-10-22 23. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse18 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("<2015-10-22 23"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445554800 && dd->mode == DETECT_TLS_VALIDITY_LT); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22 23:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse19 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22 23:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558340 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22 23:59:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse20 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22 23:59:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558399 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22T23. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse21 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22T23"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445554800 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22T23:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse22 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22T23:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558340 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test This is a test for a valid value 2015-10-22T23:59:59. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestParse23 (void) +{ + DetectTlsValidityData *dd = NULL; + dd = DetectTlsValidityParse("2015-10-22T23:59:59"); + FAIL_IF_NULL(dd); + FAIL_IF_NOT(dd->epoch == 1445558399 && dd->mode == DETECT_TLS_VALIDITY_EQ); + DetectTlsValidityFree(dd); + PASS; +} + +/** + * \test Test matching on validity dates in a certificate. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidityTestDetect01(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_notbefore\"; " + "tls_cert_notbefore:<2016-07-20; sid:1;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_notafter\"; " + "tls_cert_notafter:>2016-09-01; sid:2;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, client_hello, + sizeof(client_hello)); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + FAIL_IF(PacketAlertCheck(p1, 2)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + FAIL_IF(PacketAlertCheck(p2, 2)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + FAIL_IF_NOT(PacketAlertCheck(p3, 2)); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +/** + * \test Test matching on an expired certificate. + * + * Traffic from expired.badssl.com + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ExpiredTestDetect01(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x5a, 0x01, 0x00, 0x00, + 0x56, 0x03, 0x03, 0x62, 0x87, 0xa4, 0x11, 0x3e, + 0x11, 0x32, 0x7d, 0xbc, 0x5b, 0x63, 0xb7, 0xaf, + 0x55, 0x8d, 0x46, 0x5b, 0x8f, 0xac, 0x50, 0x02, + 0x90, 0xe3, 0x55, 0x03, 0xfe, 0xad, 0xa6, 0x92, + 0x56, 0x75, 0xf9, 0x00, 0x00, 0x08, 0x00, 0x35, + 0x00, 0x2f, 0x00, 0x0a, 0x00, 0xff, 0x01, 0x00, + 0x00, 0x25, 0x00, 0x00, 0x00, 0x17, 0x00, 0x15, + 0x00, 0x00, 0x12, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x64, 0x2e, 0x62, 0x61, 0x64, 0x73, 0x73, + 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x0d, 0x00, + 0x06, 0x00, 0x04, 0x04, 0x01, 0x02, 0x01 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x55, 0x02, 0x00, 0x00, + 0x51, 0x03, 0x03, 0x22, 0xa1, 0xd8, 0xd0, 0x3c, + 0x8d, 0x32, 0x7e, 0x4f, 0x60, 0x27, 0xf6, 0x0c, + 0x99, 0x7a, 0x8e, 0x6e, 0x52, 0xa5, 0xf4, 0x20, + 0x2e, 0xa1, 0xa4, 0x0b, 0xd5, 0x80, 0x9b, 0xec, + 0xbd, 0x2c, 0x6c, 0x20, 0x7a, 0x9b, 0xcc, 0x6b, + 0xbf, 0x3d, 0xfc, 0x7c, 0x31, 0x78, 0x65, 0x1e, + 0xcc, 0x41, 0x0b, 0x8b, 0x3d, 0x4e, 0xde, 0x45, + 0xe5, 0x20, 0xf5, 0xbd, 0x8e, 0x99, 0xce, 0xc2, + 0xad, 0x88, 0x08, 0x27, 0x00, 0x2f, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, + 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x05, 0x59, 0x0b, 0x00, 0x05, + 0x55, 0x00, 0x05, 0x52, 0x00, 0x05, 0x4f, 0x30, + 0x82, 0x05, 0x4b, 0x30, 0x82, 0x04, 0x33, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x4a, 0xe7, + 0x95, 0x49, 0xfa, 0x9a, 0xbe, 0x3f, 0x10, 0x0f, + 0x17, 0xa4, 0x78, 0xe1, 0x69, 0x09, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x90, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x30, + 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, + 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, + 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, + 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x61, 0x6c, + 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, + 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, + 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, + 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x2d, 0x43, 0x4f, 0x4d, 0x4f, 0x44, + 0x4f, 0x20, 0x52, 0x53, 0x41, 0x20, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, + 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x5a, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x31, + 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, + 0x30, 0x59, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x20, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x1d, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x14, + 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x53, 0x53, 0x4c, 0x20, 0x57, 0x69, 0x6c, 0x64, + 0x63, 0x61, 0x72, 0x64, 0x31, 0x15, 0x30, 0x13, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x0c, 0x2a, + 0x2e, 0x62, 0x61, 0x64, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xc2, 0x04, 0xec, 0xf8, + 0x8c, 0xee, 0x04, 0xc2, 0xb3, 0xd8, 0x50, 0xd5, + 0x70, 0x58, 0xcc, 0x93, 0x18, 0xeb, 0x5c, 0xa8, + 0x68, 0x49, 0xb0, 0x22, 0xb5, 0xf9, 0x95, 0x9e, + 0xb1, 0x2b, 0x2c, 0x76, 0x3e, 0x6c, 0xc0, 0x4b, + 0x60, 0x4c, 0x4c, 0xea, 0xb2, 0xb4, 0xc0, 0x0f, + 0x80, 0xb6, 0xb0, 0xf9, 0x72, 0xc9, 0x86, 0x02, + 0xf9, 0x5c, 0x41, 0x5d, 0x13, 0x2b, 0x7f, 0x71, + 0xc4, 0x4b, 0xbc, 0xe9, 0x94, 0x2e, 0x50, 0x37, + 0xa6, 0x67, 0x1c, 0x61, 0x8c, 0xf6, 0x41, 0x42, + 0xc5, 0x46, 0xd3, 0x16, 0x87, 0x27, 0x9f, 0x74, + 0xeb, 0x0a, 0x9d, 0x11, 0x52, 0x26, 0x21, 0x73, + 0x6c, 0x84, 0x4c, 0x79, 0x55, 0xe4, 0xd1, 0x6b, + 0xe8, 0x06, 0x3d, 0x48, 0x15, 0x52, 0xad, 0xb3, + 0x28, 0xdb, 0xaa, 0xff, 0x6e, 0xff, 0x60, 0x95, + 0x4a, 0x77, 0x6b, 0x39, 0xf1, 0x24, 0xd1, 0x31, + 0xb6, 0xdd, 0x4d, 0xc0, 0xc4, 0xfc, 0x53, 0xb9, + 0x6d, 0x42, 0xad, 0xb5, 0x7c, 0xfe, 0xae, 0xf5, + 0x15, 0xd2, 0x33, 0x48, 0xe7, 0x22, 0x71, 0xc7, + 0xc2, 0x14, 0x7a, 0x6c, 0x28, 0xea, 0x37, 0x4a, + 0xdf, 0xea, 0x6c, 0xb5, 0x72, 0xb4, 0x7e, 0x5a, + 0xa2, 0x16, 0xdc, 0x69, 0xb1, 0x57, 0x44, 0xdb, + 0x0a, 0x12, 0xab, 0xde, 0xc3, 0x0f, 0x47, 0x74, + 0x5c, 0x41, 0x22, 0xe1, 0x9a, 0xf9, 0x1b, 0x93, + 0xe6, 0xad, 0x22, 0x06, 0x29, 0x2e, 0xb1, 0xba, + 0x49, 0x1c, 0x0c, 0x27, 0x9e, 0xa3, 0xfb, 0x8b, + 0xf7, 0x40, 0x72, 0x00, 0xac, 0x92, 0x08, 0xd9, + 0x8c, 0x57, 0x84, 0x53, 0x81, 0x05, 0xcb, 0xe6, + 0xfe, 0x6b, 0x54, 0x98, 0x40, 0x27, 0x85, 0xc7, + 0x10, 0xbb, 0x73, 0x70, 0xef, 0x69, 0x18, 0x41, + 0x07, 0x45, 0x55, 0x7c, 0xf9, 0x64, 0x3f, 0x3d, + 0x2c, 0xc3, 0xa9, 0x7c, 0xeb, 0x93, 0x1a, 0x4c, + 0x86, 0xd1, 0xca, 0x85, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0xd5, 0x30, 0x82, 0x01, + 0xd1, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x90, 0xaf, + 0x6a, 0x3a, 0x94, 0x5a, 0x0b, 0xd8, 0x90, 0xea, + 0x12, 0x56, 0x73, 0xdf, 0x43, 0xb4, 0x3a, 0x28, + 0xda, 0xe7, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, 0xee, 0xc1, + 0x7b, 0x81, 0x0b, 0x3a, 0x47, 0x69, 0x71, 0x18, + 0x7d, 0x11, 0x37, 0x93, 0xbc, 0xa5, 0x1b, 0x3f, + 0xfb, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, + 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, + 0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x4f, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x48, 0x30, + 0x46, 0x30, 0x3a, 0x06, 0x0b, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x02, 0x07, + 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1d, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x08, 0x06, + 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02, 0x01, 0x30, + 0x54, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x4d, + 0x30, 0x4b, 0x30, 0x49, 0xa0, 0x47, 0xa0, 0x45, + 0x86, 0x43, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, + 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, + 0x52, 0x53, 0x41, 0x44, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, + 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x81, 0x85, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x79, 0x30, 0x77, 0x30, 0x4f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x43, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, + 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x4f, 0x4d, 0x4f, + 0x44, 0x4f, 0x52, 0x53, 0x41, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, + 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, + 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, + 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x23, 0x06, + 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1c, 0x30, 0x1a, + 0x82, 0x0c, 0x2a, 0x2e, 0x62, 0x61, 0x64, 0x73, + 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x0a, + 0x62, 0x61, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x6a, 0x7a, + 0xf1, 0xda, 0xff, 0x03, 0x07, 0x72, 0x78, 0xc5, + 0x66, 0xa1, 0x4f, 0x46, 0x43, 0x0e, 0x5f, 0x14, + 0x21, 0x8c, 0x75, 0x1a, 0xeb, 0x36, 0xe0, 0x1f, + 0xa4, 0x10, 0x15, 0xec, 0xda, 0x33, 0x25, 0x7c, + 0x3b, 0xb5, 0x0a, 0xc7, 0x01, 0x38, 0x3d, 0x27, + 0xfd, 0x58, 0xd9, 0xcc, 0xea, 0x2d, 0x69, 0x39, + 0x7c, 0xbe, 0x97, 0xef, 0x0b, 0xd6, 0x0b, 0x58, + 0xe7, 0x8c, 0x7f, 0xbf, 0xb3, 0x4c, 0x1d, 0xf3, + 0xb7, 0x90, 0x80, 0xa6, 0x36, 0x7c, 0x14, 0x5b, + 0xec, 0x07, 0x2d, 0x02, 0x3e, 0x1b, 0x5b, 0x63, + 0x5b, 0x15, 0xab, 0x00, 0xfa, 0x1f, 0x3b, 0x19, + 0x2d, 0xdf, 0xe2, 0x23, 0x10, 0x11, 0x07, 0x7e, + 0x72, 0x7f, 0xe2, 0xbf, 0xb7, 0x00, 0x1b, 0x98, + 0x2f, 0x2c, 0x3f, 0xce, 0x85, 0x9a, 0x27, 0x8c, + 0x10, 0x22, 0x08, 0x41, 0x2b, 0x8a, 0x3e, 0x82, + 0x4e, 0xfc, 0xdd, 0x21, 0xc6, 0x56, 0x74, 0x70, + 0xa4, 0x34, 0xf2, 0xb1, 0x40, 0x9e, 0x2b, 0x58, + 0xa2, 0x59, 0x0f, 0x1d, 0x48, 0xef, 0xeb, 0x11, + 0x3e, 0xc1, 0x4a, 0x9e, 0xbc, 0x65, 0x55, 0x6d, + 0xc6, 0xa3, 0xef, 0xd5, 0xd4, 0x96, 0xcd, 0xf1, + 0xae, 0x27, 0xf7, 0xa4, 0x57, 0x14, 0x3c, 0x94, + 0x41, 0x05, 0x7a, 0x8b, 0xa1, 0x37, 0x47, 0xd7, + 0xf5, 0x7d, 0xdc, 0xfa, 0xce, 0x6f, 0x31, 0xa2, + 0xb0, 0x8c, 0xea, 0xcc, 0x12, 0x9b, 0x22, 0xf1, + 0x34, 0x70, 0xcf, 0x7d, 0x75, 0x4a, 0x8b, 0x68, + 0x29, 0x0c, 0x1e, 0xe9, 0x96, 0xa8, 0xcf, 0xb0, + 0x12, 0x1f, 0x5c, 0x2a, 0xee, 0x67, 0x2f, 0x7f, + 0xbd, 0x73, 0xf3, 0x5a, 0x01, 0x22, 0x0c, 0x70, + 0xfa, 0xcd, 0x45, 0xef, 0x78, 0x5c, 0xce, 0x0d, + 0xfa, 0x4e, 0xe1, 0xef, 0xce, 0x65, 0x9f, 0x47, + 0x0c, 0x4f, 0xbb, 0x36, 0x44, 0x68, 0x56, 0x5c, + 0x56, 0x59, 0xad, 0xaa, 0x8a, 0xbc, + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + f.lastts.tv_sec = 1474978656; /* 2016-09-27 */ + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_expired\"; " + "tls_cert_expired; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +/** + * \test Test matching on a valid TLS certificate. + * + * \retval 1 on success. + * \retval 0 on failure. + */ +int ValidTestDetect01(void) +{ + /* client hello */ + uint8_t client_hello[] = { + 0x16, 0x03, 0x01, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc4, 0x03, 0x03, 0xd6, 0x08, 0x5a, 0xa2, 0x86, + 0x5b, 0x85, 0xd4, 0x40, 0xab, 0xbe, 0xc0, 0xbc, + 0x41, 0xf2, 0x26, 0xf0, 0xfe, 0x21, 0xee, 0x8b, + 0x4c, 0x7e, 0x07, 0xc8, 0xec, 0xd2, 0x00, 0x46, + 0x4c, 0xeb, 0xb7, 0x00, 0x00, 0x16, 0xc0, 0x2b, + 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, + 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, + 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, + 0x0d, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0xff, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x29, 0x00, 0x27, 0x05, 0x68, 0x32, 0x2d, 0x31, + 0x36, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x35, 0x05, + 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, + 0x08, 0x73, 0x70, 0x64, 0x79, 0x2f, 0x33, 0x2e, + 0x31, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, + 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, + 0x14, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, + 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, + 0x03, 0x04, 0x02, 0x02, 0x02 + }; + + /* server hello */ + uint8_t server_hello[] = { + 0x16, 0x03, 0x03, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x44, 0x03, 0x03, 0x57, 0x91, 0xb8, 0x63, 0xdd, + 0xdb, 0xbb, 0x23, 0xcf, 0x0b, 0x43, 0x02, 0x1d, + 0x46, 0x11, 0x27, 0x5c, 0x98, 0xcf, 0x67, 0xe1, + 0x94, 0x3d, 0x62, 0x7d, 0x38, 0x48, 0x21, 0x23, + 0xa5, 0x62, 0x31, 0x00, 0xc0, 0x2f, 0x00, 0x00, + 0x1c, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x05, 0x00, 0x03, 0x02, 0x68, 0x32, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00 + }; + + /* certificate */ + uint8_t certificate[] = { + 0x16, 0x03, 0x03, 0x04, 0x93, 0x0b, 0x00, 0x04, + 0x8f, 0x00, 0x04, 0x8c, 0x00, 0x04, 0x89, 0x30, + 0x82, 0x04, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x5c, 0x19, + 0xb7, 0xb1, 0x32, 0x3b, 0x1c, 0xa1, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x49, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1c, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x47, 0x32, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x37, + 0x31, 0x33, 0x31, 0x33, 0x32, 0x34, 0x35, 0x32, + 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x30, + 0x35, 0x31, 0x33, 0x31, 0x36, 0x30, 0x30, 0x5a, + 0x30, 0x65, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, + 0x63, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa5, 0x0a, 0xb9, 0xb1, 0xca, 0x36, 0xd1, 0xae, + 0x22, 0x38, 0x07, 0x06, 0xc9, 0x1a, 0x56, 0x4f, + 0xbb, 0xdf, 0xa8, 0x6d, 0xbd, 0xee, 0x76, 0x16, + 0xbc, 0x53, 0x3c, 0x03, 0x6a, 0x5c, 0x94, 0x50, + 0x87, 0x2f, 0x28, 0xb4, 0x4e, 0xd5, 0x9b, 0x8f, + 0xfe, 0x02, 0xde, 0x2a, 0x83, 0x01, 0xf9, 0x45, + 0x61, 0x0e, 0x66, 0x0e, 0x24, 0x22, 0xe2, 0x59, + 0x66, 0x0d, 0xd3, 0xe9, 0x77, 0x8a, 0x7e, 0x42, + 0xaa, 0x5a, 0xf9, 0x05, 0xbf, 0x30, 0xc7, 0x03, + 0x2b, 0xdc, 0xa6, 0x9c, 0xe0, 0x9f, 0x0d, 0xf1, + 0x28, 0x19, 0xf8, 0xf2, 0x02, 0xfa, 0xbd, 0x62, + 0xa0, 0xf3, 0x02, 0x2b, 0xcd, 0xf7, 0x09, 0x04, + 0x3b, 0x52, 0xd8, 0x65, 0x4b, 0x4a, 0x70, 0xe4, + 0x57, 0xc9, 0x2e, 0x2a, 0xf6, 0x9c, 0x6e, 0xd8, + 0xde, 0x01, 0x52, 0xc9, 0x6f, 0xe9, 0xef, 0x82, + 0xbc, 0x0b, 0x95, 0xb2, 0xef, 0xcb, 0x91, 0xa6, + 0x0b, 0x2d, 0x14, 0xc6, 0x00, 0xa9, 0x33, 0x86, + 0x64, 0x00, 0xd4, 0x92, 0x19, 0x53, 0x3d, 0xfd, + 0xcd, 0xc6, 0x1a, 0xf2, 0x0e, 0x67, 0xc2, 0x1d, + 0x2c, 0xe0, 0xe8, 0x29, 0x97, 0x1c, 0xb6, 0xc4, + 0xb2, 0x02, 0x0c, 0x83, 0xb8, 0x60, 0x61, 0xf5, + 0x61, 0x2d, 0x73, 0x5e, 0x85, 0x4d, 0xbd, 0x0d, + 0xe7, 0x1a, 0x37, 0x56, 0x8d, 0xe5, 0x50, 0x0c, + 0xc9, 0x64, 0x4c, 0x11, 0xea, 0xf3, 0xcb, 0x26, + 0x34, 0xbd, 0x02, 0xf5, 0xc1, 0xfb, 0xa2, 0xec, + 0x27, 0xbb, 0x60, 0xbe, 0x0b, 0xf6, 0xe7, 0x3c, + 0x2d, 0xc9, 0xe7, 0xb0, 0x30, 0x28, 0x17, 0x3d, + 0x90, 0xf1, 0x63, 0x8e, 0x49, 0xf7, 0x15, 0x78, + 0x21, 0xcc, 0x45, 0xe6, 0x86, 0xb2, 0xd8, 0xb0, + 0x2e, 0x5a, 0xb0, 0x58, 0xd3, 0xb6, 0x11, 0x40, + 0xae, 0x81, 0x1f, 0x6b, 0x7a, 0xaf, 0x40, 0x50, + 0xf9, 0x2e, 0x81, 0x8b, 0xec, 0x26, 0x11, 0x3f, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, + 0x53, 0x30, 0x82, 0x01, 0x4f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, + 0x0b, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x6e, 0x6f, 0x82, 0x09, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6e, 0x6f, 0x30, + 0x68, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x5c, 0x30, 0x5a, 0x30, + 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x30, 0x02, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x74, 0x30, 0x2b, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, + 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x63, 0x73, + 0x70, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xc6, 0x53, 0x87, 0x42, + 0x2d, 0xc8, 0xee, 0x7a, 0x62, 0x1e, 0x83, 0xdb, + 0x0d, 0xe2, 0x32, 0xeb, 0x8b, 0xaf, 0x69, 0x40, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, + 0x16, 0x80, 0x14, 0x4a, 0xdd, 0x06, 0x16, 0x1b, + 0xbc, 0xf6, 0x68, 0xb5, 0x76, 0xf5, 0x81, 0xb6, + 0xbb, 0x62, 0x1a, 0xba, 0x5a, 0x81, 0x2f, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x1a, + 0x30, 0x18, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x05, 0x01, + 0x30, 0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, + 0x02, 0x02, 0x30, 0x30, 0x06, 0x03, 0x55, 0x1d, + 0x1f, 0x04, 0x29, 0x30, 0x27, 0x30, 0x25, 0xa0, + 0x23, 0xa0, 0x21, 0x86, 0x1f, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6b, 0x69, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x47, 0x49, 0x41, 0x47, 0x32, + 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x7b, 0x27, 0x00, 0x46, 0x8f, 0xfd, 0x5b, 0xff, + 0xcb, 0x05, 0x9b, 0xf7, 0xf1, 0x68, 0xf6, 0x9a, + 0x7b, 0xba, 0x53, 0xdf, 0x63, 0xed, 0x11, 0x94, + 0x39, 0xf2, 0xd0, 0x20, 0xcd, 0xa3, 0xc4, 0x98, + 0xa5, 0x10, 0x74, 0xe7, 0x10, 0x6d, 0x07, 0xf8, + 0x33, 0x87, 0x05, 0x43, 0x0e, 0x64, 0x77, 0x09, + 0x18, 0x4f, 0x38, 0x2e, 0x45, 0xae, 0xa8, 0x34, + 0x3a, 0xa8, 0x33, 0xac, 0x9d, 0xdd, 0x25, 0x91, + 0x59, 0x43, 0xbe, 0x0f, 0x87, 0x16, 0x2f, 0xb5, + 0x27, 0xfd, 0xce, 0x2f, 0x35, 0x5d, 0x12, 0xa1, + 0x66, 0xac, 0xf7, 0x95, 0x38, 0x0f, 0xe5, 0xb1, + 0x18, 0x18, 0xe6, 0x80, 0x52, 0x31, 0x8a, 0x66, + 0x02, 0x52, 0x1a, 0xa4, 0x32, 0x6a, 0x61, 0x05, + 0xcf, 0x1d, 0xf9, 0x90, 0x73, 0xf0, 0xeb, 0x20, + 0x31, 0x7b, 0x2e, 0xc0, 0xb0, 0xfb, 0x5c, 0xcc, + 0xdc, 0x76, 0x55, 0x72, 0xaf, 0xb1, 0x05, 0xf4, + 0xad, 0xf9, 0xd7, 0x73, 0x5c, 0x2c, 0xbf, 0x0d, + 0x84, 0x18, 0x01, 0x1d, 0x4d, 0x08, 0xa9, 0x4e, + 0x37, 0xb7, 0x58, 0xc4, 0x05, 0x0e, 0x65, 0x63, + 0xd2, 0x88, 0x02, 0xf5, 0x82, 0x17, 0x08, 0xd5, + 0x8f, 0x80, 0xc7, 0x82, 0x29, 0xbb, 0xe1, 0x04, + 0xbe, 0xf6, 0xe1, 0x8c, 0xbc, 0x3a, 0xf8, 0xf9, + 0x56, 0xda, 0xdc, 0x8e, 0xc6, 0xe6, 0x63, 0x98, + 0x12, 0x08, 0x41, 0x2c, 0x9d, 0x7c, 0x82, 0x0d, + 0x1e, 0xea, 0xba, 0xde, 0x32, 0x09, 0xda, 0x52, + 0x24, 0x4f, 0xcc, 0xb6, 0x09, 0x33, 0x8b, 0x00, + 0xf9, 0x83, 0xb3, 0xc6, 0xa4, 0x90, 0x49, 0x83, + 0x2d, 0x36, 0xd9, 0x11, 0x78, 0xd0, 0x62, 0x9f, + 0xc4, 0x8f, 0x84, 0xba, 0x7f, 0xaa, 0x04, 0xf1, + 0xd9, 0xa4, 0xad, 0x5d, 0x63, 0xee, 0x72, 0xc6, + 0x4d, 0xd1, 0x4b, 0x41, 0x8f, 0x40, 0x0f, 0x7d, + 0xcd, 0xb8, 0x2e, 0x5b, 0x6e, 0x21, 0xc9, 0x3d + }; + + Flow f; + SSLState *ssl_state = NULL; + TcpSession ssn; + Packet *p1 = NULL; + Packet *p2 = NULL; + Packet *p3 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p1 = UTHBuildPacketReal(client_hello, sizeof(client_hello), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 51251, 443); + p2 = UTHBuildPacketReal(server_hello, sizeof(server_hello), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + p3 = UTHBuildPacketReal(certificate, sizeof(certificate), IPPROTO_TCP, + "192.168.1.1", "192.168.1.5", 443, 51251); + + FLOW_INITIALIZE(&f); + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + f.alproto = ALPROTO_TLS; + + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p1->flowflags |= FLOW_PKT_TOSERVER; + p1->flowflags |= FLOW_PKT_ESTABLISHED; + p1->pcap_cnt = 1; + + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p2->flowflags |= FLOW_PKT_TOCLIENT; + p2->flowflags |= FLOW_PKT_ESTABLISHED; + p2->pcap_cnt = 2; + + p3->flow = &f; + p3->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p3->flowflags |= FLOW_PKT_TOCLIENT; + p3->flowflags |= FLOW_PKT_ESTABLISHED; + p3->pcap_cnt = 3; + + f.lastts.tv_sec = 1474978656; /* 2016-09-27 */ + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_cert_valid\"; " + "tls_cert_valid; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + client_hello, sizeof(client_hello)); + + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + FAIL_IF(PacketAlertCheck(p1, 1)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + server_hello, sizeof(server_hello)); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p2); + + FAIL_IF(PacketAlertCheck(p2, 1)); + + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOCLIENT, + certificate, sizeof(certificate)); + + FAIL_IF(r != 0); + + SigMatchSignatures(&tv, de_ctx, det_ctx, p3); + + FAIL_IF_NOT(PacketAlertCheck(p3, 1)); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p1); + UTHFreePacket(p2); + UTHFreePacket(p3); + + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief Register unit tests for tls_cert_notbefore. + */ +void TlsNotBeforeRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ValidityTestParse01", ValidityTestParse01); + UtRegisterTest("ValidityTestParse03", ValidityTestParse03); + UtRegisterTest("ValidityTestParse05", ValidityTestParse05); + UtRegisterTest("ValidityTestParse07", ValidityTestParse07); + UtRegisterTest("ValidityTestParse09", ValidityTestParse09); + UtRegisterTest("ValidityTestParse11", ValidityTestParse11); + UtRegisterTest("ValidityTestParse13", ValidityTestParse13); + UtRegisterTest("ValidityTestParse15", ValidityTestParse15); + UtRegisterTest("ValidityTestParse17", ValidityTestParse17); + UtRegisterTest("ValidityTestParse19", ValidityTestParse19); + UtRegisterTest("ValidityTestParse21", ValidityTestParse21); + UtRegisterTest("ValidityTestParse23", ValidityTestParse23); + UtRegisterTest("ValidityTestDetect01", ValidityTestDetect01); +#endif /* UNITTESTS */ +} + +/** + * \brief Register unit tests for tls_cert_notafter. + */ +void TlsNotAfterRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ValidityTestParse02", ValidityTestParse02); + UtRegisterTest("ValidityTestParse04", ValidityTestParse04); + UtRegisterTest("ValidityTestParse06", ValidityTestParse06); + UtRegisterTest("ValidityTestParse08", ValidityTestParse08); + UtRegisterTest("ValidityTestParse10", ValidityTestParse10); + UtRegisterTest("ValidityTestParse12", ValidityTestParse12); + UtRegisterTest("ValidityTestParse14", ValidityTestParse14); + UtRegisterTest("ValidityTestParse16", ValidityTestParse16); + UtRegisterTest("ValidityTestParse18", ValidityTestParse18); + UtRegisterTest("ValidityTestParse20", ValidityTestParse20); + UtRegisterTest("ValidityTestParse22", ValidityTestParse22); +#endif /* UNITTESTS */ +} + +/** + * \brief Register unit tests for tls_cert_expired + */ +void TlsExpiredRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ExpiredTestDetect01", ExpiredTestDetect01); +#endif /* UNITTESTS */ +} + +/** + * \brief Register unit tests for tls_cert_valid + */ +void TlsValidRegisterTests(void) +{ +#ifdef UNITTESTS /* UNITTESTS */ + UtRegisterTest("ValidTestDetect01", ValidTestDetect01); +#endif /* UNITTESTS */ +} diff --git a/src/detect-tls-cert-validity.h b/src/detect-tls-cert-validity.h new file mode 100644 index 000000000000..256be6b4b2b5 --- /dev/null +++ b/src/detect-tls-cert-validity.h @@ -0,0 +1,51 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_VALIDITY_H__ +#define __DETECT_TLS_VALIDITY_H__ + +#define DETECT_TLS_VALIDITY_EQ (1) /* equal */ +#define DETECT_TLS_VALIDITY_LT (1<<1) /* less than */ +#define DETECT_TLS_VALIDITY_GT (1<<2) /* greater than */ +#define DETECT_TLS_VALIDITY_RA (1<<3) /* range */ + +/* Used by tls_cert_expired */ +#define DETECT_TLS_VALIDITY_EX (1<<4) /* expired */ + +/* Used by tls_cert_valid */ +#define DETECT_TLS_VALIDITY_VA (1<<5) /* valid */ + +#define DETECT_TLS_TYPE_NOTBEFORE 0 +#define DETECT_TLS_TYPE_NOTAFTER 1 + +typedef struct DetectTlsValidityData_ { + time_t epoch; + time_t epoch2; + uint8_t mode; + uint8_t type; +} DetectTlsValidityData; + +/* prototypes */ +void DetectTlsValidityRegister (void); + +#endif /* __DETECT_TLS_VALIDITY_H__ */ diff --git a/src/detect-tls-sni.c b/src/detect-tls-sni.c new file mode 100644 index 000000000000..195175a70f66 --- /dev/null +++ b/src/detect-tls-sni.c @@ -0,0 +1,304 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + * + * Implements support for tls_sni keyword. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-util.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "stream-tcp.h" + +#include "app-layer.h" +#include "app-layer-ssl.h" +#include "detect-engine-tls.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +static int DetectTlsSniSetup(DetectEngineCtx *, Signature *, char *); +static void DetectTlsSniRegisterTests(void); +static int g_tls_sni_buffer_id = 0; + +/** + * \brief Registration function for keyword: tls_sni + */ +void DetectTlsSniRegister(void) +{ + sigmatch_table[DETECT_AL_TLS_SNI].name = "tls_sni"; + sigmatch_table[DETECT_AL_TLS_SNI].desc = "content modifier to match specifically and only on the TLS SNI buffer"; + sigmatch_table[DETECT_AL_TLS_SNI].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tls-sni"; + sigmatch_table[DETECT_AL_TLS_SNI].Match = NULL; + sigmatch_table[DETECT_AL_TLS_SNI].Setup = DetectTlsSniSetup; + sigmatch_table[DETECT_AL_TLS_SNI].Free = NULL; + sigmatch_table[DETECT_AL_TLS_SNI].RegisterTests = DetectTlsSniRegisterTests; + + sigmatch_table[DETECT_AL_TLS_SNI].flags |= SIGMATCH_NOOPT; + + DetectAppLayerMpmRegister("tls_sni", SIG_FLAG_TOSERVER, 2, + PrefilterTxTlsSniRegister); + + DetectAppLayerInspectEngineRegister("tls_sni", + ALPROTO_TLS, SIG_FLAG_TOSERVER, + DetectEngineInspectTlsSni); + + g_tls_sni_buffer_id = DetectBufferTypeGetByName("tls_sni"); +} + + +/** + * \brief this function setup the tls_sni modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + */ +static int DetectTlsSniSetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + s->init_data->list = g_tls_sni_buffer_id; + s->alproto = ALPROTO_TLS; + return 0; +} + +#ifdef UNITTESTS + +/** + * \test Test matching on a simple google.com SNI + */ +static int DetectTlsSniTest01(void) +{ + /* client hello */ + uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0x82, 0x01, 0x00, 0x00, 0x7E, + 0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87, + 0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31, + 0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC, + 0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00, + 0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D, + 0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, + 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, + 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00, + 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, + 0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00, + 0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63, + 0x6F, 0x6D, }; + + Flow f; + SSLState *ssl_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", + 41424, 443); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_TLS; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_sni option\"; " + "tls_sni; content:\"google.com\"; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf, sizeof(buf)); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + PASS; +} + +/** + * \test Test matching on a simple google.com SNI with pcre + */ +static int DetectTlsSniTest02(void) +{ + /* client hello */ + uint8_t buf[] = { 0x16, 0x03, 0x03, 0x00, 0x82, 0x01, 0x00, 0x00, 0x7E, + 0x03, 0x03, 0x57, 0x04, 0x9F, 0x5D, 0xC9, 0x5C, 0x87, + 0xAE, 0xF2, 0xA7, 0x4A, 0xFC, 0x59, 0x78, 0x23, 0x31, + 0x61, 0x2D, 0x29, 0x92, 0xB6, 0x70, 0xA5, 0xA1, 0xFC, + 0x0E, 0x79, 0xFE, 0xC3, 0x97, 0x37, 0xC0, 0x00, 0x00, + 0x44, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0D, + 0x00, 0x10, 0x00, 0x13, 0x00, 0x16, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, + 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, + 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x40, + 0x00, 0x41, 0x00, 0x44, 0x00, 0x45, 0x00, 0x66, 0x00, + 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6A, 0x00, 0x6B, + 0x00, 0x84, 0x00, 0x87, 0x00, 0xFF, 0x01, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00, + 0x0A, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x63, + 0x6F, 0x6D, }; + + Flow f; + SSLState *ssl_state = NULL; + Packet *p = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", + 41424, 443); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + f.protomap = FlowGetProtoMapping(f.proto); + + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED; + f.alproto = ALPROTO_TLS; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + + de_ctx->mpm_matcher = mpm_default_matcher; + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_sni option\"; " + "tls_sni; content:\"google\"; nocase; " + "pcre:\"/google\\.com$/i\"; sid:1;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, "alert tls any any -> any any " + "(msg:\"Test tls_sni option\"; " + "tls_sni; content:\"google\"; nocase; " + "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, buf, sizeof(buf)); + FLOWLOCK_UNLOCK(&f); + FAIL_IF(r != 0); + + ssl_state = f.alstate; + FAIL_IF_NULL(ssl_state); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + FAIL_IF_NOT(PacketAlertCheck(p, 1)); + FAIL_IF_NOT(PacketAlertCheck(p, 2)); + + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&tv, det_ctx); + DetectEngineCtxFree(de_ctx); + + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePacket(p); + + PASS; +} + +#endif + +static void DetectTlsSniRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("DetectTlsSniTest01", DetectTlsSniTest01); + UtRegisterTest("DetectTlsSniTest02", DetectTlsSniTest02); +#endif +} diff --git a/src/detect-tls-sni.h b/src/detect-tls-sni.h new file mode 100644 index 000000000000..a3117906c1b3 --- /dev/null +++ b/src/detect-tls-sni.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __DETECT_TLS_SNI_H__ +#define __DETECT_TLS_SNI_H__ + +#include "app-layer-ssl.h" + +void DetectTlsSniRegister(void); +uint32_t DetectTlsSniInspectMpm(DetectEngineThreadCtx *det_ctx, SSLState *ssl_state); + +#endif /* __DETECT_TLS_SNI_H__ */ diff --git a/src/detect-tls-version.c b/src/detect-tls-version.c index 51547260cc6b..1f027b8247b8 100644 --- a/src/detect-tls-version.c +++ b/src/detect-tls-version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -59,10 +59,13 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsVersionMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, char *); -void DetectTlsVersionRegisterTests(void); -void DetectTlsVersionFree(void *); +static void DetectTlsVersionRegisterTests(void); +static void DetectTlsVersionFree(void *); +static int g_tls_generic_list_id = 0; /** * \brief Registration function for keyword: tls.version @@ -71,36 +74,15 @@ void DetectTlsVersionRegister (void) { sigmatch_table[DETECT_AL_TLS_VERSION].name = "tls.version"; sigmatch_table[DETECT_AL_TLS_VERSION].desc = "match on TLS/SSL version"; - sigmatch_table[DETECT_AL_TLS_VERSION].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsversion"; - sigmatch_table[DETECT_AL_TLS_VERSION].Match = NULL; - sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerMatch = DetectTlsVersionMatch; - sigmatch_table[DETECT_AL_TLS_VERSION].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_TLS_VERSION].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsversion"; + sigmatch_table[DETECT_AL_TLS_VERSION].AppLayerTxMatch = DetectTlsVersionMatch; sigmatch_table[DETECT_AL_TLS_VERSION].Setup = DetectTlsVersionSetup; sigmatch_table[DETECT_AL_TLS_VERSION].Free = DetectTlsVersionFree; sigmatch_table[DETECT_AL_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests; - const char *eb; - int eo; - int opts = 0; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - SCLogDebug("registering tls.version rule option"); - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - return; + g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic"); } /** @@ -114,11 +96,13 @@ void DetectTlsVersionRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectTlsVersionData *tls_data = (DetectTlsVersionData *)m->ctx; + const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -149,7 +133,7 @@ int DetectTlsVersionMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow * * \retval id_d pointer to DetectTlsVersionData on success * \retval NULL on failure */ -DetectTlsVersionData *DetectTlsVersionParse (char *str) +static DetectTlsVersionData *DetectTlsVersionParse (char *str) { uint16_t temp; DetectTlsVersionData *tls = NULL; @@ -201,6 +185,7 @@ DetectTlsVersionData *DetectTlsVersionParse (char *str) temp = TLS_VERSION_12; } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid value"); + SCFree(orig); goto error; } @@ -236,8 +221,12 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectTlsVersionData *tls = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + tls = DetectTlsVersionParse(str); - if (tls == NULL) goto error; + if (tls == NULL) + goto error; /* Okay so far so good, lets get this into a SigMatch * and put it in the Signature. */ @@ -248,19 +237,15 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s sm->type = DETECT_AL_TLS_VERSION; sm->ctx = (void *)tls; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + SigMatchAppendSMToList(s, sm, g_tls_generic_list_id); - s->alproto = ALPROTO_TLS; return 0; error: - if (tls != NULL) DetectTlsVersionFree(tls); - if (sm != NULL) SCFree(sm); + if (tls != NULL) + DetectTlsVersionFree(tls); + if (sm != NULL) + SCFree(sm); return -1; } @@ -270,7 +255,7 @@ static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, char *s * * \param id_d pointer to DetectTlsVersionData */ -void DetectTlsVersionFree(void *ptr) +static void DetectTlsVersionFree(void *ptr) { DetectTlsVersionData *id_d = (DetectTlsVersionData *)ptr; SCFree(id_d); @@ -282,16 +267,14 @@ void DetectTlsVersionFree(void *ptr) * \test DetectTlsVersionTestParse01 is a test to make sure that we parse the "id" * option correctly when given valid id option */ -int DetectTlsVersionTestParse01 (void) +static int DetectTlsVersionTestParse01 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("1.0"); - if (tls != NULL && tls->ver == TLS_VERSION_10) { - DetectTlsVersionFree(tls); - return 1; - } - - return 0; + FAIL_IF_NULL(tls); + FAIL_IF_NOT(tls->ver == TLS_VERSION_10); + DetectTlsVersionFree(tls); + PASS; } /** @@ -299,16 +282,13 @@ int DetectTlsVersionTestParse01 (void) * option correctly when given an invalid id option * it should return id_d = NULL */ -int DetectTlsVersionTestParse02 (void) +static int DetectTlsVersionTestParse02 (void) { DetectTlsVersionData *tls = NULL; tls = DetectTlsVersionParse("2.5"); - if (tls == NULL) { - DetectTlsVersionFree(tls); - return 1; - } - - return 0; + FAIL_IF_NOT_NULL(tls); + DetectTlsVersionFree(tls); + PASS; } #include "stream-tcp-reassemble.h" @@ -316,7 +296,6 @@ int DetectTlsVersionTestParse02 (void) /** \test Send a get request in three chunks + more data. */ static int DetectTlsVersionTestDetect01(void) { - int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -351,67 +330,40 @@ static int DetectTlsVersionTestDetect01(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; tls.version:1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - 0x16, ssl_state->client_connp.content_type); - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - goto end; - } + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); SCLogDebug("ssl_state is at %p, ssl_state->server_version 0x%02X " "ssl_state->client_version 0x%02X", @@ -421,14 +373,9 @@ static int DetectTlsVersionTestDetect01(void) /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -439,12 +386,12 @@ static int DetectTlsVersionTestDetect01(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectTlsVersionTestDetect02(void) { - int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -479,80 +426,47 @@ static int DetectTlsVersionTestDetect02(void) StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tls any any -> any any (msg:\"TLS\"; tls.version:1.0; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - 0x16, ssl_state->client_connp.content_type); - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - goto end; - } + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); + AppLayerParserThreadCtxFree(alp_tctx); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); @@ -563,13 +477,13 @@ static int DetectTlsVersionTestDetect02(void) FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } static int DetectTlsVersionTestDetect03(void) { DetectEngineCtx *de_ctx = NULL; - int result = 0; Flow f; uint8_t tlsbuf1[] = { 0x16 }; uint32_t tlslen1 = sizeof(tlsbuf1); @@ -605,10 +519,7 @@ static int DetectTlsVersionTestDetect03(void) StreamTcpInitConfig(TRUE); StreamMsg *stream_msg = StreamMsgGetFromPool(); - if (stream_msg == NULL) { - printf("no stream_msg: "); - goto end; - } + FAIL_IF_NULL(stream_msg); memcpy(stream_msg->data, tlsbuf4, tlslen4); stream_msg->data_len = tlslen4; @@ -617,91 +528,55 @@ static int DetectTlsVersionTestDetect03(void) ssn.toserver_smsg_tail = stream_msg; de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"TLS\"; tls.version:1.0; content:\"|01 00 00 AD|\"; sid:1;)"); - if (s == NULL) { - goto end; - } + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf1, tlslen1); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, + STREAM_TOSERVER, tlsbuf1, tlslen1); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf2, tlslen2); - if (r != 0) { - printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf2, tlslen2); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf3, tlslen3); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf3, tlslen3); + FAIL_IF(r != 0); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, tlsbuf4, tlslen4); - if (r != 0) { - printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TLS, STREAM_TOSERVER, + tlsbuf4, tlslen4); + FAIL_IF(r != 0); + FLOWLOCK_UNLOCK(&f); SSLState *ssl_state = f.alstate; - if (ssl_state == NULL) { - printf("no tls state: "); - goto end; - } + FAIL_IF_NULL(ssl_state); - if (ssl_state->client_connp.content_type != 0x16) { - printf("expected content_type %" PRIu8 ", got %" PRIu8 ": ", - 0x16, ssl_state->client_connp.content_type); - goto end; - } + FAIL_IF(ssl_state->client_connp.content_type != 0x16); - if (ssl_state->client_connp.version != TLS_VERSION_10) { - printf("expected version %04" PRIu16 ", got %04" PRIu16 ": ", - TLS_VERSION_10, ssl_state->client_connp.version); - goto end; - } + FAIL_IF(ssl_state->client_connp.version != TLS_VERSION_10); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!(PacketAlertCheck(p, 1))) { - printf("signature 1 didn't match while it should have: "); - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p, 1)); - result = 1; -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } + AppLayerParserThreadCtxFree(alp_tctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); StreamTcpFreeConfig(TRUE); FLOW_DESTROY(&f); UTHFreePackets(&p, 1); - return result; + + PASS; } #endif /* UNITTESTS */ @@ -709,14 +584,17 @@ static int DetectTlsVersionTestDetect03(void) /** * \brief this function registers unit tests for DetectTlsVersion */ -void DetectTlsVersionRegisterTests(void) +static void DetectTlsVersionRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01, 1); - UtRegisterTest("DetectTlsVersionTestParse02", DetectTlsVersionTestParse02, 1); - UtRegisterTest("DetectTlsVersionTestDetect01", DetectTlsVersionTestDetect01, 1); - UtRegisterTest("DetectTlsVersionTestDetect02", DetectTlsVersionTestDetect02, 1); - UtRegisterTest("DetectTlsVersionTestDetect03", DetectTlsVersionTestDetect03, 1); + UtRegisterTest("DetectTlsVersionTestParse01", DetectTlsVersionTestParse01); + UtRegisterTest("DetectTlsVersionTestParse02", DetectTlsVersionTestParse02); + UtRegisterTest("DetectTlsVersionTestDetect01", + DetectTlsVersionTestDetect01); + UtRegisterTest("DetectTlsVersionTestDetect02", + DetectTlsVersionTestDetect02); + UtRegisterTest("DetectTlsVersionTestDetect03", + DetectTlsVersionTestDetect03); #endif /* UNITTESTS */ } diff --git a/src/detect-tls.c b/src/detect-tls.c index 9b1d237baf0c..585eabe3c94a 100644 --- a/src/detect-tls.c +++ b/src/detect-tls.c @@ -74,19 +74,41 @@ static pcre_extra *issuerdn_parse_regex_study; static pcre *fingerprint_parse_regex; static pcre_extra *fingerprint_parse_regex_study; -static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsSubjectMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsSubjectRegisterTests(void); static void DetectTlsSubjectFree(void *); -static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); + +static int DetectTlsIssuerDNMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsIssuerDNRegisterTests(void); static void DetectTlsIssuerDNFree(void *); -static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); + +static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, + Flow *, uint8_t, void *, void *, + const Signature *, const SigMatchCtx *); static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *); static void DetectTlsFingerprintFree(void *); + static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *); -static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *); +static int DetectTlsStorePostMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *, const Signature *s, const SigMatchCtx *unused); + +static int g_tls_cert_list_id = 0; + +static int InspectTlsCert(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const Signature *s, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *txv, uint64_t tx_id) +{ + return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd, + f, flags, alstate, txv, tx_id); +} /** * \brief Registration function for keyword: tls.version @@ -95,97 +117,50 @@ void DetectTlsRegister (void) { sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject"; sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlssubject"; - sigmatch_table[DETECT_AL_TLS_SUBJECT].Match = NULL; - sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerMatch = DetectTlsSubjectMatch; - sigmatch_table[DETECT_AL_TLS_SUBJECT].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_TLS_SUBJECT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlssubject"; + sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerTxMatch = DetectTlsSubjectMatch; sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; sigmatch_table[DETECT_AL_TLS_SUBJECT].Free = DetectTlsSubjectFree; sigmatch_table[DETECT_AL_TLS_SUBJECT].RegisterTests = DetectTlsSubjectRegisterTests; sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn"; sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsissuerdn"; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].Match = NULL; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerMatch = DetectTlsIssuerDNMatch; - sigmatch_table[DETECT_AL_TLS_ISSUERDN].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsissuerdn"; + sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerTxMatch = DetectTlsIssuerDNMatch; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; sigmatch_table[DETECT_AL_TLS_ISSUERDN].RegisterTests = DetectTlsIssuerDNRegisterTests; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint"; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsfingerprint"; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Match = NULL; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerMatch = DetectTlsFingerprintMatch; - sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsfingerprint"; + sigmatch_table[DETECT_AL_TLS_FINGERPRINT].AppLayerTxMatch = DetectTlsFingerprintMatch; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL; - sigmatch_table[DETECT_AL_TLS_STORE].name = "tls.store"; + sigmatch_table[DETECT_AL_TLS_STORE].name = "tls_store"; + sigmatch_table[DETECT_AL_TLS_STORE].alias = "tls.store"; sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk"; - sigmatch_table[DETECT_AL_TLS_STORE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/TLS-keywords#tlsstore"; - sigmatch_table[DETECT_AL_TLS_STORE].Match = NULL; - sigmatch_table[DETECT_AL_TLS_STORE].AppLayerMatch = DetectTlsStoreMatch; - sigmatch_table[DETECT_AL_TLS_STORE].alproto = ALPROTO_TLS; + sigmatch_table[DETECT_AL_TLS_STORE].url = DOC_URL DOC_VERSION "/rules/tls-keywords.html#tlsstore"; + sigmatch_table[DETECT_AL_TLS_STORE].Match = DetectTlsStorePostMatch; sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup; sigmatch_table[DETECT_AL_TLS_STORE].Free = NULL; sigmatch_table[DETECT_AL_TLS_STORE].RegisterTests = NULL; sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT; - const char *eb; - int eo; - int opts = 0; - - SCLogDebug("registering tls.subject rule option"); - - subject_parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (subject_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - subject_parse_regex_study = pcre_study(subject_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - SCLogDebug("registering tls.issuerdn rule option"); - - issuerdn_parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (issuerdn_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - issuerdn_parse_regex_study = pcre_study(issuerdn_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - SCLogDebug("registering tls.fingerprint rule option"); - - fingerprint_parse_regex = pcre_compile(PARSE_REGEX_FINGERPRINT, opts, &eb, &eo, NULL); - if (fingerprint_parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX_FINGERPRINT, eo, eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, + &subject_parse_regex, &subject_parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX, + &issuerdn_parse_regex, &issuerdn_parse_regex_study); + DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, + &fingerprint_parse_regex, &fingerprint_parse_regex_study); - fingerprint_parse_regex_study = pcre_study(fingerprint_parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } + g_tls_cert_list_id = DetectBufferTypeRegister("tls_cert"); - return; - -error: - return; + DetectAppLayerInspectEngineRegister("tls_cert", + ALPROTO_TLS, SIG_FLAG_TOCLIENT, + InspectTlsCert); } /** @@ -199,11 +174,13 @@ void DetectTlsRegister (void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsSubjectMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectTlsData *tls_data = (DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -277,6 +254,7 @@ static DetectTlsData *DetectTlsSubjectParse (char *str) } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; + pcre_free_substring(str_ptr); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { @@ -295,6 +273,8 @@ static DetectTlsData *DetectTlsSubjectParse (char *str) if (unlikely(orig == NULL)) { goto error; } + pcre_free_substring(str_ptr); + tmp_str=orig; /* Let's see if we need to escape "'s */ @@ -339,6 +319,9 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s DetectTlsData *tls = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + tls = DetectTlsSubjectParse(str); if (tls == NULL) goto error; @@ -349,19 +332,10 @@ static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, char *s if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_TLS_SUBJECT; sm->ctx = (void *)tls; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - + SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); return 0; error: @@ -406,11 +380,13 @@ static void DetectTlsSubjectRegisterTests(void) * \retval 0 no match * \retval 1 match */ -static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsIssuerDNMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectTlsData *tls_data = (DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -484,6 +460,7 @@ static DetectTlsData *DetectTlsIssuerDNParse(char *str) } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; + pcre_free_substring(str_ptr); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { @@ -502,6 +479,8 @@ static DetectTlsData *DetectTlsIssuerDNParse(char *str) if (unlikely(orig == NULL)) { goto error; } + pcre_free_substring(str_ptr); + tmp_str=orig; /* Let's see if we need to escape "'s */ @@ -547,6 +526,9 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * DetectTlsData *tls = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + tls = DetectTlsIssuerDNParse(str); if (tls == NULL) goto error; @@ -557,19 +539,10 @@ static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, char * if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_TLS_ISSUERDN; sm->ctx = (void *)tls; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - + SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); return 0; error: @@ -627,6 +600,7 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) } if (str_ptr[0] == '!') flag = DETECT_CONTENT_NEGATED; + pcre_free_substring(str_ptr); res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { @@ -645,6 +619,8 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) if (unlikely(orig == NULL)) { goto error; } + pcre_free_substring(str_ptr); + tmp_str=orig; /* Let's see if we need to escape "'s */ @@ -682,10 +658,12 @@ static DetectTlsData *DetectTlsFingerprintParse (char *str) * \retval 0 no match * \retval 1 match */ -static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Flow *f, uint8_t flags, void *state, void *txv, + const Signature *s, const SigMatchCtx *m) { SCEnter(); - DetectTlsData *tls_data = (DetectTlsData *)m->ctx; + const DetectTlsData *tls_data = (const DetectTlsData *)m; SSLState *ssl_state = (SSLState *)state; if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); @@ -694,13 +672,20 @@ static int DetectTlsFingerprintMatch (ThreadVars *t, DetectEngineThreadCtx *det_ int ret = 0; - if (ssl_state->server_connp.cert0_fingerprint != NULL) { + SSLStateConnp *connp = NULL; + if (flags & STREAM_TOSERVER) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_fingerprint != NULL) { SCLogDebug("TLS: Fingerprint is [%s], looking for [%s]\n", - ssl_state->server_connp.cert0_fingerprint, + connp->cert0_fingerprint, tls_data->fingerprint); if (tls_data->fingerprint && - (strstr(ssl_state->server_connp.cert0_fingerprint, + (strstr(connp->cert0_fingerprint, tls_data->fingerprint) != NULL)) { if (tls_data->flags & DETECT_CONTENT_NEGATED) { ret = 0; @@ -738,6 +723,9 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha DetectTlsData *tls = NULL; SigMatch *sm = NULL; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; + tls = DetectTlsFingerprintParse(str); if (tls == NULL) goto error; @@ -748,19 +736,10 @@ static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, cha if (sm == NULL) goto error; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } - sm->type = DETECT_AL_TLS_FINGERPRINT; sm->ctx = (void *)tls; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - + SigMatchAppendSMToList(s, sm, g_tls_cert_list_id); return 0; error: @@ -800,47 +779,36 @@ static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str { SigMatch *sm = NULL; - s->flags |= SIG_FLAG_TLSSTORE; + if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) + return -1; sm = SigMatchAlloc(); if (sm == NULL) - goto error; - - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords."); - goto error; - } + return -1; sm->type = DETECT_AL_TLS_STORE; - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_TLS; - - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->flags |= SIG_FLAG_TLSSTORE; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); return 0; - -error: - if (sm != NULL) - SCFree(sm); - return -1; - } -/** \warning modifies state */ -static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) +/** \warning modifies Flow::alstate */ +static int DetectTlsStorePostMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, + Packet *p, const Signature *s, const SigMatchCtx *unused) { SCEnter(); - SSLState *ssl_state = (SSLState *)state; + if (p->flow == NULL) + return 0; + + SSLState *ssl_state = FlowGetAppState(p->flow); if (ssl_state == NULL) { SCLogDebug("no tls state, no match"); - SCReturnInt(1); - } - - if (s->flags & SIG_FLAG_TLSSTORE) { - ssl_state->server_connp.cert_log_flag |= SSL_TLS_LOG_PEM; + SCReturnInt(0); } + ssl_state->server_connp.cert_log_flag |= SSL_TLS_LOG_PEM; SCReturnInt(1); } diff --git a/src/detect-tos.c b/src/detect-tos.c index 942dd28b5e58..699d2474b11a 100644 --- a/src/detect-tos.c +++ b/src/detect-tos.c @@ -50,7 +50,7 @@ static pcre_extra *parse_regex_study; static int DetectTosSetup(DetectEngineCtx *, Signature *, char *); static int DetectTosMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, - Signature *, SigMatch *); + const Signature *, const SigMatchCtx *); static void DetectTosRegisterTests(void); static void DetectTosFree(void *); @@ -68,27 +68,7 @@ void DetectTosRegister(void) sigmatch_table[DETECT_TOS].Free = DetectTosFree; sigmatch_table[DETECT_TOS].RegisterTests = DetectTosRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at " - "offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - - return; - -error: - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -102,10 +82,10 @@ void DetectTosRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTosMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s, SigMatch *sm) +static int DetectTosMatch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - DetectTosData *tosd = (DetectTosData *)sm->ctx; + const DetectTosData *tosd = (const DetectTosData *)ctx; int result = 0; if (!PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p)) { @@ -183,8 +163,6 @@ DetectTosData *DetectTosParse(char *arg) return tosd; error: - if (tosd != NULL) - DetectTosFree(tosd); return NULL; } @@ -215,7 +193,7 @@ int DetectTosSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) goto error; sm->type = DETECT_TOS; - sm->ctx = (void *)tosd; + sm->ctx = (SigMatchCtx *)tosd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -412,18 +390,18 @@ int DetectTosTest12(void) void DetectTosRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTosTest01", DetectTosTest01, 1); - UtRegisterTest("DetectTosTest02", DetectTosTest02, 1); - UtRegisterTest("DetectTosTest03", DetectTosTest03, 1); - UtRegisterTest("DetectTosTest04", DetectTosTest04, 1); - UtRegisterTest("DetectTosTest05", DetectTosTest05, 1); - UtRegisterTest("DetectTosTest06", DetectTosTest06, 1); - UtRegisterTest("DetectTosTest07", DetectTosTest07, 1); - UtRegisterTest("DetectTosTest08", DetectTosTest08, 1); - UtRegisterTest("DetectTosTest09", DetectTosTest09, 1); - UtRegisterTest("DetectTosTest10", DetectTosTest10, 1); - UtRegisterTest("DetectTosTest11", DetectTosTest11, 1); - UtRegisterTest("DetectTosTest12", DetectTosTest12, 1); + UtRegisterTest("DetectTosTest01", DetectTosTest01); + UtRegisterTest("DetectTosTest02", DetectTosTest02); + UtRegisterTest("DetectTosTest03", DetectTosTest03); + UtRegisterTest("DetectTosTest04", DetectTosTest04); + UtRegisterTest("DetectTosTest05", DetectTosTest05); + UtRegisterTest("DetectTosTest06", DetectTosTest06); + UtRegisterTest("DetectTosTest07", DetectTosTest07); + UtRegisterTest("DetectTosTest08", DetectTosTest08); + UtRegisterTest("DetectTosTest09", DetectTosTest09); + UtRegisterTest("DetectTosTest10", DetectTosTest10); + UtRegisterTest("DetectTosTest11", DetectTosTest11); + UtRegisterTest("DetectTosTest12", DetectTosTest12); #endif return; diff --git a/src/detect-ttl.c b/src/detect-ttl.c index f348ea2b02d8..b70312e47e68 100644 --- a/src/detect-ttl.c +++ b/src/detect-ttl.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-ttl.h" #include "util-debug.h" @@ -42,11 +43,15 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; /*prototypes*/ -int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +static int DetectTtlMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); static int DetectTtlSetup (DetectEngineCtx *, Signature *, char *); void DetectTtlFree (void *); void DetectTtlRegisterTests (void); +static int PrefilterSetupTtl(SigGroupHead *sgh); +static _Bool PrefilterTtlIsPrefilterable(const Signature *s); + /** * \brief Registration function for ttl: keyword */ @@ -55,33 +60,33 @@ void DetectTtlRegister(void) { sigmatch_table[DETECT_TTL].name = "ttl"; sigmatch_table[DETECT_TTL].desc = "check for a specific IP time-to-live value"; - sigmatch_table[DETECT_TTL].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#ttl"; + sigmatch_table[DETECT_TTL].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#ttl"; sigmatch_table[DETECT_TTL].Match = DetectTtlMatch; sigmatch_table[DETECT_TTL].Setup = DetectTtlSetup; sigmatch_table[DETECT_TTL].Free = DetectTtlFree; sigmatch_table[DETECT_TTL].RegisterTests = DetectTtlRegisterTests; - const char *eb; - int eo; - int opts = 0; - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } + sigmatch_table[DETECT_TTL].SupportsPrefilter = PrefilterTtlIsPrefilterable; + sigmatch_table[DETECT_TTL].SetupPrefilter = PrefilterSetupTtl; - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); return; +} + +static inline int TtlMatch(const uint8_t pttl, const uint8_t mode, + const uint8_t dttl1, const uint8_t dttl2) +{ + if (mode == DETECT_TTL_EQ && pttl == dttl1) + return 1; + else if (mode == DETECT_TTL_LT && pttl < dttl1) + return 1; + else if (mode == DETECT_TTL_GT && pttl > dttl1) + return 1; + else if (mode == DETECT_TTL_RA && (pttl > dttl1 && pttl < dttl2)) + return 1; + + return 0; -error: - if (parse_regex != NULL) SCFree(parse_regex); - if (parse_regex_study != NULL) SCFree(parse_regex_study); - return; } /** @@ -95,35 +100,25 @@ void DetectTtlRegister(void) * \retval 0 no match * \retval 1 match */ -int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectTtlMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - uint8_t pttl; - DetectTtlData *ttld = (DetectTtlData *) m->ctx; - if (PKT_IS_PSEUDOPKT(p)) return 0; + uint8_t pttl; if (PKT_IS_IPV4(p)) { pttl = IPV4_GET_IPTTL(p); } else if (PKT_IS_IPV6(p)) { pttl = IPV6_GET_HLIM(p); } else { SCLogDebug("Packet is of not IPv4 or IPv6"); - return ret; + return 0; } - if (ttld->mode == DETECT_TTL_EQ && pttl == ttld->ttl1) - ret = 1; - else if (ttld->mode == DETECT_TTL_LT && pttl < ttld->ttl1) - ret = 1; - else if (ttld->mode == DETECT_TTL_GT && pttl > ttld->ttl1) - ret = 1; - else if (ttld->mode == DETECT_TTL_RA && (pttl > ttld->ttl1 && pttl < ttld->ttl2)) - ret = 1; - - return ret; + const DetectTtlData *ttld = (const DetectTtlData *)ctx; + return TtlMatch(pttl, ttld->mode, ttld->ttl1, ttld->ttl2); } /** @@ -183,7 +178,7 @@ DetectTtlData *DetectTtlParse (char *ttlstr) ttld = SCMalloc(sizeof (DetectTtlData)); if (unlikely(ttld == NULL)) - goto error; + goto error; ttld->ttl1 = 0; ttld->ttl2 = 0; @@ -233,7 +228,9 @@ DetectTtlData *DetectTtlParse (char *ttlstr) default: ttld->mode = DETECT_TTL_EQ; - if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0)) + if ((arg2 != NULL && strlen(arg2) > 0) || + (arg3 != NULL && strlen(arg3) > 0) || + (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); @@ -242,9 +239,8 @@ DetectTtlData *DetectTtlParse (char *ttlstr) } else { ttld->mode = DETECT_TTL_EQ; - if ((arg2 != NULL && strlen(arg2) > 0) || - (arg3 != NULL && strlen(arg3) > 0) || - (arg1 == NULL ||strlen(arg1) == 0)) + if ((arg3 != NULL && strlen(arg3) > 0) || + (arg1 == NULL ||strlen(arg1) == 0)) goto error; ttld->ttl1 = (uint8_t) atoi(arg1); @@ -256,10 +252,14 @@ DetectTtlData *DetectTtlParse (char *ttlstr) return ttld; error: - if (ttld) SCFree(ttld); - if (arg1) SCFree(arg1); - if (arg2) SCFree(arg2); - if (arg3) SCFree(arg3); + if (ttld) + SCFree(ttld); + if (arg1) + SCFree(arg1); + if (arg2) + SCFree(arg2); + if (arg3) + SCFree(arg3); return NULL; } @@ -288,7 +288,7 @@ static int DetectTtlSetup (DetectEngineCtx *de_ctx, Signature *s, char *ttlstr) goto error; sm->type = DETECT_TTL; - sm->ctx = (void *)ttld; + sm->ctx = (SigMatchCtx *)ttld; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -312,9 +312,77 @@ void DetectTtlFree(void *ptr) SCFree(ttld); } -#ifdef UNITTESTS +/* prefilter code */ -#include "detect-parse.h" +static void +PrefilterPacketTtlMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + if (PKT_IS_PSEUDOPKT(p)) { + SCReturn; + } + + uint8_t pttl; + if (PKT_IS_IPV4(p)) { + pttl = IPV4_GET_IPTTL(p); + } else if (PKT_IS_IPV6(p)) { + pttl = IPV6_GET_HLIM(p); + } else { + SCLogDebug("Packet is of not IPv4 or IPv6"); + return; + } + + const PrefilterPacketHeaderCtx *ctx = pectx; + if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE) + return; + + if (TtlMatch(pttl, ctx->v1.u8[0], ctx->v1.u8[1], ctx->v1.u8[2])) + { + SCLogDebug("packet matches ttl/hl %u", pttl); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketTtlSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectTtlData *a = smctx; + v->u8[0] = a->mode; + v->u8[1] = a->ttl1; + v->u8[2] = a->ttl2; +} + +static _Bool +PrefilterPacketTtlCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectTtlData *a = smctx; + if (v.u8[0] == a->mode && + v.u8[1] == a->ttl1 && + v.u8[2] == a->ttl2) + return TRUE; + return FALSE; +} + +static int PrefilterSetupTtl(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_TTL, + PrefilterPacketTtlSet, + PrefilterPacketTtlCompare, + PrefilterPacketTtlMatch); +} + +static _Bool PrefilterTtlIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_TTL: + return TRUE; + } + } + return FALSE; +} + +#ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -625,14 +693,14 @@ static int DetectTtlTestSig1(void) void DetectTtlRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectTtlParseTest01", DetectTtlParseTest01, 1); - UtRegisterTest("DetectTtlParseTest02", DetectTtlParseTest02, 1); - UtRegisterTest("DetectTtlParseTest03", DetectTtlParseTest03, 1); - UtRegisterTest("DetectTtlParseTest04", DetectTtlParseTest04, 1); - UtRegisterTest("DetectTtlParseTest05", DetectTtlParseTest05, 1); - UtRegisterTest("DetectTtlParseTest06", DetectTtlParseTest06, 1); - UtRegisterTest("DetectTtlParseTest07", DetectTtlParseTest07, 1); - UtRegisterTest("DetectTtlSetpTest01", DetectTtlSetpTest01, 1); - UtRegisterTest("DetectTtlTestSig1", DetectTtlTestSig1, 1); + UtRegisterTest("DetectTtlParseTest01", DetectTtlParseTest01); + UtRegisterTest("DetectTtlParseTest02", DetectTtlParseTest02); + UtRegisterTest("DetectTtlParseTest03", DetectTtlParseTest03); + UtRegisterTest("DetectTtlParseTest04", DetectTtlParseTest04); + UtRegisterTest("DetectTtlParseTest05", DetectTtlParseTest05); + UtRegisterTest("DetectTtlParseTest06", DetectTtlParseTest06); + UtRegisterTest("DetectTtlParseTest07", DetectTtlParseTest07); + UtRegisterTest("DetectTtlSetpTest01", DetectTtlSetpTest01); + UtRegisterTest("DetectTtlTestSig1", DetectTtlTestSig1); #endif /* UNITTESTS */ } diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index a22479b07958..b541e0873523 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -54,17 +54,14 @@ #include "util-unittest-helper.h" #include "util-binsearch.h" #include "util-spm.h" -#include "util-spm-bm.h" #include "conf.h" /* prototypes */ static int DetectUricontentSetup (DetectEngineCtx *, Signature *, char *); -void HttpUriRegisterTests(void); +static void DetectUricontentRegisterTests(void); +static void DetectUricontentFree(void *); -int DetectAppLayerUricontentMatch (ThreadVars *, DetectEngineThreadCtx *, - Flow *, uint8_t , void *, - Signature *, SigMatch *); -void DetectUricontentFree(void *); +static int g_http_uri_buffer_id = 0; /** * \brief Registration function for uricontent: keyword @@ -72,23 +69,12 @@ void DetectUricontentFree(void *); void DetectUricontentRegister (void) { sigmatch_table[DETECT_URICONTENT].name = "uricontent"; - sigmatch_table[DETECT_URICONTENT].AppLayerMatch = NULL; sigmatch_table[DETECT_URICONTENT].Match = NULL; sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup; sigmatch_table[DETECT_URICONTENT].Free = DetectUricontentFree; - sigmatch_table[DETECT_URICONTENT].RegisterTests = HttpUriRegisterTests; - sigmatch_table[DETECT_URICONTENT].alproto = ALPROTO_HTTP; + sigmatch_table[DETECT_URICONTENT].RegisterTests = DetectUricontentRegisterTests; - sigmatch_table[DETECT_URICONTENT].flags |= SIGMATCH_PAYLOAD; -} - -/** - * \brief pass on the uricontent_max_id - * \param de_ctx pointer to the detect egine context whose max id is asked - */ -uint32_t DetectUricontentMaxId(DetectEngineCtx *de_ctx) -{ - return MpmPatternIdStoreGetMaxId(de_ctx->mpm_pattern_id_store); + g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); } /** @@ -104,7 +90,7 @@ void DetectUricontentFree(void *ptr) if (cd == NULL) SCReturn; - BoyerMooreCtxDeInit(cd->bm_ctx); + SpmDestroyCtx(cd->spm_ctx); SCFree(cd); SCReturn; @@ -199,78 +185,13 @@ int DetectUricontentSetup(DetectEngineCtx *de_ctx, Signature *s, char *contentst SCReturnInt(-1); } -/** - * \brief Checks if the content sent as the argument, has a uricontent which - * has been provided in the rule. This match function matches the - * normalized http uri against the given rule using multi pattern - * search algorithms. - * - * \param det_ctx Pointer to the detection engine thread context - * \param content Pointer to the uri content currently being matched - * \param content_len Content_len of the received uri content - * - * \retval 1 if the uri contents match; 0 no match - */ -static inline int DoDetectAppLayerUricontentMatch (DetectEngineThreadCtx *det_ctx, - uint8_t *uri, uint16_t uri_len, uint8_t flags) -{ - int ret = 0; - /* run the pattern matcher against the uri */ - if (det_ctx->sgh->mpm_uricontent_maxlen > uri_len) { - SCLogDebug("not searching as pkt payload is smaller than the " - "largest uricontent length we need to match"); - } else { - SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt " - "%" PRIu32 ")", det_ctx->sgh, det_ctx->sgh-> - mpm_uricontent_maxlen, det_ctx->sgh->sig_cnt); - - ret += UriPatternSearch(det_ctx, uri, uri_len, flags); - - SCLogDebug("post search: cnt %" PRIu32, ret); - } - return ret; -} - -/** - * \brief Run the pattern matcher against the uri(s) - * - * We run against _all_ uri(s) we have as the pattern matcher will - * flag each sig that has a match. We need to do this for all uri(s) - * to not miss possible events. - * - * \param f locked flow - * \param htp_state initialized htp state - * - * \warning Make sure the flow/state is locked - * \todo what should we return? Just the fact that we matched? - */ -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *txv, uint64_t idx) -{ - SCEnter(); - - htp_tx_t *tx = (htp_tx_t *)txv; - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - uint32_t cnt = 0; - - if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) - goto end; - cnt = DoDetectAppLayerUricontentMatch(det_ctx, (uint8_t *) - bstr_ptr(tx_ud->request_uri_normalized), - bstr_len(tx_ud->request_uri_normalized), - flags); - -end: - SCReturnUInt(cnt); -} - /* * UNITTTESTS */ #ifdef UNITTESTS +#include "detect-isdataat.h" #include "stream-tcp-reassemble.h" /** \test Test case where path traversal has been sent as a path string in the @@ -295,9 +216,11 @@ static int HTTPUriTest01(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -334,7 +257,7 @@ static int HTTPUriTest01(void) if (alp_tctx != NULL) AppLayerParserThreadCtxFree(alp_tctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -363,9 +286,11 @@ static int HTTPUriTest02(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -404,7 +329,7 @@ static int HTTPUriTest02(void) StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -433,9 +358,11 @@ static int HTTPUriTest03(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -474,7 +401,7 @@ static int HTTPUriTest03(void) StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -504,9 +431,11 @@ static int HTTPUriTest04(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START| - STREAM_EOF, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER | STREAM_START | STREAM_EOF, + httpbuf1, + httplen1); if (r != 0) { printf("AppLayerParse failed: r(%d) != 0: ", r); goto end; @@ -545,7 +474,7 @@ static int HTTPUriTest04(void) StreamTcpFreeConfig(TRUE); if (htp_state != NULL) HTPStateFree(htp_state); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); return result; } @@ -555,45 +484,24 @@ static int HTTPUriTest04(void) */ int DetectUriSigTest01(void) { - SigMatch *sm = NULL; - int result = 0; ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; Signature *s = NULL; memset(&th_v, 0, sizeof(th_v)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx,"alert http any any -> any any (msg:" - "\" Test uricontent\"; " - "content:\"me\"; uricontent:\"me\"; sid:1;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + s = DetectEngineAppendSig(de_ctx,"alert http any any -> any any (msg:" + "\" Test uricontent\"; content:\"me\"; uricontent:\"me\"; sid:1;)"); + FAIL_IF_NULL(s); - BUG_ON(de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH] == NULL); - - sm = de_ctx->sig_list->sm_lists[DETECT_SM_LIST_UMATCH]; - if (sm->type == DETECT_CONTENT) { - result = 1; - } else { - result = 0; - } + BUG_ON(s->sm_lists[g_http_uri_buffer_id] == NULL); + FAIL_IF_NOT(de_ctx->sig_list->sm_lists[g_http_uri_buffer_id]->type == DETECT_CONTENT); - end: - if (de_ctx != NULL) SigGroupCleanup(de_ctx); - if (de_ctx != NULL) SigCleanSignatures(de_ctx); - if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, det_ctx); - if (de_ctx != NULL) DetectEngineCtxFree(de_ctx); - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** \test Check the signature working to alert when http_cookie is matched . */ @@ -635,7 +543,6 @@ static int DetectUriSigTest02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -663,14 +570,15 @@ static int DetectUriSigTest02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -751,7 +659,6 @@ static int DetectUriSigTest03(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -779,14 +686,15 @@ static int DetectUriSigTest03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -803,14 +711,15 @@ static int DetectUriSigTest03(void) } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf2, httplen2); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -866,7 +775,7 @@ static int DetectUriSigTest04(void) "\" Test uricontent\"; " "uricontent:\"foo\"; sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { @@ -878,7 +787,7 @@ static int DetectUriSigTest04(void) "\" Test uricontent and content\"; " "uricontent:\"foo\"; content:\"bar\";sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { @@ -891,7 +800,7 @@ static int DetectUriSigTest04(void) "uricontent:\"foo\"; content:\"bar\";" " depth:10; offset: 5; sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || @@ -906,10 +815,10 @@ static int DetectUriSigTest04(void) "content:\"foo\"; uricontent:\"bar\";" " depth:10; offset: 5; sid:1;)"); if (s == NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || - ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->depth != 15 || - ((DetectContentData *)s->sm_lists[DETECT_SM_LIST_UMATCH]->ctx)->offset != 5 || + ((DetectContentData *)s->sm_lists[g_http_uri_buffer_id]->ctx)->depth != 15 || + ((DetectContentData *)s->sm_lists[g_http_uri_buffer_id]->ctx)->offset != 5 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 4 failed to parse: "); @@ -941,7 +850,7 @@ static int DetectUriSigTest04(void) "\"two_contents\"; within:30; sid:1;)"); if (s == NULL) { goto end; - } else if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + } else if (s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || @@ -960,15 +869,15 @@ static int DetectUriSigTest04(void) "\"two_uricontents\"; within:30; sid:1;)"); if (s == NULL) { goto end; - } else if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + } else if (s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->within != 30 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->within != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 8 failed to parse: "); - DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); + DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx); goto end; } @@ -980,7 +889,7 @@ static int DetectUriSigTest04(void) if (s == NULL) { goto end; } else if ( - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || @@ -1000,15 +909,15 @@ static int DetectUriSigTest04(void) if (s == NULL) { goto end; } else if ( - s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || + s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->distance != 30 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->distance != 30 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 10 failed to parse: "); - DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); + DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx); goto end; } @@ -1024,21 +933,21 @@ static int DetectUriSigTest04(void) goto end; } - if (s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { - printf("umatch %p or pmatch %p: ", s->sm_lists[DETECT_SM_LIST_UMATCH], s->sm_lists[DETECT_SM_LIST_PMATCH]); + if (s->sm_lists[g_http_uri_buffer_id] == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL) { + printf("umatch %p or pmatch %p: ", s->sm_lists[g_http_uri_buffer_id], s->sm_lists[DETECT_SM_LIST_PMATCH]); goto end; } if ( ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->depth != 15 || ((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx)->offset != 5 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->distance != 30 || - ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx)->within != 60 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->distance != 30 || + ((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx)->within != 60 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->distance != 45 || ((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx)->within != 70 || s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { printf("sig 10 failed to parse, content not setup properly: "); DetectContentPrint((DetectContentData*) s->sm_lists[DETECT_SM_LIST_PMATCH]->ctx); - DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx); + DetectUricontentPrint((DetectContentData*) s->sm_lists_tail[g_http_uri_buffer_id]->ctx); DetectContentPrint((DetectContentData*) s->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx); goto end; } @@ -1106,7 +1015,6 @@ static int DetectUriSigTest05(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -1132,14 +1040,15 @@ static int DetectUriSigTest05(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1235,7 +1144,6 @@ static int DetectUriSigTest06(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -1273,14 +1181,15 @@ static int DetectUriSigTest06(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1358,7 +1267,6 @@ static int DetectUriSigTest07(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:" @@ -1396,14 +1304,15 @@ static int DetectUriSigTest07(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&th_v, de_ctx, det_ctx, p); @@ -1579,12 +1488,12 @@ int DetectUriSigTest12(void) goto end; } - if (s->sm_lists_tail[DETECT_SM_LIST_UMATCH] == NULL || s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx == NULL) { + if (s->sm_lists_tail[g_http_uri_buffer_id] == NULL || s->sm_lists_tail[g_http_uri_buffer_id]->ctx == NULL) { printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: "); goto end; } - ud = (DetectContentData *)s->sm_lists_tail[DETECT_SM_LIST_UMATCH]->ctx; + ud = (DetectContentData *)s->sm_lists_tail[g_http_uri_buffer_id]->ctx; result = (strncmp("boo", (char *)ud->content, ud->content_len) == 0); end: @@ -1944,40 +1853,68 @@ int DetectUriContentParseTest24(void) return result; } +static int DetectUricontentIsdataatParseTest(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (" + "uricontent:\"one\"; " + "isdataat:!4,relative; sid:1;)"); + FAIL_IF_NULL(s); + + SigMatch *sm = s->init_data->smlists_tail[g_http_uri_buffer_id]; + FAIL_IF_NULL(sm); + FAIL_IF_NOT(sm->type == DETECT_ISDATAAT); + + DetectIsdataatData *data = (DetectIsdataatData *)sm->ctx; + FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); + FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); + FAIL_IF(data->flags & ISDATAAT_RAWBYTES); + + DetectEngineCtxFree(de_ctx); + PASS; +} + #endif /* UNITTESTS */ -void HttpUriRegisterTests(void) +static void DetectUricontentRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HTTPUriTest01", HTTPUriTest01, 1); - UtRegisterTest("HTTPUriTest02", HTTPUriTest02, 1); - UtRegisterTest("HTTPUriTest03", HTTPUriTest03, 1); - UtRegisterTest("HTTPUriTest04", HTTPUriTest04, 1); - - UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01, 1); - UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02, 1); - UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03, 1); - UtRegisterTest("DetectUriSigTest04 - Modifiers", DetectUriSigTest04, 1); - UtRegisterTest("DetectUriSigTest05 - Inspection", DetectUriSigTest05, 1); - UtRegisterTest("DetectUriSigTest06 - Inspection", DetectUriSigTest06, 1); - UtRegisterTest("DetectUriSigTest07 - Inspection", DetectUriSigTest07, 1); - UtRegisterTest("DetectUriSigTest08", DetectUriSigTest08, 1); - UtRegisterTest("DetectUriSigTest09", DetectUriSigTest09, 1); - UtRegisterTest("DetectUriSigTest10", DetectUriSigTest10, 1); - UtRegisterTest("DetectUriSigTest11", DetectUriSigTest11, 1); - UtRegisterTest("DetectUriSigTest12", DetectUriSigTest12, 1); - - UtRegisterTest("DetectUriContentParseTest13", DetectUriContentParseTest13, 1); - UtRegisterTest("DetectUriContentParseTest14", DetectUriContentParseTest14, 1); - UtRegisterTest("DetectUriContentParseTest15", DetectUriContentParseTest15, 1); - UtRegisterTest("DetectUriContentParseTest16", DetectUriContentParseTest16, 1); - UtRegisterTest("DetectUriContentParseTest17", DetectUriContentParseTest17, 1); - UtRegisterTest("DetectUriContentParseTest18", DetectUriContentParseTest18, 1); - UtRegisterTest("DetectUriContentParseTest19", DetectUriContentParseTest19, 1); - UtRegisterTest("DetectUriContentParseTest20", DetectUriContentParseTest20, 1); - UtRegisterTest("DetectUriContentParseTest21", DetectUriContentParseTest21, 1); - UtRegisterTest("DetectUriContentParseTest22", DetectUriContentParseTest22, 1); - UtRegisterTest("DetectUriContentParseTest23", DetectUriContentParseTest23, 1); - UtRegisterTest("DetectUriContentParseTest24", DetectUriContentParseTest24, 1); + UtRegisterTest("HTTPUriTest01", HTTPUriTest01); + UtRegisterTest("HTTPUriTest02", HTTPUriTest02); + UtRegisterTest("HTTPUriTest03", HTTPUriTest03); + UtRegisterTest("HTTPUriTest04", HTTPUriTest04); + + UtRegisterTest("DetectUriSigTest01", DetectUriSigTest01); + UtRegisterTest("DetectUriSigTest02", DetectUriSigTest02); + UtRegisterTest("DetectUriSigTest03", DetectUriSigTest03); + UtRegisterTest("DetectUriSigTest04 - Modifiers", DetectUriSigTest04); + UtRegisterTest("DetectUriSigTest05 - Inspection", DetectUriSigTest05); + UtRegisterTest("DetectUriSigTest06 - Inspection", DetectUriSigTest06); + UtRegisterTest("DetectUriSigTest07 - Inspection", DetectUriSigTest07); + UtRegisterTest("DetectUriSigTest08", DetectUriSigTest08); + UtRegisterTest("DetectUriSigTest09", DetectUriSigTest09); + UtRegisterTest("DetectUriSigTest10", DetectUriSigTest10); + UtRegisterTest("DetectUriSigTest11", DetectUriSigTest11); + UtRegisterTest("DetectUriSigTest12", DetectUriSigTest12); + + UtRegisterTest("DetectUriContentParseTest13", DetectUriContentParseTest13); + UtRegisterTest("DetectUriContentParseTest14", DetectUriContentParseTest14); + UtRegisterTest("DetectUriContentParseTest15", DetectUriContentParseTest15); + UtRegisterTest("DetectUriContentParseTest16", DetectUriContentParseTest16); + UtRegisterTest("DetectUriContentParseTest17", DetectUriContentParseTest17); + UtRegisterTest("DetectUriContentParseTest18", DetectUriContentParseTest18); + UtRegisterTest("DetectUriContentParseTest19", DetectUriContentParseTest19); + UtRegisterTest("DetectUriContentParseTest20", DetectUriContentParseTest20); + UtRegisterTest("DetectUriContentParseTest21", DetectUriContentParseTest21); + UtRegisterTest("DetectUriContentParseTest22", DetectUriContentParseTest22); + UtRegisterTest("DetectUriContentParseTest23", DetectUriContentParseTest23); + UtRegisterTest("DetectUriContentParseTest24", DetectUriContentParseTest24); + + UtRegisterTest("DetectUricontentIsdataatParseTest", + DetectUricontentIsdataatParseTest); #endif /* UNITTESTS */ } diff --git a/src/detect-uricontent.h b/src/detect-uricontent.h index c32a923e35a6..1729e58f3e3d 100644 --- a/src/detect-uricontent.h +++ b/src/detect-uricontent.h @@ -27,16 +27,10 @@ #include "detect-content.h" -#include "util-spm-bm.h" #include "app-layer-htp.h" /* prototypes */ void DetectUricontentRegister (void); -uint32_t DetectUricontentMaxId(DetectEngineCtx *); void DetectUricontentPrint(DetectContentData *); -uint32_t DetectUricontentInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f, - HtpState *htp_state, uint8_t flags, - void *tx, uint64_t idx); - #endif /* __DETECT_URICONTENT_H__ */ diff --git a/src/detect-urilen.c b/src/detect-urilen.c index 1355f5594232..65f4b0b24bc1 100644 --- a/src/detect-urilen.c +++ b/src/detect-urilen.c @@ -32,6 +32,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine.h" #include "detect-engine-state.h" #include "detect-urilen.h" @@ -53,6 +54,9 @@ static int DetectUrilenSetup (DetectEngineCtx *, Signature *, char *); void DetectUrilenFree (void *); void DetectUrilenRegisterTests (void); +static int g_http_uri_buffer_id = 0; +static int g_http_raw_uri_buffer_id = 0; + /** * \brief Registration function for urilen: keyword */ @@ -61,39 +65,16 @@ void DetectUrilenRegister(void) { sigmatch_table[DETECT_AL_URILEN].name = "urilen"; sigmatch_table[DETECT_AL_URILEN].desc = "match on the length of the HTTP uri"; - sigmatch_table[DETECT_AL_URILEN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/HTTP-keywords#Urilen"; + sigmatch_table[DETECT_AL_URILEN].url = DOC_URL DOC_VERSION "/rules/http-keywords.html#urilen"; sigmatch_table[DETECT_AL_URILEN].Match = NULL; - sigmatch_table[DETECT_AL_URILEN].alproto = ALPROTO_HTTP; - sigmatch_table[DETECT_AL_URILEN].AppLayerMatch = NULL /**< We handle this at detect-engine-uri.c now */; sigmatch_table[DETECT_AL_URILEN].Setup = DetectUrilenSetup; sigmatch_table[DETECT_AL_URILEN].Free = DetectUrilenFree; sigmatch_table[DETECT_AL_URILEN].RegisterTests = DetectUrilenRegisterTests; - sigmatch_table[DETECT_AL_URILEN].flags |= SIGMATCH_PAYLOAD; - const char *eb; - int eo; - int opts = 0; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if (parse_regex == NULL) { - SCLogDebug("pcre compile of \"%s\" failed at offset %" PRId32 ": %s", - PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - return; - -error: - if (parse_regex != NULL) - pcre_free(parse_regex); - if (parse_regex_study != NULL) - pcre_free_study(parse_regex_study); - return; + g_http_uri_buffer_id = DetectBufferTypeRegister("http_uri"); + g_http_raw_uri_buffer_id = DetectBufferTypeRegister("http_raw_uri"); } /** @@ -266,11 +247,8 @@ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urile DetectUrilenData *urilend = NULL; SigMatch *sm = NULL; - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) { - SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http " - "alproto set"); - goto error; - } + if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) != 0) + return -1; urilend = DetectUrilenParse(urilenstr); if (urilend == NULL) @@ -282,13 +260,9 @@ static int DetectUrilenSetup (DetectEngineCtx *de_ctx, Signature *s, char *urile sm->ctx = (void *)urilend; if (urilend->raw_buffer) - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_HRUDMATCH); + SigMatchAppendSMToList(s, sm, g_http_raw_uri_buffer_id); else - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_UMATCH); - - /* Flagged the signature as to inspect the app layer data */ - s->flags |= SIG_FLAG_APPLAYER; - s->alproto = ALPROTO_HTTP; + SigMatchAppendSMToList(s, sm, g_http_uri_buffer_id); SCReturnInt(0); @@ -316,7 +290,6 @@ void DetectUrilenFree(void *ptr) #include "stream.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" -#include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "app-layer-parser.h" @@ -635,14 +608,15 @@ static int DetectUrilenSigTest01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, httpbuf1, httplen1); if (r != 0) { SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); HtpState *htp_state = f.alstate; if (htp_state == NULL) { @@ -684,17 +658,17 @@ static int DetectUrilenSigTest01(void) void DetectUrilenRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectUrilenParseTest01", DetectUrilenParseTest01, 1); - UtRegisterTest("DetectUrilenParseTest02", DetectUrilenParseTest02, 1); - UtRegisterTest("DetectUrilenParseTest03", DetectUrilenParseTest03, 1); - UtRegisterTest("DetectUrilenParseTest04", DetectUrilenParseTest04, 1); - UtRegisterTest("DetectUrilenParseTest05", DetectUrilenParseTest05, 1); - UtRegisterTest("DetectUrilenParseTest06", DetectUrilenParseTest06, 1); - UtRegisterTest("DetectUrilenParseTest07", DetectUrilenParseTest07, 1); - UtRegisterTest("DetectUrilenParseTest08", DetectUrilenParseTest08, 1); - UtRegisterTest("DetectUrilenParseTest09", DetectUrilenParseTest09, 1); - UtRegisterTest("DetectUrilenParseTest10", DetectUrilenParseTest10, 1); - UtRegisterTest("DetectUrilenSetpTest01", DetectUrilenSetpTest01, 1); - UtRegisterTest("DetectUrilenSigTest01", DetectUrilenSigTest01, 1); + UtRegisterTest("DetectUrilenParseTest01", DetectUrilenParseTest01); + UtRegisterTest("DetectUrilenParseTest02", DetectUrilenParseTest02); + UtRegisterTest("DetectUrilenParseTest03", DetectUrilenParseTest03); + UtRegisterTest("DetectUrilenParseTest04", DetectUrilenParseTest04); + UtRegisterTest("DetectUrilenParseTest05", DetectUrilenParseTest05); + UtRegisterTest("DetectUrilenParseTest06", DetectUrilenParseTest06); + UtRegisterTest("DetectUrilenParseTest07", DetectUrilenParseTest07); + UtRegisterTest("DetectUrilenParseTest08", DetectUrilenParseTest08); + UtRegisterTest("DetectUrilenParseTest09", DetectUrilenParseTest09); + UtRegisterTest("DetectUrilenParseTest10", DetectUrilenParseTest10); + UtRegisterTest("DetectUrilenSetpTest01", DetectUrilenSetpTest01); + UtRegisterTest("DetectUrilenSigTest01", DetectUrilenSigTest01); #endif /* UNITTESTS */ } diff --git a/src/detect-window.c b/src/detect-window.c index f98e0258ebf0..4c4468254412 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -47,8 +47,9 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -int DetectWindowSetup(DetectEngineCtx *, Signature *, char *); +static int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, + const Signature *, const SigMatchCtx *); +static int DetectWindowSetup(DetectEngineCtx *, Signature *, char *); void DetectWindowRegisterTests(void); void DetectWindowFree(void *); @@ -59,38 +60,13 @@ void DetectWindowRegister (void) { sigmatch_table[DETECT_WINDOW].name = "window"; sigmatch_table[DETECT_WINDOW].desc = "check for a specific TCP window size"; - sigmatch_table[DETECT_WINDOW].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Header_keywords#Window"; + sigmatch_table[DETECT_WINDOW].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#window"; sigmatch_table[DETECT_WINDOW].Match = DetectWindowMatch; sigmatch_table[DETECT_WINDOW].Setup = DetectWindowSetup; sigmatch_table[DETECT_WINDOW].Free = DetectWindowFree; sigmatch_table[DETECT_WINDOW].RegisterTests = DetectWindowRegisterTests; - const char *eb; - int eo; - int opts = 0; - - #ifdef WINDOW_DEBUG - printf("detect-window: Registering window rule option\n"); - #endif - - parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); - if(parse_regex == NULL) - { - SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); - goto error; - } - - parse_regex_study = pcre_study(parse_regex, 0, &eb); - if(eb != NULL) - { - SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); - goto error; - } - return; - -error: - /* XXX */ - return; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } /** @@ -104,9 +80,10 @@ void DetectWindowRegister (void) * \retval 0 no match * \retval 1 match */ -int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) +static int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, + const Signature *s, const SigMatchCtx *ctx) { - DetectWindowData *wd = (DetectWindowData *)m->ctx; + const DetectWindowData *wd = (const DetectWindowData *)ctx; if ( !(PKT_IS_TCP(p)) || wd == NULL || PKT_IS_PSEUDOPKT(p)) { return 0; @@ -127,18 +104,14 @@ int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, * \retval wd pointer to DetectWindowData on success * \retval NULL on failure */ -DetectWindowData *DetectWindowParse(char *windowstr) +static DetectWindowData *DetectWindowParse(char *windowstr) { DetectWindowData *wd = NULL; - char *args[3] = {NULL,NULL,NULL}; /* PR: Why PCRE MAX_SUBSTRING must be multiple of 3? */ - #define MAX_SUBSTRINGS 30 - +#define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; - ret = pcre_exec(parse_regex, parse_regex_study, windowstr, strlen(windowstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 1 || ret > 3) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, windowstr); goto error; @@ -149,45 +122,39 @@ DetectWindowData *DetectWindowParse(char *windowstr) goto error; if (ret > 1) { - const char *str_ptr; - res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); + char copy_str[128] = ""; + res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 1, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - args[0] = (char *)str_ptr; + /* Detect if it's negated */ - if (args[0][0] == '!') + if (copy_str[0] == '!') wd->negated = 1; else wd->negated = 0; if (ret > 2) { - res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); + res = pcre_copy_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2, + copy_str, sizeof(copy_str)); if (res < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - /* Get the window size if it's a valid value (in packets, we should alert if this doesn't happend from decode) */ - if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, str_ptr)) { + /* Get the window size if it's a valid value (in packets, we + * should alert if this doesn't happend from decode) */ + if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, copy_str)) { goto error; } } } - int i = 0; - for (i = 0; i < (ret -1); i++){ - if (args[i] != NULL) - SCFree(args[i]); - } return wd; error: - for (i = 0; i < (ret -1) && i < 3; i++){ - if (args[i] != NULL) - SCFree(args[i]); - } if (wd != NULL) DetectWindowFree(wd); return NULL; @@ -204,7 +171,7 @@ DetectWindowData *DetectWindowParse(char *windowstr) * \retval 0 on Success * \retval -1 on Failure */ -int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) +static int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) { DetectWindowData *wd = NULL; SigMatch *sm = NULL; @@ -219,7 +186,7 @@ int DetectWindowSetup (DetectEngineCtx *de_ctx, Signature *s, char *windowstr) goto error; sm->type = DETECT_WINDOW; - sm->ctx = (void *)wd; + sm->ctx = (SigMatchCtx *)wd; SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); s->flags |= SIG_FLAG_REQUIRE_PACKET; @@ -368,10 +335,10 @@ int DetectWindowTestPacket01 (void) void DetectWindowRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01, 1); - UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02, 1); - UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03, 1); - UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04, 1); - UtRegisterTest("DetectWindowTestPacket01" , DetectWindowTestPacket01 , 1); + UtRegisterTest("DetectWindowTestParse01", DetectWindowTestParse01); + UtRegisterTest("DetectWindowTestParse02", DetectWindowTestParse02); + UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03); + UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04); + UtRegisterTest("DetectWindowTestPacket01", DetectWindowTestPacket01); #endif /* UNITTESTS */ } diff --git a/src/detect-within.c b/src/detect-within.c index 0aefdffc8162..b7921a3138a2 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -36,7 +36,6 @@ #include "detect-bytejump.h" #include "detect-byte-extract.h" #include "app-layer.h" -#include "detect-parse.h" #include "flow-var.h" @@ -51,13 +50,11 @@ void DetectWithinRegister(void) { sigmatch_table[DETECT_WITHIN].name = "within"; sigmatch_table[DETECT_WITHIN].desc = "indicate that this content match has to be within a certain distance of the previous content keyword match"; - sigmatch_table[DETECT_WITHIN].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Payload_keywords#Within"; + sigmatch_table[DETECT_WITHIN].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#within"; sigmatch_table[DETECT_WITHIN].Match = NULL; sigmatch_table[DETECT_WITHIN].Setup = DetectWithinSetup; sigmatch_table[DETECT_WITHIN].Free = NULL; sigmatch_table[DETECT_WITHIN].RegisterTests = DetectWithinRegisterTests; - - sigmatch_table[DETECT_WITHIN].flags |= SIGMATCH_PAYLOAD; } /** \brief Setup within pattern (content/uricontent) modifier. @@ -74,46 +71,25 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within SigMatch *pm = NULL; int ret = -1; - /* strip "'s */ - if (withinstr[0] == '\"' && withinstr[strlen(withinstr)-1] == '\"') { + /* Strip leading and trailing "s. */ + if (withinstr[0] == '\"') { str = SCStrdup(withinstr+1); if (unlikely(str == NULL)) goto end; - str[strlen(withinstr) - 2] = '\0'; + if (strlen(str) && str[strlen(str) - 1] == '\"') { + str[strlen(str) - 1] = '\0'; + } dubbed = 1; } - /* retrive the sm to apply the depth against */ - if (s->list != DETECT_SM_LIST_NOTSET) { - pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]); - } else { - pm = SigMatchGetLastSMFromLists(s, 28, - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSBDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH], - DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]); - } + /* retrieve the sm to apply the within against */ + pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm == NULL) { SCLogError(SC_ERR_OFFSET_MISSING_CONTENT, "within needs " - "preceding content, uricontent option, http_client_body, " - "http_server_body, http_header option, http_raw_header option, " - "http_method option, http_cookie, http_raw_uri, " - "http_stat_msg, http_stat_code, http_user_agent or " - "file_data/dce_stub_data sticky buffer option"); + "preceding content option"); goto end; } - /* verify other conditions */ DetectContentData *cd = (DetectContentData *)pm->ctx; if (cd->flags & DETECT_CONTENT_WITHIN) { @@ -161,23 +137,22 @@ static int DetectWithinSetup(DetectEngineCtx *de_ctx, Signature *s, char *within /* these are the only ones against which we set a flag. We have other * relative keywords like byttest, isdataat, bytejump, but we don't * set a flag against them */ - SigMatch *prev_pm = SigMatchGetLastSMFromLists(s, 4, - DETECT_CONTENT, pm->prev, - DETECT_PCRE, pm->prev); + SigMatch *prev_pm = DetectGetLastSMByListPtr(s, pm->prev, + DETECT_CONTENT, DETECT_PCRE, -1); if (prev_pm == NULL) { ret = 0; goto end; } if (prev_pm->type == DETECT_CONTENT) { - DetectContentData *cd = (DetectContentData *)prev_pm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + DetectContentData *prev_cd = (DetectContentData *)prev_pm->ctx; + if (prev_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { SCLogError(SC_ERR_INVALID_SIGNATURE, "previous keyword " "has a fast_pattern:only; set. Can't " "have relative keywords around a fast_pattern " "only content"); goto end; } - cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + prev_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; } else if (prev_pm->type == DETECT_PCRE) { DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx; pd->flags |= DETECT_PCRE_RELATIVE_NEXT; @@ -285,8 +260,8 @@ static int DetectWithinTestVarSetup(void) void DetectWithinRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectWithinTestPacket01", DetectWithinTestPacket01, 1); - UtRegisterTest("DetectWithinTestPacket02", DetectWithinTestPacket02, 1); - UtRegisterTest("DetectWithinTestVarSetup", DetectWithinTestVarSetup, 1); + UtRegisterTest("DetectWithinTestPacket01", DetectWithinTestPacket01); + UtRegisterTest("DetectWithinTestPacket02", DetectWithinTestPacket02); + UtRegisterTest("DetectWithinTestVarSetup", DetectWithinTestVarSetup); #endif /* UNITTESTS */ } diff --git a/src/detect-xbits.c b/src/detect-xbits.c new file mode 100644 index 000000000000..a6264ea26709 --- /dev/null +++ b/src/detect-xbits.c @@ -0,0 +1,547 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements the xbits keyword + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "threads.h" +#include "flow.h" +#include "flow-util.h" +#include "detect-xbits.h" +#include "detect-hostbits.h" +#include "util-spm.h" + +#include "detect-engine-sigorder.h" + +#include "app-layer-parser.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow-bit.h" +#include "host-bit.h" +#include "ippair-bit.h" +#include "util-var-name.h" +#include "util-unittest.h" +#include "util-debug.h" + +/* + xbits:set,bitname,track ip_pair,expire 60 + */ + +#define PARSE_REGEX "([a-z]+)" "(?:,\\s*([^,]+))?" "(?:,\\s*(?:track\\s+([^,]+)))" "(?:,\\s*(?:expire\\s+([^,]+)))?" +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +static int DetectXbitMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static int DetectXbitSetup (DetectEngineCtx *, Signature *, char *); +void DetectXbitFree (void *); +void XBitsRegisterTests(void); + +void DetectXbitsRegister (void) +{ + sigmatch_table[DETECT_XBITS].name = "xbits"; + sigmatch_table[DETECT_XBITS].desc = "operate on bits"; + sigmatch_table[DETECT_XBITS].url = DOC_URL DOC_VERSION "/rules/xbits.html"; + sigmatch_table[DETECT_XBITS].Match = DetectXbitMatch; + sigmatch_table[DETECT_XBITS].Setup = DetectXbitSetup; + sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; + sigmatch_table[DETECT_XBITS].RegisterTests = XBitsRegisterTests; + /* this is compatible to ip-only signatures */ + sigmatch_table[DETECT_XBITS].flags |= SIGMATCH_IPONLY_COMPAT; + + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); +} + +static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) +{ + IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 0; + + IPPairBitToggle(pair,fd->idx,p->ts.tv_sec + fd->expire); + IPPairRelease(pair); + return 1; +} + +/* return true even if bit not found */ +static int DetectIPPairbitMatchUnset (Packet *p, const DetectXbitsData *fd) +{ + IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 1; + + IPPairBitUnset(pair,fd->idx); + IPPairRelease(pair); + return 1; +} + +static int DetectIPPairbitMatchSet (Packet *p, const DetectXbitsData *fd) +{ + IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 0; + + IPPairBitSet(pair, fd->idx, p->ts.tv_sec + fd->expire); + IPPairRelease(pair); + return 1; +} + +static int DetectIPPairbitMatchIsset (Packet *p, const DetectXbitsData *fd) +{ + int r = 0; + IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 0; + + r = IPPairBitIsset(pair,fd->idx,p->ts.tv_sec); + IPPairRelease(pair); + return r; +} + +static int DetectIPPairbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) +{ + int r = 0; + IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); + if (pair == NULL) + return 1; + + r = IPPairBitIsnotset(pair,fd->idx,p->ts.tv_sec); + IPPairRelease(pair); + return r; +} + +static int DetectXbitMatchIPPair(Packet *p, const DetectXbitsData *xd) +{ + switch (xd->cmd) { + case DETECT_XBITS_CMD_ISSET: + return DetectIPPairbitMatchIsset(p,xd); + case DETECT_XBITS_CMD_ISNOTSET: + return DetectIPPairbitMatchIsnotset(p,xd); + case DETECT_XBITS_CMD_SET: + return DetectIPPairbitMatchSet(p,xd); + case DETECT_XBITS_CMD_UNSET: + return DetectIPPairbitMatchUnset(p,xd); + case DETECT_XBITS_CMD_TOGGLE: + return DetectIPPairbitMatchToggle(p,xd); + default: + SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", xd->cmd); + return 0; + } + return 0; +} + +/* + * returns 0: no match + * 1: match + * -1: error + */ + +static int DetectXbitMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectXbitsData *fd = (const DetectXbitsData *)ctx; + if (fd == NULL) + return 0; + + switch (fd->type) { + case VAR_TYPE_HOST_BIT: + return DetectXbitMatchHost(p, (const DetectXbitsData *)fd); + break; + case VAR_TYPE_IPPAIR_BIT: + return DetectXbitMatchIPPair(p, (const DetectXbitsData *)fd); + break; + default: + break; + } + return 0; +} + +/** \internal + * \brief parse xbits rule options + * \retval 0 ok + * \retval -1 bad + * \param[out] cdout return DetectXbitsData structure or NULL if noalert + */ +static int DetectXbitParse(DetectEngineCtx *de_ctx, + const char *rawstr, DetectXbitsData **cdout) +{ + DetectXbitsData *cd = NULL; + uint8_t fb_cmd = 0; + uint8_t hb_dir = 0; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + char fb_cmd_str[16] = "", fb_name[256] = ""; + char hb_dir_str[16] = ""; + enum VarTypes var_type = VAR_TYPE_NOT_SET; + int expire = DETECT_XBITS_EXPIRE_DEFAULT; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret != 2 && ret != 3 && ret != 4 && ret != 5) { + SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for xbits.", rawstr); + return -1; + } + SCLogDebug("ret %d, %s", ret, rawstr); + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, fb_cmd_str, sizeof(fb_cmd_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + + if (ret >= 3) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, fb_name, sizeof(fb_name)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + if (ret >= 4) { + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, hb_dir_str, sizeof(hb_dir_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + SCLogDebug("hb_dir_str %s", hb_dir_str); + if (strlen(hb_dir_str) > 0) { + if (strcmp(hb_dir_str, "ip_src") == 0) { + hb_dir = DETECT_XBITS_TRACK_IPSRC; + var_type = VAR_TYPE_HOST_BIT; + } else if (strcmp(hb_dir_str, "ip_dst") == 0) { + hb_dir = DETECT_XBITS_TRACK_IPDST; + var_type = VAR_TYPE_HOST_BIT; + } else if (strcmp(hb_dir_str, "ip_pair") == 0) { + hb_dir = DETECT_XBITS_TRACK_IPPAIR; + var_type = VAR_TYPE_IPPAIR_BIT; + } else { + // TODO + return -1; + } + } + + if (ret >= 5) { + char expire_str[16] = ""; + res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, expire_str, sizeof(expire_str)); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); + return -1; + } + SCLogDebug("expire_str %s", expire_str); + expire = atoi(expire_str); + if (expire < 0) { + SCLogError(SC_ERR_INVALID_VALUE, "expire must be positive. " + "Got %d (\"%s\")", expire, expire_str); + return -1; + } + if (expire == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "expire must be bigger than 0"); + return -1; + } + SCLogDebug("expire %d", expire); + } + } + } + + if (strcmp(fb_cmd_str,"noalert") == 0) { + fb_cmd = DETECT_XBITS_CMD_NOALERT; + } else if (strcmp(fb_cmd_str,"isset") == 0) { + fb_cmd = DETECT_XBITS_CMD_ISSET; + } else if (strcmp(fb_cmd_str,"isnotset") == 0) { + fb_cmd = DETECT_XBITS_CMD_ISNOTSET; + } else if (strcmp(fb_cmd_str,"set") == 0) { + fb_cmd = DETECT_XBITS_CMD_SET; + } else if (strcmp(fb_cmd_str,"unset") == 0) { + fb_cmd = DETECT_XBITS_CMD_UNSET; + } else if (strcmp(fb_cmd_str,"toggle") == 0) { + fb_cmd = DETECT_XBITS_CMD_TOGGLE; + } else { + SCLogError(SC_ERR_UNKNOWN_VALUE, "xbits action \"%s\" is not supported.", fb_cmd_str); + return -1; + } + + switch (fb_cmd) { + case DETECT_XBITS_CMD_NOALERT: { + if (strlen(fb_name) != 0) + return -1; + /* return ok, cd is NULL. Flag sig. */ + *cdout = NULL; + return 0; + } + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: + default: + if (strlen(fb_name) == 0) + return -1; + break; + } + + cd = SCMalloc(sizeof(DetectXbitsData)); + if (unlikely(cd == NULL)) + return -1; + + cd->idx = VarNameStoreSetupAdd(fb_name, var_type); + cd->cmd = fb_cmd; + cd->tracker = hb_dir; + cd->type = var_type; + cd->expire = expire; + + SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", + cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); + + *cdout = cd; + return 0; +} + +int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + SigMatch *sm = NULL; + DetectXbitsData *cd = NULL; + + int result = DetectXbitParse(de_ctx, rawstr, &cd); + if (result < 0) { + return -1; + /* noalert doesn't use a cd/sm struct. It flags the sig. We're done. */ + } else if (result == 0 && cd == NULL) { + s->flags |= SIG_FLAG_NOALERT; + return 0; + } + + /* Okay so far so good, lets get this into a SigMatch + * and put it in the Signature. */ + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_XBITS; + sm->ctx = (void *)cd; + + switch (cd->cmd) { + /* case DETECT_XBITS_CMD_NOALERT can't happen here */ + + case DETECT_XBITS_CMD_ISNOTSET: + case DETECT_XBITS_CMD_ISSET: + /* checks, so packet list */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + break; + + case DETECT_XBITS_CMD_SET: + case DETECT_XBITS_CMD_UNSET: + case DETECT_XBITS_CMD_TOGGLE: + /* modifiers, only run when entire sig has matched */ + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); + break; + } + + return 0; + +error: + if (cd != NULL) + SCFree(cd); + return -1; +} + +void DetectXbitFree (void *ptr) +{ + DetectXbitsData *fd = (DetectXbitsData *)ptr; + + if (fd == NULL) + return; + + SCFree(fd); +} + +#ifdef UNITTESTS + +static void XBitsTestSetup(void) +{ + StorageInit(); + HostBitInitCtx(); + IPPairBitInitCtx(); + StorageFinalize(); + HostInitConfig(TRUE); + IPPairInitConfig(TRUE); +} + +static void XBitsTestShutdown(void) +{ + HostCleanup(); + IPPairCleanup(); + StorageCleanup(); +} + + +static int XBitsTestParse01(void) +{ + DetectEngineCtx *de_ctx = NULL; + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectXbitsData *cd = NULL; + +#define BAD_INPUT(str) \ + FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == -1); + + BAD_INPUT("alert"); + BAD_INPUT("n0alert"); + BAD_INPUT("nOalert"); + BAD_INPUT("set,abc,track nonsense, expire 3600"); + BAD_INPUT("set,abc,track ip_source, expire 3600"); + BAD_INPUT("set,abc,track ip_src, expire -1"); + BAD_INPUT("set,abc,track ip_src, expire 0"); + +#undef BAD_INPUT + +#define GOOD_INPUT(str, command, trk, typ, exp) \ + FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == 0); \ + FAIL_IF_NULL(cd); \ + FAIL_IF_NOT(cd->cmd == (command)); \ + FAIL_IF_NOT(cd->tracker == (trk)); \ + FAIL_IF_NOT(cd->type == (typ)); \ + FAIL_IF_NOT(cd->expire == (exp)); \ + DetectXbitFree(cd); \ + cd = NULL; + + GOOD_INPUT("set,abc,track ip_pair", + DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, + DETECT_XBITS_EXPIRE_DEFAULT); + GOOD_INPUT("set,abc,track ip_pair, expire 3600", + DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, + 3600); + GOOD_INPUT("set,abc,track ip_src, expire 1234", + DETECT_XBITS_CMD_SET, + DETECT_XBITS_TRACK_IPSRC, VAR_TYPE_HOST_BIT, + 1234); + +#undef GOOD_INPUT + + DetectEngineCtxFree(de_ctx); + PASS; +} + +/** + * \test + */ + +static int XBitsTestSig01(void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p); + Signature *s = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = NULL; + + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + + XBitsTestSetup(); + + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + XBitsTestShutdown(); + SCFree(p); + StatsThreadCleanup(&th_v); + StatsReleaseResources(); + PASS; +} + +/** + * \test various options + * + * \retval 1 on succces + * \retval 0 on failure + */ + +static int XBitsTestSig02(void) +{ + Signature *s = NULL; + DetectEngineCtx *de_ctx = NULL; + de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:isset,abc,track ip_src; content:\"GET \"; sid:1;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:isnotset,abc,track ip_dst; content:\"GET \"; sid:2;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:3;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:unset,abc,track ip_src; content:\"GET \"; sid:4;)"); + FAIL_IF_NULL(s); + + s = DetectEngineAppendSig(de_ctx, + "alert ip any any -> any any (xbits:toggle,abc,track ip_dst; content:\"GET \"; sid:5;)"); + FAIL_IF_NULL(s); + + DetectEngineCtxFree(de_ctx); + PASS; +} + +#endif /* UNITTESTS */ + +/** + * \brief this function registers unit tests for XBits + */ +void XBitsRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("XBitsTestParse01", XBitsTestParse01); + UtRegisterTest("XBitsTestSig01", XBitsTestSig01); + UtRegisterTest("XBitsTestSig02", XBitsTestSig02); +#endif /* UNITTESTS */ +} diff --git a/src/detect-xbits.h b/src/detect-xbits.h new file mode 100644 index 000000000000..4f34ef0dfe1e --- /dev/null +++ b/src/detect-xbits.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_XBITS_H__ +#define __DETECT_XBITS_H__ + +#define DETECT_XBITS_CMD_SET 0 +#define DETECT_XBITS_CMD_TOGGLE 1 +#define DETECT_XBITS_CMD_UNSET 2 +#define DETECT_XBITS_CMD_ISNOTSET 3 +#define DETECT_XBITS_CMD_ISSET 4 +#define DETECT_XBITS_CMD_NOALERT 5 +#define DETECT_XBITS_CMD_MAX 6 + +#define DETECT_XBITS_TRACK_IPSRC 0 +#define DETECT_XBITS_TRACK_IPDST 1 +#define DETECT_XBITS_TRACK_IPPAIR 2 +#define DETECT_XBITS_TRACK_FLOW 3 + +#define DETECT_XBITS_EXPIRE_DEFAULT 30 + +typedef struct DetectXbitsData_ { + uint32_t idx; + uint8_t cmd; + uint8_t tracker; + uint32_t expire; + /** data type: host/ippair/flow used for sig sorting in sigorder */ + enum VarTypes type; +} DetectXbitsData; + +/* prototypes */ +void DetectXbitsRegister (void); + +#endif /* __DETECT_XBITS_H__ */ diff --git a/src/detect.c b/src/detect.c index f4f0d54e3daa..21bffc78ba6f 100644 --- a/src/detect.c +++ b/src/detect.c @@ -33,6 +33,7 @@ #include "detect-parse.h" #include "detect-engine.h" +#include "detect-engine-profile.h" #include "detect-engine-alert.h" #include "detect-engine-siggroup.h" @@ -42,13 +43,19 @@ #include "detect-engine-mpm.h" #include "detect-engine-iponly.h" #include "detect-engine-threshold.h" +#include "detect-engine-prefilter.h" #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" #include "detect-engine-uri.h" #include "detect-dns-query.h" +#include "detect-tls-sni.h" +#include "detect-tls-cert-issuer.h" +#include "detect-tls-cert-subject.h" +#include "detect-tls-cert-serial.h" #include "detect-engine-state.h" #include "detect-engine-analyzer.h" +#include "detect-engine-filedata-smtp.h" #include "detect-http-cookie.h" #include "detect-http-method.h" @@ -59,6 +66,8 @@ #include "detect-engine-event.h" #include "decode.h" +#include "detect-base64-decode.h" +#include "detect-base64-data.h" #include "detect-ipopts.h" #include "detect-flags.h" #include "detect-fragbits.h" @@ -81,6 +90,7 @@ #include "detect-distance.h" #include "detect-offset.h" #include "detect-sid.h" +#include "detect-prefilter.h" #include "detect-priority.h" #include "detect-classtype.h" #include "detect-reference.h" @@ -101,6 +111,8 @@ #include "detect-filestore.h" #include "detect-filemagic.h" #include "detect-filemd5.h" +#include "detect-filesha1.h" +#include "detect-filesha256.h" #include "detect-filesize.h" #include "detect-dsize.h" #include "detect-flowvar.h" @@ -108,6 +120,8 @@ #include "detect-pktvar.h" #include "detect-noalert.h" #include "detect-flowbits.h" +#include "detect-hostbits.h" +#include "detect-xbits.h" #include "detect-csum.h" #include "detect-stream_size.h" #include "detect-engine-sigorder.h" @@ -125,13 +139,17 @@ #include "detect-http-client-body.h" #include "detect-http-server-body.h" #include "detect-http-header.h" +#include "detect-http-header-names.h" #include "detect-http-raw-header.h" #include "detect-http-uri.h" +#include "detect-http-protocol.h" +#include "detect-http-start.h" #include "detect-http-raw-uri.h" #include "detect-http-stat-msg.h" +#include "detect-http-request-line.h" +#include "detect-http-response-line.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" @@ -150,21 +168,31 @@ #include "detect-lua.h" #include "detect-iprep.h" #include "detect-geoip.h" -#include "detect-dns-query.h" #include "detect-app-layer-protocol.h" +#include "detect-template.h" +#include "detect-template-buffer.h" +#include "detect-bypass.h" #include "util-rule-vars.h" #include "app-layer.h" #include "app-layer-protos.h" #include "app-layer-htp.h" +#include "app-layer-smtp.h" +#include "app-layer-template.h" #include "detect-tls.h" +#include "detect-tls-cert-validity.h" #include "detect-tls-version.h" +#include "detect-ssh-proto.h" #include "detect-ssh-proto-version.h" +#include "detect-ssh-software.h" #include "detect-ssh-software-version.h" #include "detect-http-stat-code.h" #include "detect-ssl-version.h" #include "detect-ssl-state.h" +#include "detect-modbus.h" +#include "detect-cipservice.h" +#include "detect-dnp3.h" #include "action-globals.h" #include "tm-threads.h" @@ -177,8 +205,10 @@ #include "stream-tcp.h" #include "stream-tcp-inline.h" +#include "util-lua.h" #include "util-var-name.h" #include "util-classification-config.h" +#include "util-threshold-config.h" #include "util-print.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -191,9 +221,10 @@ #include "util-optimize.h" #include "util-path.h" #include "util-mpm-ac.h" - #include "runmodes.h" +#include + extern int rule_reload; extern int engine_analysis; @@ -207,45 +238,27 @@ void DbgPrintSigs(DetectEngineCtx *, SigGroupHead *); void DbgPrintSigs2(DetectEngineCtx *, SigGroupHead *); static void PacketCreateMask(Packet *, SignatureMask *, uint16_t, int, StreamMsg *, int); -/* tm module api functions */ -TmEcode Detect(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode DetectThreadInit(ThreadVars *, void *, void **); -TmEcode DetectThreadDeinit(ThreadVars *, void *); - -void TmModuleDetectRegister (void) -{ - tmm_modules[TMM_DETECT].name = "Detect"; - tmm_modules[TMM_DETECT].ThreadInit = DetectThreadInit; - tmm_modules[TMM_DETECT].Func = Detect; - tmm_modules[TMM_DETECT].ThreadExitPrintStats = DetectExitPrintStats; - tmm_modules[TMM_DETECT].ThreadDeinit = DetectThreadDeinit; - tmm_modules[TMM_DETECT].RegisterTests = SigRegisterTests; - tmm_modules[TMM_DETECT].cap_flags = 0; - tmm_modules[TMM_DETECT].flags = TM_FLAG_DETECT_TM; - - PacketAlertTagInit(); -} - -void DetectExitPrintStats(ThreadVars *tv, void *data) -{ - DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; - if (det_ctx == NULL) - return; -} - /** * \brief Create the path if default-rule-path was specified * \param sig_file The name of the file * \retval str Pointer to the string path + sig_file */ -char *DetectLoadCompleteSigPath(char *sig_file) +char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, char *sig_file) { char *defaultpath = NULL; char *path = NULL; + char varname[128]; + + if (strlen(de_ctx->config_prefix) > 0) { + snprintf(varname, sizeof(varname), "%s.default-rule-path", + de_ctx->config_prefix); + } else { + snprintf(varname, sizeof(varname), "default-rule-path"); + } /* Path not specified */ if (PathIsRelative(sig_file)) { - if (ConfGet("default-rule-path", &defaultpath) == 1) { + if (ConfGet(varname, &defaultpath) == 1) { SCLogDebug("Default path: %s", defaultpath); size_t path_len = sizeof(char) * (strlen(defaultpath) + strlen(sig_file) + 2); @@ -254,10 +267,10 @@ char *DetectLoadCompleteSigPath(char *sig_file) return NULL; strlcpy(path, defaultpath, path_len); #if defined OS_WIN32 || defined __CYGWIN__ - if (path[strlen(path) - 1] != '\\') + if (path[strlen(path) - 1] != '\\') strlcat(path, "\\\\", path_len); #else - if (path[strlen(path) - 1] != '/') + if (path[strlen(path) - 1] != '/') strlcat(path, "/", path_len); #endif strlcat(path, sig_file, path_len); @@ -278,10 +291,12 @@ char *DetectLoadCompleteSigPath(char *sig_file) * \brief Load a file with signatures * \param de_ctx Pointer to the detection engine context * \param sig_file Filename to load signatures from - * \param sigs_tot Will store number of signatures processed in the file - * \retval Number of rules loaded successfully, -1 on error + * \param goodsigs_tot Will store number of valid signatures in the file + * \param badsigs_tot Will store number of invalid signatures in the file + * \retval 0 on success, -1 on error */ -int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) +static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, + int *goodsigs, int *badsigs) { Signature *sig = NULL; int good = 0, bad = 0; @@ -289,10 +304,8 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) size_t offset = 0; int lineno = 0, multiline = 0; - if (sig_file == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); - return -1; - } + (*goodsigs) = 0; + (*badsigs) = 0; FILE *fp = fopen(sig_file, "r"); if (fp == NULL) { @@ -335,10 +348,9 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) de_ctx->rule_line = lineno - multiline; sig = DetectEngineAppendSig(de_ctx, line); - (*sigs_tot)++; if (sig != NULL) { if (rule_engine_analysis_set || fp_engine_analysis_set) { - sig->mpm_sm = RetrieveFPForSigV2(sig); + RetrieveFPForSig(sig); if (fp_engine_analysis_set) { EngineAnalysisFP(sig, line); } @@ -355,22 +367,70 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) if (rule_engine_analysis_set) { EngineAnalysisRulesFailure(line, sig_file, lineno - multiline); } - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } bad++; } multiline = 0; } fclose(fp); - return good; + *goodsigs = good; + *badsigs = bad; + return 0; +} + +/** + * \brief Expands wildcards and reads signatures from each matching file + * \param de_ctx Pointer to the detection engine context + * \param sig_file Filename (or pattern) holding signatures + * \retval -1 on error + */ +static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, + SigFileLoaderStat *st, int *good_sigs, int *bad_sigs) +{ + if (pattern == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); + return -1; + } + + glob_t files; + int r = glob(pattern, 0, NULL, &files); + + if (r == GLOB_NOMATCH) { + SCLogWarning(SC_ERR_NO_RULES, "No rule files match the pattern %s", pattern); + ++(st->bad_files); + ++(st->total_files); + return -1; + } else if (r != 0) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "error expanding template %s: %s", + pattern, strerror(errno)); + return -1; + } + + for (size_t i = 0; i < (size_t)files.gl_pathc; i++) { + char *fname = files.gl_pathv[i]; + if (strcmp("/dev/null", fname) == 0) + continue; + + SCLogConfig("Loading rule file: %s", fname); + r = DetectLoadSigFile(de_ctx, fname, good_sigs, bad_sigs); + if (r < 0) { + ++(st->bad_files); + } + + ++(st->total_files); + + st->good_sigs_total += *good_sigs; + st->bad_sigs_total += *bad_sigs; + } + + globfree(&files); + return r; } /** * \brief Load signatures * \param de_ctx Pointer to the detection engine context - * \param sig_file Filename holding signatures + * \param sig_file Filename (or pattern) holding signatures * \param sig_file_exclusive File passed in 'sig_file' should be loaded exclusively. * \retval -1 on error */ @@ -380,12 +440,19 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl ConfNode *rule_files; ConfNode *file = NULL; + SigFileLoaderStat sig_stat; int ret = 0; - int r = 0; - int cnt = 0; - int cntf = 0; - int sigtotal = 0; char *sfile = NULL; + char varname[128] = "rule-files"; + int good_sigs = 0; + int bad_sigs = 0; + + memset(&sig_stat, 0, sizeof(SigFileLoaderStat)); + + if (strlen(de_ctx->config_prefix) > 0) { + snprintf(varname, sizeof(varname), "%s.rule-files", + de_ctx->config_prefix); + } if (RunmodeGetCurrent() == RUNMODE_ENGINE_ANALYSIS) { fp_engine_analysis_set = SetupFPAnalyzer(); @@ -394,68 +461,65 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl /* ok, let's load signature files from the general config */ if (!(sig_file != NULL && sig_file_exclusive == TRUE)) { - rule_files = ConfGetNode("rule-files"); + rule_files = ConfGetNode(varname); if (rule_files != NULL) { - TAILQ_FOREACH(file, &rule_files->head, next) { - sfile = DetectLoadCompleteSigPath(file->val); - SCLogDebug("Loading rule file: %s", sfile); - - r = DetectLoadSigFile(de_ctx, sfile, &sigtotal); - cntf++; - if (r > 0) { - cnt += r; - } else if (r == 0){ - SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sfile); - if (de_ctx->failure_fatal == 1) { + if (!ConfNodeIsSequence(rule_files)) { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, + "Invalid rule-files configuration section: " + "expected a list of filenames."); + } + else { + TAILQ_FOREACH(file, &rule_files->head, next) { + sfile = DetectLoadCompleteSigPath(de_ctx, file->val); + good_sigs = bad_sigs = 0; + ret = ProcessSigFiles(de_ctx, sfile, &sig_stat, &good_sigs, &bad_sigs); + SCFree(sfile); + + if (de_ctx->failure_fatal && ret != 0) { + /* Some rules failed to load, just exit as + * errors would have already been logged. */ exit(EXIT_FAILURE); } - } else if (r < 0){ - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); + + if (good_sigs == 0) { + SCLogConfig("No rules loaded from %s.", file->val); } } - SCFree(sfile); } } } /* If a Signature file is specified from commandline, parse it too */ if (sig_file != NULL) { - SCLogInfo("Loading rule file: %s", sig_file); - r = DetectLoadSigFile(de_ctx, sig_file, &sigtotal); - cntf++; - if (r > 0) { - cnt += r; - } else if (r == 0) { - SCLogError(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); + ret = ProcessSigFiles(de_ctx, sig_file, &sig_stat, &good_sigs, &bad_sigs); + + if (ret != 0) { if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); } - } else if (r < 0){ - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } + } + + if (good_sigs == 0) { + SCLogConfig("No rules loaded from %s", sig_file); } } /* now we should have signatures to work with */ - if (cnt <= 0) { - if (cntf > 0) { - SCLogError(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", cntf); - if (de_ctx->failure_fatal == 1) { - exit(EXIT_FAILURE); - } - ret = -1; + if (sig_stat.good_sigs_total <= 0) { + if (sig_stat.total_files > 0) { + SCLogWarning(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", sig_stat.total_files); } else { SCLogInfo("No signatures supplied."); goto end; } } else { /* we report the total of files and rules successfully loaded and failed */ - SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", cntf, cnt, sigtotal-cnt); + SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", + sig_stat.total_files, sig_stat.good_sigs_total, sig_stat.bad_sigs_total); } - if (ret < 0 && de_ctx->failure_fatal) { + if ((sig_stat.bad_sigs_total || sig_stat.bad_files) && de_ctx->failure_fatal) { + ret = -1; goto end; } @@ -463,6 +527,8 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl SCSigOrderSignatures(de_ctx); SCSigSignatureOrderingModuleCleanup(de_ctx); + SCThresholdConfInitContext(de_ctx); + /* Setup the signature group lookup structure and pattern matchers */ if (SigGroupBuild(de_ctx) < 0) goto end; @@ -483,137 +549,24 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl SCReturnInt(ret); } -/** - * \brief See if we can prefilter a signature on inexpensive checks - * - * Order of SignatureHeader access: - * 1. flags - * 2. alproto - * 3. mpm_pattern_id_div8 - * 4. mpm_pattern_id_mod8 - * 5. num - * - * \retval 0 can't match, don't inspect - * \retval 1 might match, further inspection required - */ -int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureHeader *s, - AppProto alproto) -{ - /* if the sig has alproto and the session as well they should match */ - if (likely(s->flags & SIG_FLAG_APPLAYER)) { - if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { - if (s->alproto == ALPROTO_DCERPC) { - if (alproto != ALPROTO_SMB && alproto != ALPROTO_SMB2) { - SCLogDebug("DCERPC sig, alproto not SMB or SMB2"); - return 0; - } - } else { - SCLogDebug("alproto mismatch"); - return 0; - } - } - } - - if (unlikely(s->flags & SIG_FLAG_DSIZE)) { - if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { - SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", - p->payload_len, s->dsize_low, s->dsize_high); - return 0; - } - } - - /* check for a pattern match of the one pattern in this sig. */ - if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_APPLAYER))) - { - /* filter out sigs that want pattern matches, but - * have no matches */ - if (!(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { - if (s->flags & SIG_FLAG_MPM_PACKET) { - if (!(s->flags & SIG_FLAG_MPM_PACKET_NEG)) { - return 0; - } - } else if (s->flags & SIG_FLAG_MPM_STREAM) { - /* filter out sigs that want pattern matches, but - * have no matches */ - if (!(s->flags & SIG_FLAG_MPM_STREAM_NEG)) { - return 0; - } - } else if (s->flags & SIG_FLAG_MPM_APPLAYER) { - if (!(s->flags & SIG_FLAG_MPM_APPLAYER_NEG)) { - return 0; - } - } - } - } - - /* de_state check, filter out all signatures that already had a match before - * or just partially match */ - if (s->flags & SIG_FLAG_STATE_MATCH) { - /* we run after DeStateDetectContinueDetection, so we might have - * state NEW here. In that case we'd want to continue detection - * for this sig. If we have NOSTATE, stateful detection didn't - * start yet for this sig, so we will inspect it. - */ - if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NO_NEW_STATE) - return 0; - } - - return 1; -} - -#if defined(__SSE3__) || defined(__tile__) -/* SIMD implementations are in detect-simd.c */ -#else -/* Non-SIMD implementation */ -/** - * \brief build an array of signatures that will be inspected - * - * All signatures that can be filtered out on forehand are not added to it. - * - * \param de_ctx detection engine ctx - * \param det_ctx detection engine thread ctx -- array is stored here - * \param p packet - * \param mask Packets mask - * \param alproto application layer protocol - */ -void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *det_ctx, - Packet *p, SignatureMask mask, - AppProto alproto) -{ - uint32_t u; - - /* reset previous run */ - det_ctx->match_array_cnt = 0; - - for (u = 0; u < det_ctx->sgh->sig_cnt; u++) { - SignatureHeader *s = &det_ctx->sgh->head_array[u]; - if ((mask & s->mask) == s->mask) { - if (SigMatchSignaturesBuildMatchArrayAddSignature(det_ctx, p, s, alproto) == 1) { - /* okay, store it */ - det_ctx->match_array[det_ctx->match_array_cnt] = s->full_sig; - det_ctx->match_array_cnt++; - } - } - } -} -#endif /* No SIMD implementation */ - int SigMatchSignaturesRunPostMatch(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s) + const Signature *s) { /* run the packet match functions */ - if (s->sm_lists[DETECT_SM_LIST_POSTMATCH] != NULL) { + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH]; + if (smd != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH); - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_POSTMATCH]; - SCLogDebug("running match functions, sm %p", sm); + SCLogDebug("running match functions, sm %p", smd); - for ( ; sm != NULL; sm = sm->next) { + while (1) { KEYWORD_PROFILING_START; - (void)sigmatch_table[sm->type].Match(tv, det_ctx, p, s, sm); - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); + (void)sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx); + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) + break; + smd++; } } @@ -645,6 +598,11 @@ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThre * the decoder events sgh we have. */ if (p->proto == 0 && p->events.cnt > 0) { SCReturnPtr(de_ctx->decoder_event_sgh, "SigGroupHead"); + } else if (p->proto == 0) { + if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { + /* not IP, so nothing to do */ + SCReturnPtr(NULL, "SigGroupHead"); + } } /* select the flow_gh */ @@ -653,38 +611,28 @@ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThre else f = 1; - SCLogDebug("f %d", f); - SCLogDebug("IP_GET_IPPROTO(p) %u", IP_GET_IPPROTO(p)); - - /* find the right mpm instance */ - DetectAddress *ag = DetectAddressLookupInHead(de_ctx->flow_gh[f].src_gh[IP_GET_IPPROTO(p)], &p->src); - if (ag != NULL) { - /* source group found, lets try a dst group */ - ag = DetectAddressLookupInHead(ag->dst_gh, &p->dst); - if (ag != NULL) { - if (ag->port == NULL) { - SCLogDebug("we don't have ports"); - sgh = ag->sh; - } else { - SCLogDebug("we have ports"); - - DetectPort *sport = DetectPortLookupGroup(ag->port,p->sp); - if (sport != NULL) { - DetectPort *dport = DetectPortLookupGroup(sport->dst_ph,p->dp); - if (dport != NULL) { - sgh = dport->sh; - } else { - SCLogDebug("no dst port group found for the packet with dp %"PRIu16"", p->dp); - } - } else { - SCLogDebug("no src port group found for the packet with sp %"PRIu16"", p->sp); - } - } - } else { - SCLogDebug("no dst address group found for the packet"); - } + int proto = IP_GET_IPPROTO(p); + if (proto == IPPROTO_TCP) { + DetectPort *list = de_ctx->flow_gh[f].tcp; + SCLogDebug("tcp toserver %p, tcp toclient %p: going to use %p", + de_ctx->flow_gh[1].tcp, de_ctx->flow_gh[0].tcp, de_ctx->flow_gh[f].tcp); + uint16_t port = f ? p->dp : p->sp; + SCLogDebug("tcp port %u -> %u:%u", port, p->sp, p->dp); + DetectPort *sghport = DetectPortLookupGroup(list, port); + if (sghport != NULL) + sgh = sghport->sh; + SCLogDebug("TCP list %p, port %u, direction %s, sghport %p, sgh %p", + list, port, f ? "toserver" : "toclient", sghport, sgh); + } else if (proto == IPPROTO_UDP) { + DetectPort *list = de_ctx->flow_gh[f].udp; + uint16_t port = f ? p->dp : p->sp; + DetectPort *sghport = DetectPortLookupGroup(list, port); + if (sghport != NULL) + sgh = sghport->sh; + SCLogDebug("UDP list %p, port %u, direction %s, sghport %p, sgh %p", + list, port, f ? "toserver" : "toclient", sghport, sgh); } else { - SCLogDebug("no src address group found for the packet"); + sgh = de_ctx->flow_gh[f].sgh[proto]; } SCReturnPtr(sgh, "SigGroupHead"); @@ -734,7 +682,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) /* if the smsg is bigger than the current packet, we will * process the smsg in a later run */ - if ((head->seq + head->data_len) > (TCP_GET_SEQ(p) + p->payload_len)) { + if (SEQ_GT((head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len))) { SCLogDebug("smsg ends beyond current packet, skipping for now %"PRIu32">%"PRIu32, (head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len)); goto end; @@ -753,7 +701,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) /* if the smsg is bigger than the current packet, we will * process the smsg in a later run */ - if ((head->seq + head->data_len) > (TCP_GET_SEQ(p) + p->payload_len)) { + if (SEQ_GT((head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len))) { SCLogDebug("smsg ends beyond current packet, skipping for now %"PRIu32">%"PRIu32, (head->seq + head->data_len), (TCP_GET_SEQ(p) + p->payload_len)); goto end; @@ -773,254 +721,133 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags) SCReturnPtr(smsg, "StreamMsg"); } -#define SMS_USE_FLOW_SGH 0x01 -#define SMS_USED_PM 0x02 -#define SMS_USED_STREAM_PM 0x04 - -/** - * \internal - * \brief Run mpm on packet, stream and other buffers based on - * alproto, sgh state. - * - * \param de_ctx Pointer to the detection engine context. - * \param det_ctx Pointer to the detection engine thread context. - * \param smsg The stream segment to inspect for stream mpm. - * \param p Packet. - * \param flags Flags. - * \param alproto Flow alproto. - * \param has_state Bool indicating we have (al)state - * \param sms_runflags Used to store state by detection engine. - */ -static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, StreamMsg *smsg, Packet *p, - uint8_t flags, AppProto alproto, int has_state, uint8_t *sms_runflags) -{ - /* have a look at the reassembled stream (if any) */ - if (p->flowflags & FLOW_PKT_ESTABLISHED) { - SCLogDebug("p->flowflags & FLOW_PKT_ESTABLISHED"); - - /* all http based mpms */ - if (has_state && alproto == ALPROTO_HTTP) { - FLOWLOCK_WRLOCK(p->flow); - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); - return; +static inline void DetectPrefilterMergeSort(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx) +{ + SigIntId mpm, nonmpm; + det_ctx->match_array_cnt = 0; + SigIntId *mpm_ptr = det_ctx->pmq.rule_id_array; + SigIntId *nonmpm_ptr = det_ctx->non_pf_id_array; + uint32_t m_cnt = det_ctx->pmq.rule_id_array_cnt; + uint32_t n_cnt = det_ctx->non_pf_id_cnt; + SigIntId *final_ptr; + uint32_t final_cnt; + SigIntId id; + SigIntId previous_id = (SigIntId)-1; + Signature **sig_array = de_ctx->sig_array; + Signature **match_array = det_ctx->match_array; + Signature *s; + + SCLogDebug("PMQ rule id array count %d", det_ctx->pmq.rule_id_array_cnt); + + /* Load first values. */ + if (likely(m_cnt)) { + mpm = *mpm_ptr; + } else { + /* mpm list is empty */ + final_ptr = nonmpm_ptr; + final_cnt = n_cnt; + goto final; + } + if (likely(n_cnt)) { + nonmpm = *nonmpm_ptr; + } else { + /* non-mpm list is empty. */ + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; + } + while (1) { + if (mpm < nonmpm) { + /* Take from mpm list */ + id = mpm; + + s = sig_array[id]; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; } - - HtpState *htp_state = (HtpState *)alstate; - if (htp_state->connp == NULL) { - SCLogDebug("no HTTP connp"); - FLOWLOCK_UNLOCK(p->flow); - return; + if (unlikely(--m_cnt == 0)) { + /* mpm list is now empty */ + final_ptr = nonmpm_ptr; + final_cnt = n_cnt; + goto final; + } + mpm_ptr++; + mpm = *mpm_ptr; + } else if (mpm > nonmpm) { + id = nonmpm; + + s = sig_array[id]; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; + } + if (unlikely(--n_cnt == 0)) { + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; + } + nonmpm_ptr++; + nonmpm = *nonmpm_ptr; + + } else { /* implied mpm == nonmpm */ + /* special case: if on both lists, it's a negated mpm pattern */ + + /* mpm list may have dups, so skip past them here */ + while (--m_cnt != 0) { + mpm_ptr++; + mpm = *mpm_ptr; + if (mpm != nonmpm) + break; } - - int tx_progress = 0; - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, ALPROTO_HTTP, alstate); - for (; idx < total_txs; idx++) { - htp_tx_t *tx = AppLayerParserGetTx(p->flow->proto, ALPROTO_HTTP, htp_state, idx); - if (tx == NULL) - continue; - tx_progress = AppLayerParserGetStateProgress(p->flow->proto, ALPROTO_HTTP, tx, STREAM_TOSERVER); - - if (p->flowflags & FLOW_PKT_TOSERVER) { - if (tx_progress > HTP_REQUEST_LINE) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_URI) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_URI); - DetectUricontentInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_URI); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRUD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRUD); - DetectEngineRunHttpRawUriMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRUD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HMD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HMD); - DetectEngineRunHttpMethodMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HMD); - } - } - - if (tx_progress >= HTP_REQUEST_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHHD); - DetectEngineRunHttpHHMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHHD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHHD); - DetectEngineRunHttpHRHMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHHD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); - DetectEngineRunHttpCookieMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HUAD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HUAD); - DetectEngineRunHttpUAMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HUAD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); - DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); - DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); - } - } - - if (tx_progress >= HTP_REQUEST_BODY) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCBD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCBD); - DetectEngineRunHttpClientBodyMpm(de_ctx, det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCBD); - } - } - } else { /* implied FLOW_PKT_TOCLIENT */ - tx_progress = AppLayerParserGetStateProgress(p->flow->proto, ALPROTO_HTTP, tx, STREAM_TOCLIENT); - - if (tx_progress > HTP_RESPONSE_LINE) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSMD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSMD); - DetectEngineRunHttpStatMsgMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSMD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSCD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSCD); - DetectEngineRunHttpStatCodeMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSCD); - } - } - - if (tx_progress >= HTP_RESPONSE_HEADERS) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HHD); - DetectEngineRunHttpHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HHD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HRHD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HRHD); - DetectEngineRunHttpRawHeaderMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HRHD); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HCD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HCD); - DetectEngineRunHttpCookieMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HCD); - } - } - - if (tx_progress >= HTP_RESPONSE_BODY) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_HSBD) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_HSBD); - DetectEngineRunHttpServerBodyMpm(de_ctx, det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_HSBD); - } - } - } - } /* for */ - - FLOWLOCK_UNLOCK(p->flow); - } - /* all dns based mpms */ - else if (alproto == ALPROTO_DNS && has_state) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) { - FLOWLOCK_RDLOCK(p->flow); - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); - return; - } - - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, alproto, alstate); - for (; idx < total_txs; idx++) { - void *tx = AppLayerParserGetTx(p->flow->proto, alproto, alstate, idx); - if (tx == NULL) - continue; - - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY); - DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); - } - FLOWLOCK_UNLOCK(p->flow); - } + /* if mpm is done, update nonmpm_ptrs and jump to final */ + if (unlikely(m_cnt == 0)) { + n_cnt--; + + /* mpm list is now empty */ + final_ptr = ++nonmpm_ptr; + final_cnt = n_cnt; + goto final; + } + /* otherwise, if nonmpm is done jump to final for mpm + * mpm ptrs alrady updated */ + if (unlikely(--n_cnt == 0)) { + final_ptr = mpm_ptr; + final_cnt = m_cnt; + goto final; } - } - - if (smsg != NULL && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_STREAM); - StreamPatternSearch(det_ctx, p, smsg, flags); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_STREAM); - *sms_runflags |= SMS_USED_STREAM_PM; - } else { - SCLogDebug("smsg NULL or no stream mpm for this sgh"); + /* not at end of the lists, update nonmpm. Mpm already + * updated in while loop above. */ + nonmpm_ptr++; + nonmpm = *nonmpm_ptr; } - } else { - SCLogDebug("NOT p->flowflags & FLOW_PKT_ESTABLISHED"); } - if (p->payload_len > 0 && (!(p->flags & PKT_NOPAYLOAD_INSPECTION))) { - if (!(p->flags & PKT_STREAM_ADD) && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) { - *sms_runflags |= SMS_USED_PM; - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PKT_STREAM); - PacketPatternSearchWithStreamCtx(det_ctx, p); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PKT_STREAM); - } - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_PACKET) { - /* run the multi packet matcher against the payload of the packet */ - SCLogDebug("search: (%p, maxlen %" PRIu32 ", sgh->sig_cnt %" PRIu32 ")", - det_ctx->sgh, det_ctx->sgh->mpm_content_maxlen, det_ctx->sgh->sig_cnt); + final: /* Only one list remaining. Just walk that list. */ - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_PACKET); - PacketPatternSearch(det_ctx, p); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_PACKET); + while (final_cnt-- > 0) { + id = *final_ptr++; + s = sig_array[id]; - *sms_runflags |= SMS_USED_PM; + /* As the mpm list can contain duplicates, check for that here. */ + if (likely(id != previous_id)) { + *match_array++ = s; + previous_id = id; } } - /* UDP DNS inspection is independent of est or not */ - if (alproto == ALPROTO_DNS && has_state) { - if (p->flowflags & FLOW_PKT_TOSERVER) { - SCLogDebug("mpm inspection"); - if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) { - FLOWLOCK_RDLOCK(p->flow); - void *alstate = FlowGetAppState(p->flow); - if (alstate == NULL) { - SCLogDebug("no alstate"); - FLOWLOCK_UNLOCK(p->flow); - return; - } + det_ctx->match_array_cnt = match_array - det_ctx->match_array; - uint64_t idx = AppLayerParserGetTransactionInspectId(p->flow->alparser, flags); - uint64_t total_txs = AppLayerParserGetTxCnt(p->flow->proto, alproto, alstate); - for (; idx < total_txs; idx++) { - void *tx = AppLayerParserGetTx(p->flow->proto, alproto, alstate, idx); - if (tx == NULL) - continue; - SCLogDebug("tx %p",tx); - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY); - DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY); - } - FLOWLOCK_UNLOCK(p->flow); - } - } - } + BUG_ON((det_ctx->pmq.rule_id_array_cnt + det_ctx->non_pf_id_cnt) < det_ctx->match_array_cnt); } +#define SMS_USE_FLOW_SGH 0x01 +#define SMS_USED_PM 0x02 + #ifdef DEBUG static void DebugInspectIds(Packet *p, Flow *f, StreamMsg *smsg) { @@ -1032,70 +859,110 @@ static void DebugInspectIds(Packet *p, Flow *f, StreamMsg *smsg) } #endif -static void AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(Packet *p, DetectEngineCtx *de_ctx) +static inline void +DetectPrefilterBuildNonPrefilterList(DetectEngineThreadCtx *det_ctx, SignatureMask mask) { -#define MALLOC_JUMP 5 + uint32_t x = 0; + for (x = 0; x < det_ctx->non_pf_store_cnt; x++) { + /* only if the mask matches this rule can possibly match, + * so build the non_mpm array only for match candidates */ + SignatureMask rule_mask = det_ctx->non_pf_store_ptr[x].mask; + if ((rule_mask & mask) == rule_mask) { + det_ctx->non_pf_id_array[det_ctx->non_pf_id_cnt++] = det_ctx->non_pf_store_ptr[x].id; + } + } +} - int i = 0; +/** \internal + * \brief select non-mpm list + * Based on the packet properties, select the non-mpm list to use */ +static inline void +DetectPrefilterSetNonPrefilterList(const Packet *p, DetectEngineThreadCtx *det_ctx) +{ + if ((p->proto == IPPROTO_TCP) && (p->tcph != NULL) && (p->tcph->th_flags & TH_SYN)) { + det_ctx->non_pf_store_ptr = det_ctx->sgh->non_pf_syn_store_array; + det_ctx->non_pf_store_cnt = det_ctx->sgh->non_pf_syn_store_cnt; + } else { + det_ctx->non_pf_store_ptr = det_ctx->sgh->non_pf_other_store_array; + det_ctx->non_pf_store_cnt = det_ctx->sgh->non_pf_other_store_cnt; + } + SCLogDebug("sgh non_pf ptr %p cnt %u (syn %p/%u, other %p/%u)", + det_ctx->non_pf_store_ptr, det_ctx->non_pf_store_cnt, + det_ctx->sgh->non_pf_syn_store_array, det_ctx->sgh->non_pf_syn_store_cnt, + det_ctx->sgh->non_pf_other_store_array, det_ctx->sgh->non_pf_other_store_cnt); +} - GenericVar *gv = p->flow->flowvar; +/** \internal + * \brief update flow's file tracking flags based on the detection engine + */ +static inline void +DetectPostInspectFileFlagsUpdate(Flow *pflow, const SigGroupHead *sgh, uint8_t direction) +{ + /* see if this sgh requires us to consider file storing */ + if (!FileForceFilestore() && (sgh == NULL || + sgh->filestore_cnt == 0)) + { + FileDisableStoring(pflow, direction); + } +#ifdef HAVE_MAGIC + /* see if this sgh requires us to consider file magic */ + if (!FileForceMagic() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) + { + SCLogDebug("disabling magic for flow"); + FileDisableMagic(pflow, direction); + } +#endif + /* see if this sgh requires us to consider file md5 */ + if (!FileForceMd5() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) + { + SCLogDebug("disabling md5 for flow"); + FileDisableMd5(pflow, direction); + } - while (gv != NULL) { - i++; - gv = gv->next; + /* see if this sgh requires us to consider file sha1 */ + if (!FileForceSha1() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA1))) + { + SCLogDebug("disabling sha1 for flow"); + FileDisableSha1(pflow, direction); } - if (i == 0) - return; - p->debuglog_flowbits_names_len = i; + /* see if this sgh requires us to consider file sha256 */ + if (!FileForceSha256() && (sgh == NULL || + !(sgh->flags & SIG_GROUP_HEAD_HAVEFILESHA256))) + { + SCLogDebug("disabling sha256 for flow"); + FileDisableSha256(pflow, direction); + } - p->debuglog_flowbits_names = SCMalloc(sizeof(char *) * - p->debuglog_flowbits_names_len); - if (p->debuglog_flowbits_names == NULL) { - return; + /* see if this sgh requires us to consider filesize */ + if (sgh == NULL || !(sgh->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) + { + SCLogDebug("disabling filesize for flow"); + FileDisableFilesize(pflow, direction); } - memset(p->debuglog_flowbits_names, 0, - sizeof(char *) * p->debuglog_flowbits_names_len); +} - i = 0; - gv = p->flow->flowvar; - while (gv != NULL) { - if (gv->type != DETECT_FLOWBITS) { - gv = gv->next; - continue; - } +static inline void +DetectPostInspectFirstSGH(const Packet *p, Flow *pflow, const SigGroupHead *sgh) +{ + if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { + /* first time we see this toserver sgh, store it */ + pflow->sgh_toserver = sgh; + pflow->flags |= FLOW_SGH_TOSERVER; - FlowBit *fb = (FlowBit *) gv; - char *name = VariableIdxGetName(de_ctx, fb->idx, fb->type); - if (name != NULL) { - p->debuglog_flowbits_names[i] = SCStrdup(name); - if (p->debuglog_flowbits_names[i] == NULL) { - return; - } - i++; - } + DetectPostInspectFileFlagsUpdate(pflow, + pflow->sgh_toserver, STREAM_TOSERVER); - if (i == p->debuglog_flowbits_names_len) { - p->debuglog_flowbits_names_len += MALLOC_JUMP; - const char **names = SCRealloc(p->debuglog_flowbits_names, - sizeof(char *) * - p->debuglog_flowbits_names_len); - if (names == NULL) { - SCFree(p->debuglog_flowbits_names); - p->debuglog_flowbits_names = NULL; - p->debuglog_flowbits_names_len = 0; - return; - } - p->debuglog_flowbits_names = names; - memset(p->debuglog_flowbits_names + - p->debuglog_flowbits_names_len - MALLOC_JUMP, - 0, sizeof(char *) * MALLOC_JUMP); - } + } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) { + pflow->sgh_toclient = sgh; + pflow->flags |= FLOW_SGH_TOCLIENT; - gv = gv->next; + DetectPostInspectFileFlagsUpdate(pflow, + pflow->sgh_toclient, STREAM_TOCLIENT); } - - return; } /** @@ -1112,13 +979,9 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #ifdef PROFILING int smatch = 0; /* signature match: 1, no match: 0 */ #endif - uint32_t idx; - uint8_t flags = 0; /* flow/state flags */ - StreamMsg *smsg = NULL; - Signature *s = NULL; - SigMatch *sm = NULL; - uint16_t alversion = 0; - int reset_de_state = 0; + uint8_t flow_flags = 0; /* flow/state flags */ + const Signature *s = NULL; + const Signature *next_s = NULL; int state_alert = 0; int alerts = 0; int app_decoder_events = 0; @@ -1128,8 +991,11 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SCLogDebug("pcap_cnt %"PRIu64, p->pcap_cnt); + det_ctx->ticker++; p->alerts.cnt = 0; det_ctx->filestore_cnt = 0; + det_ctx->smsg = NULL; + det_ctx->base64_decoded_len = 0; /* No need to perform any detection on this packet, if the the given flag is set.*/ if (p->flags & PKT_NOPACKET_INSPECTION) { @@ -1143,28 +1009,43 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* grab the protocol state we will detect on */ if (p->flags & PKT_HAS_FLOW) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flow_flags = STREAM_TOSERVER; + SCLogDebug("flag STREAM_TOSERVER set"); + } else if (p->flowflags & FLOW_PKT_TOCLIENT) { + flow_flags = STREAM_TOCLIENT; + SCLogDebug("flag STREAM_TOCLIENT set"); + } + SCLogDebug("p->flowflags 0x%02x", p->flowflags); + if (p->flags & PKT_STREAM_EOF) { - flags |= STREAM_EOF; + flow_flags |= STREAM_EOF; SCLogDebug("STREAM_EOF set"); } - FLOWLOCK_WRLOCK(pflow); { + /* store tenant_id in the flow so that we can use it + * for creating pseudo packets */ + if (p->tenant_id > 0 && pflow->tenant_id == 0) { + pflow->tenant_id = p->tenant_id; + } + /* live ruleswap check for flow updates */ - if (pflow->de_ctx_id == 0) { + if (pflow->de_ctx_version == 0) { /* first time this flow is inspected, set id */ - pflow->de_ctx_id = de_ctx->id; - } else if (pflow->de_ctx_id != de_ctx->id) { + pflow->de_ctx_version = de_ctx->version; + } else if (pflow->de_ctx_version != de_ctx->version) { /* first time we inspect flow with this de_ctx, reset */ pflow->flags &= ~FLOW_SGH_TOSERVER; pflow->flags &= ~FLOW_SGH_TOCLIENT; pflow->sgh_toserver = NULL; pflow->sgh_toclient = NULL; - reset_de_state = 1; - pflow->de_ctx_id = de_ctx->id; + pflow->de_ctx_version = de_ctx->version; GenericVarFree(pflow->flowvar); pflow->flowvar = NULL; + + DetectEngineStateResetTxs(pflow); } /* set the iponly stuff */ @@ -1179,14 +1060,16 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_GETSGH); if ((p->flowflags & FLOW_PKT_TOSERVER) && (pflow->flags & FLOW_SGH_TOSERVER)) { det_ctx->sgh = pflow->sgh_toserver; + SCLogDebug("det_ctx->sgh = pflow->sgh_toserver; => %p", det_ctx->sgh); sms_runflags |= SMS_USE_FLOW_SGH; } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && (pflow->flags & FLOW_SGH_TOCLIENT)) { det_ctx->sgh = pflow->sgh_toclient; + SCLogDebug("det_ctx->sgh = pflow->sgh_toclient; => %p", det_ctx->sgh); sms_runflags |= SMS_USE_FLOW_SGH; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_GETSGH); - smsg = SigMatchSignaturesGetSmsg(pflow, p, flags); + det_ctx->smsg = SigMatchSignaturesGetSmsg(pflow, p, flow_flags); #if 0 StreamMsg *tmpsmsg = smsg; while (tmpsmsg) { @@ -1204,9 +1087,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh (p->proto == IPPROTO_UDP) || (p->proto == IPPROTO_SCTP && (p->flowflags & FLOW_PKT_ESTABLISHED))) { + /* update flow flags with knowledge on disruptions */ + flow_flags = FlowGetDisruptionFlags(pflow, flow_flags); has_state = (FlowGetAppState(pflow) != NULL); alproto = FlowGetAppProtocol(pflow); - alversion = AppLayerParserGetStateVersion(pflow->alparser); SCLogDebug("alstate %s, alproto %u", has_state ? "true" : "false", alproto); } else { SCLogDebug("packet doesn't have established flag set (proto %d)", p->proto); @@ -1216,24 +1100,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh pflow->alproto, pflow->alstate, pflow->alparser, - flags); - } - FLOWLOCK_UNLOCK(pflow); - - if (p->flowflags & FLOW_PKT_TOSERVER) { - flags |= STREAM_TOSERVER; - SCLogDebug("flag STREAM_TOSERVER set"); - } else if (p->flowflags & FLOW_PKT_TOCLIENT) { - flags |= STREAM_TOCLIENT; - SCLogDebug("flag STREAM_TOCLIENT set"); - } - SCLogDebug("p->flowflags 0x%02x", p->flowflags); - - /* reset because of ruleswap */ - if (reset_de_state) { - SCMutexLock(&pflow->de_state_m); - DetectEngineStateReset(pflow->de_state, (STREAM_TOSERVER|STREAM_TOCLIENT)); - SCMutexUnlock(&pflow->de_state_m); + flow_flags); } if (((p->flowflags & FLOW_PKT_TOSERVER) && !(p->flowflags & FLOW_PKT_TOSERVER_IPONLY_SET)) || @@ -1245,8 +1112,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh IPOnlyMatchPacket(th_v, de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_IPONLY); - /* save in the flow that we scanned this direction... locking is - * done in the FlowSetIPOnlyFlag function. */ + /* save in the flow that we scanned this direction... */ FlowSetIPOnlyFlag(pflow, p->flowflags & FLOW_PKT_TOSERVER ? 1 : 0); } else if (((p->flowflags & FLOW_PKT_TOSERVER) && @@ -1272,9 +1138,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh #ifdef DEBUG if (pflow) { - SCMutexLock(&pflow->m); - DebugInspectIds(p, pflow, smsg); - SCMutexUnlock(&pflow->m); + DebugInspectIds(p, pflow, det_ctx->smsg); } #endif } else { /* p->flags & PKT_HAS_FLOW */ @@ -1298,69 +1162,149 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto end; } + DetectPrefilterSetNonPrefilterList(p, det_ctx); + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); /* stateful app layer detection */ if ((p->flags & PKT_HAS_FLOW) && has_state) { - /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ memset(det_ctx->de_state_sig_array, 0x00, det_ctx->de_state_sig_array_len); - int has_inspectable_state = DeStateFlowHasInspectableState(pflow, alproto, alversion, flags); + int has_inspectable_state = DeStateFlowHasInspectableState(pflow, flow_flags); if (has_inspectable_state == 1) { + /* initialize to 0(DE_STATE_MATCH_HAS_NEW_STATE) */ DeStateDetectContinueDetection(th_v, de_ctx, det_ctx, p, pflow, - flags, alproto, alversion); - } else if (has_inspectable_state == 2) { - /* no inspectable state, so pretend we don't have a state at all */ - has_state = 0; + flow_flags, alproto); } } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); /* create our prefilter mask */ SignatureMask mask = 0; - PacketCreateMask(p, &mask, alproto, has_state, smsg, app_decoder_events); + PacketCreateMask(p, &mask, alproto, has_state, det_ctx->smsg, + app_decoder_events); - /* run the mpm for each type */ - PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM); - DetectMpmPrefilter(de_ctx, det_ctx, smsg, p, flags, alproto, has_state, &sms_runflags); - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM); + /* build and prefilter non_pf list against the mask of the packet */ + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_NONMPMLIST); + det_ctx->non_pf_id_cnt = 0; + if (likely(det_ctx->non_pf_store_cnt > 0)) { + DetectPrefilterBuildNonPrefilterList(det_ctx, mask); + } + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_NONMPMLIST); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PREFILTER); - /* build the match array */ - SigMatchSignaturesBuildMatchArray(det_ctx, p, mask, alproto); + /* run the prefilter engines */ + Prefilter(det_ctx, det_ctx->sgh, p, flow_flags, has_state); + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT2); + DetectPrefilterMergeSort(de_ctx, det_ctx); + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT2); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PREFILTER); +#ifdef PROFILING + if (th_v) { + StatsAddUI64(th_v, det_ctx->counter_mpm_list, + (uint64_t)det_ctx->pmq.rule_id_array_cnt); + StatsAddUI64(th_v, det_ctx->counter_nonmpm_list, + (uint64_t)det_ctx->non_pf_store_cnt); + /* non mpm sigs after mask prefilter */ + StatsAddUI64(th_v, det_ctx->counter_fnonmpm_list, + (uint64_t)det_ctx->non_pf_id_cnt); + } +#endif + + PACKET_PROFILING_DETECT_START(p, PROF_DETECT_RULES); /* inspect the sigs against the packet */ - for (idx = 0; idx < det_ctx->match_array_cnt; idx++) { - RULE_PROFILING_START(p); - state_alert = 0; + /* Prefetch the next signature. */ + SigIntId match_cnt = det_ctx->match_array_cnt; #ifdef PROFILING - smatch = 0; + if (th_v) { + StatsAddUI64(th_v, det_ctx->counter_match_list, + (uint64_t)match_cnt); + } #endif + Signature **match_array = det_ctx->match_array; + + SGH_PROFILING_RECORD(det_ctx, det_ctx->sgh); + +#ifdef PROFILING +#ifdef HAVE_LIBJANSSON + if (match_cnt >= de_ctx->profile_match_logging_threshold) + RulesDumpMatchArray(det_ctx, p); +#endif +#endif + + uint32_t sflags, next_sflags = 0; + if (match_cnt) { + next_s = *match_array++; + next_sflags = next_s->flags; + } + + while (match_cnt--) { + RULE_PROFILING_START(p); + state_alert = 0; +#ifdef PROFILING + smatch = 0; +#endif + + s = next_s; + sflags = next_sflags; + if (match_cnt) { + next_s = *match_array++; + next_sflags = next_s->flags; + } + uint8_t s_proto_flags = s->proto.flags; - s = det_ctx->match_array[idx]; SCLogDebug("inspecting signature id %"PRIu32"", s->id); + if ((s->mask & mask) != s->mask) + goto next; + + /* if the sig has alproto and the session as well they should match */ + if (likely(sflags & SIG_FLAG_APPLAYER)) { + if (s->alproto != ALPROTO_UNKNOWN && s->alproto != alproto) { + if (s->alproto == ALPROTO_DCERPC) { + if (alproto != ALPROTO_SMB && alproto != ALPROTO_SMB2) { + SCLogDebug("DCERPC sig, alproto not SMB or SMB2"); + goto next; + } + } else { + SCLogDebug("alproto mismatch"); + goto next; + } + } + } + + if (unlikely(sflags & SIG_FLAG_DSIZE)) { + if (likely(p->payload_len < s->dsize_low || p->payload_len > s->dsize_high)) { + SCLogDebug("kicked out as p->payload_len %u, dsize low %u, hi %u", + p->payload_len, s->dsize_low, s->dsize_high); + goto next; + } + } + + if (sflags & SIG_FLAG_STATE_MATCH) { + if (det_ctx->de_state_sig_array[s->num] & DE_STATE_MATCH_NO_NEW_STATE) + goto next; + } + /* check if this signature has a requirement for flowvars of some type * and if so, if we actually have any in the flow. If not, the sig * can't match and we skip it. */ - if ((p->flags & PKT_HAS_FLOW) && (s->flags & SIG_FLAG_REQUIRE_FLOWVAR)) { - FLOWLOCK_RDLOCK(pflow); + if ((p->flags & PKT_HAS_FLOW) && (sflags & SIG_FLAG_REQUIRE_FLOWVAR)) { int m = pflow->flowvar ? 1 : 0; - FLOWLOCK_UNLOCK(pflow); /* no flowvars? skip this sig */ if (m == 0) { SCLogDebug("skipping sig as the flow has no flowvars and sig " - "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); + "has SIG_FLAG_REQUIRE_FLOWVAR flag set."); goto next; } } - if ((s->proto.flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) { + if ((s_proto_flags & DETECT_PROTO_IPV4) && !PKT_IS_IPV4(p)) { SCLogDebug("ip version didn't match"); goto next; } - if ((s->proto.flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) { + if ((s_proto_flags & DETECT_PROTO_IPV6) && !PKT_IS_IPV6(p)) { SCLogDebug("ip version didn't match"); goto next; } @@ -1372,7 +1316,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* check the source & dst port in the sig */ if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { - if (!(s->flags & SIG_FLAG_DP_ANY)) { + if (!(sflags & SIG_FLAG_DP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) goto next; DetectPort *dport = DetectPortLookupGroup(s->dp,p->dp); @@ -1381,7 +1325,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto next; } } - if (!(s->flags & SIG_FLAG_SP_ANY)) { + if (!(sflags & SIG_FLAG_SP_ANY)) { if (p->flags & PKT_IS_FRAGMENT) goto next; DetectPort *sport = DetectPortLookupGroup(s->sp,p->sp); @@ -1390,13 +1334,13 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh goto next; } } - } else if ((s->flags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) { + } else if ((sflags & (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) != (SIG_FLAG_DP_ANY|SIG_FLAG_SP_ANY)) { SCLogDebug("port-less protocol and sig needs ports"); goto next; } /* check the destination address */ - if (!(s->flags & SIG_FLAG_DST_ANY)) { + if (!(sflags & SIG_FLAG_DST_ANY)) { if (PKT_IS_IPV4(p)) { if (DetectAddressMatchIPv4(s->addr_dst_match4, s->addr_dst_match4_cnt, &p->dst) == 0) goto next; @@ -1406,7 +1350,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh } } /* check the source address */ - if (!(s->flags & SIG_FLAG_SRC_ANY)) { + if (!(sflags & SIG_FLAG_SRC_ANY)) { if (PKT_IS_IPV4(p)) { if (DetectAddressMatchIPv4(s->addr_src_match4, s->addr_src_match4_cnt, &p->src) == 0) goto next; @@ -1418,32 +1362,23 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* Check the payload keywords. If we are a MPM sig and we've made * to here, we've had at least one of the patterns match */ - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_PMATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH); /* if we have stream msgs, inspect against those first, * but not for a "dsize" signature */ - if (s->flags & SIG_FLAG_REQUIRE_STREAM) { + if (sflags & SIG_FLAG_REQUIRE_STREAM) { char pmatch = 0; - if (smsg != NULL) { - uint8_t pmq_idx = 0; - StreamMsg *smsg_inspect = smsg; - for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next, pmq_idx++) { - /* filter out sigs that want pattern matches, but - * have no matches */ - if ((s->flags & SIG_FLAG_MPM_STREAM) && !(s->flags & SIG_FLAG_MPM_STREAM_NEG) && - !(det_ctx->smsg_pmq[pmq_idx].pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & s->mpm_pattern_id_mod_8)) { - SCLogDebug("no match in this smsg"); - continue; - } - + if (det_ctx->smsg != NULL) { + StreamMsg *smsg_inspect = det_ctx->smsg; + for ( ; smsg_inspect != NULL; smsg_inspect = smsg_inspect->next) { if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, pflow, smsg_inspect->data, smsg_inspect->data_len) == 1) { - SCLogDebug("match in smsg %p", smsg); + SCLogDebug("match in smsg %p", smsg_inspect); pmatch = 1; det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH; /* Tell the engine that this reassembled stream can drop the * rest of the pkts with no further inspection */ if (s->action & ACTION_DROP) - alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; + alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW; alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH; break; @@ -1456,71 +1391,48 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (pmatch == 0) { SCLogDebug("no match in smsg, fall back to packet payload"); - if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) { + if (!(sflags & SIG_FLAG_REQUIRE_PACKET)) { if (p->flags & PKT_STREAM_ADD) goto next; } - if (sms_runflags & SMS_USED_PM) { - if ((s->flags & SIG_FLAG_MPM_PACKET) && !(s->flags & SIG_FLAG_MPM_PACKET_NEG) && - !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & - s->mpm_pattern_id_mod_8)) { - goto next; - } - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { - goto next; - } - } else { - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { - goto next; - } - } - } - } else { - if (sms_runflags & SMS_USED_PM) { - if ((s->flags & SIG_FLAG_MPM_PACKET) && !(s->flags & SIG_FLAG_MPM_PACKET_NEG) && - !(det_ctx->pmq.pattern_id_bitarray[(s->mpm_pattern_id_div_8)] & - s->mpm_pattern_id_mod_8)) { - goto next; - } if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { goto next; } - - } else { - if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) - goto next; + } + } else { + if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) { + goto next; } } } /* run the packet match functions */ - if (s->sm_lists[DETECT_SM_LIST_MATCH] != NULL) { + if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) { KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH); - sm = s->sm_lists[DETECT_SM_LIST_MATCH]; - - SCLogDebug("running match functions, sm %p", sm); - for ( ; sm != NULL; sm = sm->next) { - KEYWORD_PROFILING_START; - if (sigmatch_table[sm->type].Match(th_v, det_ctx, p, s, sm) <= 0) { - KEYWORD_PROFILING_END(det_ctx, sm->type, 0); - goto next; + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH]; + + SCLogDebug("running match functions, sm %p", smd); + if (smd != NULL) { + while (1) { + KEYWORD_PROFILING_START; + if (sigmatch_table[smd->type].Match(th_v, det_ctx, p, s, smd->ctx) <= 0) { + KEYWORD_PROFILING_END(det_ctx, smd->type, 0); + SCLogDebug("no match"); + goto next; + } + KEYWORD_PROFILING_END(det_ctx, smd->type, 1); + if (smd->is_last) { + SCLogDebug("match and is_last"); + break; + } + smd++; } - KEYWORD_PROFILING_END(det_ctx, sm->type, 1); } } - SCLogDebug("s->sm_lists[DETECT_SM_LIST_AMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_UMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_DMATCH] %p, " - "s->sm_lists[DETECT_SM_LIST_HCDMATCH] %p", - s->sm_lists[DETECT_SM_LIST_AMATCH], - s->sm_lists[DETECT_SM_LIST_UMATCH], - s->sm_lists[DETECT_SM_LIST_DMATCH], - s->sm_lists[DETECT_SM_LIST_HCDMATCH]); - /* consider stateful sig matches */ - if (s->flags & SIG_FLAG_STATE_MATCH) { + if (sflags & SIG_FLAG_STATE_MATCH) { if (has_state == 0) { SCLogDebug("state matches but no state, we can't match"); goto next; @@ -1534,7 +1446,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh * can store the tx_id with the alert */ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); state_alert = DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s, - p, pflow, flags, alproto, alversion); + p, pflow, flow_flags, alproto); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); if (state_alert == 0) goto next; @@ -1552,17 +1464,17 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh SigMatchSignaturesRunPostMatch(th_v, de_ctx, det_ctx, p, s); - if (!(s->flags & SIG_FLAG_NOALERT)) { + if (!(sflags & SIG_FLAG_NOALERT)) { /* stateful sigs call PacketAlertAppend from DeStateDetectStartDetection */ if (!state_alert) PacketAlertAppend(det_ctx, s, p, 0, alert_flags); } else { /* apply actions even if not alerting */ - PACKET_UPDATE_ACTION(p, s->action); + DetectSignatureApplyActions(p, s); } alerts++; next: - DetectFlowvarProcessList(det_ctx, pflow); + DetectVarProcessList(det_ctx, pflow, p); DetectReplaceFree(det_ctx); RULE_PROFILING_END(det_ctx, s, smatch, p); @@ -1579,7 +1491,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh /* see if we need to increment the inspect_id and reset the de_state */ if (has_state && AppLayerParserProtocolSupportsTxs(p->proto, alproto)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_STATEFUL); - DeStateUpdateInspectTransactionId(pflow, flags); + DeStateUpdateInspectTransactionId(pflow, flow_flags); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_STATEFUL); } @@ -1590,7 +1502,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh PACKET_PROFILING_DETECT_START(p, PROF_DETECT_ALERT); PacketAlertFinalize(de_ctx, det_ctx, p); if (p->alerts.cnt > 0) { - SCPerfCounterAddUI64(det_ctx->counter_alerts, det_ctx->tv->sc_perf_pca, (uint64_t)p->alerts.cnt); + StatsAddUI64(th_v, det_ctx->counter_alerts, (uint64_t)p->alerts.cnt); } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_ALERT); @@ -1600,104 +1512,102 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh DetectEngineCleanHCBDBuffers(det_ctx); DetectEngineCleanHSBDBuffers(det_ctx); - DetectEngineCleanHHDBuffers(det_ctx); + DetectEngineCleanSMTPBuffers(det_ctx); /* store the found sgh (or NULL) in the flow to save us from looking it * up again for the next packet. Also return any stream chunk we processed * to the pool. */ if (p->flags & PKT_HAS_FLOW) { - if (sms_runflags & SMS_USED_STREAM_PM) { - StreamPatternCleanup(th_v, det_ctx, smsg); - } + /* HACK: prevent the wrong sgh (or NULL) from being stored in the + * flow's sgh pointers */ + if (PKT_IS_ICMPV4(p) && ICMPV4_DEST_UNREACH_IS_VALID(p)) { + ; /* no-op */ - FLOWLOCK_WRLOCK(pflow); - if (debuglog_enabled) { - if (p->alerts.cnt > 0) { - AlertDebugLogModeSyncFlowbitsNamesToPacketStruct(p, de_ctx); - } + } else if (!(sms_runflags & SMS_USE_FLOW_SGH)) { + DetectPostInspectFirstSGH(p, pflow, det_ctx->sgh); } - if (!(sms_runflags & SMS_USE_FLOW_SGH)) { - if ((p->flowflags & FLOW_PKT_TOSERVER) && !(pflow->flags & FLOW_SGH_TOSERVER)) { - /* first time we see this toserver sgh, store it */ - pflow->sgh_toserver = det_ctx->sgh; - pflow->flags |= FLOW_SGH_TOSERVER; - - /* see if this sgh requires us to consider file storing */ - if (pflow->sgh_toserver == NULL || pflow->sgh_toserver->filestore_cnt == 0) { - FileDisableStoring(pflow, STREAM_TOSERVER); - } - - /* see if this sgh requires us to consider file magic */ - if (!FileForceMagic() && (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) - { - SCLogDebug("disabling magic for flow"); - FileDisableMagic(pflow, STREAM_TOSERVER); - } + /* if we had no alerts that involved the smsgs, + * we can get rid of them now. */ + StreamMsgReturnListToPool(det_ctx->smsg); + det_ctx->smsg = NULL; + } + PACKET_PROFILING_DETECT_END(p, PROF_DETECT_CLEANUP); - /* see if this sgh requires us to consider file md5 */ - if (!FileForceMd5() && (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) - { - SCLogDebug("disabling md5 for flow"); - FileDisableMd5(pflow, STREAM_TOSERVER); - } + SCReturnInt((int)(alerts > 0)); +} - /* see if this sgh requires us to consider filesize */ - if (pflow->sgh_toserver == NULL || - !(pflow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) - { - SCLogDebug("disabling filesize for flow"); - FileDisableFilesize(pflow, STREAM_TOSERVER); - } - } else if ((p->flowflags & FLOW_PKT_TOCLIENT) && !(pflow->flags & FLOW_SGH_TOCLIENT)) { - pflow->sgh_toclient = det_ctx->sgh; - pflow->flags |= FLOW_SGH_TOCLIENT; +/** \brief Apply action(s) and Set 'drop' sig info, + * if applicable */ +void DetectSignatureApplyActions(Packet *p, const Signature *s) +{ + PACKET_UPDATE_ACTION(p, s->action); - if (pflow->sgh_toclient == NULL || pflow->sgh_toclient->filestore_cnt == 0) { - FileDisableStoring(pflow, STREAM_TOCLIENT); - } + if (s->action & ACTION_DROP) { + if (p->alerts.drop.action == 0) { + p->alerts.drop.num = s->num; + p->alerts.drop.action = s->action; + p->alerts.drop.s = (Signature *)s; + } + } +} - /* check if this flow needs magic, if not disable it */ - if (!FileForceMagic() && (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))) - { - SCLogDebug("disabling magic for flow"); - FileDisableMagic(pflow, STREAM_TOCLIENT); - } +/* tm module api functions */ - /* check if this flow needs md5, if not disable it */ - if (!FileForceMd5() && (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMD5))) - { - SCLogDebug("disabling md5 for flow"); - FileDisableMd5(pflow, STREAM_TOCLIENT); - } +static DetectEngineThreadCtx *GetTenantById(HashTable *h, uint32_t id) +{ + /* technically we need to pass a DetectEngineThreadCtx struct with the + * tentant_id member. But as that member is the first in the struct, we + * can use the id directly. */ + return HashTableLookup(h, &id, 0); +} - /* see if this sgh requires us to consider filesize */ - if (pflow->sgh_toclient == NULL || - !(pflow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILESIZE)) - { - SCLogDebug("disabling filesize for flow"); - FileDisableFilesize(pflow, STREAM_TOCLIENT); - } +static void DetectFlow(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Packet *p) +{ + /* No need to perform any detection on this packet, if the the given flag is set.*/ + if ((p->flags & PKT_NOPACKET_INSPECTION) || + (PACKET_TEST_ACTION(p, ACTION_DROP))) + { + /* hack: if we are in pass the entire flow mode, we need to still + * update the inspect_id forward. So test for the condition here, + * and call the update code if necessary. */ + int pass = ((p->flow->flags & FLOW_NOPACKET_INSPECTION)); + uint8_t flags = FlowGetDisruptionFlags(p->flow, 0); + AppProto alproto = FlowGetAppProtocol(p->flow); + if (pass && AppLayerParserProtocolSupportsTxs(p->proto, alproto)) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flags |= STREAM_TOSERVER; + } else { + flags |= STREAM_TOCLIENT; } + DeStateUpdateInspectTransactionId(p->flow, flags); } + return; + } + + /* see if the packet matches one or more of the sigs */ + (void)SigMatchSignatures(tv,de_ctx,det_ctx,p); +} - /* if we had no alerts that involved the smsgs, - * we can get rid of them now. */ - StreamMsgReturnListToPool(smsg); - FLOWLOCK_UNLOCK(pflow); +static void DetectNoFlow(ThreadVars *tv, + DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Packet *p) +{ + /* No need to perform any detection on this packet, if the the given flag is set.*/ + if ((p->flags & PKT_NOPACKET_INSPECTION) || + (PACKET_TEST_ACTION(p, ACTION_DROP))) + { + return; } - PACKET_PROFILING_DETECT_END(p, PROF_DETECT_CLEANUP); - SCReturnInt((int)(alerts > 0)); + /* see if the packet matches one or more of the sigs */ + (void)SigMatchSignatures(tv,de_ctx,det_ctx,p); + return; } -/* tm module api functions */ - /** \brief Detection engine thread wrapper. * \param tv thread vars * \param p packet to inspect @@ -1710,49 +1620,57 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue { DEBUG_VALIDATE_PACKET(p); - /* No need to perform any detection on this packet, if the the given flag is set.*/ - if ((p->flags & PKT_NOPACKET_INSPECTION) || (PACKET_TEST_ACTION(p, - ACTION_DROP))) - return 0; - + DetectEngineCtx *de_ctx = NULL; DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data; if (det_ctx == NULL) { printf("ERROR: Detect has no thread ctx\n"); goto error; } - DetectEngineCtx *de_ctx = det_ctx->de_ctx; - if (de_ctx == NULL) { - printf("ERROR: Detect has no detection engine ctx\n"); - goto error; - } - - if (SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0) { + if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) { (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); - SCLogDebug("Detect Engine using new det_ctx - %p and de_ctx - %p", - det_ctx, de_ctx); + SCLogDebug("Detect Engine using new det_ctx - %p", + det_ctx); } - /* see if the packet matches one or more of the sigs */ - int r = SigMatchSignatures(tv,de_ctx,det_ctx,p); - if (r >= 0) { - return TM_ECODE_OK; + /* if in MT mode _and_ we have tenants registered, use + * MT logic. */ + if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL) + { + uint32_t tenant_id = p->tenant_id; + if (tenant_id == 0) + tenant_id = det_ctx->TenantGetId(det_ctx, p); + if (tenant_id > 0 && tenant_id < det_ctx->mt_det_ctxs_cnt) { + p->tenant_id = tenant_id; + det_ctx = GetTenantById(det_ctx->mt_det_ctxs_hash, tenant_id); + if (det_ctx == NULL) + return TM_ECODE_OK; + de_ctx = det_ctx->de_ctx; + if (de_ctx == NULL) + return TM_ECODE_OK; + + if (unlikely(SC_ATOMIC_GET(det_ctx->so_far_used_by_detect) == 0)) { + (void)SC_ATOMIC_SET(det_ctx->so_far_used_by_detect, 1); + SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id); + } + } else { + /* use default if no tenants are registered for this packet */ + de_ctx = det_ctx->de_ctx; + } + } else { + de_ctx = det_ctx->de_ctx; } + if (p->flow) { + DetectFlow(tv, de_ctx, det_ctx, p); + } else { + DetectNoFlow(tv, de_ctx, det_ctx, p); + } + return TM_ECODE_OK; error: return TM_ECODE_FAILED; } -TmEcode DetectThreadInit(ThreadVars *t, void *initdata, void **data) -{ - return DetectEngineThreadCtxInit(t,initdata,data); -} - -TmEcode DetectThreadDeinit(ThreadVars *t, void *data) -{ - return DetectEngineThreadCtxDeinit(t,data); -} - void SigCleanSignatures(DetectEngineCtx *de_ctx) { Signature *s = NULL, *ns; @@ -1796,7 +1714,7 @@ Signature *SigFindSignatureBySidGid(DetectEngineCtx *de_ctx, uint32_t sid, uint3 } -int SignatureIsAppLayer(DetectEngineCtx *de_ctx, Signature *s) +int SignatureIsAppLayer(DetectEngineCtx *de_ctx, const Signature *s) { if (s->alproto != 0) return 1; @@ -1812,7 +1730,7 @@ int SignatureIsAppLayer(DetectEngineCtx *de_ctx, Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFilestoring(Signature *s) +int SignatureIsFilestoring(const Signature *s) { if (s == NULL) return 0; @@ -1831,7 +1749,7 @@ int SignatureIsFilestoring(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFilemagicInspecting(Signature *s) +int SignatureIsFilemagicInspecting(const Signature *s) { if (s == NULL) return 0; @@ -1850,12 +1768,41 @@ int SignatureIsFilemagicInspecting(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFileMd5Inspecting(Signature *s) +int SignatureIsFileMd5Inspecting(const Signature *s) { - if (s == NULL) - return 0; + if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_MD5)) + return 1; + + return 0; +} + +/** + * \brief Check if a signature contains the filesha1 keyword. + * + * \param s signature + * + * \retval 0 no + * \retval 1 yes + */ +int SignatureIsFileSha1Inspecting(const Signature *s) +{ + if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA1)) + return 1; + + return 0; +} - if (s->file_flags & FILE_SIG_NEED_MD5) +/** + * \brief Check if a signature contains the filesha256 keyword. + * + * \param s signature + * + * \retval 0 no + * \retval 1 yes + */ +int SignatureIsFileSha256Inspecting(const Signature *s) +{ + if ((s != NULL) && (s->file_flags & FILE_SIG_NEED_SHA256)) return 1; return 0; @@ -1869,7 +1816,7 @@ int SignatureIsFileMd5Inspecting(Signature *s) * \retval 0 no * \retval 1 yes */ -int SignatureIsFilesizeInspecting(Signature *s) +int SignatureIsFilesizeInspecting(const Signature *s) { if (s == NULL) return 0; @@ -1886,55 +1833,24 @@ int SignatureIsFilesizeInspecting(Signature *s) * \retval 1 sig is ip only * \retval 0 sig is not ip only */ -int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) +int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s) { if (s->alproto != ALPROTO_UNKNOWN) return 0; - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) return 0; - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) - return 0; - - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) - return 0; + /* for now assume that all registered buffer types are incompatible */ + const int nlists = DetectBufferTypeMaxId(); + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) - return 0; + SCReturnInt(0); + } /* TMATCH list can be ignored, it contains TAGs and * tags are compatible to IP-only. */ @@ -1955,7 +1871,7 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) cidr_item = cidr_item->next; } - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; if (sm == NULL) goto iponly; @@ -1979,6 +1895,72 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) return 1; } +/** \internal + * \brief Test is a initialized signature is inspecting protocol detection only + * \param de_ctx detection engine ctx + * \param s the signature + * \retval 1 sig is dp only + * \retval 0 sig is not dp only + */ +static int SignatureIsPDOnly(const Signature *s) +{ + if (s->alproto != ALPROTO_UNKNOWN) + return 0; + + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) + return 0; + + /* for now assume that all registered buffer types are incompatible */ + const int nlists = DetectBufferTypeMaxId(); + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; + + SCReturnInt(0); + } + + /* TMATCH list can be ignored, it contains TAGs and + * tags are compatible to DP-only. */ + + /* match list matches may be compatible to DP only. We follow the same + * logic as IP-only so we can use that flag */ + + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; + if (sm == NULL) + return 0; + + int pd = 0; + for ( ; sm != NULL; sm = sm->next) { + if (sm->type == DETECT_AL_APP_LAYER_PROTOCOL) { + pd = 1; + } else { + /* flowbits are supported for dp only sigs, as long + * as the sig only has a "set" flowbits */ + if (sm->type == DETECT_FLOWBITS) { + if ((((DetectFlowbitsData *)sm->ctx)->cmd != DETECT_FLOWBITS_CMD_SET) ) { + SCLogDebug("%u: not PD-only: flowbit settings other than 'set'", s->id); + return 0; + } + } else if (sm->type == DETECT_FLOW) { + if (((DetectFlowData *)sm->ctx)->flags & ~(DETECT_FLOW_FLAG_TOSERVER|DETECT_FLOW_FLAG_TOCLIENT)) { + SCLogDebug("%u: not PD-only: flow settings other than toserver/toclient", s->id); + return 0; + } + } else if ( !(sigmatch_table[sm->type].flags & SIGMATCH_IPONLY_COMPAT)) { + SCLogDebug("%u: not PD-only: %s not PD/IP-only compat", s->id, sigmatch_table[sm->type].name); + return 0; + } + } + } + + if (pd) { + SCLogDebug("PD-ONLY (%" PRIu32 ")", s->id); + } + return pd; +} + /** * \internal * \brief Check if the initialized signature is inspecting the packet payload @@ -1987,25 +1969,12 @@ int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) * \retval 1 sig is inspecting the payload * \retval 0 sig is not inspecting the payload */ -static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, Signature *s) +static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, const Signature *s) { - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { return 1; } -#if 0 - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; - if (sm == NULL) - return 0; - - for (; sm != NULL; sm = sm->next) { - if (sigmatch_table[sm->type].flags & SIGMATCH_PAYLOAD) { - if (!(de_ctx->flags & DE_QUIET)) - SCLogDebug("Signature (%" PRIu32 "): is inspecting payload.", s->id); - return 1; - } - } -#endif return 0; } @@ -2017,40 +1986,37 @@ static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, Signature *s) * \retval 0 not a DEOnly sig * \retval 1 DEOnly sig */ -static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) +static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, const Signature *s) { if (s->alproto != ALPROTO_UNKNOWN) { SCReturnInt(0); } - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL || - s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { SCReturnInt(0); } + /* for now assume that all registered buffer types are incompatible */ + const int nlists = DetectBufferTypeMaxId(); + for (int i = 0; i < nlists; i++) { + if (s->init_data->smlists[i] == NULL) + continue; + if (!(DetectBufferTypeGetNameById(i))) + continue; + + SCReturnInt(0); + } + /* check for conflicting keywords */ - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { if ( !(sigmatch_table[sm->type].flags & SIGMATCH_DEONLY_COMPAT)) SCReturnInt(0); } /* need at least one decode event keyword to be considered decode event. */ - sm = s->sm_lists[DETECT_SM_LIST_MATCH]; + sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; for ( ;sm != NULL; sm = sm->next) { if (sm->type == DETECT_DECODE_EVENT) goto deonly; @@ -2123,6 +2089,38 @@ PacketCreateMask(Packet *p, SignatureMask *mask, AppProto alproto, int has_state SCLogDebug("packet/flow has dce state"); (*mask) |= SIG_MASK_REQUIRE_DCE_STATE; break; + case ALPROTO_SSH: + SCLogDebug("packet/flow has ssh state"); + (*mask) |= SIG_MASK_REQUIRE_SSH_STATE; + break; + case ALPROTO_TLS: + SCLogDebug("packet/flow has tls state"); + (*mask) |= SIG_MASK_REQUIRE_TLS_STATE; + break; + case ALPROTO_DNS: + SCLogDebug("packet/flow has dns state"); + (*mask) |= SIG_MASK_REQUIRE_DNS_STATE; + break; + case ALPROTO_FTP: + SCLogDebug("packet/flow has ftp state"); + (*mask) |= SIG_MASK_REQUIRE_FTP_STATE; + break; + case ALPROTO_SMTP: + SCLogDebug("packet/flow has smtp state"); + (*mask) |= SIG_MASK_REQUIRE_SMTP_STATE; + break; + case ALPROTO_ENIP: + SCLogDebug("packet/flow has enip state"); + (*mask) |= SIG_MASK_REQUIRE_ENIP_STATE; + break; + case ALPROTO_DNP3: + SCLogDebug("packet/flow has dnp3 state"); + (*mask) |= SIG_MASK_REQUIRE_DNP3_STATE; + break; + case ALPROTO_TEMPLATE: + SCLogDebug("packet/flow has template state"); + (*mask) |= SIG_MASK_REQUIRE_TEMPLATE_STATE; + break; default: SCLogDebug("packet/flow has other state"); break; @@ -2137,108 +2135,25 @@ static int SignatureCreateMask(Signature *s) { SCEnter(); - if (s->sm_lists[DETECT_SM_LIST_PMATCH] != NULL) { + if (s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) { s->mask |= SIG_MASK_REQUIRE_PAYLOAD; SCLogDebug("sig requires payload"); } - if (s->sm_lists[DETECT_SM_LIST_DMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_DCE_STATE; - SCLogDebug("sig requires dce state"); - } + SigMatch *sm; + for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch(sm->type) { + case DETECT_FLOWBITS: + { + /* figure out what flowbit action */ + DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx; + if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { + /* not a mask flag, but still set it here */ + s->flags |= SIG_FLAG_REQUIRE_FLOWVAR; - if (s->sm_lists[DETECT_SM_LIST_UMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HCBDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HSBDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HRHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HMDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HCDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HRUDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HSMDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HSCDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HUADMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HHHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) { - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires http app state"); - } - - SigMatch *sm; - for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH] ; sm != NULL; sm = sm->next) { - switch(sm->type) { - case DETECT_AL_URILEN: - case DETECT_AL_HTTP_URI: - s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; - SCLogDebug("sig requires dce http state"); - break; - case DETECT_AL_APP_LAYER_EVENT: - s->mask |= SIG_MASK_REQUIRE_ENGINE_EVENT; - break; - } - } - - for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { - switch(sm->type) { - case DETECT_FLOWBITS: - { - /* figure out what flowbit action */ - DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx; - if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) { - /* not a mask flag, but still set it here */ - s->flags |= SIG_FLAG_REQUIRE_FLOWVAR; - - SCLogDebug("SIG_FLAG_REQUIRE_FLOWVAR set as sig has " - "flowbit isset option."); - } + SCLogDebug("SIG_FLAG_REQUIRE_FLOWVAR set as sig has " + "flowbit isset option."); + } /* flow is required for any flowbit manipulation */ s->mask |= SIG_MASK_REQUIRE_FLOW; @@ -2311,19 +2226,55 @@ static int SignatureCreateMask(Signature *s) } } - if ((s->mask & SIG_MASK_REQUIRE_DCE_STATE) || - (s->mask & SIG_MASK_REQUIRE_HTTP_STATE)) - { - s->mask |= SIG_MASK_REQUIRE_FLOW; - SCLogDebug("sig requires flow"); + if (s->alproto == ALPROTO_SSH) { + s->mask |= SIG_MASK_REQUIRE_SSH_STATE; + SCLogDebug("sig requires ssh state"); + } + if (s->alproto == ALPROTO_TLS) { + s->mask |= SIG_MASK_REQUIRE_TLS_STATE; + SCLogDebug("sig requires tls state"); + } + if (s->alproto == ALPROTO_DNS) { + s->mask |= SIG_MASK_REQUIRE_DNS_STATE; + SCLogDebug("sig requires dns state"); + } + if (s->alproto == ALPROTO_DNP3) { + s->mask |= SIG_MASK_REQUIRE_DNP3_STATE; + SCLogDebug("sig requires dnp3 state"); + } + if (s->alproto == ALPROTO_FTP) { + s->mask |= SIG_MASK_REQUIRE_FTP_STATE; + SCLogDebug("sig requires ftp state"); + } + if (s->alproto == ALPROTO_SMTP) { + s->mask |= SIG_MASK_REQUIRE_SMTP_STATE; + SCLogDebug("sig requires smtp state"); + } + if (s->alproto == ALPROTO_ENIP) { + s->mask |= SIG_MASK_REQUIRE_ENIP_STATE; + SCLogDebug("sig requires enip state"); + } + if (s->alproto == ALPROTO_TEMPLATE) { + s->mask |= SIG_MASK_REQUIRE_TEMPLATE_STATE; + SCLogDebug("sig requires template state"); } - if (s->init_flags & SIG_FLAG_INIT_FLOW) { + if ((s->mask & SIG_MASK_REQUIRE_DCE_STATE) || + (s->mask & SIG_MASK_REQUIRE_HTTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_SSH_STATE) || + (s->mask & SIG_MASK_REQUIRE_DNS_STATE) || + (s->mask & SIG_MASK_REQUIRE_DNP3_STATE) || + (s->mask & SIG_MASK_REQUIRE_FTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_SMTP_STATE) || + (s->mask & SIG_MASK_REQUIRE_ENIP_STATE) || + (s->mask & SIG_MASK_REQUIRE_TEMPLATE_STATE) || + (s->mask & SIG_MASK_REQUIRE_TLS_STATE)) + { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } - if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) { + if (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) { s->mask |= SIG_MASK_REQUIRE_FLOW; SCLogDebug("sig requires flow"); } @@ -2337,61 +2288,19 @@ static int SignatureCreateMask(Signature *s) SCReturnInt(0); } +/** \brief disable file features we don't need + * Called if we have no detection engine. + */ +void DisableDetectFlowFileFlags(Flow *f) +{ + DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOSERVER); + DetectPostInspectFileFlagsUpdate(f, NULL /* no sgh */, STREAM_TOCLIENT); +} + static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) { - de_ctx->sgh_mpm_context_proto_tcp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_tcp", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_proto_udp_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_udp", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_proto_other_packet = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "packet_proto_other", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_uri = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "uri", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_stream = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "stream", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hcbd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hcbd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hsbd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hsbd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hrhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hmd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hmd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hcd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hcd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hrud = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrud", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hsmd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hsmd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hscd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hscd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_huad = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "huad", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hhhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hhhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_hrhhd = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "hrhhd", - MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD); - de_ctx->sgh_mpm_context_app_proto_detect = - MpmFactoryRegisterMpmCtxProfile(de_ctx, "app_proto_detect", 0); + DetectMpmInitializeBuiltinMpms(de_ctx); + DetectMpmInitializeAppMpms(de_ctx); return; } @@ -2402,8 +2311,8 @@ static void SigInitStandardMpmFactoryContexts(DetectEngineCtx *de_ctx) */ static int SigParseGetMaxDsize(Signature *s) { - if (s->flags & SIG_FLAG_DSIZE && s->dsize_sm != NULL) { - DetectDsizeData *dd = (DetectDsizeData *)s->dsize_sm->ctx; + if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) { + DetectDsizeData *dd = (DetectDsizeData *)s->init_data->dsize_sm->ctx; switch (dd->mode) { case DETECTDSIZE_LT: @@ -2424,8 +2333,8 @@ static int SigParseGetMaxDsize(Signature *s) */ static void SigParseSetDsizePair(Signature *s) { - if (s->flags & SIG_FLAG_DSIZE && s->dsize_sm != NULL) { - DetectDsizeData *dd = (DetectDsizeData *)s->dsize_sm->ctx; + if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) { + DetectDsizeData *dd = (DetectDsizeData *)s->init_data->dsize_sm->ctx; uint16_t low = 0; uint16_t high = 65535; @@ -2472,7 +2381,7 @@ static void SigParseApplyDsizeToContent(Signature *s) return; } - SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; + SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; for ( ; sm != NULL; sm = sm->next) { if (sm->type != DETECT_CONTENT) { continue; @@ -2492,567 +2401,1021 @@ static void SigParseApplyDsizeToContent(Signature *s) } } -/** - * \brief Preprocess signature, classify ip-only, etc, build sig array - * - * \param de_ctx Pointer to the Detection Engine Context - * - * \retval 0 on success - * \retval -1 on failure - */ -int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) +/** \brief Pure-PCRE or bytetest rule */ +int RuleInspectsPayloadHasNoMpm(const Signature *s) { - Signature *tmp_s = NULL; - uint32_t cnt_iponly = 0; - uint32_t cnt_payload = 0; - uint32_t cnt_applayer = 0; - uint32_t cnt_deonly = 0; + if (s->init_data->mpm_sm == NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL) + return 1; + return 0; +} - //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); - //DetectPortPrintMemory(); +int RuleGetMpmPatternSize(const Signature *s) +{ + if (s->init_data->mpm_sm == NULL) + return -1; + int mpm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); + if (mpm_list < 0) + return -1; + const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx; + if (cd == NULL) + return -1; + return (int)cd->content_len; +} - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("building signature grouping structure, stage 1: " - "preprocessing rules..."); - } +int RuleMpmIsNegated(const Signature *s) +{ + if (s->init_data->mpm_sm == NULL) + return 0; + int mpm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); + if (mpm_list < 0) + return 0; + const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx; + if (cd == NULL) + return 0; + return (cd->flags & DETECT_CONTENT_NEGATED); +} + +#ifdef HAVE_LIBJANSSON +json_t *RulesGroupPrintSghStats(const SigGroupHead *sgh, + const int add_rules, const int add_mpm_stats) +{ + uint32_t mpm_cnt = 0; + uint32_t nonmpm_cnt = 0; + uint32_t negmpm_cnt = 0; + uint32_t any5_cnt = 0; + uint32_t payload_no_mpm_cnt = 0; + uint32_t syn_cnt = 0; + + uint32_t mpms_total = 0; + uint32_t mpms_min = 0; + uint32_t mpms_max = 0; + + struct { + uint32_t total; + uint32_t cnt; + uint32_t min; + uint32_t max; + } mpm_stats[DETECT_SM_LIST_MAX]; + memset(mpm_stats, 0x00, sizeof(mpm_stats)); + + uint32_t alstats[ALPROTO_MAX] = {0}; + uint32_t mpm_sizes[DETECT_SM_LIST_MAX][256]; + memset(mpm_sizes, 0, sizeof(mpm_sizes)); + uint32_t alproto_mpm_bufs[ALPROTO_MAX][DETECT_SM_LIST_MAX]; + memset(alproto_mpm_bufs, 0, sizeof(alproto_mpm_bufs)); + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return NULL; -#ifdef HAVE_LUAJIT - /* run this before the mpm states are initialized */ - if (DetectLuajitSetupStatesPool(de_ctx->detect_luajit_instances, - IsRuleReloadSet(TRUE)) - != 0) { - if (de_ctx->failure_fatal) - return -1; - } -#endif + json_object_set_new(js, "id", json_integer(sgh->id)); - de_ctx->sig_array_len = DetectEngineGetMaxSigId(de_ctx); - de_ctx->sig_array_size = (de_ctx->sig_array_len * sizeof(Signature *)); - de_ctx->sig_array = (Signature **)SCMalloc(de_ctx->sig_array_size); - if (de_ctx->sig_array == NULL) - goto error; - memset(de_ctx->sig_array,0,de_ctx->sig_array_size); + json_t *js_array = json_array(); - SCLogDebug("signature lookup array: %" PRIu32 " sigs, %" PRIu32 " bytes", - de_ctx->sig_array_len, de_ctx->sig_array_size); + const Signature *s; + uint32_t x; + for (x = 0; x < sgh->sig_cnt; x++) { + s = sgh->match_array[x]; + if (s == NULL) + continue; - /* now for every rule add the source group */ - for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { - de_ctx->sig_array[tmp_s->num] = tmp_s; + int any = 0; + if (s->proto.flags & DETECT_PROTO_ANY) { + any++; + } + if (s->flags & SIG_FLAG_DST_ANY) { + any++; + } + if (s->flags & SIG_FLAG_SRC_ANY) { + any++; + } + if (s->flags & SIG_FLAG_DP_ANY) { + any++; + } + if (s->flags & SIG_FLAG_SP_ANY) { + any++; + } + if (any == 5) { + any5_cnt++; + } - SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", tmp_s->id, tmp_s->num, tmp_s, de_ctx->sig_array[tmp_s->num]); + if (s->init_data->mpm_sm == NULL) { + nonmpm_cnt++; - /* see if the sig is ip only */ - if (SignatureIsIPOnly(de_ctx, tmp_s) == 1) { - tmp_s->flags |= SIG_FLAG_IPONLY; - cnt_iponly++; + if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) { + SCLogDebug("SGH %p Non-MPM inspecting only packets. Rule %u", sgh, s->id); + } - SCLogDebug("Signature %"PRIu32" is considered \"IP only\"", tmp_s->id); + DetectPort *sp = s->sp; + DetectPort *dp = s->dp; - /* see if any sig is inspecting the packet payload */ - } else if (SignatureIsInspectingPayload(de_ctx, tmp_s) == 1) { - tmp_s->init_flags |= SIG_FLAG_INIT_PAYLOAD; - cnt_payload++; + if (s->flags & SIG_FLAG_TOSERVER && (dp->port == 0 && dp->port2 == 65535)) { + SCLogDebug("SGH %p Non-MPM toserver and to 'any'. Rule %u", sgh, s->id); + } + if (s->flags & SIG_FLAG_TOCLIENT && (sp->port == 0 && sp->port2 == 65535)) { + SCLogDebug("SGH %p Non-MPM toclient and to 'any'. Rule %u", sgh, s->id); + } - SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", tmp_s->id); - } else if (SignatureIsDEOnly(de_ctx, tmp_s) == 1) { - tmp_s->init_flags |= SIG_FLAG_INIT_DEONLY; - SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", tmp_s->id); - cnt_deonly++; - } + if (DetectFlagsSignatureNeedsSynPackets(s)) { + syn_cnt++; + } - if (tmp_s->flags & SIG_FLAG_APPLAYER) { - SCLogDebug("Signature %"PRIu32" is considered \"Applayer inspecting\"", tmp_s->id); - cnt_applayer++; - } + } else { + int mpm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm); + BUG_ON(mpm_list < 0); + const DetectContentData *cd = (const DetectContentData *)s->init_data->mpm_sm->ctx; + uint32_t size = cd->content_len < 256 ? cd->content_len : 255; + + mpm_sizes[mpm_list][size]++; + if (s->alproto != ALPROTO_UNKNOWN) { + alproto_mpm_bufs[s->alproto][mpm_list]++; + } -#ifdef DEBUG - if (SCLogDebugEnabled()) { - uint16_t colen = 0; - char copresent = 0; - SigMatch *sm; - DetectContentData *co; - for (sm = tmp_s->sm_lists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; + if (mpm_list == DETECT_SM_LIST_PMATCH) { + if (size == 1) { + DetectPort *sp = s->sp; + DetectPort *dp = s->dp; + if (s->flags & SIG_FLAG_TOSERVER) { + if (dp->port == 0 && dp->port2 == 65535) { + SCLogDebug("SGH %p toserver 1byte fast_pattern to ANY. Rule %u", sgh, s->id); + } else { + SCLogDebug("SGH %p toserver 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, dp->port, dp->port2, s->id); + } + } + if (s->flags & SIG_FLAG_TOCLIENT) { + if (sp->port == 0 && sp->port2 == 65535) { + SCLogDebug("SGH %p toclient 1byte fast_pattern to ANY. Rule %u", sgh, s->id); + } else { + SCLogDebug("SGH %p toclient 1byte fast_pattern to port(s) %u-%u. Rule %u", sgh, sp->port, sp->port2, s->id); + } + } + } + } - copresent = 1; - co = (DetectContentData *)sm->ctx; - if (co->content_len > colen) - colen = co->content_len; + uint32_t w = PatternStrength(cd->content, cd->content_len); + mpms_total += w; + if (mpms_min == 0) + mpms_min = w; + if (w < mpms_min) + mpms_min = w; + if (w > mpms_max) + mpms_max = w; + + mpm_stats[mpm_list].total += w; + mpm_stats[mpm_list].cnt++; + if (mpm_stats[mpm_list].min == 0 || w < mpm_stats[mpm_list].min) + mpm_stats[mpm_list].min = w; + if (w > mpm_stats[mpm_list].max) + mpm_stats[mpm_list].max = w; + + mpm_cnt++; + + if (w < 10) { + SCLogDebug("SGH %p Weak MPM Pattern on %s. Rule %u", sgh, DetectListToString(mpm_list), s->id); + } + if (w < 10 && any == 5) { + SCLogDebug("SGH %p Weak MPM Pattern on %s, rule is 5xAny. Rule %u", sgh, DetectListToString(mpm_list), s->id); } - if (copresent && colen == 1) { - SCLogDebug("signature %8u content maxlen 1", tmp_s->id); - int proto; - for (proto = 0; proto < 256; proto++) { - if (tmp_s->proto.proto[(proto/8)] & (1<<(proto%8))) - SCLogDebug("=> proto %" PRId32 "", proto); - } + if (cd->flags & DETECT_CONTENT_NEGATED) { + SCLogDebug("SGH %p MPM Pattern on %s, is negated. Rule %u", sgh, DetectListToString(mpm_list), s->id); + negmpm_cnt++; } } -#endif /* DEBUG */ - SignatureCreateMask(tmp_s); - SigParseApplyDsizeToContent(tmp_s); + if (RuleInspectsPayloadHasNoMpm(s)) { + SCLogDebug("SGH %p No MPM. Payload inspecting. Rule %u", sgh, s->id); + payload_no_mpm_cnt++; + } - de_ctx->sig_cnt++; + if (s->alproto != ALPROTO_UNKNOWN) { + alstats[s->alproto]++; + } + + if (add_rules) { + json_t *js_sig = json_object(); + if (unlikely(js == NULL)) + continue; + json_object_set_new(js_sig, "sig_id", json_integer(s->id)); + json_array_append_new(js_array, js_sig); + } } - //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); - //DetectPortPrintMemory(); + json_object_set_new(js, "rules", js_array); - if (!(de_ctx->flags & DE_QUIET)) { - SCLogInfo("%" PRIu32 " signatures processed. %" PRIu32 " are IP-only " - "rules, %" PRIu32 " are inspecting packet payload, %"PRIu32 - " inspect application layer, %"PRIu32" are decoder event only", - de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer, - cnt_deonly); + json_t *stats = json_object(); + json_object_set_new(stats, "total", json_integer(sgh->sig_cnt)); - SCLogInfo("building signature grouping structure, stage 1: " - "preprocessing rules... complete"); - } - return 0; + json_t *types = json_object(); + json_object_set_new(types, "mpm", json_integer(mpm_cnt)); + json_object_set_new(types, "non_mpm", json_integer(nonmpm_cnt)); + json_object_set_new(types, "negated_mpm", json_integer(negmpm_cnt)); + json_object_set_new(types, "payload_but_no_mpm", json_integer(payload_no_mpm_cnt)); + json_object_set_new(types, "syn", json_integer(syn_cnt)); + json_object_set_new(types, "any5", json_integer(any5_cnt)); + json_object_set_new(stats, "types", types); -error: - return -1; -} + int i; + for (i = 0; i < ALPROTO_MAX; i++) { + if (alstats[i] > 0) { + json_t *app = json_object(); + json_object_set_new(app, "total", json_integer(alstats[i])); -static int DetectEngineLookupBuildSourceAddressList(DetectEngineCtx *de_ctx, DetectEngineLookupFlow *flow_gh, Signature *s, int family) -{ - DetectAddress *gr = NULL, *lookup_gr = NULL, *head = NULL; - int proto; + for (x = 0; x < DETECT_SM_LIST_MAX; x++) { + if (alproto_mpm_bufs[i][x] == 0) + continue; + json_object_set_new(app, DetectListToHumanString(x), json_integer(alproto_mpm_bufs[i][x])); + } - if (family == AF_INET) { - head = s->src.ipv4_head; - } else if (family == AF_INET6) { - head = s->src.ipv6_head; - } else { - head = s->src.any_head; + json_object_set_new(stats, AppProtoToString(i), app); + } } - /* for each source address group in the signature... */ - for (gr = head; gr != NULL; gr = gr->next) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); + if (add_mpm_stats) { + json_t *mpm_js = json_object(); - /* ...and each protocol the signature matches on... */ - for (proto = 0; proto < 256; proto++) { - if ((s->proto.proto[(proto/8)] & (1<<(proto%8))) || (s->proto.flags & DETECT_PROTO_ANY)) { - /* ...see if the group is in the tmp list, and if not add it. */ - if (family == AF_INET) { - lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->ipv4_head,gr); - } else if (family == AF_INET6) { - lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->ipv6_head,gr); - } else { - lookup_gr = DetectAddressLookupInList(flow_gh->tmp_gh[proto]->any_head,gr); - } + for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + if (mpm_stats[i].cnt > 0) { - if (lookup_gr == NULL) { - DetectAddress *grtmp = DetectAddressCopy(gr); - if (grtmp == NULL) { - goto error; - } - SigGroupHeadAppendSig(de_ctx, &grtmp->sh, s); + json_t *mpm_sizes_array = json_array(); + for (x = 0; x < 256; x++) { + if (mpm_sizes[i][x] == 0) + continue; - /* add to the lookup list */ - if (family == AF_INET) { - DetectAddressAdd(&flow_gh->tmp_gh[proto]->ipv4_head, grtmp); - } else if (family == AF_INET6) { - DetectAddressAdd(&flow_gh->tmp_gh[proto]->ipv6_head, grtmp); - } else { - DetectAddressAdd(&flow_gh->tmp_gh[proto]->any_head, grtmp); - } - } else { - /* our group will only have one sig, this one. So add that. */ - SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, s); - lookup_gr->cnt++; + json_t *e = json_object(); + json_object_set_new(e, "size", json_integer(x)); + json_object_set_new(e, "count", json_integer(mpm_sizes[i][x])); + json_array_append_new(mpm_sizes_array, e); } + + json_t *buf = json_object(); + json_object_set_new(buf, "total", json_integer(mpm_stats[i].cnt)); + json_object_set_new(buf, "avg_strength", json_integer(mpm_stats[i].total / mpm_stats[i].cnt)); + json_object_set_new(buf, "min_strength", json_integer(mpm_stats[i].min)); + json_object_set_new(buf, "max_strength", json_integer(mpm_stats[i].max)); + + json_object_set_new(buf, "sizes", mpm_sizes_array); + + json_object_set_new(mpm_js, DetectListToHumanString(i), buf); } } + + json_object_set_new(stats, "mpm", mpm_js); } + json_object_set_new(js, "stats", stats); - return 0; -error: - return -1; + json_object_set_new(js, "whitelist", json_integer(sgh->init->whitelist)); + + return js; } +#endif /* HAVE_LIBJANSSON */ -/** - * \brief add signature to the right flow group(s) - */ -static int DetectEngineLookupFlowAddSig(DetectEngineCtx *de_ctx, Signature *s, int family) +void RulesDumpGrouping(const DetectEngineCtx *de_ctx, + const int add_rules, const int add_mpm_stats) { - SCLogDebug("s->id %u", s->id); +#ifdef HAVE_LIBJANSSON + json_t *js = json_object(); + if (unlikely(js == NULL)) + return; - if (s->flags & SIG_FLAG_TOCLIENT) { - SCLogDebug("s->id %u (toclient)", s->id); - DetectEngineLookupBuildSourceAddressList(de_ctx, - &de_ctx->flow_gh[0], s, family); - } + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) { + const char *name = (p == IPPROTO_TCP) ? "tcp" : "udp"; - if (s->flags & SIG_FLAG_TOSERVER) { - SCLogDebug("s->id %u (toserver)", s->id); - DetectEngineLookupBuildSourceAddressList(de_ctx, - &de_ctx->flow_gh[1], s, family); - } + json_t *tcp = json_object(); - return 0; -} + json_t *ts_array = json_array(); + DetectPort *list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[1].tcp : + de_ctx->flow_gh[1].udp; + while (list != NULL) { + json_t *port = json_object(); + json_object_set_new(port, "port", json_integer(list->port)); + json_object_set_new(port, "port2", json_integer(list->port2)); -static DetectAddress *GetHeadPtr(DetectAddressHead *head, int family) -{ - DetectAddress *grhead; + json_t *tcp_ts = RulesGroupPrintSghStats(list->sh, + add_rules, add_mpm_stats); + json_object_set_new(port, "rulegroup", tcp_ts); + json_array_append_new(ts_array, port); - if (head == NULL) - return NULL; + list = list->next; + } + json_object_set_new(tcp, "toserver", ts_array); + + json_t *tc_array = json_array(); + list = (p == IPPROTO_TCP) ? de_ctx->flow_gh[0].tcp : + de_ctx->flow_gh[0].udp; + while (list != NULL) { + json_t *port = json_object(); + json_object_set_new(port, "port", json_integer(list->port)); + json_object_set_new(port, "port2", json_integer(list->port2)); + + json_t *tcp_tc = RulesGroupPrintSghStats(list->sh, + add_rules, add_mpm_stats); + json_object_set_new(port, "rulegroup", tcp_tc); + json_array_append_new(tc_array, port); + + list = list->next; + } + json_object_set_new(tcp, "toclient", tc_array); + + json_object_set_new(js, name, tcp); + } - if (family == AF_INET) { - grhead = head->ipv4_head; - } else if (family == AF_INET6) { - grhead = head->ipv6_head; - } else { - grhead = head->any_head; } - return grhead; -} + const char *filename = "rule_group.json"; + const char *log_dir = ConfigGetLogDirectory(); + char log_path[PATH_MAX] = ""; -//#define SMALL_MPM(c) 0 -#define SMALL_MPM(c) ((c) == 1) -// || (c) == 2) -// || (c) == 3) + snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename); -int CreateGroupedAddrListCmpCnt(DetectAddress *a, DetectAddress *b) -{ - if (a->cnt > b->cnt) - return 1; - return 0; -} + FILE *fp = fopen(log_path, "w"); + if (fp == NULL) { + return; + } -int CreateGroupedAddrListCmpMpmMaxlen(DetectAddress *a, DetectAddress *b) -{ - if (a->sh == NULL || b->sh == NULL) - return 0; + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_ESCAPE_SLASH); + if (unlikely(js_s == NULL)) { + fclose(fp); + return; + } - if (SMALL_MPM(a->sh->mpm_content_maxlen)) - return 1; + json_object_clear(js); + json_decref(js); - if (a->sh->mpm_content_maxlen < b->sh->mpm_content_maxlen) - return 1; - return 0; + fprintf(fp, "%s\n", js_s); + free(js_s); + fclose(fp); +#endif + return; } -/* set unique_groups to 0 for no grouping. - * - * srchead is a ordered "inserted" list w/o internal overlap - * - */ -int CreateGroupedAddrList(DetectEngineCtx *de_ctx, DetectAddress *srchead, - int family, DetectAddressHead *newhead, - uint32_t unique_groups, - int (*CompareFunc)(DetectAddress *, DetectAddress *), - uint32_t max_idx) +int RulesGroupByProto(DetectEngineCtx *de_ctx) { - DetectAddress *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; - char insert = 0; - DetectAddress *gr, *next_gr; - uint32_t groups = 0; - - /* insert the addresses into the tmplist, where it will - * be sorted descending on 'cnt'. */ - for (gr = srchead; gr != NULL; gr = gr->next) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); + Signature *s = de_ctx->sig_list; - if (SMALL_MPM(gr->sh->mpm_content_maxlen) && unique_groups > 0) - unique_groups++; + uint32_t max_idx = 0; + SigGroupHead *sgh_ts[256] = {NULL}; + SigGroupHead *sgh_tc[256] = {NULL}; - groups++; + for ( ; s != NULL; s = s->next) { + if (s->flags & SIG_FLAG_IPONLY) + continue; - /* alloc a copy */ - DetectAddress *newtmp = DetectAddressCopy(gr); - if (newtmp == NULL) { - goto error; - } - SigGroupHeadCopySigs(de_ctx, gr->sh,&newtmp->sh); + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) { + continue; + } + if (!(s->proto.proto[p / 8] & (1<<(p % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) { + continue; + } - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx,&newtmp->port, port); - newtmp->flags |= ADDRESS_HAVEPORT; + if (s->flags & SIG_FLAG_TOCLIENT) { + SigGroupHeadAppendSig(de_ctx, &sgh_tc[p], s); + max_idx = s->num; + } + if (s->flags & SIG_FLAG_TOSERVER) { + SigGroupHeadAppendSig(de_ctx, &sgh_ts[p], s); + max_idx = s->num; + } } + } + SCLogDebug("max_idx %u", max_idx); - /* insert it */ - DetectAddress *tmpgr = tmplist, *prevtmpgr = NULL; - if (tmplist == NULL) { - /* empty list, set head */ - tmplist = newtmp; + /* lets look at deduplicating this list */ + SigGroupHeadHashFree(de_ctx); + SigGroupHeadHashInit(de_ctx); + + uint32_t cnt = 0; + uint32_t own = 0; + uint32_t ref = 0; + int p; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + if (sgh_ts[p] == NULL) + continue; + + cnt++; + + SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, sgh_ts[p]); + if (lookup_sgh == NULL) { + SCLogDebug("proto group %d sgh %p is the original", p, sgh_ts[p]); + + SigGroupHeadSetSigCnt(sgh_ts[p], max_idx); + SigGroupHeadBuildMatchArray(de_ctx, sgh_ts[p], max_idx); + + SigGroupHeadHashAdd(de_ctx, sgh_ts[p]); + SigGroupHeadStore(de_ctx, sgh_ts[p]); + + de_ctx->gh_unique++; + own++; } else { - /* look for the place to insert */ - for ( ; tmpgr != NULL&&!insert; tmpgr = tmpgr->next) { - if (CompareFunc(gr, tmpgr)) { - if (tmpgr == tmplist) { - newtmp->next = tmplist; - tmplist = newtmp; - } else { - newtmp->next = prevtmpgr->next; - prevtmpgr->next = newtmp; - } - insert = 1; - } - prevtmpgr = tmpgr; - } - if (insert == 0) { - newtmp->next = NULL; - prevtmpgr->next = newtmp; - } - insert = 0; + SCLogDebug("proto group %d sgh %p is a copy", p, sgh_ts[p]); + + SigGroupHeadFree(sgh_ts[p]); + sgh_ts[p] = lookup_sgh; + + de_ctx->gh_reuse++; + ref++; } } + SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", + "toserver", cnt, own, ref); - uint32_t i = unique_groups; - if (i == 0) i = groups; + cnt = 0; + own = 0; + ref = 0; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + if (sgh_tc[p] == NULL) + continue; - for (gr = tmplist; gr != NULL; ) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); + cnt++; - if (i == 0) { - if (joingr == NULL) { - joingr = DetectAddressCopy(gr); - if (joingr == NULL) { - goto error; - } + SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, sgh_tc[p]); + if (lookup_sgh == NULL) { + SCLogDebug("proto group %d sgh %p is the original", p, sgh_tc[p]); - SigGroupHeadCopySigs(de_ctx,gr->sh,&joingr->sh); + SigGroupHeadSetSigCnt(sgh_tc[p], max_idx); + SigGroupHeadBuildMatchArray(de_ctx, sgh_tc[p], max_idx); + + SigGroupHeadHashAdd(de_ctx, sgh_tc[p]); + SigGroupHeadStore(de_ctx, sgh_tc[p]); + + de_ctx->gh_unique++; + own++; - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx,&joingr->port, port); - joingr->flags |= ADDRESS_HAVEPORT; - } - } else { - DetectAddressJoin(de_ctx, joingr, gr); - } } else { - DetectAddress *newtmp = DetectAddressCopy(gr); - if (newtmp == NULL) { - goto error; - } + SCLogDebug("proto group %d sgh %p is a copy", p, sgh_tc[p]); - SigGroupHeadCopySigs(de_ctx,gr->sh,&newtmp->sh); + SigGroupHeadFree(sgh_tc[p]); + sgh_tc[p] = lookup_sgh; - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx,&newtmp->port, port); - newtmp->flags |= ADDRESS_HAVEPORT; - } + de_ctx->gh_reuse++; + ref++; + } + } + SCLogPerf("OTHER %s: %u proto groups, %u unique SGH's, %u copies", + "toclient", cnt, own, ref); - if (tmplist2 == NULL) { - tmplist2 = newtmp; + for (p = 0; p < 256; p++) { + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + continue; + + de_ctx->flow_gh[0].sgh[p] = sgh_tc[p]; + de_ctx->flow_gh[1].sgh[p] = sgh_ts[p]; + } + + return 0; +} + +static int PortIsWhitelisted(const DetectEngineCtx *de_ctx, + const DetectPort *a, int ipproto) +{ + DetectPort *w = de_ctx->tcp_whitelist; + if (ipproto == IPPROTO_UDP) + w = de_ctx->udp_whitelist; + + while (w) { + if (a->port >= w->port && a->port2 <= w->port) { + SCLogDebug("port group %u:%u whitelisted -> %d", a->port, a->port2, w->port); + return 1; + } + w = w->next; + } + + return 0; +} + +static int RuleSetWhitelist(Signature *s) +{ + DetectPort *p = NULL; + if (s->flags & SIG_FLAG_TOSERVER) + p = s->dp; + else if (s->flags & SIG_FLAG_TOCLIENT) + p = s->sp; + else + return 0; + + /* for sigs that don't use 'any' as port, see if we want to + * whitelist poor sigs */ + int wl = 0; + if (!(p->port == 0 && p->port2 == 65535)) { + /* pure pcre, bytetest, etc rules */ + if (RuleInspectsPayloadHasNoMpm(s)) { + SCLogDebug("Rule %u MPM has 1 byte fast_pattern. Whitelisting SGH's.", s->id); + wl = 99; + + } else if (RuleMpmIsNegated(s)) { + SCLogDebug("Rule %u MPM is negated. Whitelisting SGH's.", s->id); + wl = 77; + + /* one byte pattern in packet/stream payloads */ + } else if (s->init_data->mpm_sm != NULL && + SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == DETECT_SM_LIST_PMATCH && + RuleGetMpmPatternSize(s) == 1) + { + SCLogDebug("Rule %u No MPM. Payload inspecting. Whitelisting SGH's.", s->id); + wl = 55; + + } else if (DetectFlagsSignatureNeedsSynPackets(s) && + DetectFlagsSignatureNeedsSynOnlyPackets(s)) + { + SCLogDebug("Rule %u Needs SYN, so inspected often. Whitelisting SGH's.", s->id); + wl = 33; + } + } + + s->init_data->whitelist = wl; + return wl; +} + +int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx); +int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b); + +static DetectPort *RulesGroupByPorts(DetectEngineCtx *de_ctx, int ipproto, uint32_t direction) { + /* step 1: create a hash of 'DetectPort' objects based on all the + * rules. Each object will have a SGH with the sigs added + * that belong to the SGH. */ + DetectPortHashInit(de_ctx); + + uint32_t max_idx = 0; + const Signature *s = de_ctx->sig_list; + DetectPort *list = NULL; + while (s) { + /* IP Only rules are handled separately */ + if (s->flags & SIG_FLAG_IPONLY) + goto next; + if (!(s->proto.proto[ipproto / 8] & (1<<(ipproto % 8)) || (s->proto.flags & DETECT_PROTO_ANY))) + goto next; + if (direction == SIG_FLAG_TOSERVER) { + if (!(s->flags & SIG_FLAG_TOSERVER)) + goto next; + } else if (direction == SIG_FLAG_TOCLIENT) { + if (!(s->flags & SIG_FLAG_TOCLIENT)) + goto next; + } + + DetectPort *p = NULL; + if (direction == SIG_FLAG_TOSERVER) + p = s->dp; + else if (direction == SIG_FLAG_TOCLIENT) + p = s->sp; + else + BUG_ON(1); + + /* see if we want to exclude directionless sigs that really care only for + * to_server syn scans/floods */ + if ((direction == SIG_FLAG_TOCLIENT) && + DetectFlagsSignatureNeedsSynPackets(s) && + DetectFlagsSignatureNeedsSynOnlyPackets(s) && + ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) && + (!(s->dp->port == 0 && s->dp->port2 == 65535))) + { + SCLogWarning(SC_WARN_POOR_RULE, "rule %u: SYN-only to port(s) %u:%u " + "w/o direction specified, disabling for toclient direction", + s->id, s->dp->port, s->dp->port2); + goto next; + } + + int wl = s->init_data->whitelist; + while (p) { + int pwl = PortIsWhitelisted(de_ctx, p, ipproto) ? 111 : 0; + pwl = MAX(wl,pwl); + + DetectPort *lookup = DetectPortHashLookup(de_ctx, p); + if (lookup) { + SigGroupHeadAppendSig(de_ctx, &lookup->sh, s); + lookup->sh->init->whitelist = MAX(lookup->sh->init->whitelist, pwl); } else { - newtmp->next = tmplist2; - tmplist2 = newtmp; + DetectPort *tmp2 = DetectPortCopySingle(de_ctx, p); + BUG_ON(tmp2 == NULL); + SigGroupHeadAppendSig(de_ctx, &tmp2->sh, s); + tmp2->sh->init->whitelist = pwl; + DetectPortHashAdd(de_ctx, tmp2); } + + p = p->next; } - if (i)i--; + max_idx = s->num; + next: + s = s->next; + } - next_gr = gr->next; - DetectAddressFree(gr); - gr = next_gr; + /* step 2: create a list of DetectPort objects */ + HashListTableBucket *htb = NULL; + for (htb = HashListTableGetListHead(de_ctx->dport_hash_table); + htb != NULL; + htb = HashListTableGetListNext(htb)) + { + DetectPort *p = HashListTableGetListData(htb); + DetectPort *tmp = DetectPortCopySingle(de_ctx, p); + BUG_ON(tmp == NULL); + int r = DetectPortInsert(de_ctx, &list , tmp); + BUG_ON(r == -1); } + DetectPortHashFree(de_ctx); + de_ctx->dport_hash_table = NULL; - /* we now have a tmplist2 containing the 'unique' groups and - * possibly a joingr that covers the rest. Now build the newhead - * that we will pass back to the caller. - * - * Start with inserting the unique groups */ - for (gr = tmplist2; gr != NULL; ) { - BUG_ON(gr->ip.family == 0 && !(gr->flags & ADDRESS_FLAG_ANY)); + SCLogDebug("rules analyzed"); - DetectAddress *newtmp = DetectAddressCopy(gr); - if (newtmp == NULL) { - goto error; - } - SigGroupHeadCopySigs(de_ctx, gr->sh,&newtmp->sh); + /* step 3: group the list and shrink it if necessary */ + DetectPort *newlist = NULL; + uint16_t groupmax = (direction == SIG_FLAG_TOCLIENT) ? de_ctx->max_uniq_toclient_groups : + de_ctx->max_uniq_toserver_groups; + CreateGroupedPortList(de_ctx, list, &newlist, groupmax, CreateGroupedPortListCmpCnt, max_idx); + list = newlist; + + /* step 4: deduplicate the SGH's */ + SigGroupHeadHashFree(de_ctx); + SigGroupHeadHashInit(de_ctx); + + uint32_t cnt = 0; + uint32_t own = 0; + uint32_t ref = 0; + DetectPort *iter; + for (iter = list ; iter != NULL; iter = iter->next) { + BUG_ON (iter->sh == NULL); + cnt++; + + SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, iter->sh); + if (lookup_sgh == NULL) { + SCLogDebug("port group %p sgh %p is the original", iter, iter->sh); + + SigGroupHeadSetSigCnt(iter->sh, max_idx); + SigGroupHeadBuildMatchArray(de_ctx, iter->sh, max_idx); + SigGroupHeadSetProtoAndDirection(iter->sh, ipproto, direction); + SigGroupHeadHashAdd(de_ctx, iter->sh); + SigGroupHeadStore(de_ctx, iter->sh); + iter->flags |= PORT_SIGGROUPHEAD_COPY; + de_ctx->gh_unique++; + own++; + } else { + SCLogDebug("port group %p sgh %p is a copy", iter, iter->sh); - DetectPort *port = gr->port; - for ( ; port != NULL; port = port->next) { - DetectPortInsertCopy(de_ctx, &newtmp->port, port); - newtmp->flags |= ADDRESS_HAVEPORT; + SigGroupHeadFree(iter->sh); + iter->sh = lookup_sgh; + iter->flags |= PORT_SIGGROUPHEAD_COPY; + + de_ctx->gh_reuse++; + ref++; } + } +#if 0 + for (iter = list ; iter != NULL; iter = iter->next) { + SCLogInfo("PORT %u-%u %p (sgh=%s, whitelisted=%s/%d)", + iter->port, iter->port2, iter->sh, + iter->flags & PORT_SIGGROUPHEAD_COPY ? "ref" : "own", + iter->sh->init->whitelist ? "true" : "false", + iter->sh->init->whitelist); + } +#endif + SCLogPerf("%s %s: %u port groups, %u unique SGH's, %u copies", + ipproto == 6 ? "TCP" : "UDP", + direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient", + cnt, own, ref); + return list; +} - DetectAddressInsert(de_ctx, newhead, newtmp); +/** + * \brief Preprocess signature, classify ip-only, etc, build sig array + * + * \param de_ctx Pointer to the Detection Engine Context + * + * \retval 0 on success + * \retval -1 on failure + */ +int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) +{ + Signature *tmp_s = NULL; + uint32_t cnt_iponly = 0; + uint32_t cnt_payload = 0; + uint32_t cnt_applayer = 0; + uint32_t cnt_deonly = 0; + const int nlists = DetectBufferTypeMaxId(); - next_gr = gr->next; - DetectAddressFree(gr); - gr = next_gr; + if (!(de_ctx->flags & DE_QUIET)) { + SCLogDebug("building signature grouping structure, stage 1: " + "preprocessing rules..."); } - /* if present, insert the joingr that covers the rest */ - if (joingr != NULL) { - DetectAddressInsert(de_ctx, newhead, joingr); + de_ctx->sig_array_len = DetectEngineGetMaxSigId(de_ctx); + de_ctx->sig_array_size = (de_ctx->sig_array_len * sizeof(Signature *)); + de_ctx->sig_array = (Signature **)SCMalloc(de_ctx->sig_array_size); + if (de_ctx->sig_array == NULL) + goto error; + memset(de_ctx->sig_array,0,de_ctx->sig_array_size); + + SCLogDebug("signature lookup array: %" PRIu32 " sigs, %" PRIu32 " bytes", + de_ctx->sig_array_len, de_ctx->sig_array_size); + + /* now for every rule add the source group */ + for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { + de_ctx->sig_array[tmp_s->num] = tmp_s; + + SCLogDebug("Signature %" PRIu32 ", internal id %" PRIu32 ", ptrs %p %p ", tmp_s->id, tmp_s->num, tmp_s, de_ctx->sig_array[tmp_s->num]); + + /* see if the sig is dp only */ + if (SignatureIsPDOnly(tmp_s) == 1) { + tmp_s->flags |= SIG_FLAG_PDONLY; + SCLogDebug("Signature %"PRIu32" is considered \"PD only\"", tmp_s->id); + + /* see if the sig is ip only */ + } else if (SignatureIsIPOnly(de_ctx, tmp_s) == 1) { + tmp_s->flags |= SIG_FLAG_IPONLY; + cnt_iponly++; + + SCLogDebug("Signature %"PRIu32" is considered \"IP only\"", tmp_s->id); + + /* see if any sig is inspecting the packet payload */ + } else if (SignatureIsInspectingPayload(de_ctx, tmp_s) == 1) { + cnt_payload++; + + SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", tmp_s->id); + } else if (SignatureIsDEOnly(de_ctx, tmp_s) == 1) { + tmp_s->init_data->init_flags |= SIG_FLAG_INIT_DEONLY; + SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", tmp_s->id); + cnt_deonly++; + } + + if (tmp_s->flags & SIG_FLAG_APPLAYER) { + SCLogDebug("Signature %"PRIu32" is considered \"Applayer inspecting\"", tmp_s->id); + cnt_applayer++; + } + +#ifdef DEBUG + if (SCLogDebugEnabled()) { + uint16_t colen = 0; + char copresent = 0; + SigMatch *sm; + DetectContentData *co; + for (sm = tmp_s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + copresent = 1; + co = (DetectContentData *)sm->ctx; + if (co->content_len > colen) + colen = co->content_len; + } + + if (copresent && colen == 1) { + SCLogDebug("signature %8u content maxlen 1", tmp_s->id); + int proto; + for (proto = 0; proto < 256; proto++) { + if (tmp_s->proto.proto[(proto/8)] & (1<<(proto%8))) + SCLogDebug("=> proto %" PRId32 "", proto); + } + } + } +#endif /* DEBUG */ + + if (RuleMpmIsNegated(tmp_s)) { + tmp_s->flags |= SIG_FLAG_MPM_NEG; + } + + SignatureCreateMask(tmp_s); + SigParseApplyDsizeToContent(tmp_s); + + RuleSetWhitelist(tmp_s); + + /* if keyword engines are enabled in the config, handle them here */ + if (de_ctx->prefilter_setting == DETECT_PREFILTER_AUTO && + !(tmp_s->flags & SIG_FLAG_PREFILTER)) + { + int i; + int prefilter_list = DETECT_TBLSIZE; + + /* get the keyword supporting prefilter with the lowest type */ + for (i = 0; i < nlists; i++) { + SigMatch *sm = tmp_s->init_data->smlists[i]; + while (sm != NULL) { + if (sigmatch_table[sm->type].SupportsPrefilter != NULL) { + if (sigmatch_table[sm->type].SupportsPrefilter(tmp_s) == TRUE) { + prefilter_list = MIN(prefilter_list, sm->type); + } + } + sm = sm->next; + } + } + + /* apply that keyword as prefilter */ + if (prefilter_list != DETECT_TBLSIZE) { + for (i = 0; i < nlists; i++) { + SigMatch *sm = tmp_s->init_data->smlists[i]; + while (sm != NULL) { + if (sm->type == prefilter_list) { + tmp_s->init_data->prefilter_sm = sm; + tmp_s->flags |= SIG_FLAG_PREFILTER; + SCLogConfig("sid %u: prefilter is on \"%s\"", tmp_s->id, sigmatch_table[sm->type].name); + break; + } + sm = sm->next; + } + } + } + } + + /* run buffer type callbacks if any */ + int x; + for (x = 0; x < nlists; x++) { + if (tmp_s->init_data->smlists[x]) + DetectBufferRunSetupCallback(x, tmp_s); + } + + de_ctx->sig_cnt++; } + if (!(de_ctx->flags & DE_QUIET)) { + SCLogInfo("%" PRIu32 " signatures processed. %" PRIu32 " are IP-only " + "rules, %" PRIu32 " are inspecting packet payload, %"PRIu32 + " inspect application layer, %"PRIu32" are decoder event only", + de_ctx->sig_cnt, cnt_iponly, cnt_payload, cnt_applayer, + cnt_deonly); + + SCLogConfig("building signature grouping structure, stage 1: " + "preprocessing rules... complete"); + } return 0; + error: return -1; } -int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) +static int PortGroupWhitelist(const DetectPort *a) { - if (a->cnt > b->cnt) - return 1; - return 0; + return a->sh->init->whitelist; } -int CreateGroupedPortListCmpMpmMaxlen(DetectPort *a, DetectPort *b) +int CreateGroupedPortListCmpCnt(DetectPort *a, DetectPort *b) { - if (a->sh == NULL || b->sh == NULL) - return 0; - - if (SMALL_MPM(a->sh->mpm_content_maxlen)) + if (PortGroupWhitelist(a) && !PortGroupWhitelist(b)) { + SCLogDebug("%u:%u (cnt %u, wl %d) wins against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 1; - - if (a->sh->mpm_content_maxlen < b->sh->mpm_content_maxlen) + } else if (!PortGroupWhitelist(a) && PortGroupWhitelist(b)) { + SCLogDebug("%u:%u (cnt %u, wl %d) loses against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); + return 0; + } else if (PortGroupWhitelist(a) > PortGroupWhitelist(b)) { + SCLogDebug("%u:%u (cnt %u, wl %d) wins against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 1; + } else if (PortGroupWhitelist(a) == PortGroupWhitelist(b)) { + if (a->sh->sig_cnt > b->sh->sig_cnt) { + SCLogDebug("%u:%u (cnt %u, wl %d) wins against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); + return 1; + } + } + SCLogDebug("%u:%u (cnt %u, wl %d) loses against %u:%u (cnt %u, wl %d)", + a->port, a->port2, a->sh->sig_cnt, PortGroupWhitelist(a), + b->port, b->port2, b->sh->sig_cnt, PortGroupWhitelist(b)); return 0; } -static uint32_t g_groupportlist_maxgroups = 0; -static uint32_t g_groupportlist_groupscnt = 0; -static uint32_t g_groupportlist_totgroups = 0; - -int CreateGroupedPortList(DetectEngineCtx *de_ctx,HashListTable *port_hash, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) +/** \internal + * \brief Create a list of DetectPort objects sorted based on CompareFunc's + * logic. + * + * List can limit the number of groups. In this case an extra "join" group + * is created that contains the sigs belonging to that. It's *appended* to + * the list, meaning that if the list is walked linearly it's found last. + * The joingr is meant to be a catch all. + * + */ +int CreateGroupedPortList(DetectEngineCtx *de_ctx, DetectPort *port_list, DetectPort **newhead, uint32_t unique_groups, int (*CompareFunc)(DetectPort *, DetectPort *), uint32_t max_idx) { - DetectPort *tmplist = NULL, *tmplist2 = NULL, *joingr = NULL; + DetectPort *tmplist = NULL, *joingr = NULL; char insert = 0; - DetectPort *gr, *next_gr; uint32_t groups = 0; + DetectPort *list; - HashListTableBucket *htb = HashListTableGetListHead(port_hash); - - /* insert the addresses into the tmplist, where it will - * be sorted descending on 'cnt'. */ - for ( ; htb != NULL; htb = HashListTableGetListNext(htb)) { - gr = (DetectPort *)HashListTableGetListData(htb); - - SCLogDebug("hash list gr %p", gr); - DetectPortPrint(gr); + /* insert the addresses into the tmplist, where it will + * be sorted descending on 'cnt' and on wehther a group + * is whitelisted. */ - if (SMALL_MPM(gr->sh->mpm_content_maxlen) && unique_groups > 0) - unique_groups++; + DetectPort *oldhead = port_list; + while (oldhead) { + /* take the top of the list */ + list = oldhead; + oldhead = oldhead->next; + list->next = NULL; groups++; - /* alloc a copy */ - DetectPort *newtmp = DetectPortCopySingle(de_ctx, gr); - if (newtmp == NULL) { - goto error; - } + SigGroupHeadSetSigCnt(list->sh, max_idx); /* insert it */ DetectPort *tmpgr = tmplist, *prevtmpgr = NULL; if (tmplist == NULL) { /* empty list, set head */ - tmplist = newtmp; + tmplist = list; } else { /* look for the place to insert */ - for ( ; tmpgr != NULL&&!insert; tmpgr = tmpgr->next) { - if (CompareFunc(gr, tmpgr)) { + for ( ; tmpgr != NULL && !insert; tmpgr = tmpgr->next) { + if (CompareFunc(list, tmpgr) == 1) { if (tmpgr == tmplist) { - newtmp->next = tmplist; - tmplist = newtmp; + list->next = tmplist; + tmplist = list; + SCLogDebug("new list top: %u:%u", tmplist->port, tmplist->port2); } else { - newtmp->next = prevtmpgr->next; - prevtmpgr->next = newtmp; + list->next = prevtmpgr->next; + prevtmpgr->next = list; } insert = 1; + break; } prevtmpgr = tmpgr; } if (insert == 0) { - newtmp->next = NULL; - prevtmpgr->next = newtmp; + list->next = NULL; + prevtmpgr->next = list; } insert = 0; } } - uint32_t i = unique_groups; - if (i == 0) i = groups; - - if (unique_groups > g_groupportlist_maxgroups) - g_groupportlist_maxgroups = unique_groups; - g_groupportlist_groupscnt++; - g_groupportlist_totgroups += unique_groups; + uint32_t left = unique_groups; + if (left == 0) + left = groups; + /* create another list: take the port groups from above + * and add them to the 2nd list until we have met our + * count. The rest is added to the 'join' group. */ + DetectPort *tmplist2 = NULL, *tmplist2_tail = NULL; + DetectPort *gr, *next_gr; for (gr = tmplist; gr != NULL; ) { - SCLogDebug("temp list gr %p", gr); + next_gr = gr->next; + + SCLogDebug("temp list gr %p %u:%u", gr, gr->port, gr->port2); DetectPortPrint(gr); - if (i == 0) { + /* if we've set up all the unique groups, add the rest to the + * catch-all joingr */ + if (left == 0) { if (joingr == NULL) { - joingr = DetectPortCopySingle(de_ctx,gr); + DetectPortParse(de_ctx, &joingr, "0:65535"); if (joingr == NULL) { goto error; } - } else { - DetectPortJoin(de_ctx,joingr, gr); + SCLogDebug("joingr => %u-%u", joingr->port, joingr->port2); + joingr->next = NULL; } + SigGroupHeadCopySigs(de_ctx,gr->sh,&joingr->sh); + + /* when a group's sigs are added to the joingr, we can free it */ + gr->next = NULL; + DetectPortFree(gr); + gr = NULL; + + /* append */ } else { - DetectPort *newtmp = DetectPortCopySingle(de_ctx,gr); - if (newtmp == NULL) { - goto error; - } + gr->next = NULL; if (tmplist2 == NULL) { - tmplist2 = newtmp; + tmplist2 = gr; + tmplist2_tail = gr; } else { - newtmp->next = tmplist2; - tmplist2 = newtmp; + tmplist2_tail->next = gr; + tmplist2_tail = gr; } } - if (i)i--; - next_gr = gr->next; - gr->next = NULL; - DetectPortFree(gr); + if (left > 0) + left--; + gr = next_gr; } - /* we now have a tmplist2 containing the 'unique' groups and - * possibly a joingr that covers the rest. Now build the newhead - * that we will pass back to the caller. - * - * Start with inserting the unique groups */ - for (gr = tmplist2; gr != NULL; ) { - SCLogDebug("temp list2 gr %p", gr); - DetectPortPrint(gr); + /* if present, append the joingr that covers the rest */ + if (joingr != NULL) { + SCLogDebug("appending joingr %p %u:%u", joingr, joingr->port, joingr->port2); - DetectPort *newtmp = DetectPortCopySingle(de_ctx,gr); - if (newtmp == NULL) { - goto error; + if (tmplist2 == NULL) { + tmplist2 = joingr; + //tmplist2_tail = joingr; + } else { + tmplist2_tail->next = joingr; + //tmplist2_tail = joingr; } + } else { + SCLogDebug("no joingr"); + } - int r = DetectPortInsert(de_ctx,newhead,newtmp); - BUG_ON(r == -1); - - next_gr = gr->next; - gr->next = NULL; - DetectPortFree(gr); - gr = next_gr; - } - - DetectPortPrintList(*newhead); - - /* if present, insert the joingr that covers the rest */ - if (joingr != NULL) { - SCLogDebug("inserting joingr %p", joingr); - DetectPortInsert(de_ctx,newhead,joingr); - } else { - SCLogDebug("no joingr"); - } + /* pass back our new list to the caller */ + *newhead = tmplist2; + DetectPortPrintList(*newhead); return 0; error: @@ -3090,1649 +3453,538 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) IPOnlyInit(de_ctx, &de_ctx->io_ctx); - int f, proto; - for (f = 0; f < FLOW_STATES; f++) { - for (proto = 0; proto < 256; proto++) { - de_ctx->flow_gh[f].src_gh[proto] = DetectAddressHeadInit(); - if (de_ctx->flow_gh[f].src_gh[proto] == NULL) { - goto error; - } - de_ctx->flow_gh[f].tmp_gh[proto] = DetectAddressHeadInit(); - if (de_ctx->flow_gh[f].tmp_gh[proto] == NULL) { - goto error; - } - } - } + de_ctx->flow_gh[1].tcp = RulesGroupByPorts(de_ctx, IPPROTO_TCP, SIG_FLAG_TOSERVER); + de_ctx->flow_gh[0].tcp = RulesGroupByPorts(de_ctx, IPPROTO_TCP, SIG_FLAG_TOCLIENT); + de_ctx->flow_gh[1].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOSERVER); + de_ctx->flow_gh[0].udp = RulesGroupByPorts(de_ctx, IPPROTO_UDP, SIG_FLAG_TOCLIENT); + + /* Setup the other IP Protocols (so not TCP/UDP) */ + RulesGroupByProto(de_ctx); /* now for every rule add the source group to our temp lists */ for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { SCLogDebug("tmp_s->id %"PRIu32, tmp_s->id); if (tmp_s->flags & SIG_FLAG_IPONLY) { IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); - } else { - DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET); - DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET6); - DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_UNSPEC); } - if (tmp_s->init_flags & SIG_FLAG_INIT_DEONLY) { + if (tmp_s->init_data->init_flags & SIG_FLAG_INIT_DEONLY) { DetectEngineAddDecoderEventSig(de_ctx, tmp_s); } sigs++; } - /* create the final src addr list based on the tmplist. */ - for (f = 0; f < FLOW_STATES; f++) { - for (proto = 0; proto < 256; proto++) { - int groups = (f ? de_ctx->max_uniq_toserver_src_groups : de_ctx->max_uniq_toclient_src_groups); - - CreateGroupedAddrList(de_ctx, - de_ctx->flow_gh[f].tmp_gh[proto]->ipv4_head, AF_INET, - de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); - - CreateGroupedAddrList(de_ctx, - de_ctx->flow_gh[f].tmp_gh[proto]->ipv6_head, AF_INET6, - de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); - CreateGroupedAddrList(de_ctx, - de_ctx->flow_gh[f].tmp_gh[proto]->any_head, AF_UNSPEC, - de_ctx->flow_gh[f].src_gh[proto], groups, - CreateGroupedAddrListCmpMpmMaxlen, DetectEngineGetMaxSigId(de_ctx)); - - DetectAddressHeadFree(de_ctx->flow_gh[f].tmp_gh[proto]); - de_ctx->flow_gh[f].tmp_gh[proto] = NULL; - } - } - //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); - - //printf("g_src_gh strt\n"); - //DetectAddressPrintList(g_src_gh->ipv4_head); - //printf("g_src_gh end\n"); - IPOnlyPrepare(de_ctx); IPOnlyPrint(de_ctx, &de_ctx->io_ctx); -#ifdef DEBUG - DetectAddress *gr = NULL; - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("%" PRIu32 " total signatures:", sigs); - } - /* TCP */ - uint32_t cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_TCP]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } - } + return 0; +} + +static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx) +{ + if (de_ctx->decoder_event_sgh == NULL) + return; + + uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); + SigGroupHeadSetSigCnt(de_ctx->decoder_event_sgh, max_idx); + SigGroupHeadBuildMatchArray(de_ctx, de_ctx->decoder_event_sgh, max_idx); +} + +int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) +{ + /* prepare the decoder event sgh */ + DetectEngineBuildDecoderEventSgh(de_ctx); + return 0; +} + +int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) +{ + BUG_ON(de_ctx == NULL); + if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("TCP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); + SCLogDebug("cleaning up signature grouping structure..."); } + if (de_ctx->decoder_event_sgh) + SigGroupHeadFree(de_ctx->decoder_event_sgh); + de_ctx->decoder_event_sgh = NULL; - cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - /* UDP */ - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } + int f; for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; + int p; + for (p = 0; p < 256; p++) { + de_ctx->flow_gh[f].sgh[p] = NULL; } + + /* free lookup lists */ + DetectPortCleanupList(de_ctx->flow_gh[f].tcp); + de_ctx->flow_gh[f].tcp = NULL; + DetectPortCleanupList(de_ctx->flow_gh[f].udp); + de_ctx->flow_gh[f].udp = NULL; } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_UDP]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } + + uint32_t idx; + for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { + SigGroupHead *sgh = de_ctx->sgh_array[idx]; + if (sgh == NULL) + continue; + + SCLogDebug("sgh %p", sgh); + SigGroupHeadFree(sgh); } + SCFree(de_ctx->sgh_array); + de_ctx->sgh_array = NULL; + de_ctx->sgh_array_cnt = 0; + de_ctx->sgh_array_size = 0; + + IPOnlyDeinit(de_ctx, &de_ctx->io_ctx); + if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("UDP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); + SCLogInfo("cleaning up signature grouping structure... complete"); } + return 0; +} - cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - /* SCTP */ - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } - } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; - } - } - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("SCTP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); +void DbgPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + if (sgh == NULL) { + printf("\n"); + return; } - /* ICMP */ - cnt_any = 0, cnt_ipv4 = 0, cnt_ipv6 = 0; - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[1]->any_head; gr != NULL; gr = gr->next) { - cnt_any++; - } + uint32_t sig; + for (sig = 0; sig < sgh->sig_cnt; sig++) { + printf("%" PRIu32 " ", sgh->match_array[sig]->id); } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[1]->ipv4_head; gr != NULL; gr = gr->next) { - cnt_ipv4++; - } + printf("\n"); +} + +void DbgPrintSigs2(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + if (sgh == NULL || sgh->init == NULL) { + printf("\n"); + return; } - for (f = 0; f < FLOW_STATES; f++) { - for (gr = de_ctx->flow_gh[f].src_gh[1]->ipv6_head; gr != NULL; gr = gr->next) { - cnt_ipv6++; + + uint32_t sig; + for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) { + if (sgh->init->sig_array[(sig/8)] & (1<<(sig%8))) { + printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id); } } - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("ICMP Source address blocks: any: %4u, ipv4: %4u, ipv6: %4u.", cnt_any, cnt_ipv4, cnt_ipv6); - } -#endif /* DEBUG */ - if (!(de_ctx->flags & DE_QUIET)) { - SCLogInfo("building signature grouping structure, stage 2: building source address list... complete"); - } - - return 0; -error: - printf("SigAddressPrepareStage2 error\n"); - return -1; + printf("\n"); } -/** - * \brief Build the destination address portion of the match tree - */ -int BuildDestinationAddressHeads(DetectEngineCtx *de_ctx, DetectAddressHead *head, int family, int flow) +void DbgSghContainsSig(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid) { - Signature *tmp_s = NULL; - DetectAddress *gr = NULL, *sgr = NULL, *lookup_gr = NULL; - uint32_t max_idx = 0; - - DetectAddress *grhead = NULL, *grdsthead = NULL, *grsighead = NULL; + if (sgh == NULL || sgh->init == NULL) { + printf("\n"); + return; + } - /* based on the family, select the list we are using in the head */ - grhead = GetHeadPtr(head, family); + uint32_t sig; + for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) { + if (!(sgh->init->sig_array[(sig/8)] & (1<<(sig%8)))) + continue; - /* loop through the global source address list */ - for (gr = grhead; gr != NULL; gr = gr->next) { - //printf(" * Source group (BuildDestinationAddressHeads): "); DetectAddressPrint(gr); printf(" (%p)\n", gr); + Signature *s = de_ctx->sig_array[sig]; + if (s == NULL) + continue; - /* initialize the destination group head */ - gr->dst_gh = DetectAddressHeadInit(); - if (gr->dst_gh == NULL) { - goto error; + if (sid == s->id) { + printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id); } + } + printf("\n"); +} - /* use a tmp list for speeding up insertions */ - DetectAddress *tmp_gr_list = NULL; - - /* loop through all signatures in this source address group - * and build the temporary destination address list for it */ - uint32_t sig; - for (sig = 0; sig < de_ctx->sig_array_len; sig++) { - if (!(gr->sh->init->sig_array[(sig/8)] & (1<<(sig%8)))) - continue; +/** \brief finalize preparing sgh's */ +int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) +{ + SCEnter(); - tmp_s = de_ctx->sig_array[sig]; - if (tmp_s == NULL) - continue; + //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); - //printf(" * (tmp) Signature %u (num %u)\n", tmp_s->id, tmp_s->num); + uint32_t cnt = 0; + uint32_t idx = 0; + for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { + SigGroupHead *sgh = de_ctx->sgh_array[idx]; + if (sgh == NULL) + continue; - max_idx = sig; + SCLogDebug("sgh %p", sgh); - /* build the temp list */ - grsighead = GetHeadPtr(&tmp_s->dst, family); - for (sgr = grsighead; sgr != NULL; sgr = sgr->next) { - //printf(" * (tmp) dst group: "); DetectAddressPrint(sgr); printf(" (%p)\n", sgr); + SigGroupHeadSetFilemagicFlag(de_ctx, sgh); + SigGroupHeadSetFileHashFlag(de_ctx, sgh); + SigGroupHeadSetFilesizeFlag(de_ctx, sgh); + SigGroupHeadSetFilestoreCount(de_ctx, sgh); + SCLogDebug("filestore count %u", sgh->filestore_cnt); - if ((lookup_gr = DetectAddressLookupInList(tmp_gr_list, sgr)) == NULL) { - DetectAddress *grtmp = DetectAddressCopy(sgr); - if (grtmp == NULL) { - goto error; - } - SigGroupHeadAppendSig(de_ctx,&grtmp->sh,tmp_s); + PrefilterSetupRuleGroup(de_ctx, sgh); - DetectAddressAdd(&tmp_gr_list,grtmp); - } else { - /* our group will only have one sig, this one. So add that. */ - SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, tmp_s); - lookup_gr->cnt++; - } - } + SigGroupHeadBuildNonPrefilterArray(de_ctx, sgh); - } + sgh->id = idx; + cnt++; + } + SCLogPerf("Unique rule groups: %u", cnt); - /* Create the destination address list, keeping in - * mind the limits we use. */ - int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); - - CreateGroupedAddrList(de_ctx, tmp_gr_list, family, gr->dst_gh, groups, CreateGroupedAddrListCmpMpmMaxlen, max_idx); - - /* see if the sig group head of each address group is the - * same as an earlier one. If it is, free our head and use - * a pointer to the earlier one. This saves _a lot_ of memory. - */ - grdsthead = GetHeadPtr(gr->dst_gh, family); - for (sgr = grdsthead; sgr != NULL; sgr = sgr->next) { - //printf(" * Destination group: "); DetectAddressPrint(sgr); printf("\n"); - - /* Because a pattern matcher context uses quite some - * memory, we first check if we can reuse it from - * another group head. */ - SigGroupHead *sgh = SigGroupHeadHashLookup(de_ctx, sgr->sh); - if (sgh == NULL) { - /* put the contents in our sig group head */ - SigGroupHeadSetSigCnt(sgr->sh, max_idx); - SigGroupHeadBuildMatchArray(de_ctx, sgr->sh, max_idx); - - /* init the pattern matcher, this will respect the copy - * setting */ - if (PatternMatchPrepareGroup(de_ctx, sgr->sh) < 0) { - printf("PatternMatchPrepareGroup failed\n"); - goto error; - } - if (sgr->sh->mpm_proto_tcp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; + MpmStoreReportStats(de_ctx); - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - } - if (sgr->sh->mpm_proto_tcp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; + if (de_ctx->decoder_event_sgh != NULL) { + /* no need to set filestore count here as that would make a + * signature not decode event only. */ + } - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - } - if (sgr->sh->mpm_proto_udp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt; + /* cleanup the hashes now since we won't need them + * after the initialization phase. */ + SigGroupHeadHashFree(de_ctx); - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - } - if (sgr->sh->mpm_proto_udp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt; + int dump_grouping = 0; + (void)ConfGetBool("detect.profiling.grouping.dump-to-disk", &dump_grouping); - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - } - if (sgr->sh->mpm_proto_other_ctx != NULL) { - if (de_ctx->mpm_max_patcnt < sgr->sh->mpm_proto_other_ctx->pattern_cnt) - de_ctx->mpm_max_patcnt = sgr->sh->mpm_proto_other_ctx->pattern_cnt; + if (dump_grouping) { + int add_rules = 0; + (void)ConfGetBool("detect.profiling.grouping.include-rules", &add_rules); + int add_mpm_stats = 0; + (void)ConfGetBool("detect.profiling.grouping.include-mpm-stats", &add_rules); - de_ctx->mpm_tot_patcnt += sgr->sh->mpm_proto_other_ctx->pattern_cnt; - } - if (sgr->sh->mpm_uri_ctx_ts != NULL) { - if (de_ctx->mpm_uri_max_patcnt < sgr->sh->mpm_uri_ctx_ts->pattern_cnt) - de_ctx->mpm_uri_max_patcnt = sgr->sh->mpm_uri_ctx_ts->pattern_cnt; + RulesDumpGrouping(de_ctx, add_rules, add_mpm_stats); + } - de_ctx->mpm_uri_tot_patcnt += sgr->sh->mpm_uri_ctx_ts->pattern_cnt; - } - /* dbg */ - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_tcp_ctx_ts) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_tcp_ctx_ts->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_tcp_ctx_tc) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_tcp_ctx_tc->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_udp_ctx_ts) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_udp_ctx_ts->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_udp_ctx_tc) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_udp_ctx_tc->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && sgr->sh->mpm_proto_other_ctx) { - de_ctx->mpm_memory_size += sgr->sh->mpm_proto_other_ctx->memory_size; - } - if (!(sgr->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && sgr->sh->mpm_uri_ctx_ts) { - de_ctx->mpm_memory_size += sgr->sh->mpm_uri_ctx_ts->memory_size; - } +#ifdef PROFILING + SCProfilingSghInitCounters(de_ctx); +#endif + SCReturnInt(0); +} - SigGroupHeadHashAdd(de_ctx, sgr->sh); - SigGroupHeadStore(de_ctx, sgr->sh); - de_ctx->gh_unique++; - } else { - SCLogDebug("calling SigGroupHeadFree sgr %p, sgr->sh %p", sgr, sgr->sh); - SigGroupHeadFree(sgr->sh); - sgr->sh = sgh; +/** \internal + * \brief perform final per signature setup tasks + * + * - Create SigMatchData arrays from the init only SigMatch lists + * - Setup per signature inspect engines + * - remove signature init data. + */ +static int SigMatchPrepare(DetectEngineCtx *de_ctx) +{ + SCEnter(); - de_ctx->gh_reuse++; - sgr->flags |= ADDRESS_SIGGROUPHEAD_COPY; - sgr->sh->flags |= SIG_GROUP_HEAD_REFERENCED; + const int nlists = DetectBufferTypeMaxId(); + Signature *s = de_ctx->sig_list; + for (; s != NULL; s = s->next) { + /* set up inspect engines */ + DetectEngineAppInspectionEngine2Signature(s); + + /* built-ins */ + int type; + for (type = 0; type < DETECT_SM_LIST_MAX; type++) { + SigMatch *sm = s->init_data->smlists[type]; + s->sm_arrays[type] = SigMatchList2DataArray(sm); + } + + /* free lists. Ctx' are xferred to sm_arrays so won't get freed */ + int i; + for (i = 0; i < nlists; i++) { + SigMatch *sm = s->init_data->smlists[i]; + while (sm != NULL) { + SigMatch *nsm = sm->next; + SigMatchFree(sm); + sm = nsm; } } - - /* free the temp list */ - DetectAddressCleanupList(tmp_gr_list); - /* clear now unneeded sig group head */ - SCLogDebug("calling SigGroupHeadFree gr %p, gr->sh %p", gr, gr->sh); - SigGroupHeadFree(gr->sh); - gr->sh = NULL; + SCFree(s->init_data->smlists); + SCFree(s->init_data->smlists_tail); + SCFree(s->init_data); + s->init_data = NULL; } - return 0; -error: - return -1; + + SCReturnInt(0); } -//static -int BuildDestinationAddressHeadsWithBothPorts(DetectEngineCtx *de_ctx, DetectAddressHead *head, int family, int flow) +/** + * \brief Convert the signature list into the runtime match structure. + * + * \param de_ctx Pointer to the Detection Engine Context whose Signatures have + * to be processed + * + * \retval 0 On Success. + * \retval -1 On failure. + */ +int SigGroupBuild(DetectEngineCtx *de_ctx) { - Signature *tmp_s = NULL; - DetectAddress *src_gr = NULL, *dst_gr = NULL, *sig_gr = NULL, *lookup_gr = NULL; - DetectAddress *src_gr_head = NULL, *dst_gr_head = NULL, *sig_gr_head = NULL; - uint32_t max_idx = 0; - - /* loop through the global source address list */ - src_gr_head = GetHeadPtr(head,family); - for (src_gr = src_gr_head; src_gr != NULL; src_gr = src_gr->next) { - //printf(" * Source group: "); DetectAddressPrint(src_gr); printf("\n"); - - /* initialize the destination group head */ - src_gr->dst_gh = DetectAddressHeadInit(); - if (src_gr->dst_gh == NULL) { - goto error; - } - - /* use a tmp list for speeding up insertions */ - DetectAddress *tmp_gr_list = NULL; + Signature *s = de_ctx->sig_list; - /* loop through all signatures in this source address group - * and build the temporary destination address list for it */ - uint32_t sig; - for (sig = 0; sig < de_ctx->sig_array_len; sig++) { - if (!(src_gr->sh->init->sig_array[(sig/8)] & (1<<(sig%8)))) - continue; + /* Assign the unique order id of signatures after sorting, + * so the IP Only engine process them in order too. Also + * reset the old signums and assign new signums. We would + * have experienced Sig reordering by now, hence the new + * signums. */ + de_ctx->signum = 0; + while (s != NULL) { + s->num = de_ctx->signum++; - tmp_s = de_ctx->sig_array[sig]; - if (tmp_s == NULL) - continue; + s = s->next; + } - //printf(" * Source group: "); DetectAddressPrint(src_gr); printf("\n"); + if (DetectSetFastPatternAndItsId(de_ctx) < 0) + return -1; - max_idx = sig; + SigInitStandardMpmFactoryContexts(de_ctx); - /* build the temp list */ - sig_gr_head = GetHeadPtr(&tmp_s->dst,family); - for (sig_gr = sig_gr_head; sig_gr != NULL; sig_gr = sig_gr->next) { - //printf(" * Sig dst addr: "); DetectAddressPrint(sig_gr); printf("\n"); + if (SigAddressPrepareStage1(de_ctx) != 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } - if ((lookup_gr = DetectAddressLookupInList(tmp_gr_list, sig_gr)) == NULL) { - DetectAddress *grtmp = DetectAddressCopy(sig_gr); - if (grtmp == NULL) { - goto error; - } - SigGroupHeadAppendSig(de_ctx, &grtmp->sh, tmp_s); + if (SigAddressPrepareStage2(de_ctx) != 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } - DetectAddressAdd(&tmp_gr_list,grtmp); - } else { - /* our group will only have one sig, this one. So add that. */ - SigGroupHeadAppendSig(de_ctx, &lookup_gr->sh, tmp_s); - lookup_gr->cnt++; - } - - SCLogDebug("calling SigGroupHeadFree sig_gr %p, sig_gr->sh %p", sig_gr, sig_gr->sh); - SigGroupHeadFree(sig_gr->sh); - sig_gr->sh = NULL; - } - } - - /* Create the destination address list, keeping in - * mind the limits we use. */ - int groups = (flow ? de_ctx->max_uniq_toserver_dst_groups : de_ctx->max_uniq_toclient_dst_groups); - - CreateGroupedAddrList(de_ctx, tmp_gr_list, family, src_gr->dst_gh, groups, CreateGroupedAddrListCmpMpmMaxlen, max_idx); - - /* add the ports to the dst address groups and the sigs - * to the ports */ - dst_gr_head = GetHeadPtr(src_gr->dst_gh,family); - for (dst_gr = dst_gr_head; dst_gr != NULL; dst_gr = dst_gr->next) { - //printf(" * Destination group: "); DetectAddressPrint(dst_gr); printf("\n"); - - dst_gr->flags |= ADDRESS_HAVEPORT; - - if (dst_gr->sh == NULL) - continue; - - /* we will reuse address sig group heads at this points, - * because if the sigs are the same, the ports will be - * the same. Saves memory and a lot of init time. */ - SigGroupHead *lookup_sgh = SigGroupHeadHashLookup(de_ctx, dst_gr->sh); - if (lookup_sgh == NULL) { - DetectPortSpHashReset(de_ctx); - - uint32_t sig2; - for (sig2 = 0; sig2 < max_idx+1; sig2++) { - if (!(dst_gr->sh->init->sig_array[(sig2/8)] & (1<<(sig2%8)))) - continue; - - Signature *s = de_ctx->sig_array[sig2]; - if (s == NULL) - continue; - - //printf(" + Destination group (grouped): "); DetectAddressPrint(dst_gr); printf("\n"); - - DetectPort *sdp = s->sp; - for ( ; sdp != NULL; sdp = sdp->next) { - DetectPort *lookup_port = DetectPortSpHashLookup(de_ctx, sdp); - if (lookup_port == NULL) { - DetectPort *port = DetectPortCopySingle(de_ctx,sdp); - if (port == NULL) - goto error; - - SigGroupHeadAppendSig(de_ctx, &port->sh, s); - DetectPortSpHashAdd(de_ctx, port); - port->cnt = 1; - } else { - SigGroupHeadAppendSig(de_ctx, &lookup_port->sh, s); - lookup_port->cnt++; - } - } - } - - int spgroups = (flow ? de_ctx->max_uniq_toserver_sp_groups : de_ctx->max_uniq_toclient_sp_groups); - - CreateGroupedPortList(de_ctx, de_ctx->sport_hash_table, &dst_gr->port, spgroups, CreateGroupedPortListCmpMpmMaxlen, max_idx); - - SCLogDebug("adding sgh %p to the hash", dst_gr->sh); - SigGroupHeadHashAdd(de_ctx, dst_gr->sh); - - dst_gr->sh->init->port = dst_gr->port; - /* mark this head for deletion once we no longer need - * the hash. We're only using the port ptr, so no problem - * when we remove this after initialization is done */ - dst_gr->sh->flags |= SIG_GROUP_HEAD_FREE; - - /* for each destination port we setup the siggrouphead here */ - DetectPort *sp = dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - //printf(" * Src Port(range): "); DetectPortPrint(sp); printf("\n"); - - if (sp->sh == NULL) - continue; - - /* we will reuse address sig group heads at this points, - * because if the sigs are the same, the ports will be - * the same. Saves memory and a lot of init time. */ - SigGroupHead *lookup_sp_sgh = SigGroupHeadSPortHashLookup(de_ctx, sp->sh); - if (lookup_sp_sgh == NULL) { - DetectPortDpHashReset(de_ctx); - uint32_t sig2; - for (sig2 = 0; sig2 < max_idx+1; sig2++) { - if (!(sp->sh->init->sig_array[(sig2/8)] & (1<<(sig2%8)))) - continue; - - Signature *s = de_ctx->sig_array[sig2]; - if (s == NULL) - continue; - - DetectPort *sdp = s->dp; - for ( ; sdp != NULL; sdp = sdp->next) { - DetectPort *lookup_port = DetectPortDpHashLookup(de_ctx,sdp); - if (lookup_port == NULL) { - DetectPort *port = DetectPortCopySingle(de_ctx,sdp); - if (port == NULL) - goto error; - - SigGroupHeadAppendSig(de_ctx, &port->sh, s); - DetectPortDpHashAdd(de_ctx,port); - port->cnt = 1; - } else { - SigGroupHeadAppendSig(de_ctx, &lookup_port->sh, s); - lookup_port->cnt++; - } - } - } - - int dpgroups = (flow ? de_ctx->max_uniq_toserver_dp_groups : de_ctx->max_uniq_toclient_dp_groups); - - CreateGroupedPortList(de_ctx, de_ctx->dport_hash_table, - &sp->dst_ph, dpgroups, - CreateGroupedPortListCmpMpmMaxlen, max_idx); - - SigGroupHeadSPortHashAdd(de_ctx, sp->sh); - - sp->sh->init->port = sp->dst_ph; - /* mark this head for deletion once we no longer need - * the hash. We're only using the port ptr, so no problem - * when we remove this after initialization is done */ - sp->sh->flags |= SIG_GROUP_HEAD_FREE; - - /* for each destination port we setup the siggrouphead here */ - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - if (dp->sh == NULL) - continue; - - /* Because a pattern matcher context uses quite some - * memory, we first check if we can reuse it from - * another group head. */ - SigGroupHead *lookup_dp_sgh = SigGroupHeadDPortHashLookup(de_ctx, dp->sh); - if (lookup_dp_sgh == NULL) { - SCLogDebug("dp %p dp->sh %p is the original (sp %p, dst_gr %p, src_gr %p)", dp, dp->sh, sp, dst_gr, src_gr); - - SigGroupHeadSetSigCnt(dp->sh, max_idx); - SigGroupHeadBuildMatchArray(de_ctx,dp->sh, max_idx); - - /* init the pattern matcher, this will respect the copy - * setting */ - if (PatternMatchPrepareGroup(de_ctx, dp->sh) < 0) { - printf("PatternMatchPrepareGroup failed\n"); - goto error; - } - if (dp->sh->mpm_proto_tcp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_tcp_ctx_ts->pattern_cnt; - } - if (dp->sh->mpm_proto_tcp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_tcp_ctx_tc->pattern_cnt; - } - if (dp->sh->mpm_proto_udp_ctx_ts != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_udp_ctx_ts->pattern_cnt; - } - if (dp->sh->mpm_proto_udp_ctx_tc != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_udp_ctx_tc->pattern_cnt; - } - if (dp->sh->mpm_proto_other_ctx != NULL) { - if (de_ctx->mpm_max_patcnt < dp->sh->mpm_proto_other_ctx->pattern_cnt) - de_ctx->mpm_max_patcnt = dp->sh->mpm_proto_other_ctx->pattern_cnt; - - de_ctx->mpm_tot_patcnt += dp->sh->mpm_proto_other_ctx->pattern_cnt; - } - if (dp->sh->mpm_uri_ctx_ts != NULL) { - if (de_ctx->mpm_uri_max_patcnt < dp->sh->mpm_uri_ctx_ts->pattern_cnt) - de_ctx->mpm_uri_max_patcnt = dp->sh->mpm_uri_ctx_ts->pattern_cnt; - - de_ctx->mpm_uri_tot_patcnt += dp->sh->mpm_uri_ctx_ts->pattern_cnt; - } - /* dbg */ - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_tcp_ctx_ts) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_tcp_ctx_ts->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_tcp_ctx_tc) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_tcp_ctx_tc->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_udp_ctx_ts) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_udp_ctx_ts->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_udp_ctx_tc) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_udp_ctx_tc->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_COPY) && dp->sh->mpm_proto_other_ctx) { - de_ctx->mpm_memory_size += dp->sh->mpm_proto_other_ctx->memory_size; - } - if (!(dp->sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY) && dp->sh->mpm_uri_ctx_ts) { - de_ctx->mpm_memory_size += dp->sh->mpm_uri_ctx_ts->memory_size; - } - - SigGroupHeadDPortHashAdd(de_ctx, dp->sh); - SigGroupHeadStore(de_ctx, dp->sh); - de_ctx->gh_unique++; - } else { - SCLogDebug("dp %p dp->sh %p is a copy", dp, dp->sh); - - SigGroupHeadFree(dp->sh); - dp->sh = lookup_dp_sgh; - dp->flags |= PORT_SIGGROUPHEAD_COPY; - dp->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - - de_ctx->gh_reuse++; - } - } - /* sig group head found in hash, free it and use the hashed one */ - } else { - SigGroupHeadFree(sp->sh); - sp->sh = lookup_sp_sgh; - sp->flags |= PORT_SIGGROUPHEAD_COPY; - sp->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - - SCLogDebug("replacing sp->dst_ph %p with lookup_sp_sgh->init->port %p", sp->dst_ph, lookup_sp_sgh->init->port); - DetectPortCleanupList(sp->dst_ph); - sp->dst_ph = lookup_sp_sgh->init->port; - sp->flags |= PORT_GROUP_PORTS_COPY; - - de_ctx->gh_reuse++; - } - } - } else { - SigGroupHeadFree(dst_gr->sh); - dst_gr->sh = lookup_sgh; - dst_gr->flags |= ADDRESS_SIGGROUPHEAD_COPY; - dst_gr->sh->flags |= SIG_GROUP_HEAD_REFERENCED; - - SCLogDebug("replacing dst_gr->port %p with lookup_sgh->init->port %p", dst_gr->port, lookup_sgh->init->port); - DetectPortCleanupList(dst_gr->port); - dst_gr->port = lookup_sgh->init->port; - dst_gr->flags |= ADDRESS_PORTS_COPY; - - de_ctx->gh_reuse++; - } - } - /* free the temp list */ - DetectAddressCleanupList(tmp_gr_list); - /* clear now unneeded sig group head */ - SigGroupHeadFree(src_gr->sh); - src_gr->sh = NULL; - - /* free dst addr sgh's */ - dst_gr_head = GetHeadPtr(src_gr->dst_gh,family); - for (dst_gr = dst_gr_head; dst_gr != NULL; dst_gr = dst_gr->next) { - if (!(dst_gr->flags & ADDRESS_SIGGROUPHEAD_COPY)) { - if (!(dst_gr->sh->flags & SIG_GROUP_HEAD_REFERENCED)) { - SCLogDebug("removing sgh %p from hash", dst_gr->sh); - - int r = SigGroupHeadHashRemove(de_ctx,dst_gr->sh); - BUG_ON(r == -1); - if (r == 0) { - SCLogDebug("removed sgh %p from hash", dst_gr->sh); - SigGroupHeadFree(dst_gr->sh); - dst_gr->sh = NULL; - } - } - } - } + if (SigAddressPrepareStage3(de_ctx) != 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); } - - return 0; -error: - return -1; -} - -static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx) -{ - if (de_ctx->decoder_event_sgh == NULL) - return; - - uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); - SigGroupHeadSetSigCnt(de_ctx->decoder_event_sgh, max_idx); - SigGroupHeadBuildMatchArray(de_ctx, de_ctx->decoder_event_sgh, max_idx); -} - -int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) -{ - int r; - - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("building signature grouping structure, stage 3: " - "building destination address lists..."); + if (SigAddressPrepareStage4(de_ctx) != 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); } - //DetectAddressPrintMemory(); - //DetectSigGroupPrintMemory(); - //DetectPortPrintMemory(); - int f = 0; - int proto; - for (f = 0; f < FLOW_STATES; f++) { - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_INET6,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_INET6,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_INET6,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_TCP],AF_UNSPEC,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[6],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_UDP],AF_UNSPEC,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[17],AF_INET) failed\n"); - goto error; - } - r = BuildDestinationAddressHeadsWithBothPorts(de_ctx, de_ctx->flow_gh[f].src_gh[IPPROTO_SCTP],AF_UNSPEC,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[IPPROTO_SCTP],AF_INET) failed\n"); - goto error; - } - for (proto = 0; proto < 256; proto++) { - if (proto == IPPROTO_TCP || proto == IPPROTO_UDP || proto == IPPROTO_SCTP) - continue; +#ifdef __SC_CUDA_SUPPORT__ + if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { + /* setting it to default. You've gotta remove it once you fix the state table thing */ + SCACConstructBoth16and32StateTables(); - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET,f); - if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET) failed\n", proto); - goto error; + MpmCudaConf *conf = CudaHandlerGetCudaProfile("mpm"); + CUcontext cuda_context = CudaHandlerModuleGetContext(MPM_AC_CUDA_MODULE_NAME, conf->device_id); + if (cuda_context == 0) { + SCLogError(SC_ERR_FATAL, "cuda context is NULL."); + exit(EXIT_FAILURE); } - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_INET6,f); + int r = SCCudaCtxPushCurrent(cuda_context); if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_INET6) failed\n", proto); - goto error; + SCLogError(SC_ERR_FATAL, "context push failed."); + exit(EXIT_FAILURE); } - r = BuildDestinationAddressHeads(de_ctx, de_ctx->flow_gh[f].src_gh[proto],AF_UNSPEC,f); /* for any */ + } + + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { + int r = SCCudaCtxPopCurrent(NULL); if (r < 0) { - printf ("BuildDestinationAddressHeads(src_gh[%" PRId32 "],AF_UNSPEC) failed\n", proto); - goto error; + SCLogError(SC_ERR_FATAL, "cuda context pop failure."); + exit(EXIT_FAILURE); } } + + /* too late to call this either ways. Should be called post ac goto. + * \todo Support this. */ + DetermineCudaStateTableSize(de_ctx); } +#endif - /* prepare the decoder event sgh */ - DetectEngineBuildDecoderEventSgh(de_ctx); + DetectMpmPrepareBuiltinMpms(de_ctx); + DetectMpmPrepareAppMpms(de_ctx); - /* cleanup group head (uri)content_array's */ - SigGroupHeadFreeMpmArrays(de_ctx); - /* cleanup group head sig arrays */ - SigGroupHeadFreeSigArrays(de_ctx); + if (SigMatchPrepare(de_ctx) != 0) { + SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); + exit(EXIT_FAILURE); + } - /* cleanup the hashes now since we won't need them - * after the initialization phase. */ - SigGroupHeadHashFree(de_ctx); - SigGroupHeadDPortHashFree(de_ctx); - SigGroupHeadSPortHashFree(de_ctx); - SigGroupHeadMpmHashFree(de_ctx); - SigGroupHeadMpmUriHashFree(de_ctx); - DetectPortDpHashFree(de_ctx); - DetectPortSpHashFree(de_ctx); +#ifdef PROFILING + SCProfilingRuleInitCounters(de_ctx); +#endif + SCFree(de_ctx->app_mpms); + de_ctx->app_mpms = NULL; - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("MPM memory %" PRIuMAX " (dynamic %" PRIu32 ", ctxs %" PRIuMAX ", avg per ctx %" PRIu32 ")", - de_ctx->mpm_memory_size + ((de_ctx->mpm_unique + de_ctx->mpm_uri_unique) * (uintmax_t)sizeof(MpmCtx)), - de_ctx->mpm_memory_size, ((de_ctx->mpm_unique + de_ctx->mpm_uri_unique) * (uintmax_t)sizeof(MpmCtx)), - de_ctx->mpm_unique ? de_ctx->mpm_memory_size / de_ctx->mpm_unique: 0); - - SCLogDebug("max sig id %" PRIu32 ", array size %" PRIu32 "", DetectEngineGetMaxSigId(de_ctx), DetectEngineGetMaxSigId(de_ctx) / 8 + 1); - SCLogDebug("signature group heads: unique %" PRIu32 ", copies %" PRIu32 ".", de_ctx->gh_unique, de_ctx->gh_reuse); - SCLogDebug("MPM instances: %" PRIu32 " unique, copies %" PRIu32 " (none %" PRIu32 ").", - de_ctx->mpm_unique, de_ctx->mpm_reuse, de_ctx->mpm_none); - SCLogDebug("MPM (URI) instances: %" PRIu32 " unique, copies %" PRIu32 " (none %" PRIu32 ").", - de_ctx->mpm_uri_unique, de_ctx->mpm_uri_reuse, de_ctx->mpm_uri_none); - SCLogDebug("MPM max patcnt %" PRIu32 ", avg %" PRIu32 "", de_ctx->mpm_max_patcnt, de_ctx->mpm_unique?de_ctx->mpm_tot_patcnt/de_ctx->mpm_unique:0); - if (de_ctx->mpm_uri_tot_patcnt && de_ctx->mpm_uri_unique) - SCLogDebug("MPM (URI) max patcnt %" PRIu32 ", avg %" PRIu32 " (%" PRIu32 "/%" PRIu32 ")", de_ctx->mpm_uri_max_patcnt, de_ctx->mpm_uri_tot_patcnt/de_ctx->mpm_uri_unique, de_ctx->mpm_uri_tot_patcnt, de_ctx->mpm_uri_unique); - SCLogDebug("port maxgroups: %" PRIu32 ", avg %" PRIu32 ", tot %" PRIu32 "", g_groupportlist_maxgroups, g_groupportlist_groupscnt ? g_groupportlist_totgroups/g_groupportlist_groupscnt : 0, g_groupportlist_totgroups); - - SCLogInfo("building signature grouping structure, stage 3: building destination address lists... complete"); + if (!DetectEngineMultiTenantEnabled()) { + VarNameStoreActivateStaging(); } return 0; -error: - printf("SigAddressPrepareStage3 error\n"); - return -1; } -int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) +int SigGroupCleanup (DetectEngineCtx *de_ctx) { - BUG_ON(de_ctx == NULL); - - if (!(de_ctx->flags & DE_QUIET)) { - SCLogDebug("cleaning up signature grouping structure..."); - } - - int f, proto; - for (f = 0; f < FLOW_STATES; f++) { - for (proto = 0; proto < 256; proto++) { - /* XXX fix this */ - DetectAddressHeadFree(de_ctx->flow_gh[f].src_gh[proto]); - de_ctx->flow_gh[f].src_gh[proto] = NULL; - } - } - - if (de_ctx->decoder_event_sgh) - SigGroupHeadFree(de_ctx->decoder_event_sgh); - de_ctx->decoder_event_sgh = NULL; - - IPOnlyDeinit(de_ctx, &de_ctx->io_ctx); + SigAddressCleanupStage1(de_ctx); - if (!(de_ctx->flags & DE_QUIET)) { - SCLogInfo("cleaning up signature grouping structure... complete"); - } return 0; } -void DbgPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +static void PrintFeatureList(const SigTableElmt *e, char sep) { - if (sgh == NULL) { - printf("\n"); - return; - } + const uint8_t flags = e->flags; - uint32_t sig; - for (sig = 0; sig < sgh->sig_cnt; sig++) { - printf("%" PRIu32 " ", sgh->match_array[sig]->id); + int prev = 0; + if (flags & SIGMATCH_NOOPT) { + printf("No option"); + prev = 1; } - printf("\n"); -} - -void DbgPrintSigs2(DetectEngineCtx *de_ctx, SigGroupHead *sgh) -{ - if (sgh == NULL || sgh->init == NULL) { - printf("\n"); - return; + if (flags & SIGMATCH_IPONLY_COMPAT) { + if (prev == 1) + printf("%c", sep); + printf("compatible with IP only rule"); + prev = 1; } - - uint32_t sig; - for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) { - if (sgh->init->sig_array[(sig/8)] & (1<<(sig%8))) { - printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id); - } + if (flags & SIGMATCH_DEONLY_COMPAT) { + if (prev == 1) + printf("%c", sep); + printf("compatible with decoder event only rule"); + prev = 1; } - printf("\n"); -} - -void DbgSghContainsSig(DetectEngineCtx *de_ctx, SigGroupHead *sgh, uint32_t sid) -{ - if (sgh == NULL || sgh->init == NULL) { - printf("\n"); - return; + if (e->SupportsPrefilter) { + if (prev == 1) + printf("%c", sep); + printf("prefilter"); + prev = 1; } - - uint32_t sig; - for (sig = 0; sig < DetectEngineGetMaxSigId(de_ctx); sig++) { - if (!(sgh->init->sig_array[(sig/8)] & (1<<(sig%8)))) - continue; - - Signature *s = de_ctx->sig_array[sig]; - if (s == NULL) - continue; - - if (sid == s->id) { - printf("%" PRIu32 " ", de_ctx->sig_array[sig]->id); - } + if (prev == 0) { + printf("none"); } - printf("\n"); } -/** \brief finalize preparing sgh's */ -int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) +static void SigMultilinePrint(int i, char *prefix) { - SCEnter(); - - //SCLogInfo("sgh's %"PRIu32, de_ctx->sgh_array_cnt); - - uint32_t idx = 0; - - for (idx = 0; idx < de_ctx->sgh_array_cnt; idx++) { - SigGroupHead *sgh = de_ctx->sgh_array[idx]; - if (sgh == NULL) - continue; - - SigGroupHeadBuildHeadArray(de_ctx, sgh); - SigGroupHeadSetFilemagicFlag(de_ctx, sgh); - SigGroupHeadSetFileMd5Flag(de_ctx, sgh); - SigGroupHeadSetFilesizeFlag(de_ctx, sgh); - SigGroupHeadSetFilestoreCount(de_ctx, sgh); - SCLogDebug("filestore count %u", sgh->filestore_cnt); + if (sigmatch_table[i].desc) { + printf("%sDescription: %s\n", prefix, sigmatch_table[i].desc); } - - if (de_ctx->decoder_event_sgh != NULL) { - SigGroupHeadBuildHeadArray(de_ctx, de_ctx->decoder_event_sgh); - /* no need to set filestore count here as that would make a - * signature not decode event only. */ + printf("%sFeatures: ", prefix); + PrintFeatureList(&sigmatch_table[i], ','); + if (sigmatch_table[i].url) { + printf("\n%sDocumentation: %s", prefix, sigmatch_table[i].url); } - - SCFree(de_ctx->sgh_array); - de_ctx->sgh_array_cnt = 0; - de_ctx->sgh_array_size = 0; - - SCReturnInt(0); + printf("\n"); } -/* shortcut for debugging. If enabled Stage5 will - * print sigid's for all groups */ -#define PRINTSIGS - -/* just printing */ -int SigAddressPrepareStage5(DetectEngineCtx *de_ctx) +void SigTableList(const char *keyword) { - DetectAddressHead *global_dst_gh = NULL; - DetectAddress *global_src_gr = NULL, *global_dst_gr = NULL; - uint32_t u; - - printf("* Building signature grouping structure, stage 5: print...\n"); + size_t size = sizeof(sigmatch_table) / sizeof(SigTableElmt); + size_t i; - int f, proto; - printf("\n"); - for (f = 0; f < FLOW_STATES; f++) { - printf("\n"); - for (proto = 0; proto < 256; proto++) { - if (proto != IPPROTO_TCP) - continue; - - for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv4_head; global_src_gr != NULL; - global_src_gr = global_src_gr->next) - { - printf("1 Src Addr: "); DetectAddressPrint(global_src_gr); - printf(" (sh %p)\n", global_src_gr->sh); - //printf("\n"); - -#ifdef PRINTSIGS - SigGroupHeadPrintSigs(de_ctx, global_src_gr->sh); - if (global_src_gr->sh != NULL) { - printf(" - "); - for (u = 0; u < global_src_gr->sh->sig_cnt; u++) { - Signature *s = global_src_gr->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } - printf("\n"); - } -#endif - - global_dst_gh = global_src_gr->dst_gh; - if (global_dst_gh == NULL) - continue; - - for (global_dst_gr = global_dst_gh->ipv4_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" 2 Dst Addr: "); DetectAddressPrint(global_dst_gr); - - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf(" (COPY): "); - } else { - printf(" (ORIGINAL): "); - } - } else { - printf(" "); - } - -#ifdef PRINTSIGS - if (global_dst_gr->sh != NULL) { - printf(" - "); - for (u = 0; u < global_dst_gr->sh->sig_cnt; u++) { - Signature *s = global_dst_gr->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } - printf("\n"); - } -#endif - - - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" 3 Src port(range): "); DetectPortPrint(sp); - //printf(" (sh %p)", sp->sh); - printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" 4 Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ", sgh %p, maxlen %" PRIu32 ")", dp->sh->sig_cnt, dp->sh, dp->sh->mpm_content_maxlen); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = dp->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - for (global_dst_gr = global_dst_gh->any_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = dp->sh->match_array[u]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } + if (keyword == NULL) { + printf("=====Supported keywords=====\n"); + for (i = 0; i < size; i++) { + if (sigmatch_table[i].name != NULL) { + if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { + printf("- %s (not built-in)\n", sigmatch_table[i].name); + } else { + printf("- %s\n", sigmatch_table[i].name); } } -#if 0 - for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv6_head; global_src_gr != NULL; - global_src_gr = global_src_gr->next) - { - printf("- "); DetectAddressPrint(global_src_gr); - //printf(" (sh %p)\n", global_src_gr->sh); - - global_dst_gh = global_src_gr->dst_gh; - if (global_dst_gh == NULL) + } + } else if (strcmp("csv", keyword) == 0) { + printf("name;description;app layer;features;documentation\n"); + for (i = 0; i < size; i++) { + if (sigmatch_table[i].name != NULL) { + if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { continue; - - for (global_dst_gr = global_dst_gh->ipv6_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } - } - for (global_dst_gr = global_dst_gh->any_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } } - } - - for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->any_head; global_src_gr != NULL; - global_src_gr = global_src_gr->next) - { - printf("- "); DetectAddressPrint(global_src_gr); - //printf(" (sh %p)\n", global_src_gr->sh); - - global_dst_gh = global_src_gr->dst_gh; - if (global_dst_gh == NULL) - continue; - - for (global_dst_gr = global_dst_gh->any_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } + printf("%s;", sigmatch_table[i].name); + if (sigmatch_table[i].desc) { + printf("%s", sigmatch_table[i].desc); } - for (global_dst_gr = global_dst_gh->ipv4_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } + /* Build feature */ + printf(";Unset;"); // this used to be alproto + PrintFeatureList(&sigmatch_table[i], ':'); + printf(";"); + if (sigmatch_table[i].url) { + printf("%s", sigmatch_table[i].url); } - for (global_dst_gr = global_dst_gh->ipv6_head; - global_dst_gr != NULL; - global_dst_gr = global_dst_gr->next) - { - printf(" - "); DetectAddressPrint(global_dst_gr); - //printf(" (sh %p) ", global_dst_gr->sh); - if (global_dst_gr->sh) { - if (global_dst_gr->sh->flags & ADDRESS_SIGGROUPHEAD_COPY) { - printf("(COPY)\n"); - } else { - printf("\n"); - } - } - DetectPort *sp = global_dst_gr->port; - for ( ; sp != NULL; sp = sp->next) { - printf(" * Src port(range): "); DetectPortPrint(sp); printf("\n"); - DetectPort *dp = sp->dst_ph; - for ( ; dp != NULL; dp = dp->next) { - printf(" * Dst port(range): "); DetectPortPrint(dp); - printf(" (sigs %" PRIu32 ")", dp->sh->sig_cnt); -#ifdef PRINTSIGS - printf(" - "); - for (u = 0; u < dp->sh->sig_cnt; u++) { - Signature *s = de_ctx->sig_array[dp->sh->match_array[u]]; - printf("%" PRIu32 " ", s->id); - } -#endif - printf("\n"); - } - } + printf(";"); + printf("\n"); + } + } + } else if (strcmp("all", keyword) == 0) { + for (i = 0; i < size; i++) { + if (sigmatch_table[i].name != NULL) { + printf("%s:\n", sigmatch_table[i].name); + SigMultilinePrint(i, "\t"); + } + } + } else { + for (i = 0; i < size; i++) { + if ((sigmatch_table[i].name != NULL) && + strcmp(sigmatch_table[i].name, keyword) == 0) { + printf("= %s =\n", sigmatch_table[i].name); + if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { + printf("Not built-in\n"); + return; } + SigMultilinePrint(i, ""); + return; } -#endif } } - - printf("* Building signature grouping structure, stage 5: print... done\n"); - return 0; + return; } -/** - * \brief Convert the signature list into the runtime match structure. - * - * \param de_ctx Pointer to the Detection Engine Context whose Signatures have - * to be processed - * - * \retval 0 On Success. - * \retval -1 On failure. - */ -int SigGroupBuild(DetectEngineCtx *de_ctx) +void SigTableSetup(void) { - Signature *s = de_ctx->sig_list; - - /* Assign the unique order id of signatures after sorting, - * so the IP Only engine process them in order too. Also - * reset the old signums and assign new signums. We would - * have experienced Sig reordering by now, hence the new - * signums. */ - de_ctx->signum = 0; - while (s != NULL) { - s->num = de_ctx->signum++; - - s = s->next; - } - - if (DetectSetFastPatternAndItsId(de_ctx) < 0) - return -1; - - /* if we are using single sgh_mpm_context then let us init the standard mpm - * contexts using the mpm_ctx factory */ - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - SigInitStandardMpmFactoryContexts(de_ctx); - } - - if (SigAddressPrepareStage1(de_ctx) != 0) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - exit(EXIT_FAILURE); - } -//exit(0); - if (SigAddressPrepareStage2(de_ctx) != 0) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - exit(EXIT_FAILURE); - } - - if (SigAddressPrepareStage3(de_ctx) != 0) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - exit(EXIT_FAILURE); - } - if (SigAddressPrepareStage4(de_ctx) != 0) { - SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed"); - exit(EXIT_FAILURE); - } - - if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) { - MpmCtx *mpm_ctx = NULL; - -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { - /* setting it to default. You've gotta remove it once you fix the state table thing */ - SCACConstructBoth16and32StateTables(); - - MpmCudaConf *conf = CudaHandlerGetCudaProfile("mpm"); - CUcontext cuda_context = CudaHandlerModuleGetContext(MPM_AC_CUDA_MODULE_NAME, conf->device_id); - if (cuda_context == 0) { - SCLogError(SC_ERR_FATAL, "cuda context is NULL."); - exit(EXIT_FAILURE); - } - int r = SCCudaCtxPushCurrent(cuda_context); - if (r < 0) { - SCLogError(SC_ERR_FATAL, "context push failed."); - exit(EXIT_FAILURE); - } - } -#endif - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("packet- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("packet- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("packet- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("uri- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hcbd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsbd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hsbd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrhd- %d\n", mpm_ctx->pattern_cnt); + memset(sigmatch_table, 0, sizeof(sigmatch_table)); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hmd- %d\n", mpm_ctx->pattern_cnt); + DetectSidRegister(); + DetectPriorityRegister(); + DetectPrefilterRegister(); + DetectRevRegister(); + DetectClasstypeRegister(); + DetectReferenceRegister(); + DetectTagRegister(); + DetectThresholdRegister(); + DetectMetadataRegister(); + DetectMsgRegister(); + DetectAckRegister(); + DetectSeqRegister(); + DetectContentRegister(); + DetectUricontentRegister(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hcd- %d\n", mpm_ctx->pattern_cnt); + /* NOTE: the order of these currently affects inspect + * engine registration order and ultimately the order + * of inspect engines in the rule. Which in turn affects + * state keeping */ + DetectHttpUriRegister(); + DetectHttpRequestLineRegister(); + DetectHttpClientBodyRegister(); + DetectHttpResponseLineRegister(); + DetectHttpServerBodyRegister(); + DetectHttpHeaderRegister(); + DetectHttpHeaderNamesRegister(); + DetectHttpProtocolRegister(); + DetectHttpStartRegister(); + DetectHttpRawHeaderRegister(); + DetectHttpMethodRegister(); + DetectHttpCookieRegister(); + DetectHttpRawUriRegister(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrud- %d\n", mpm_ctx->pattern_cnt); + DetectFilenameRegister(); + DetectFileextRegister(); + DetectFilestoreRegister(); + DetectFilemagicRegister(); + DetectFileMd5Register(); + DetectFileSha1Register(); + DetectFileSha256Register(); + DetectFilesizeRegister(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("stream- %d\n", mpm_ctx->pattern_cnt); + DetectHttpUARegister(); + DetectHttpHHRegister(); + DetectHttpHRHRegister(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hsmd- %d\n", mpm_ctx->pattern_cnt); + DetectHttpStatMsgRegister(); + DetectHttpStatCodeRegister(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hscd- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hscd- %d\n", mpm_ctx->pattern_cnt); + DetectDnsQueryRegister(); + DetectModbusRegister(); + DetectCipServiceRegister(); + DetectEnipCommandRegister(); + DetectDNP3Register(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("huad- %d\n", mpm_ctx->pattern_cnt); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("huad- %d\n", mpm_ctx->pattern_cnt); + DetectTlsSniRegister(); + DetectTlsIssuerRegister(); + DetectTlsSubjectRegister(); + DetectTlsSerialRegister(); - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hhhd- %d\n", mpm_ctx->pattern_cnt); + DetectAppLayerEventRegister(); + /* end of order dependent regs */ - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hhhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 0); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrhhd- %d\n", mpm_ctx->pattern_cnt); - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhhd, 1); - if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) { - mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx); - } - //printf("hrhhd- %d\n", mpm_ctx->pattern_cnt); - -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) { - int r = SCCudaCtxPopCurrent(NULL); - if (r < 0) { - SCLogError(SC_ERR_FATAL, "cuda context pop failure."); - exit(EXIT_FAILURE); - } - } - - /* too late to call this either ways. Should be called post ac goto. - * \todo Support this. */ - DetermineCudaStateTableSize(de_ctx); -#endif - - } - -// SigAddressPrepareStage5(de_ctx); -// DetectAddressPrintMemory(); -// DetectSigGroupPrintMemory(); -// DetectPortPrintMemory(); -#ifdef PROFILING - SCProfilingRuleInitCounters(de_ctx); -#endif - return 0; -} - -int SigGroupCleanup (DetectEngineCtx *de_ctx) -{ - SigAddressCleanupStage1(de_ctx); - - return 0; -} - -static inline void PrintFeatureList(int flags, char sep) -{ - int prev = 0; - if (flags & SIGMATCH_NOOPT) { - printf("No option"); - prev = 1; - } - if (flags & SIGMATCH_IPONLY_COMPAT) { - if (prev == 1) - printf("%c", sep); - printf("compatible with IP only rule"); - prev = 1; - } - if (flags & SIGMATCH_DEONLY_COMPAT) { - if (prev == 1) - printf("%c", sep); - printf("compatible with decoder event only rule"); - prev = 1; - } - if (flags & SIGMATCH_PAYLOAD) { - if (prev == 1) - printf("%c", sep); - printf("payload inspecting keyword"); - prev = 1; - } - if (prev == 0) { - printf("none"); - } -} - -static inline void SigMultilinePrint(int i, char *prefix) -{ - if (sigmatch_table[i].desc) { - printf("%sDescription: %s\n", prefix, sigmatch_table[i].desc); - } - printf("%sProtocol: %s\n", prefix, - AppLayerGetProtoName(sigmatch_table[i].alproto)); - printf("%sFeatures: ", prefix); - PrintFeatureList(sigmatch_table[i].flags, ','); - if (sigmatch_table[i].url) { - printf("\n%sDocumentation: %s", prefix, sigmatch_table[i].url); - } - printf("\n"); -} - -void SigTableList(const char *keyword) -{ - size_t size = sizeof(sigmatch_table) / sizeof(SigTableElmt); - - size_t i; - - if (keyword == NULL) { - printf("=====Supported keywords=====\n"); - for (i = 0; i < size; i++) { - if (sigmatch_table[i].name != NULL) { - if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { - printf("- %s (not built-in)\n", sigmatch_table[i].name); - } else { - printf("- %s\n", sigmatch_table[i].name); - } - } - } - } else if (!strcmp("csv", keyword)) { - printf("name;description;app layer;features;documentation\n"); - for (i = 0; i < size; i++) { - if (sigmatch_table[i].name != NULL) { - if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { - continue; - } - printf("%s;", sigmatch_table[i].name); - if (sigmatch_table[i].desc) { - printf("%s", sigmatch_table[i].desc); - } - /* Build feature */ - printf(";%s;", - AppLayerGetProtoName(sigmatch_table[i].alproto)); - PrintFeatureList(sigmatch_table[i].flags, ':'); - printf(";"); - if (sigmatch_table[i].url) { - printf("%s", sigmatch_table[i].url); - } - printf(";"); - printf("\n"); - } - } - } else if (!strcmp("all", keyword)) { - for (i = 0; i < size; i++) { - printf("%s:\n", sigmatch_table[i].name); - SigMultilinePrint(i, "\t"); - } - } else { - for (i = 0; i < size; i++) { - if ((sigmatch_table[i].name != NULL) && - !strcmp(sigmatch_table[i].name, keyword)) { - printf("= %s =\n", sigmatch_table[i].name); - if (sigmatch_table[i].flags & SIGMATCH_NOT_BUILT) { - printf("Not built-in\n"); - return; - } - SigMultilinePrint(i, ""); - return; - } - } - } - return; -} - -void SigTableSetup(void) -{ - memset(sigmatch_table, 0, sizeof(sigmatch_table)); - - DetectSidRegister(); - DetectPriorityRegister(); - DetectRevRegister(); - DetectClasstypeRegister(); - DetectReferenceRegister(); - DetectTagRegister(); - DetectThresholdRegister(); - DetectMetadataRegister(); - DetectMsgRegister(); - DetectAckRegister(); - DetectSeqRegister(); - DetectContentRegister(); - DetectUricontentRegister(); DetectPcreRegister(); DetectDepthRegister(); DetectNocaseRegister(); @@ -4759,6 +4011,8 @@ void SigTableSetup(void) DetectPktvarRegister(); DetectNoalertRegister(); DetectFlowbitsRegister(); + DetectHostbitsRegister(); + DetectXbitsRegister(); DetectEngineEventRegister(); DetectIpOptsRegister(); DetectFlagsRegister(); @@ -4778,1011 +4032,194 @@ void SigTableSetup(void) DetectDceIfaceRegister(); DetectDceOpnumRegister(); DetectDceStubDataRegister(); - DetectHttpCookieRegister(); - DetectHttpMethodRegister(); - DetectHttpStatMsgRegister(); DetectTlsRegister(); + DetectTlsValidityRegister(); DetectTlsVersionRegister(); DetectUrilenRegister(); DetectDetectionFilterRegister(); - DetectHttpHeaderRegister(); - DetectHttpRawHeaderRegister(); - DetectHttpClientBodyRegister(); - DetectHttpServerBodyRegister(); - DetectHttpUriRegister(); - DetectHttpRawUriRegister(); DetectAsn1Register(); + DetectSshProtocolRegister(); DetectSshVersionRegister(); - DetectSshSoftwareVersionRegister(); - DetectSslStateRegister(); - DetectHttpStatCodeRegister(); - DetectSslVersionRegister(); - DetectByteExtractRegister(); - DetectFiledataRegister(); - DetectPktDataRegister(); - DetectFilenameRegister(); - DetectFileextRegister(); - DetectFilestoreRegister(); - DetectFilemagicRegister(); - DetectFileMd5Register(); - DetectFilesizeRegister(); - DetectAppLayerEventRegister(); - DetectHttpUARegister(); - DetectHttpHHRegister(); - DetectHttpHRHRegister(); - DetectLuaRegister(); - DetectIPRepRegister(); - DetectDnsQueryRegister(); - DetectAppLayerProtocolRegister(); -} - -void SigTableRegisterTests(void) -{ - /* register the tests */ - int i = 0; - for (i = 0; i < DETECT_TBLSIZE; i++) { - g_ut_modules++; - if (sigmatch_table[i].RegisterTests != NULL) { - sigmatch_table[i].RegisterTests(); - g_ut_covered++; - } else { - SCLogDebug("detection plugin %s has no unittest " - "registration function.", sigmatch_table[i].name); - - if (coverage_unittests) - SCLogWarning(SC_WARN_NO_UNITTESTS, "detection plugin %s has no unittest " - "registration function.", sigmatch_table[i].name); - } - } -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -#include "flow-util.h" -#include "stream-tcp-reassemble.h" -#include "util-var-name.h" - -static const char *dummy_conf_string = - "%YAML 1.1\n" - "---\n" - "\n" - "default-log-dir: /var/log/suricata\n" - "\n" - "logging:\n" - "\n" - " default-log-level: debug\n" - "\n" - " default-format: \"<%t> - <%l>\"\n" - "\n" - " default-startup-message: Your IDS has started.\n" - "\n" - " default-output-filter:\n" - "\n" - " output:\n" - "\n" - " - interface: console\n" - " log-level: info\n" - "\n" - " - interface: file\n" - " filename: /var/log/suricata.log\n" - "\n" - " - interface: syslog\n" - " facility: local5\n" - " format: \"%l\"\n" - "\n" - "pfring:\n" - "\n" - " interface: eth0\n" - "\n" - " clusterid: 99\n" - "\n" - "vars:\n" - "\n" - " address-groups:\n" - "\n" - " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" - "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" - "\n" - " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" - "\n" - " HTTP_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " SMTP_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " SQL_SERVERS: \"!192.168.0.0/16\"\n" - "\n" - " DNS_SERVERS: any\n" - "\n" - " TELNET_SERVERS: any\n" - "\n" - " AIM_SERVERS: any\n" - "\n" - " port-groups:\n" - "\n" - " HTTP_PORTS: \"80:81,88\"\n" - "\n" - " SHELLCODE_PORTS: 80\n" - "\n" - " ORACLE_PORTS: 1521\n" - "\n" - " SSH_PORTS: 22\n" - "\n"; - -static int SigTest01Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - int result = 0; - - char sig[] = "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"; - if (UTHPacketMatchSigMpm(p, sig, mpm_type) == 0) { - result = 0; - goto end; - } -#if 0 - //printf("URI0 \"%s\", len %" PRIu32 "\n", p.http_uri.raw[0], p.http_uri.raw_size[0]); - //printf("URI1 \"%s\", len %" PRIu32 "\n", p.http_uri.raw[1], p.http_uri.raw_size[1]); - - if (p->http_uri.raw_size[0] == 5 && - memcmp(p->http_uri.raw[0], "/one/", 5) == 0 && - p->http_uri.raw_size[1] == 5 && - memcmp(p->http_uri.raw[1], "/two/", 5) == 0) - { - result = 1; - } - -#endif - result = 1; -end: - if (p != NULL) - UTHFreePacket(p); - return result; -} - -static int SigTest01B2g (void) -{ - return SigTest01Real(MPM_B2G); -} -static int SigTest01B3g (void) -{ - return SigTest01Real(MPM_B3G); -} -static int SigTest01Wm (void) -{ - return SigTest01Real(MPM_WUMANBER); -} - -static int SigTest02Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); - char sig[] = "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:41; sid:1;)"; - int ret = UTHPacketMatchSigMpm(p, sig, mpm_type); - UTHFreePacket(p); - return ret; -} - -static int SigTest02B2g (void) -{ - return SigTest02Real(MPM_B2G); -} -static int SigTest02B3g (void) -{ - return SigTest02Real(MPM_B3G); -} -static int SigTest02Wm (void) -{ - return SigTest02Real(MPM_WUMANBER); -} - - -static int SigTest03Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:39; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); - DetectEngineCtxFree(de_ctx); -end: - UTHFreePackets(&p, 1); - return result; -} -static int SigTest03B2g (void) -{ - return SigTest03Real(MPM_B2G); -} -static int SigTest03B3g (void) -{ - return SigTest03Real(MPM_B3G); -} -static int SigTest03Wm (void) -{ - return SigTest03Real(MPM_WUMANBER); -} - - -static int SigTest04Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20*/ - "Host: one.example.org\r\n" /* 23, post "Host:" 18 */ - "\r\n\r\n" /* 4 */ - "GET /two/ HTTP/1.1\r\n" /* 20 */ - "Host: two.example.org\r\n" /* 23 */ - "\r\n\r\n"; /* 4 */ - uint16_t buflen = strlen((char *)buf); - - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:42; within:47; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - result = 1; - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); -end: - UTHFreePackets(&p, 1); - return result; -} -static int SigTest04B2g (void) -{ - return SigTest04Real(MPM_B2G); -} -static int SigTest04B3g (void) -{ - return SigTest04Real(MPM_B3G); -} -static int SigTest04Wm (void) -{ - return SigTest04Real(MPM_WUMANBER); -} - - -static int SigTest05Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:48; within:52; sid:1;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 1)) { - result = 1; - } else { - printf("sig matched but shouldn't have: "); - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); -end: - UTHFreePackets(&p, 1); - return result; -} -static int SigTest05B2g (void) -{ - return SigTest05Real(MPM_B2G); -} -static int SigTest05B3g (void) -{ - return SigTest05Real(MPM_B3G); -} -static int SigTest05Wm (void) -{ - return SigTest05Real(MPM_WUMANBER); -} - - -static int SigTest06Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - TcpSession ssn; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) - result = 1; - else - printf("sid:1 %s, sid:2 %s: ", - PacketAlertCheck(p, 1) ? "OK" : "FAIL", - PacketAlertCheck(p, 2) ? "OK" : "FAIL"); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - UTHFreePackets(&p, 1); - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - return result; -} -static int SigTest06B2g (void) -{ - return SigTest06Real(MPM_B2G); -} -static int SigTest06B3g (void) -{ - return SigTest06Real(MPM_B3G); -} -static int SigTest06Wm (void) -{ - return SigTest06Real(MPM_WUMANBER); -} - - -static int SigTest07Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - TcpSession ssn; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"three\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) - result = 0; - else - result = 1; - -end: - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - UTHFreePackets(&p, 1); - StreamTcpFreeConfig(TRUE); - FlowCleanupAppLayer(&f); - FLOW_DESTROY(&f); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); - DetectEngineCtxFree(de_ctx); - - return result; -} -static int SigTest07B2g (void) -{ - return SigTest07Real(MPM_B2G); -} -static int SigTest07B3g (void) -{ - return SigTest07Real(MPM_B3G); -} -static int SigTest07Wm (void) -{ - return SigTest07Real(MPM_WUMANBER); -} - - -static int SigTest08Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.0\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - TcpSession ssn; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&f, 0, sizeof(Flow)); - memset(&th_v, 0, sizeof(th_v)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"one\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) - result = 1; - else - printf("sid:1 %s, sid:2 %s: ", - PacketAlertCheck(p, 1) ? "OK" : "FAIL", - PacketAlertCheck(p, 2) ? "OK" : "FAIL"); - -end: - FlowCleanupAppLayer(&f); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - UTHFreePackets(&p, 1); - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - return result; -} -static int SigTest08B2g (void) -{ - return SigTest08Real(MPM_B2G); -} -static int SigTest08B3g (void) -{ - return SigTest08Real(MPM_B3G); -} -static int SigTest08Wm (void) -{ - return SigTest08Real(MPM_WUMANBER); -} - - -static int SigTest09Real (int mpm_type) -{ - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.0\r\n" /* 20 */ - "Host: one.example.org\r\n" /* 23, 43 */ - "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ - "Host: two.example.org\r\n" /* 23, 90 */ - "\r\n\r\n"; /* 4, 94 */ - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; - } - SCMutexUnlock(&f.m); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) - result = 1; - else - result = 0; - -end: - FlowCleanupAppLayer(&f); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - UTHFreePackets(&p, 1); - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - return result; -} -static int SigTest09B2g (void) -{ - return SigTest09Real(MPM_B2G); -} -static int SigTest09B3g (void) -{ - return SigTest09Real(MPM_B3G); -} -static int SigTest09Wm (void) -{ - return SigTest09Real(MPM_WUMANBER); -} + DetectSshSoftwareRegister(); + DetectSshSoftwareVersionRegister(); + DetectSslStateRegister(); + DetectSslVersionRegister(); + DetectByteExtractRegister(); + DetectFiledataRegister(); + DetectPktDataRegister(); + DetectLuaRegister(); + DetectIPRepRegister(); + DetectAppLayerProtocolRegister(); + DetectBase64DecodeRegister(); + DetectBase64DataRegister(); + DetectTemplateRegister(); + DetectTemplateBufferRegister(); + DetectBypassRegister(); + DetectHttpRequestLineRegister(); + DetectHttpResponseLineRegister(); + /* close keyword registration */ + DetectBufferTypeFinalizeRegistration(); +} -static int SigTest10Real (int mpm_type) +void SigTableRegisterTests(void) { - uint8_t *buf = (uint8_t *) - "ABC"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - TcpSession ssn; - int result = 0; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flowflags |= FLOW_PKT_ESTABLISHED; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (1)\"; content:\"ABCD\"; depth:4; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (2)\"; content:\"VWXYZ\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - + /* register the tests */ + int i = 0; + for (i = 0; i < DETECT_TBLSIZE; i++) { + g_ut_modules++; + if (sigmatch_table[i].RegisterTests != NULL) { + sigmatch_table[i].RegisterTests(); + g_ut_covered++; + } else { + SCLogDebug("detection plugin %s has no unittest " + "registration function.", sigmatch_table[i].name); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, buf, buflen); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - result = 0; - SCMutexUnlock(&f.m); - goto end; + if (coverage_unittests) + SCLogWarning(SC_WARN_NO_UNITTESTS, "detection plugin %s has no unittest " + "registration function.", sigmatch_table[i].name); + } } - SCMutexUnlock(&f.m); +} - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) - result = 0; - else - result = 1; +/* + * TESTS + */ - end: - FlowCleanupAppLayer(&f); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - UTHFreePackets(&p, 1); - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); - return result; -} -static int SigTest10B2g (void) -{ - return SigTest10Real(MPM_B2G); -} -static int SigTest10B3g (void) -{ - return SigTest10Real(MPM_B3G); -} -static int SigTest10Wm (void) -{ - return SigTest10Real(MPM_WUMANBER); -} +#ifdef UNITTESTS +#include "flow-util.h" +#include "stream-tcp-reassemble.h" +static const char *dummy_conf_string = + "%YAML 1.1\n" + "---\n" + "\n" + "default-log-dir: /var/log/suricata\n" + "\n" + "logging:\n" + "\n" + " default-log-level: debug\n" + "\n" + " default-format: \"<%t> - <%l>\"\n" + "\n" + " default-startup-message: Your IDS has started.\n" + "\n" + " default-output-filter:\n" + "\n" + " output:\n" + "\n" + " - interface: console\n" + " log-level: info\n" + "\n" + " - interface: file\n" + " filename: /var/log/suricata.log\n" + "\n" + " - interface: syslog\n" + " facility: local5\n" + " format: \"%l\"\n" + "\n" + "pfring:\n" + "\n" + " interface: eth0\n" + "\n" + " clusterid: 99\n" + "\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:" + "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n" + "\n" + " EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n" + "\n" + " HTTP_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " SMTP_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " SQL_SERVERS: \"!192.168.0.0/16\"\n" + "\n" + " DNS_SERVERS: any\n" + "\n" + " TELNET_SERVERS: any\n" + "\n" + " AIM_SERVERS: any\n" + "\n" + " port-groups:\n" + "\n" + " HTTP_PORTS: \"80:81,88\"\n" + "\n" + " SHELLCODE_PORTS: 80\n" + "\n" + " ORACLE_PORTS: 1521\n" + "\n" + " SSH_PORTS: 22\n" + "\n"; -static int SigTest11Real (int mpm_type) +static int SigTest01 (void) { uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - Flow f; - TcpSession ssn; + Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); int result = 0; - memset(&th_v, 0, sizeof(th_v)); - memset(&f, 0, sizeof(f)); - memset(&ssn, 0, sizeof(ssn)); - - p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.proto = IPPROTO_TCP; - f.flags |= FLOW_IPV4; - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - f.alproto = ALPROTO_HTTP; - - StreamTcpInitConfig(TRUE); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (content:\"VWXYZabcde\"; content:\"5678\"; content:\"89\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + char sig[] = "alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"; + if (UTHPacketMatchSigMpm(p, sig, MPM_AC) == 0) { + result = 0; goto end; } +#if 0 + //printf("URI0 \"%s\", len %" PRIu32 "\n", p.http_uri.raw[0], p.http_uri.raw_size[0]); + //printf("URI1 \"%s\", len %" PRIu32 "\n", p.http_uri.raw[1], p.http_uri.raw_size[1]); - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) + if (p->http_uri.raw_size[0] == 5 && + memcmp(p->http_uri.raw[0], "/one/", 5) == 0 && + p->http_uri.raw_size[1] == 5 && + memcmp(p->http_uri.raw[1], "/two/", 5) == 0) + { result = 1; + } - end: - FlowCleanupAppLayer(&f); - SigGroupCleanup(de_ctx); - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - UTHFreePackets(&p, 1); - StreamTcpFreeConfig(TRUE); - FLOW_DESTROY(&f); +#endif + result = 1; +end: + if (p != NULL) + UTHFreePacket(p); return result; } -static int SigTest11B2g (void) -{ - return SigTest11Real(MPM_B2G); -} -static int SigTest11B3g (void) -{ - return SigTest11Real(MPM_B3G); -} -static int SigTest11Wm (void) + +static int SigTest02 (void) { - return SigTest11Real(MPM_WUMANBER); + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = UTHBuildPacket( buf, buflen, IPPROTO_TCP); + char sig[] = "alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:41; sid:1;)"; + int ret = UTHPacketMatchSigMpm(p, sig, MPM_AC); + UTHFreePacket(p); + return ret; } - -static int SigTest12Real (int mpm_type) +static int SigTest03 (void) { uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -5790,134 +4227,98 @@ static int SigTest12Real (int mpm_type) int result = 0; memset(&th_v, 0, sizeof(th_v)); - Flow f; - memset(&f, 0, sizeof(Flow)); - - FLOW_INITIALIZE(&f); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host: one.example.org\"; offset:20; depth:39; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; - else - result = 0; - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - } - FLOW_DESTROY(&f); return result; } -static int SigTest12B2g (void) -{ - return SigTest12Real(MPM_B2G); -} -static int SigTest12B3g (void) -{ - return SigTest12Real(MPM_B3G); -} -static int SigTest12Wm (void) -{ - return SigTest12Real(MPM_WUMANBER); -} - -static int SigTest13Real (int mpm_type) +static int SigTest04 (void) { uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + "GET /one/ HTTP/1.1\r\n" /* 20*/ + "Host: one.example.org\r\n" /* 23, post "Host:" 18 */ + "\r\n\r\n" /* 4 */ + "GET /two/ HTTP/1.1\r\n" /* 20 */ + "Host: two.example.org\r\n" /* 23 */ + "\r\n\r\n"; /* 4 */ uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; memset(&th_v, 0, sizeof(th_v)); - Flow f; - memset(&f, 0, sizeof(Flow)); - - FLOW_INITIALIZE(&f); p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:42; within:47; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (PacketAlertCheck(p, 1)) result = 1; - else - result = 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); - FLOW_DESTROY(&f); return result; } -static int SigTest13B2g (void) -{ - return SigTest13Real(MPM_B2G); -} -static int SigTest13B3g (void) -{ - return SigTest13Real(MPM_B3G); -} -static int SigTest13Wm (void) -{ - return SigTest13Real(MPM_WUMANBER); -} - -static int SigTest14Real (int mpm_type) +static int SigTest05 (void) { uint8_t *buf = (uint8_t *) - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + "GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; @@ -5933,804 +4334,720 @@ static int SigTest14Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; distance:0; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP TEST\"; content:\"Host:\"; offset:20; depth:25; content:\"Host:\"; distance:48; within:52; sid:1;)"); if (de_ctx->sig_list == NULL) { - result = 0; + printf("sig parse failed: "); goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1)) - result = 0; - else + if (!PacketAlertCheck(p, 1)) { result = 1; + } else { + printf("sig matched but shouldn't have: "); + } SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: UTHFreePackets(&p, 1); return result; } -static int SigTest14B2g (void) -{ - return SigTest14Real(MPM_B2G); -} -static int SigTest14B3g (void) -{ - return SigTest14Real(MPM_B3G); -} -static int SigTest14Wm (void) -{ - return SigTest14Real(MPM_WUMANBER); -} - -static int SigTest15Real (int mpm_type) +static int SigTest06 (void) { uint8_t *buf = (uint8_t *) - "CONNECT 213.92.8.7:31204 HTTP/1.1"; + "GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + TcpSession ssn; int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - p->dp = 80; + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; + goto end; + } + SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 2008284)) + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); result = 0; - else + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; + else + printf("sid:1 %s, sid:2 %s: ", + PacketAlertCheck(p, 1) ? "OK" : "FAIL", + PacketAlertCheck(p, 2) ? "OK" : "FAIL"); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: - ConfDeInit(); - ConfRestoreContextBackup(); - SCFree(p); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + UTHFreePackets(&p, 1); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } -static int SigTest15B2g (void) -{ - return SigTest15Real(MPM_B2G); -} -static int SigTest15B3g (void) -{ - return SigTest15Real(MPM_B3G); -} -static int SigTest15Wm (void) -{ - return SigTest15Real(MPM_WUMANBER); -} - -static int SigTest16Real (int mpm_type) +static int SigTest07 (void) { uint8_t *buf = (uint8_t *) - "CONNECT 213.92.8.7:31204 HTTP/1.1"; + "GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + TcpSession ssn; int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); - memset(&p, 0, sizeof(p)); + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); - p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 1234); + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { + result = 0; + goto end; + } + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"three\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 2008284)) - result = 1; + if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) + result = 0; else - printf("sid:2008284 %s: ", PacketAlertCheck(p, 2008284) ? "OK" : "FAIL"); + result = 1; - SigGroupCleanup(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); end: - ConfDeInit(); - ConfRestoreContextBackup(); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); UTHFreePackets(&p, 1); - return result; -} -static int SigTest16B2g (void) -{ - return SigTest16Real(MPM_B2G); -} -static int SigTest16B3g (void) -{ - return SigTest16Real(MPM_B3G); -} -static int SigTest16Wm (void) -{ - return SigTest16Real(MPM_WUMANBER); -} + StreamTcpFreeConfig(TRUE); + FlowCleanupAppLayer(&f); + FLOW_DESTROY(&f); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} -static int SigTest17Real (int mpm_type) +static int SigTest08 (void) { uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" /* 20 */ + "GET /one/ HTTP/1.0\r\n" /* 20 */ "Host: one.example.org\r\n" /* 23, 43 */ "\r\n\r\n" /* 4, 47 */ - "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ "Host: two.example.org\r\n" /* 23, 90 */ "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + TcpSession ssn; int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + memset(&f, 0, sizeof(Flow)); memset(&th_v, 0, sizeof(th_v)); + memset(&ssn, 0, sizeof(ssn)); - p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 80); + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"one\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; + goto end; + } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - PktVar *pv_hn = PktVarGet(p, "http_host"); - if (pv_hn != NULL) { - if (memcmp(pv_hn->value, "one.example.org", pv_hn->value_len < 15 ? pv_hn->value_len : 15) == 0) - result = 1; - else { - printf("\""); - PrintRawUriFp(stdout, pv_hn->value, pv_hn->value_len); - printf("\" != \"one.example.org\": "); - } - PktVarFree(pv_hn); - } else { - printf("Pkt var http_host not captured: "); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; } + FLOWLOCK_UNLOCK(&f); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) + result = 1; + else + printf("sid:1 %s, sid:2 %s: ", + PacketAlertCheck(p, 1) ? "OK" : "FAIL", + PacketAlertCheck(p, 2) ? "OK" : "FAIL"); end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - ConfDeInit(); - ConfRestoreContextBackup(); + FlowCleanupAppLayer(&f); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + if (det_ctx) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); UTHFreePackets(&p, 1); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } -static int SigTest17B2g (void) -{ - return SigTest17Real(MPM_B2G); -} -static int SigTest17B3g (void) -{ - return SigTest17Real(MPM_B3G); -} -static int SigTest17Wm (void) -{ - return SigTest17Real(MPM_WUMANBER); -} -static int SigTest18Real (int mpm_type) +static int SigTest09 (void) { uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + "GET /one/ HTTP/1.0\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.0\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + TcpSession ssn; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); int result = 0; memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - p->dp = 34260; - p->sp = 21; + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.flags |= FLOW_IPV4; + f.proto = IPPROTO_TCP; + p->flow = &f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; + + StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/1\\.0\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI test\"; uricontent:\"two\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; + goto end; + } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (!PacketAlertCheck(p, 2003055)) + if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; else - printf("signature shouldn't match, but did: "); + result = 0; +end: + FlowCleanupAppLayer(&f); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (det_ctx) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: - SCFree(p); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + UTHFreePackets(&p, 1); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } -static int SigTest18B2g (void) -{ - return SigTest18Real(MPM_B2G); -} -static int SigTest18B3g (void) -{ - return SigTest18Real(MPM_B3G); -} -static int SigTest18Wm (void) -{ - return SigTest18Real(MPM_WUMANBER); -} -int SigTest19Real (int mpm_type) +static int SigTest10 (void) { uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + "ABC"; uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + TcpSession ssn; int result = 0; + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - p->dp = 34260; - p->sp = 21; + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> 1.2.3.4 any (msg:\"IP-ONLY test (1)\"; sid:999; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (1)\"; content:\"ABCD\"; depth:4; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Long content test (2)\"; content:\"VWXYZ\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; + goto end; + } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, buf, buflen); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + result = 0; + FLOWLOCK_UNLOCK(&f); + goto end; + } + FLOWLOCK_UNLOCK(&f); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 999)) - result = 1; + if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) + result = 0; else - printf("signature didn't match, but should have: "); + result = 1; + end: + FlowCleanupAppLayer(&f); SigGroupCleanup(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + SigCleanSignatures(de_ctx); + if (det_ctx) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: - ConfDeInit(); - ConfRestoreContextBackup(); - SCFree(p); + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + UTHFreePackets(&p, 1); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } -static int SigTest19B2g (void) -{ - return SigTest19Real(MPM_B2G); -} -static int SigTest19B3g (void) -{ - return SigTest19Real(MPM_B3G); -} -static int SigTest19Wm (void) -{ - return SigTest19Real(MPM_WUMANBER); -} -static int SigTest20Real (int mpm_type) +static int SigTest11 (void) { uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + TcpSession ssn; int result = 0; memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - p->dp = 34260; - p->sp = 21; + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f.alproto = ALPROTO_HTTP; - ConfCreateContextBackup(); - ConfInit(); - ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); + StreamTcpInitConfig(TRUE); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> [99.99.99.99,1.2.3.0/24,1.1.1.1,3.0.0.0/8] any (msg:\"IP-ONLY test (2)\"; sid:999; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result = 0; + goto end; + } + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (content:\"VWXYZabcde\"; content:\"5678\"; content:\"89\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { goto end; } SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - //DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 999)) + if (PacketAlertCheck(p, 1) && PacketAlertCheck(p, 2)) result = 1; - else - printf("signature didn't match, but should have: "); + end: + FlowCleanupAppLayer(&f); SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); + if (det_ctx) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: - ConfDeInit(); - ConfRestoreContextBackup(); - SCFree(p); + UTHFreePackets(&p, 1); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); return result; } -static int SigTest20B2g (void) -{ - return SigTest20Real(MPM_B2G); -} -static int SigTest20B3g (void) -{ - return SigTest20Real(MPM_B3G); -} -static int SigTest20Wm (void) -{ - return SigTest20Real(MPM_WUMANBER); -} - -static int SigTest21Real (int mpm_type) +static int SigTest12 (void) { + uint8_t *buf = (uint8_t *) + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; + memset(&th_v, 0, sizeof(th_v)); Flow f; - memset(&f, 0, sizeof(f)); - FLOW_INITIALIZE(&f); + memset(&f, 0, sizeof(Flow)); - /* packet 1 */ - uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buf1len = strlen((char *)buf1); - Packet *p1 = NULL; - /* packet 2 */ - uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buf2len = strlen((char *)buf2); - Packet *p2 = NULL; + FLOW_INITIALIZE(&f); - p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"klmnop\"; content:\"1234\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 alerted, but shouldn't: "); - goto end; - } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) { - printf("sid 2 didn't alert, but should have: "); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) + result = 1; + else + result = 0; - result = 1; + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); end: + UTHFreePackets(&p, 1); if (de_ctx != NULL) { SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } + DetectEngineCtxFree(de_ctx); } - DetectEngineCtxFree(de_ctx); - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); FLOW_DESTROY(&f); return result; } -static int SigTest21B2g (void) -{ - return SigTest21Real(MPM_B2G); -} -static int SigTest21B3g (void) -{ - return SigTest21Real(MPM_B3G); -} -static int SigTest21Wm (void) -{ - return SigTest21Real(MPM_WUMANBER); -} - -static int SigTest22Real (int mpm_type) +static int SigTest13 (void) { + uint8_t *buf = (uint8_t *) + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; + memset(&th_v, 0, sizeof(th_v)); Flow f; - memset(&f, 0, sizeof(f)); - FLOW_INITIALIZE(&f); - - /* packet 1 */ - uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buf1len = strlen((char *)buf1); - Packet *p1 = NULL; - - p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + memset(&f, 0, sizeof(Flow)); - /* packet 2 */ - uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buf2len = strlen((char *)buf2); - Packet *p2 = NULL; + FLOW_INITIALIZE(&f); - p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p->flow = &f; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.abc; sid:2;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 alerted, but shouldn't: "); - goto end; - } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) result = 1; else - printf("sid 2 alerted, but shouldn't: "); + result = 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); end: - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); + UTHFreePackets(&p, 1); FLOW_DESTROY(&f); return result; } -static int SigTest22B2g (void) -{ - return SigTest22Real(MPM_B2G); -} -static int SigTest22B3g (void) -{ - return SigTest22Real(MPM_B3G); -} -static int SigTest22Wm (void) -{ - return SigTest22Real(MPM_WUMANBER); -} -static int SigTest23Real (int mpm_type) +static int SigTest14 (void) { + uint8_t *buf = (uint8_t *) + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - Flow f; - memset(&f, 0, sizeof(f)); - FLOW_INITIALIZE(&f); - - /* packet 1 */ - uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buf1len = strlen((char *)buf1); - Packet *p1 = NULL; - - p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - - /* packet 2 */ - uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buf2len = strlen((char *)buf2); - Packet *p2 = NULL; + memset(&th_v, 0, sizeof(th_v)); - p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Content order test\"; content:\"ABCDEFGHIJ\"; content:\"1234\"; content:\"klmnop\"; distance:0; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - printf("sid 1 alerted, but shouldn't: "); - goto end; - } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result = 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1)) + result = 0; else - printf("sid 2 didn't alert, but should have: "); + result = 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: - UTHFreePackets(&p1, 1); - UTHFreePackets(&p2, 1); - FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); return result; } -static int SigTest23B2g (void) -{ - return SigTest23Real(MPM_B2G); -} -static int SigTest23B3g (void) -{ - return SigTest23Real(MPM_B3G); -} -static int SigTest23Wm (void) -{ - return SigTest23Real(MPM_WUMANBER); -} -int SigTest24IPV4Keyword(void) +static int SigTest15 (void) { - uint8_t valid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, - 0xc0, 0xa8, 0x01, 0x03}; - - uint8_t invalid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, - 0xc0, 0xa8, 0x01, 0x06}; - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); + uint8_t *buf = (uint8_t *) + "CONNECT 213.92.8.7:31204 HTTP/1.1"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) return 0; - } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); - PACKET_RESET_CHECKSUMS(p1); - PACKET_RESET_CHECKSUMS(p2); - - p1->ip4h = (IPV4Hdr *)valid_raw_ipv4; - - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = buflen; - p1->proto = IPPROTO_TCP; - - p2->ip4h = (IPV4Hdr *)invalid_raw_ipv4; + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->dp = 80; - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = buflen; - p2->proto = IPPROTO_TCP; + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -6739,102 +5056,50 @@ int SigTest24IPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:valid; " - "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); if (de_ctx->sig_list == NULL) { - printf("sig 1 parse: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:invalid; " - "msg:\"ipv4-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - printf("sig 2 parse: "); + result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("signature 1 didn't match, but should have: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!((PacketAlertCheck(p2, 2)))) { - printf("signature 2 didn't match, but should have: "); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 2008284)) + result = 0; + else + result = 1; - result = 1; + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); end: - if (det_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - SCFree(p1); - SCFree(p2); + ConfDeInit(); + ConfRestoreContextBackup(); + SCFree(p); return result; } -int SigTest25NegativeIPV4Keyword(void) +static int SigTest16 (void) { - uint8_t valid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, - 0xc0, 0xa8, 0x01, 0x03}; - - uint8_t invalid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, - 0xc0, 0xa8, 0x01, 0x06}; - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } + uint8_t *buf = (uint8_t *) + "CONNECT 213.92.8.7:31204 HTTP/1.1"; + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); - PACKET_RESET_CHECKSUMS(p1); - PACKET_RESET_CHECKSUMS(p2); - - p1->ip4h = (IPV4Hdr *)valid_raw_ipv4; + int result = 0; - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = buflen; - p1->proto = IPPROTO_TCP; + memset(&th_v, 0, sizeof(th_v)); + memset(&p, 0, sizeof(p)); - p2->ip4h = (IPV4Hdr *)invalid_raw_ipv4; + p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 1234); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = buflen; - p2->proto = IPPROTO_TCP; + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -6843,112 +5108,102 @@ int SigTest25NegativeIPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:invalid; " - "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; sid:2008284; rev:2;)"); if (de_ctx->sig_list == NULL) { - result &= 0; - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"/one/\"; ipv4-csum:valid; " - "msg:\"ipv4-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result &= 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 0; - else - result &= 1; - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 2008284)) + result = 1; else - result &= 1; + printf("sid:2008284 %s: ", PacketAlertCheck(p, 2008284) ? "OK" : "FAIL"); SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: - SCFree(p1); - SCFree(p2); + ConfDeInit(); + ConfRestoreContextBackup(); + UTHFreePackets(&p, 1); return result; } -int SigTest26TCPV4Keyword(void) +static int SigTest17 (void) { - uint8_t raw_ipv4[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, - 0xc0, 0xa8, 0x01, 0x03}; + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" /* 20 */ + "Host: one.example.org\r\n" /* 23, 43 */ + "\r\n\r\n" /* 4, 47 */ + "GET /two/ HTTP/1.1\r\n" /* 20, 67 */ + "Host: two.example.org\r\n" /* 23, 90 */ + "\r\n\r\n"; /* 4, 94 */ + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + memset(&th_v, 0, sizeof(th_v)); - uint8_t valid_raw_tcp[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, - 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + p = UTHBuildPacketSrcDstPorts((uint8_t *)buf, buflen, IPPROTO_TCP, 12345, 80); + FAIL_IF_NULL(p); - uint8_t invalid_raw_tcp[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, - 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } + Signature *s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any $HTTP_PORTS (msg:\"HTTP host cap\"; content:\"Host:\"; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:1;)"); + FAIL_IF_NULL(s); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); + uint32_t capid = VarNameStoreLookupByName("http_host", VAR_TYPE_PKT_VAR); - PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); + PktVar *pv_hn = PktVarGet(p, capid); + FAIL_IF_NULL(pv_hn); - PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); + FAIL_IF(pv_hn->value_len != 15); + FAIL_IF_NOT(memcmp(pv_hn->value, "one.example.org", pv_hn->value_len) == 0); - PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); - p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; - p1->payload_len = 20; - p1->proto = IPPROTO_TCP; + PktVarFree(pv_hn); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + ConfDeInit(); + ConfRestoreContextBackup(); + UTHFreePackets(&p, 1); + + PASS; +} + +static int SigTest18 (void) +{ + uint8_t *buf = (uint8_t *) + "220 (vsFTPd 2.0.5)\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; - PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); - p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; - p2->payload_len = 20; - p2->proto = IPPROTO_TCP; + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->dp = 34260; + p->sp = 21; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -6957,112 +5212,58 @@ int SigTest26TCPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " - "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)"); if (de_ctx->sig_list == NULL) { - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " - "msg:\"tcpv4-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sig 1 didn't match: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) { - printf("sig 2 didn't match: "); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (!PacketAlertCheck(p, 2003055)) + result = 1; + else + printf("signature shouldn't match, but did: "); - result = 1; -end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p1); - SCFree(p2); +end: + SCFree(p); return result; } -/* Test SigTest26TCPV4Keyword but also check for invalid IPV4 checksum */ -static int SigTest26TCPV4AndNegativeIPV4Keyword(void) +static int SigTest19 (void) { - uint8_t raw_ipv4[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, - 0xc0, 0xa8, 0x01, 0x03}; - - uint8_t valid_raw_tcp[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, - 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; - - uint8_t invalid_raw_tcp[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, - 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); + uint8_t *buf = (uint8_t *) + "220 (vsFTPd 2.0.5)\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) return 0; - } - ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); - - PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); - - PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); - - PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); - p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; - p1->payload_len = 20; - p1->proto = IPPROTO_TCP; + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->dp = 34260; + p->sp = 21; + p->flowflags |= FLOW_PKT_TOSERVER; - PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); - p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; - p2->payload_len = 20; - p2->proto = IPPROTO_TCP; + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -7071,124 +5272,59 @@ static int SigTest26TCPV4AndNegativeIPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " - "ipv4-csum:invalid; " - "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> 1.2.3.4 any (msg:\"IP-ONLY test (1)\"; sid:999; rev:1;)"); if (de_ctx->sig_list == NULL) { - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " - "ipv4-csum:invalid; " - "msg:\"tcpv4-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sig 1 didn't match: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) { - printf("sig 2 didn't match: "); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 999)) + result = 1; + else + printf("signature didn't match, but should have: "); - result = 1; -end: SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p1); - SCFree(p2); +end: + ConfDeInit(); + ConfRestoreContextBackup(); + SCFree(p); return result; } -/* Similar to SigTest26, but with different packet */ -static int SigTest26TCPV4AndIPV4Keyword(void) +static int SigTest20 (void) { - /* IPV4: src:192.168.176.67 dst: 192.168.176.116 - * TTL: 64 Flags: Don't Fragment - */ - uint8_t raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x40, 0x9b, 0xa4, 0x40, 0x00, - 0x40, 0x06, 0xbd, 0x0a, 0xc0, 0xa8, 0xb0, 0x43, - 0xc0, 0xa8, 0xb0, 0x74}; - - /* TCP: sport: 49517 dport: 445 Flags: SYN - * Window size: 65535, checksum: 0x2009, - * MTU: 1460, Window scale: 4, TSACK permitted, - * 24 bytes of options, no payload. - */ - uint8_t valid_raw_tcp[] = { - 0xc1, 0x6d, 0x01, 0xbd, 0x03, 0x10, 0xd3, 0xc9, - 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xff, 0xff, - 0x20, 0x09, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x01, 0x03, 0x03, 0x04, 0x01, 0x01, 0x08, 0x0a, - 0x19, 0x69, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x02, 0x00, 0x00}; - - uint8_t invalid_raw_tcp[] = { - 0xc1, 0x6d, 0x01, 0xbd, 0x03, 0x10, 0xd3, 0xc9, - 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xff, 0xff, - 0x20, 0x09, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x01, 0x03, 0x03, 0x04, 0x01, 0x01, 0x08, 0x0a, - 0x19, 0x69, 0x81, 0x7e, 0xFF, 0xAA, 0x00, 0x00, - 0x04, 0x02, 0x00, 0x00}; - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); + uint8_t *buf = (uint8_t *) + "220 (vsFTPd 2.0.5)\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) return 0; - } - ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); - - PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); - - PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); - - PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); - p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20 + 24; - p1->payload_len = 0; - p1->proto = IPPROTO_TCP; + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; + p->dp = 34260; + p->sp = 21; + p->flowflags |= FLOW_PKT_TOSERVER; - PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); - p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20 + 24; - p2->payload_len = 0; - p2->proto = IPPROTO_TCP; + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -7197,112 +5333,60 @@ static int SigTest26TCPV4AndIPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert ip any any -> any any " - "(tcpv4-csum:valid; " - "ipv4-csum:valid; " - "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert ip $HOME_NET any -> [99.99.99.99,1.2.3.0/24,1.1.1.1,3.0.0.0/8] any (msg:\"IP-ONLY test (2)\"; sid:999; rev:1;)"); if (de_ctx->sig_list == NULL) { - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert ip any any -> any any " - "(tcpv4-csum:invalid; " - "ipv4-csum:valid; " - "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sig 1 didn't match: "); - goto end; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) { - printf("sig 2 didn't match: "); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 999)) + result = 1; + else + printf("signature didn't match, but should have: "); - result = 1; -end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p1); - SCFree(p2); +end: + ConfDeInit(); + ConfRestoreContextBackup(); + SCFree(p); return result; } -static int SigTest27NegativeTCPV4Keyword(void) +static int SigTest21 (void) { - uint8_t raw_ipv4[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, - 0xc0, 0xa8, 0x01, 0x03}; - - uint8_t valid_raw_tcp[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, - 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; - - uint8_t invalid_raw_tcp[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, - 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; - - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); - - PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); - - PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); - PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); + Flow f; + memset(&f, 0, sizeof(f)); + FLOW_INITIALIZE(&f); - PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); - p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; - p1->payload_len = 20; - p1->proto = IPPROTO_TCP; + /* packet 1 */ + uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buf1len = strlen((char *)buf1); + Packet *p1 = NULL; + /* packet 2 */ + uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buf2len = strlen((char *)buf2); + Packet *p2 = NULL; - PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); - p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; - p2->payload_len = 20; - p2->proto = IPPROTO_TCP; + p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -7311,254 +5395,153 @@ static int SigTest27NegativeTCPV4Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; dsize:20; " - "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { + result = 0; goto end; } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " - "msg:\"tcpv4-csum keyword check(2)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); + if (de_ctx->sig_list == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!PacketAlertCheck(p1, 1)) { - printf("sig 1 didn't match on p1: "); + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 alerted, but shouldn't: "); goto end; } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) { - printf("sig 2 matched on p2: "); + if (!(PacketAlertCheck(p2, 2))) { + printf("sid 2 didn't alert, but should have: "); goto end; } result = 1; end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + } DetectEngineCtxFree(de_ctx); - SCFree(p1); - SCFree(p2); + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + FLOW_DESTROY(&f); return result; } -int SigTest28TCPV6Keyword(void) +static int SigTest22 (void) { - static uint8_t valid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, - - 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, - 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, - 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, - 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, - - 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, - 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, - 0xf2, 0xf1, 0x00, 0x00, - - 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, - 0x00, 0x01, 0x69, 0x27}; - - static uint8_t invalid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, - - 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, - 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, - 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, - 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, - - 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, - 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, - 0xc2, 0xf1, 0x00, 0x00, - - 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, - 0x00, 0x01, 0x69, 0x28}; - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); + Flow f; + memset(&f, 0, sizeof(f)); + FLOW_INITIALIZE(&f); - PACKET_RESET_CHECKSUMS(p1); - p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = valid_raw_ipv6 + 54 + 20; - p1->payload_len = 12; - p1->proto = IPPROTO_TCP; + /* packet 1 */ + uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buf1len = strlen((char *)buf1); + Packet *p1 = NULL; - if (TCP_GET_HLEN(p1) != 20) { - BUG_ON(1); - } + p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - PACKET_RESET_CHECKSUMS(p2); - p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = invalid_raw_ipv6 + 54 + 20;; - p2->payload_len = 12; - p2->proto = IPPROTO_TCP; + /* packet 2 */ + uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buf2len = strlen((char *)buf2); + Packet *p2 = NULL; - if (TCP_GET_HLEN(p2) != 20) { - BUG_ON(1); - } + p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; sid:1;)"); + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:set,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { + result = 0; goto end; } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.abc; sid:2;)"); + if (de_ctx->sig_list == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (!(PacketAlertCheck(p1, 1))) { - printf("sid 1 didn't match on p1: "); + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 alerted, but shouldn't: "); goto end; } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (!(PacketAlertCheck(p2, 2))) { - printf("sid 2 didn't match on p2: "); - goto end; - } + if (!(PacketAlertCheck(p2, 2))) + result = 1; + else + printf("sid 2 alerted, but shouldn't: "); - result = 1; -end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p1); - SCFree(p2); +end: + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + FLOW_DESTROY(&f); return result; } -int SigTest29NegativeTCPV6Keyword(void) +static int SigTest23 (void) { - static uint8_t valid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, - - 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, - 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, - 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, - 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, - - 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, - 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, - 0xf2, 0xf1, 0x00, 0x00, - - 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, - 0x00, 0x01, 0x69, 0x27}; - - static uint8_t invalid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, - - 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, - 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, - 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, - 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, - - 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, - 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, - 0xc2, 0xf1, 0x00, 0x00, - - 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, - 0x00, 0x01, 0x69, 0x28}; - - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - Packet *p2 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p2 == NULL)) { - SCFree(p1); - return 0; - } ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); DetectEngineThreadCtx *det_ctx = NULL; int result = 0; - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - memset(p2, 0, SIZE_OF_PACKET); + Flow f; + memset(&f, 0, sizeof(f)); + FLOW_INITIALIZE(&f); - PACKET_RESET_CHECKSUMS(p1); - p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = valid_raw_ipv6 + 54 + 20; - p1->payload_len = 12; - p1->proto = IPPROTO_TCP; + /* packet 1 */ + uint8_t *buf1 = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buf1len = strlen((char *)buf1); + Packet *p1 = NULL; - if (TCP_GET_HLEN(p1) != 20) { - BUG_ON(1); - } + p1 = UTHBuildPacket((uint8_t *)buf1, buf1len, IPPROTO_TCP); + p1->flow = &f; + p1->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - PACKET_RESET_CHECKSUMS(p2); - p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); - p2->src.family = AF_INET; - p2->dst.family = AF_INET; - p2->payload = invalid_raw_ipv6 + 54 + 20;; - p2->payload_len = 12; - p2->proto = IPPROTO_TCP; + /* packet 2 */ + uint8_t *buf2 = (uint8_t *)"GET /two/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buf2len = strlen((char *)buf2); + Packet *p2 = NULL; - if (TCP_GET_HLEN(p2) != 20) { - BUG_ON(1); - } + p2 = UTHBuildPacket((uint8_t *)buf2, buf2len, IPPROTO_TCP); + p2->flow = &f; + p2->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -7567,79 +5550,54 @@ int SigTest29NegativeTCPV6Keyword(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; " - "sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT SET\"; content:\"/one/\"; flowbits:toggle,TEST.one; flowbits:noalert; sid:1;)"); if (de_ctx->sig_list == NULL) { + result = 0; goto end; } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " - "msg:\"tcpv6-csum keyword check(1)\"; " - "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"FLOWBIT TEST\"; content:\"/two/\"; flowbits:isset,TEST.one; sid:2;)"); + if (de_ctx->sig_list == NULL) { + result = 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) + if (PacketAlertCheck(p1, 1)) { + printf("sid 1 alerted, but shouldn't: "); goto end; - + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) - goto end; + result = 1; + else + printf("sid 2 didn't alert, but should have: "); - result = 1; -end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - SCFree(p1); - SCFree(p2); +end: + UTHFreePackets(&p1, 1); + UTHFreePackets(&p2, 1); + FLOW_DESTROY(&f); return result; } -int SigTest30UDPV4Keyword(void) +int SigTest24IPV4Keyword(void) { - uint8_t raw_ipv4[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x11, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, + uint8_t valid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; - uint8_t valid_raw_udp[] = { - 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, - 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, - 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, - 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, - 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, - 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, - 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0xc0, 0x26}; - - uint8_t invalid_raw_udp[] = { - 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, - 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, - 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, - 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, - 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, - 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, - 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0xc0, 0x27}; + uint8_t invalid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, + 0xc0, 0xa8, 0x01, 0x06}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -7651,32 +5609,33 @@ int SigTest30UDPV4Keyword(void) } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; + int result = 0; - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" - "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); memset(p2, 0, SIZE_OF_PACKET); - PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)raw_ipv4; - p1->udph = (UDPHdr *)valid_raw_udp; + PACKET_RESET_CHECKSUMS(p2); + + p1->ip4h = (IPV4Hdr *)valid_raw_ipv4; + p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; - p1->payload_len = sizeof(valid_raw_udp) - UDP_HEADER_LEN; - p1->proto = IPPROTO_UDP; + p1->payload_len = buflen; + p1->proto = IPPROTO_TCP; + + p2->ip4h = (IPV4Hdr *)invalid_raw_ipv4; - PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)raw_ipv4; - p2->udph = (UDPHdr *)invalid_raw_udp; p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; - p2->payload_len = sizeof(invalid_raw_udp) - UDP_HEADER_LEN; - p2->proto = IPPROTO_UDP; + p2->payload_len = buflen; + p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -7686,22 +5645,21 @@ int SigTest30UDPV4Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:valid; " - "msg:\"udpv4-csum keyword check(1)\"; " - "sid:1;)"); + "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:valid; " + "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result &= 0; + printf("sig 1 parse: "); goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:invalid; " - "msg:\"udpv4-csum keyword check(1)\"; " - "sid:2;)"); + "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:invalid; " + "msg:\"ipv4-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result &= 0; + printf("sig 2 parse: "); goto end; } @@ -7709,60 +5667,41 @@ int SigTest30UDPV4Keyword(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 1; - else - result &= 0; + if (!(PacketAlertCheck(p1, 1))) { + printf("signature 1 didn't match, but should have: "); + goto end; + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 1; - else - result &= 0; + if (!((PacketAlertCheck(p2, 2)))) { + printf("signature 2 didn't match, but should have: "); + goto end; + } - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); + result = 1; end: + if (det_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } SCFree(p1); SCFree(p2); return result; } -int SigTest31NegativeUDPV4Keyword(void) +int SigTest25NegativeIPV4Keyword(void) { - uint8_t raw_ipv4[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, + uint8_t valid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, 0xc0, 0xa8, 0x01, 0x03}; - uint8_t valid_raw_udp[] = { - 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, - 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, - 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, - 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, - 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, - 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, - 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0xc0, 0x26}; - - uint8_t invalid_raw_udp[] = { - 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, - 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, - 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, - 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, - 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, - 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, - 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0xc0, 0x27}; + uint8_t invalid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0xb7, 0x52, 0xc0, 0xa8, 0x01, 0x03, + 0xc0, 0xa8, 0x01, 0x06}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -7776,30 +5715,31 @@ int SigTest31NegativeUDPV4Keyword(void) DetectEngineThreadCtx *det_ctx = NULL; int result = 1; - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" - "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); memset(p2, 0, SIZE_OF_PACKET); - PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)raw_ipv4; - p1->udph = (UDPHdr *)valid_raw_udp; + PACKET_RESET_CHECKSUMS(p2); + + p1->ip4h = (IPV4Hdr *)valid_raw_ipv4; + p1->src.family = AF_INET; p1->dst.family = AF_INET; p1->payload = buf; - p1->payload_len = sizeof(valid_raw_udp) - UDP_HEADER_LEN; - p1->proto = IPPROTO_UDP; + p1->payload_len = buflen; + p1->proto = IPPROTO_TCP; + + p2->ip4h = (IPV4Hdr *)invalid_raw_ipv4; - PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)raw_ipv4; - p2->udph = (UDPHdr *)invalid_raw_udp; p2->src.family = AF_INET; p2->dst.family = AF_INET; p2->payload = buf; - p2->payload_len = sizeof(invalid_raw_udp) - UDP_HEADER_LEN; - p2->proto = IPPROTO_UDP; + p2->payload_len = buflen; + p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -7809,18 +5749,18 @@ int SigTest31NegativeUDPV4Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:invalid; " - "msg:\"udpv4-csum keyword check(1)\"; sid:1;)"); + "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:invalid; " + "msg:\"ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv4-csum:valid; " - "msg:\"udpv4-csum keyword check(1)\"; " + "alert ip any any -> any any " + "(content:\"/one/\"; ipv4-csum:valid; " + "msg:\"ipv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { result &= 0; @@ -7837,16 +5777,14 @@ int SigTest31NegativeUDPV4Keyword(void) result &= 1; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) { + if (PacketAlertCheck(p2, 2)) result &= 0; - } else result &= 1; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: SCFree(p1); @@ -7854,184 +5792,167 @@ int SigTest31NegativeUDPV4Keyword(void) return result; } - -int SigTest32UDPV6Keyword(void) +int SigTest26TCPV4Keyword(void) { - static uint8_t valid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, - 0x09, 0x00}; + uint8_t raw_ipv4[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, + 0xc0, 0xa8, 0x01, 0x03}; - static uint8_t invalid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, - 0x09, 0x01}; + uint8_t valid_raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, + 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + + uint8_t invalid_raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, + 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" - "\r\n\r\n"; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); memset(p2, 0, SIZE_OF_PACKET); + PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); + + PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); + PACKET_RESET_CHECKSUMS(p1); - p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); + p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); + p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = IPV6_GET_PLEN((p1)) - UDP_HEADER_LEN; - p1->proto = IPPROTO_UDP; + p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; + p1->payload_len = 20; + p1->proto = IPPROTO_TCP; PACKET_RESET_CHECKSUMS(p2); - p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); + p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); + p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); p2->src.family = AF_INET; p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = IPV6_GET_PLEN((p2)) - UDP_HEADER_LEN; - p2->proto = IPPROTO_UDP; + p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; + p2->payload_len = 20; + p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:valid; " - "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result &= 0; - goto end; - } + "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " + "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:invalid; " - "msg:\"udpv6-csum keyword check(1)\"; " + "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " + "msg:\"tcpv4-csum keyword check(1)\"; " "sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result &= 0; - goto end; - } + FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 1; - else - result &= 0; + FAIL_IF(!(PacketAlertCheck(p1, 1))); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 1; - else - result &= 0; + FAIL_IF(!(PacketAlertCheck(p2, 2))); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); - return result; + PASS; } -int SigTest33NegativeUDPV6Keyword(void) +/* Test SigTest26TCPV4Keyword but also check for invalid IPV4 checksum */ +static int SigTest26TCPV4AndNegativeIPV4Keyword(void) { - static uint8_t valid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, - 0x09, 0x00}; + uint8_t raw_ipv4[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, + 0xc0, 0xa8, 0x01, 0x03}; - static uint8_t invalid_raw_ipv6[] = { - 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, - 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, - 0x09, 0x01}; + uint8_t valid_raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, + 0x4A, 0x04, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + + uint8_t invalid_raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, + 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" - "\r\n\r\n"; + int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); memset(p2, 0, SIZE_OF_PACKET); + PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); + + PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); + PACKET_RESET_CHECKSUMS(p1); - p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); + p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); + p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = IPV6_GET_PLEN((p1)) - UDP_HEADER_LEN; - p1->proto = IPPROTO_UDP; + p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; + p1->payload_len = 20; + p1->proto = IPPROTO_TCP; PACKET_RESET_CHECKSUMS(p2); - p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); + p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); + p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); p2->src.family = AF_INET; p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = IPV6_GET_PLEN((p2)) - UDP_HEADER_LEN; - p2->proto = IPPROTO_UDP; + p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; + p2->payload_len = 20; + p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -8041,21 +5962,21 @@ int SigTest33NegativeUDPV6Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:invalid; " - "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); + "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " + "ipv4-csum:invalid; " + "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert udp any any -> any any " - "(content:\"/one/\"; udpv6-csum:valid; " - "msg:\"udpv6-csum keyword check(1)\"; " + "alert ip any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; " + "ipv4-csum:invalid; " + "msg:\"tcpv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result &= 0; goto end; } @@ -8063,95 +5984,101 @@ int SigTest33NegativeUDPV6Keyword(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 0; - else - result &= 1; + if (!(PacketAlertCheck(p1, 1))) { + printf("sig 1 didn't match: "); + goto end; + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 0; - else - result &= 1; + if (!(PacketAlertCheck(p2, 2))) { + printf("sig 2 didn't match: "); + goto end; + } + result = 1; +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); return result; } -int SigTest34ICMPV4Keyword(void) +/* Similar to SigTest26, but with different packet */ +static int SigTest26TCPV4AndIPV4Keyword(void) { - uint8_t valid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, - 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, - 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, - 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37}; + /* IPV4: src:192.168.176.67 dst: 192.168.176.116 + * TTL: 64 Flags: Don't Fragment + */ + uint8_t raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x40, 0x9b, 0xa4, 0x40, 0x00, + 0x40, 0x06, 0xbd, 0x0a, 0xc0, 0xa8, 0xb0, 0x43, + 0xc0, 0xa8, 0xb0, 0x74}; - uint8_t invalid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, - 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, - 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, - 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x38}; + /* TCP: sport: 49517 dport: 445 Flags: SYN + * Window size: 65535, checksum: 0x2009, + * MTU: 1460, Window scale: 4, TSACK permitted, + * 24 bytes of options, no payload. + */ + uint8_t valid_raw_tcp[] = { + 0xc1, 0x6d, 0x01, 0xbd, 0x03, 0x10, 0xd3, 0xc9, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xff, 0xff, + 0x20, 0x09, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x01, 0x03, 0x03, 0x04, 0x01, 0x01, 0x08, 0x0a, + 0x19, 0x69, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x02, 0x00, 0x00}; + + uint8_t invalid_raw_tcp[] = { + 0xc1, 0x6d, 0x01, 0xbd, 0x03, 0x10, 0xd3, 0xc9, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xff, 0xff, + 0x20, 0x09, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x01, 0x03, 0x03, 0x04, 0x01, 0x01, 0x08, 0x0a, + 0x19, 0x69, 0x81, 0x7e, 0xFF, 0xAA, 0x00, 0x00, + 0x04, 0x02, 0x00, 0x00}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p2 == NULL)) { SCFree(p1); return 0; } + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); + int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); memset(p2, 0, SIZE_OF_PACKET); + PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); + + PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); + PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); - p1->ip4h->ip_verhl = 69; - p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); + p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); + p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = buflen; - p1->proto = IPPROTO_ICMP; + p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20 + 24; + p1->payload_len = 0; + p1->proto = IPPROTO_TCP; PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); - p2->ip4h->ip_verhl = 69; - p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); + p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); + p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); p2->src.family = AF_INET; p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = buflen; - p2->proto = IPPROTO_ICMP; + p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20 + 24; + p2->payload_len = 0; + p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -8161,21 +6088,21 @@ int SigTest34ICMPV4Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:valid; " - "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); + "alert ip any any -> any any " + "(tcpv4-csum:valid; " + "ipv4-csum:valid; " + "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:invalid; " - "msg:\"icmpv4-csum keyword check(1)\"; " + "alert ip any any -> any any " + "(tcpv4-csum:invalid; " + "ipv4-csum:valid; " + "msg:\"tcpv4-csum and ipv4-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result = 0; goto end; } @@ -8183,55 +6110,49 @@ int SigTest34ICMPV4Keyword(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 1; - else - result &= 0; + if (!(PacketAlertCheck(p1, 1))) { + printf("sig 1 didn't match: "); + goto end; + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 1; - else - result &= 0; + if (!(PacketAlertCheck(p2, 2))) { + printf("sig 2 didn't match: "); + goto end; + } + result = 1; +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); return result; } -int SigTest35NegativeICMPV4Keyword(void) +static int SigTest27NegativeTCPV4Keyword(void) { - uint8_t valid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, - 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, - 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, - 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37}; + uint8_t raw_ipv4[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x8e, 0x7e, 0xb2, + 0xc0, 0xa8, 0x01, 0x03}; + + uint8_t valid_raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, + 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02}; + + uint8_t invalid_raw_tcp[] = { + 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, + 0xcf, 0x0d, 0x21, 0x80, 0x50, 0x12, 0x16, 0xa0, + 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, + 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, + 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x03}; - uint8_t invalid_raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, - 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, - 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, - 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, - 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x38}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -8243,35 +6164,35 @@ int SigTest35NegativeICMPV4Keyword(void) } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); + int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); memset(p2, 0, SIZE_OF_PACKET); + PacketCopyData(p1, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p1, GET_PKT_LEN(p1), valid_raw_tcp, sizeof(valid_raw_tcp)); + + PacketCopyData(p2, raw_ipv4, sizeof(raw_ipv4)); + PacketCopyDataOffset(p2, GET_PKT_LEN(p2), invalid_raw_tcp, sizeof(invalid_raw_tcp)); + PACKET_RESET_CHECKSUMS(p1); - p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); - p1->ip4h->ip_verhl = 69; - p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); + p1->ip4h = (IPV4Hdr *)GET_PKT_DATA(p1); + p1->tcph = (TCPHdr *)(GET_PKT_DATA(p1) + sizeof(raw_ipv4)); p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = buflen; - p1->proto = IPPROTO_ICMP; + p1->payload = (uint8_t *)GET_PKT_DATA(p1) + sizeof(raw_ipv4) + 20; + p1->payload_len = 20; + p1->proto = IPPROTO_TCP; PACKET_RESET_CHECKSUMS(p2); - p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); - p2->ip4h->ip_verhl = 69; - p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); + p2->ip4h = (IPV4Hdr *)GET_PKT_DATA(p2); + p2->tcph = (TCPHdr *)(GET_PKT_DATA(p2) + sizeof(raw_ipv4)); p2->src.family = AF_INET; p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = buflen; - p2->proto = IPPROTO_ICMP; + p2->payload = (uint8_t *)GET_PKT_DATA(p2) + sizeof(raw_ipv4) + 20; + p2->payload_len = 20; + p2->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -8281,21 +6202,19 @@ int SigTest35NegativeICMPV4Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:invalid; " - "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); + "alert tcp any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:invalid; dsize:20; " + "msg:\"tcpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert icmp any any -> any any " - "(content:\"/one/\"; icmpv4-csum:valid; " - "msg:\"icmpv4-csum keyword check(1)\"; " + "alert tcp any any -> any any " + "(content:\"|DE 01 03|\"; tcpv4-csum:valid; dsize:20; " + "msg:\"tcpv4-csum keyword check(2)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result &= 0; goto end; } @@ -8303,66 +6222,63 @@ int SigTest35NegativeICMPV4Keyword(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 0; - else - result &= 1; + if (!PacketAlertCheck(p1, 1)) { + printf("sig 1 didn't match on p1: "); + goto end; + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 0; - else { - result &= 1; + if (PacketAlertCheck(p2, 2)) { + printf("sig 2 matched on p2: "); + goto end; } + result = 1; +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); return result; } -int SigTest36ICMPV6Keyword(void) +int SigTest28TCPV6Keyword(void) { - uint8_t valid_raw_ipv6[] = { - 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, - 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, - 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, - 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, - 0x08, 0x00}; + static uint8_t valid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, - uint8_t invalid_raw_ipv6[] = { - 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, - 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, - 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, - 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, - 0x08, 0x01}; + 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, + 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, + 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, + 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, + + 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, + 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, + 0xf2, 0xf1, 0x00, 0x00, + + 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, + 0x00, 0x01, 0x69, 0x27}; + + static uint8_t invalid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, + + 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, + 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, + 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, + 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, + + 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, + 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, + 0xc2, 0xf1, 0x00, 0x00, + + 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, + 0x00, 0x01, 0x69, 0x28}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -8374,11 +6290,7 @@ int SigTest36ICMPV6Keyword(void) } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); + int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); @@ -8386,21 +6298,29 @@ int SigTest36ICMPV6Keyword(void) PACKET_RESET_CHECKSUMS(p1); p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->icmpv6h = (ICMPV6Hdr *) (valid_raw_ipv6 + 54); + p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = buflen; - p1->proto = IPPROTO_ICMPV6; + p1->payload = valid_raw_ipv6 + 54 + 20; + p1->payload_len = 12; + p1->proto = IPPROTO_TCP; + + if (TCP_GET_HLEN(p1) != 20) { + BUG_ON(1); + } PACKET_RESET_CHECKSUMS(p2); p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->icmpv6h = (ICMPV6Hdr *) (invalid_raw_ipv6 + 54); + p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = buflen; - p2->proto = IPPROTO_ICMPV6; + p2->payload = invalid_raw_ipv6 + 54 + 20;; + p2->payload_len = 12; + p2->proto = IPPROTO_TCP; + + if (TCP_GET_HLEN(p2) != 20) { + BUG_ON(1); + } DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -8410,21 +6330,19 @@ int SigTest36ICMPV6Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert icmpv6 any any -> any any " - "(content:\"/one/\"; icmpv6-csum:valid; " - "msg:\"icmpv6-csum keyword check(1)\"; sid:1;)"); + "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert icmpv6 any any -> any any " - "(content:\"/one/\"; icmpv6-csum:invalid; " - "msg:\"icmpv6-csum keyword check(1)\"; " + "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result &= 0; goto end; } @@ -8432,65 +6350,63 @@ int SigTest36ICMPV6Keyword(void) DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) - result &= 1; - else - result &= 0; + if (!(PacketAlertCheck(p1, 1))) { + printf("sid 1 didn't match on p1: "); + goto end; + } SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - if (PacketAlertCheck(p2, 2)) - result &= 1; - else - result &= 0; + if (!(PacketAlertCheck(p2, 2))) { + printf("sid 2 didn't match on p2: "); + goto end; + } + result = 1; +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); return result; } -int SigTest37NegativeICMPV6Keyword(void) +int SigTest29NegativeTCPV6Keyword(void) { - uint8_t valid_raw_ipv6[] = { - 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, - 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, - 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, - 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, - 0x08, 0x00}; + static uint8_t valid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, - uint8_t invalid_raw_ipv6[] = { - 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, - 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, - 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, - 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, - 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, - 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, - 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, - 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, - 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, - 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, - 0x08, 0x01}; + 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, + 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, + 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, + 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, + + 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, + 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, + 0xf2, 0xf1, 0x00, 0x00, + + 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, + 0x00, 0x01, 0x69, 0x27}; + + static uint8_t invalid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, + + 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x40, + 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, + 0x3f, 0xfe, 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, + 0x02, 0xc0, 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, + + 0x03, 0xfe, 0x00, 0x16, 0xd6, 0x76, 0xf5, 0x2d, + 0x0c, 0x7a, 0x08, 0x77, 0x50, 0x10, 0x21, 0x5c, + 0xc2, 0xf1, 0x00, 0x00, + + 0x01, 0x01, 0x08, 0x0a, 0x00, 0x08, 0xca, 0x5a, + 0x00, 0x01, 0x69, 0x28}; Packet *p1 = SCMalloc(SIZE_OF_PACKET); if (unlikely(p1 == NULL)) @@ -8502,11 +6418,7 @@ int SigTest37NegativeICMPV6Keyword(void) } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - - uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); + int result = 0; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); @@ -8514,21 +6426,29 @@ int SigTest37NegativeICMPV6Keyword(void) PACKET_RESET_CHECKSUMS(p1); p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); - p1->icmpv6h = (ICMPV6Hdr *) (valid_raw_ipv6 + 54); + p1->tcph = (TCPHdr *) (valid_raw_ipv6 + 54); p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = buf; - p1->payload_len = buflen; - p1->proto = IPPROTO_ICMPV6; + p1->payload = valid_raw_ipv6 + 54 + 20; + p1->payload_len = 12; + p1->proto = IPPROTO_TCP; + + if (TCP_GET_HLEN(p1) != 20) { + BUG_ON(1); + } PACKET_RESET_CHECKSUMS(p2); p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); - p2->icmpv6h = (ICMPV6Hdr *) (invalid_raw_ipv6 + 54); + p2->tcph = (TCPHdr *) (invalid_raw_ipv6 + 54); p2->src.family = AF_INET; p2->dst.family = AF_INET; - p2->payload = buf; - p2->payload_len = buflen; - p2->proto = IPPROTO_ICMPV6; + p2->payload = invalid_raw_ipv6 + 54 + 20;; + p2->payload_len = 12; + p2->proto = IPPROTO_TCP; + + if (TCP_GET_HLEN(p2) != 20) { + BUG_ON(1); + } DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -8538,21 +6458,20 @@ int SigTest37NegativeICMPV6Keyword(void) de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert icmpv6 any any -> any any " - "(content:\"/one/\"; icmpv6-csum:invalid; " - "msg:\"icmpv6-csum keyword check(1)\"; sid:1;)"); + "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:invalid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; " + "sid:1;)"); if (de_ctx->sig_list == NULL) { - result &= 0; goto end; } de_ctx->sig_list->next = SigInit(de_ctx, - "alert icmpv6 any any -> any any " - "(content:\"/one/\"; icmpv6-csum:valid; " - "msg:\"icmpv6-csum keyword check(1)\"; " + "alert tcp any any -> any any " + "(content:\"|00 01 69|\"; tcpv6-csum:valid; dsize:12; " + "msg:\"tcpv6-csum keyword check(1)\"; " "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result &= 0; goto end; } @@ -8561,650 +6480,531 @@ int SigTest37NegativeICMPV6Keyword(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); if (PacketAlertCheck(p1, 1)) - result &= 0; - else - result &= 1; + goto end; SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); if (PacketAlertCheck(p2, 2)) - result &= 0; - else - result &= 1; + goto end; + result = 1; +end: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: SCFree(p1); SCFree(p2); return result; } -int SigTest38Real(int mpm_type) +int SigTest30UDPV4Keyword(void) { - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - uint8_t raw_eth[] = { - 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00 - }; uint8_t raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, - 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, - 0x7f, 0x00, 0x00, 0x01 - }; - uint8_t raw_tcp[] = { - 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, - 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, - 0x01, 0x01, 0xfe, 0x71, 0x00, 0x00, 0x01, - 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, - 0x00, 0x22, 0xaa, 0x10 - }; - uint8_t buf[] = { - 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, - 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, - 0x20, 0x38, 0x0d, 0x0a, 0x66, 0x6f, 0x30, 0x30, /* LEN1|20| ends at 17 */ - 0x30, 0x38, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x32, /* "0008" at offset 5 */ - 0x20, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x0d, 0x0a, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, - 0x0a - }; - uint16_t ethlen = sizeof(raw_eth); - uint16_t ipv4len = sizeof(raw_ipv4); - uint16_t tcplen = sizeof(raw_tcp); - uint16_t buflen = sizeof(buf); - - memset(&th_v, 0, sizeof(ThreadVars)); - memset(p1, 0, SIZE_OF_PACKET); - - /* Copy raw data into packet */ - if (PacketCopyData(p1, raw_eth, ethlen) == -1) { - SCFree(p1); - return 1; - } - if (PacketCopyDataOffset(p1, ethlen, raw_ipv4, ipv4len) == -1) { - SCFree(p1); - return 1; - } - if (PacketCopyDataOffset(p1, ethlen + ipv4len, raw_tcp, tcplen) == -1) { - SCFree(p1); - return 1; - } - if (PacketCopyDataOffset(p1, ethlen + ipv4len + tcplen, buf, buflen) == -1) { - SCFree(p1); - return 1; - } - SET_PKT_LEN(p1, ethlen + ipv4len + tcplen + buflen); - - PACKET_RESET_CHECKSUMS(p1); - p1->ethh = (EthernetHdr *)raw_eth; - p1->ip4h = (IPV4Hdr *)raw_ipv4; - p1->tcph = (TCPHdr *)raw_tcp; - p1->src.family = AF_INET; - p1->dst.family = AF_INET; - p1->payload = GET_PKT_DATA(p1) + ethlen + ipv4len + tcplen; - p1->payload_len = buflen; - p1->proto = IPPROTO_TCP; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"LEN1|20|\"; " - "byte_test:4,=,8,0; " - "msg:\"byte_test keyword check(1)\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result &= 0; - goto end; - } - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"LEN1|20|\"; " - "byte_test:4,=,8,5,relative,string,dec; " - "msg:\"byte_test keyword check(2)\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result &= 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - result = 1; - } else { - result = 0; - printf("sid 1 didn't alert, but should have: "); - goto cleanup; - } - if (PacketAlertCheck(p1, 2)) { - result = 1; - } else { - result = 0; - printf("sid 2 didn't alert, but should have: "); - goto cleanup; - } - -cleanup: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, + 0xc0, 0xa8, 0x01, 0x03}; -end: - SCFree(p1); - return result; -} -static int SigTest38B2g (void) -{ - return SigTest38Real(MPM_B2G); -} -static int SigTest38B3g (void) -{ - return SigTest38Real(MPM_B3G); -} -static int SigTest38Wm (void) -{ - return SigTest38Real(MPM_WUMANBER); -} + uint8_t valid_raw_udp[] = { + 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, + 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, + 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0xc0, 0x26}; -int SigTest39Real(int mpm_type) -{ - Packet *p1 = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p1 == NULL)) - return 0; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 1; - uint8_t raw_eth[] = { - 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00 - }; - uint8_t raw_ipv4[] = { - 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, - 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, - 0x7f, 0x00, 0x00, 0x01 - }; - uint8_t raw_tcp[] = { - 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, - 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, - 0x01, 0x01, 0xfe, 0x71, 0x00, 0x00, 0x01, - 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, - 0x00, 0x22, 0xaa, 0x10 - }; - uint8_t buf[] = { - 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, - 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, - 0x20, 0x38, 0x0d, 0x0a, 0x66, 0x30, 0x30, 0x30, - 0x38, 0x72, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x32, - 0x20, 0x39, 0x39, 0x4c, 0x45, 0x4e, 0x32, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x0d, 0x0a, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, - 0x0a - }; - uint16_t ethlen = sizeof(raw_eth); - uint16_t ipv4len = sizeof(raw_ipv4); - uint16_t tcplen = sizeof(raw_tcp); - uint16_t buflen = sizeof(buf); + uint8_t invalid_raw_udp[] = { + 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, + 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, + 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0xc0, 0x27}; + + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p1); + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p2); + + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" + "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; memset(&th_v, 0, sizeof(ThreadVars)); memset(p1, 0, SIZE_OF_PACKET); - - /* Copy raw data into packet */ - if (PacketCopyData(p1, raw_eth, ethlen) == -1) { - SCFree(p1); - return 1; - } - if (PacketCopyDataOffset(p1, ethlen, raw_ipv4, ipv4len) == -1) { - SCFree(p1); - return 1; - } - if (PacketCopyDataOffset(p1, ethlen + ipv4len, raw_tcp, tcplen) == -1) { - SCFree(p1); - return 1; - } - if (PacketCopyDataOffset(p1, ethlen + ipv4len + tcplen, buf, buflen) == -1) { - SCFree(p1); - return 1; - } - SET_PKT_LEN(p1, ethlen + ipv4len + tcplen + buflen); + memset(p2, 0, SIZE_OF_PACKET); PACKET_RESET_CHECKSUMS(p1); - p1->ethh = (EthernetHdr *)raw_eth; p1->ip4h = (IPV4Hdr *)raw_ipv4; - p1->tcph = (TCPHdr *)raw_tcp; + p1->udph = (UDPHdr *)valid_raw_udp; p1->src.family = AF_INET; p1->dst.family = AF_INET; - p1->payload = GET_PKT_DATA(p1) + ethlen + ipv4len + tcplen; - p1->payload_len = buflen; - p1->proto = IPPROTO_TCP; + p1->payload = buf; + p1->payload_len = sizeof(valid_raw_udp) - UDP_HEADER_LEN; + p1->proto = IPPROTO_UDP; + + PACKET_RESET_CHECKSUMS(p2); + p2->ip4h = (IPV4Hdr *)raw_ipv4; + p2->udph = (UDPHdr *)invalid_raw_udp; + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = sizeof(invalid_raw_udp) - UDP_HEADER_LEN; + p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"LEN1|20|\"; " - "byte_test:4,=,8,0; " - "byte_jump:4,0; " - "byte_test:6,=,0x4c454e312038,0,relative; " - "msg:\"byte_jump keyword check(1)\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result &= 0; - goto end; - } - // XXX TODO + "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:valid; " + "msg:\"udpv4-csum keyword check(1)\"; " + "sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(content:\"LEN1|20|\"; " - "byte_test:4,=,8,4,relative,string,dec; " - "byte_jump:4,4,relative,string,dec,post_offset 2; " - "byte_test:4,=,0x4c454e32,0,relative; " - "msg:\"byte_jump keyword check(2)\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result &= 0; - goto end; - } + "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:invalid; " + "msg:\"udpv4-csum keyword check(1)\"; " + "sid:2;)"); + FAIL_IF_NULL(de_ctx->sig_list->next); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if (PacketAlertCheck(p1, 1)) { - result = 1; - } else { - result = 0; - printf("sid 1 didn't alert, but should have: "); - goto cleanup; - } - if (PacketAlertCheck(p1, 2)) { - result = 1; - } else { - result = 0; - printf("sid 2 didn't alert, but should have: "); - goto cleanup; - } + FAIL_IF_NOT(PacketAlertCheck(p1, 1)); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF_NOT(PacketAlertCheck(p2, 2)); -cleanup: SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); if (det_ctx != NULL) DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: SCFree(p1); - return result; -} -static int SigTest39B2g (void) -{ - return SigTest39Real(MPM_B2G); -} -static int SigTest39B3g (void) -{ - return SigTest39Real(MPM_B3G); -} -static int SigTest39Wm (void) -{ - return SigTest39Real(MPM_WUMANBER); + SCFree(p2); + PASS; } - - -/** - * \test SigTest36ContentAndIsdataatKeywords01 is a test to check window with constructed packets, - * \brief expecting to match a size - */ - -int SigTest36ContentAndIsdataatKeywords01Real (int mpm_type) +int SigTest31NegativeUDPV4Keyword(void) { - int result = 0; + uint8_t raw_ipv4[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd0, 0x43, 0xdc, 0xdc, + 0xc0, 0xa8, 0x01, 0x03}; - // Buid and decode the packet + uint8_t valid_raw_udp[] = { + 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, + 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, + 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0xc0, 0x26}; - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; + uint8_t invalid_raw_udp[] = { + 0x00, 0x35, 0xcf, 0x34, 0x00, 0x55, 0x6c, 0xe0, + 0x83, 0xfc, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x61, 0x67, + 0x65, 0x61, 0x64, 0x32, 0x11, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x73, 0x79, 0x6e, 0x64, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x03, 0x63, + 0x6f, 0x6d, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x4b, + 0x50, 0x00, 0x12, 0x06, 0x70, 0x61, 0x67, 0x65, + 0x61, 0x64, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0xc0, 0x27}; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) return 0; - DecodeThreadVars dtv; - + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p2 == NULL)) { + SCFree(p1); + return 0; + } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + int result = 1; - memset(p, 0, SIZE_OF_PACKET); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0yyyyyyyyyyyyyyyy\r\n" + "\r\n\r\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); + + PACKET_RESET_CHECKSUMS(p1); + p1->ip4h = (IPV4Hdr *)raw_ipv4; + p1->udph = (UDPHdr *)valid_raw_udp; + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = sizeof(valid_raw_udp) - UDP_HEADER_LEN; + p1->proto = IPPROTO_UDP; + PACKET_RESET_CHECKSUMS(p2); + p2->ip4h = (IPV4Hdr *)raw_ipv4; + p2->udph = (UDPHdr *)invalid_raw_udp; + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = sizeof(invalid_raw_udp) - UDP_HEADER_LEN; + p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest36ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:404, relative; sid:101;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - //PatternMatchPrepare(mpm_ctx, mpm_type); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 101) == 0) { - result = 0; - goto end; - } else { - result=1; - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); - DetectEngineCtxFree(de_ctx); - PACKET_RECYCLE(p); - FlowShutdown(); - - SCFree(p); - return result; - -end: - if(de_ctx) - { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + de_ctx->sig_list = SigInit(de_ctx, + "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:invalid; " + "msg:\"udpv4-csum keyword check(1)\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result &= 0; + goto end; } - if(det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - - //PatternMatchDestroy(mpm_ctx); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert udp any any -> any any " + "(content:\"/one/\"; udpv4-csum:valid; " + "msg:\"udpv4-csum keyword check(1)\"; " + "sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result &= 0; + goto end; + } - if(de_ctx) - DetectEngineCtxFree(de_ctx); + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - if (p != NULL) - PACKET_RECYCLE(p); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) + result &= 0; + else + result &= 1; - FlowShutdown(); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 2)) { + result &= 0; + } + else + result &= 1; - SCFree(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); +end: + SCFree(p1); + SCFree(p2); return result; } -/** - * \test SigTest37ContentAndIsdataatKeywords02 is a test to check window with constructed packets, - * \brief not expecting to match a size - */ - -int SigTest37ContentAndIsdataatKeywords02Real (int mpm_type) +int SigTest32UDPV6Keyword(void) { - int result = 0; - - // Buid and decode the packet + static uint8_t valid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, + 0x09, 0x00}; - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; + static uint8_t invalid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, + 0x09, 0x01}; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - DecodeThreadVars dtv; + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p1); + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p2); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - memset(p, 0, SIZE_OF_PACKET); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); + uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" + "\r\n\r\n"; - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); + + PACKET_RESET_CHECKSUMS(p1); + p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); + p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = IPV6_GET_PLEN((p1)) - UDP_HEADER_LEN; + p1->proto = IPPROTO_UDP; + PACKET_RESET_CHECKSUMS(p2); + p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); + p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = IPV6_GET_PLEN((p2)) - UDP_HEADER_LEN; + p2->proto = IPPROTO_UDP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; - Signature *s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest37ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:500, relative; sid:101;)"); - if (de_ctx->sig_list == NULL) { - printf("sig parse failed: "); - result = 0; - goto end; - } + de_ctx->sig_list = SigInit(de_ctx, + "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:valid; " + "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); + FAIL_IF_NULL(de_ctx->sig_list); + + de_ctx->sig_list->next = SigInit(de_ctx, + "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:invalid; " + "msg:\"udpv6-csum keyword check(1)\"; " + "sid:2;)"); + FAIL_IF_NULL(de_ctx->sig_list->next); - if (s->sm_lists[DETECT_SM_LIST_PMATCH]->type != DETECT_CONTENT) { - printf("type not content: "); - goto end; - } -/* - if (s->sm_lists[DETECT_SM_LIST_PMATCH]->next == NULL) { - printf("s->sm_lists[DETECT_SM_LIST_PMATCH]->next == NULL: "); - goto end; - } - if (s->sm_lists[DETECT_SM_LIST_PMATCH]->next->type != DETECT_ISDATAAT) { - printf("type not isdataat: "); - goto end; - } -*/ SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 101) == 0) { - result = 1; - goto end; - } else { - printf("sig matched, but should not have: "); - result=0; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketAlertCheck(p1, 1)); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + FAIL_IF_NOT(PacketAlertCheck(p2, 2)); SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - PACKET_RECYCLE(p); - FlowShutdown(); + SCFree(p1); + SCFree(p2); + PASS; +} - SCFree(p); - return result; +int SigTest33NegativeUDPV6Keyword(void) +{ + static uint8_t valid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, + 0x09, 0x00}; -end: - if(de_ctx) - { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + static uint8_t invalid_raw_ipv6[] = { + 0x00, 0x60, 0x97, 0x07, 0x69, 0xea, 0x00, 0x00, + 0x86, 0x05, 0x80, 0xda, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x02, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0xa0, 0x00, 0x14, 0x1a, 0xc3, 0x06, 0x02, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0x57, 0xb0, + 0x09, 0x01}; + + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p2 == NULL)) { + SCFree(p1); + return 0; + } + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 1; + + uint8_t *buf = (uint8_t *)"GET /one/ HTTP\r\n" + "\r\n\r\n"; + + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); + + PACKET_RESET_CHECKSUMS(p1); + p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); + p1->udph = (UDPHdr *) (valid_raw_ipv6 + 54); + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = IPV6_GET_PLEN((p1)) - UDP_HEADER_LEN; + p1->proto = IPPROTO_UDP; + + PACKET_RESET_CHECKSUMS(p2); + p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); + p2->udph = (UDPHdr *) (invalid_raw_ipv6 + 54); + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = IPV6_GET_PLEN((p2)) - UDP_HEADER_LEN; + p2->proto = IPPROTO_UDP; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; } - if(det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + de_ctx->flags |= DE_QUIET; - if(de_ctx) - DetectEngineCtxFree(de_ctx); + de_ctx->sig_list = SigInit(de_ctx, + "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:invalid; " + "msg:\"udpv6-csum keyword check(1)\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result &= 0; + goto end; + } - if (p != NULL) - PACKET_RECYCLE(p); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert udp any any -> any any " + "(content:\"/one/\"; udpv6-csum:valid; " + "msg:\"udpv6-csum keyword check(1)\"; " + "sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result &= 0; + goto end; + } - FlowShutdown(); + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - SCFree(p); - return result; -} + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) + result &= 0; + else + result &= 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 2)) + result &= 0; + else + result &= 1; -// Wrapper functions to pass the mpm_type -static int SigTest36ContentAndIsdataatKeywords01B2g (void) -{ - return SigTest36ContentAndIsdataatKeywords01Real(MPM_B2G); -} -static int SigTest36ContentAndIsdataatKeywords01B3g (void) -{ - return SigTest36ContentAndIsdataatKeywords01Real(MPM_B3G); -} -static int SigTest36ContentAndIsdataatKeywords01Wm (void) -{ - return SigTest36ContentAndIsdataatKeywords01Real(MPM_WUMANBER); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); +end: + SCFree(p1); + SCFree(p2); + return result; } -static int SigTest37ContentAndIsdataatKeywords02B2g (void) -{ - return SigTest37ContentAndIsdataatKeywords02Real(MPM_B2G); -} -static int SigTest37ContentAndIsdataatKeywords02B3g (void) -{ - return SigTest37ContentAndIsdataatKeywords02Real(MPM_B3G); -} -static int SigTest37ContentAndIsdataatKeywords02Wm (void) +int SigTest34ICMPV4Keyword(void) { - return SigTest37ContentAndIsdataatKeywords02Real(MPM_WUMANBER); -} - - -/** - * \test SigTest41NoPacketInspection is a test to check that when PKT_NOPACKET_INSPECTION - * flag is set, we don't need to inspect the packet protocol header or its contents. - */ + uint8_t valid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, + 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, + 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, + 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37}; -int SigTest40NoPacketInspection01(void) -{ + uint8_t invalid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, + 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, + 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, + 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x38}; - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - TCPHdr tcphdr; - if (unlikely(p == NULL)) - return 0; + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p2 == NULL)) { + SCFree(p1); + return 0; + } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - PacketQueue pq; - Flow f; - int result = 0; + int result = 1; - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - memset(&pq, 0, sizeof(pq)); - memset(&f, 0, sizeof(f)); - memset(&tcphdr, 0, sizeof(tcphdr)); + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); - p->src.family = AF_INET; - p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - p->dp = 34260; - p->sp = 21; - p->flowflags |= FLOW_PKT_TOSERVER; - p->flags |= PKT_NOPACKET_INSPECTION; - p->tcph = &tcphdr; - p->flow = &f; + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); - FLOW_INITIALIZE(&f); + PACKET_RESET_CHECKSUMS(p1); + p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); + p1->ip4h->ip_verhl = 69; + p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = buflen; + p1->proto = IPPROTO_ICMP; + + PACKET_RESET_CHECKSUMS(p2); + p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); + p2->ip4h->ip_verhl = 69; + p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = buflen; + p2->proto = IPPROTO_ICMP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -9213,119 +7013,247 @@ int SigTest40NoPacketInspection01(void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 any (msg:\"No Packet Inspection Test\"; flow:to_server; sid:2; rev:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:valid; " + "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { + result &= 0; + goto end; + } + + de_ctx->sig_list->next = SigInit(de_ctx, + "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:invalid; " + "msg:\"icmpv4-csum keyword check(1)\"; " + "sid:2;)"); + if (de_ctx->sig_list->next == NULL) { result = 0; goto end; } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - det_ctx->de_ctx = de_ctx; - Detect(&th_v, p, det_ctx, &pq, NULL); - if (PacketAlertCheck(p, 2)) - result = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) + result &= 1; else - result = 1; + result &= 0; + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 2)) + result &= 1; + else + result &= 0; SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - //PatternMatchDestroy(mpm_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: - SCFree(p); + SCFree(p1); + SCFree(p2); return result; } -/** - * \test SigTest42NoPayloadInspection is a test to check that when PKT_NOPAYLOAD_INSPECTION - * flasg is set, we don't need to inspect the packet contents. - */ - -int SigTest40NoPayloadInspection02(void) +int SigTest35NegativeICMPV4Keyword(void) { + uint8_t valid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, + 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, + 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, + 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37}; - uint8_t *buf = (uint8_t *) - "220 (vsFTPd 2.0.5)\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + uint8_t invalid_raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, + 0x40, 0x01, 0x3c, 0xa7, 0x7f, 0x00, 0x00, 0x01, + 0x7f, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc3, 0x01, + 0x2b, 0x36, 0x00, 0x01, 0x3f, 0x16, 0x9a, 0x4a, + 0x41, 0x63, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x38}; + + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p2 == NULL)) { + SCFree(p1); + return 0; + } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; int result = 1; - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; - p->flags |= PKT_NOPAYLOAD_INSPECTION; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); + + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); + + PACKET_RESET_CHECKSUMS(p1); + p1->ip4h = (IPV4Hdr *)(valid_raw_ipv4); + p1->ip4h->ip_verhl = 69; + p1->icmpv4h = (ICMPV4Hdr *) (valid_raw_ipv4 + IPV4_GET_RAW_HLEN(p1->ip4h) * 4); + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = buflen; + p1->proto = IPPROTO_ICMP; + + PACKET_RESET_CHECKSUMS(p2); + p2->ip4h = (IPV4Hdr *)(invalid_raw_ipv4); + p2->ip4h->ip_verhl = 69; + p2->icmpv4h = (ICMPV4Hdr *) (invalid_raw_ipv4 + IPV4_GET_RAW_HLEN(p2->ip4h) * 4); + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = buflen; + p2->proto = IPPROTO_ICMP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { - result = 0; goto end; } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"No Payload TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:invalid; " + "msg:\"icmpv4-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result = 0; + result &= 0; goto end; } - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - if (!(de_ctx->sig_list->init_flags & SIG_FLAG_INIT_PAYLOAD)) - result = 0; + de_ctx->sig_list->next = SigInit(de_ctx, + "alert icmp any any -> any any " + "(content:\"/one/\"; icmpv4-csum:valid; " + "msg:\"icmpv4-csum keyword check(1)\"; " + "sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result &= 0; + goto end; + } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); - if (PacketAlertCheck(p, 1)) + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) result &= 0; else result &= 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 2)) + result &= 0; + else { + result &= 1; + } + SigGroupCleanup(de_ctx); SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); end: - SCFree(p); + SCFree(p1); + SCFree(p2); return result; } -static int SigTestMemory01 (void) +int SigTest36ICMPV6Keyword(void) { - uint8_t *buf = (uint8_t *) - "GET /one/ HTTP/1.1\r\n" - "Host: one.example.org\r\n" - "\r\n\r\n" - "GET /two/ HTTP/1.1\r\n" - "Host: two.example.org\r\n" - "\r\n\r\n"; - uint16_t buflen = strlen((char *)buf); - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) + uint8_t valid_raw_ipv6[] = { + 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, + 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, + 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, + 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, + 0x08, 0x00}; + + uint8_t invalid_raw_ipv6[] = { + 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, + 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, + 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, + 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, + 0x08, 0x01}; + + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p2 == NULL)) { + SCFree(p1); return 0; + } ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; + int result = 1; - memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload = buf; - p->payload_len = buflen; - p->proto = IPPROTO_TCP; + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); + + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); + + PACKET_RESET_CHECKSUMS(p1); + p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); + p1->icmpv6h = (ICMPV6Hdr *) (valid_raw_ipv6 + 54); + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = buflen; + p1->proto = IPPROTO_ICMPV6; + + PACKET_RESET_CHECKSUMS(p2); + p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); + p2->icmpv6h = (ICMPV6Hdr *) (invalid_raw_ipv6 + 54); + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = buflen; + p2->proto = IPPROTO_ICMPV6; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -9334,85 +7262,252 @@ static int SigTestMemory01 (void) de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert icmpv6 any any -> any any " + "(content:\"/one/\"; icmpv6-csum:valid; " + "msg:\"icmpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result = 0; + result &= 0; + goto end; + } + + de_ctx->sig_list->next = SigInit(de_ctx, + "alert icmpv6 any any -> any any " + "(content:\"/one/\"; icmpv6-csum:invalid; " + "msg:\"icmpv6-csum keyword check(1)\"; " + "sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result &= 0; goto end; } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) + result &= 1; + else + result &= 0; -printf("@pre cleanup\n\n"); - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); - DetectPortPrintMemory(); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 2)) + result &= 1; + else + result &= 0; SigGroupCleanup(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + SigCleanSignatures(de_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -printf("@exit\n\n"); - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); - DetectPortPrintMemory(); - - result = 1; end: - SCFree(p); + SCFree(p1); + SCFree(p2); return result; } -static int SigTestMemory02 (void) +int SigTest37NegativeICMPV6Keyword(void) { + uint8_t valid_raw_ipv6[] = { + 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, + 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, + 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, + 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, + 0x08, 0x00}; + + uint8_t invalid_raw_ipv6[] = { + 0x00, 0x00, 0x86, 0x05, 0x80, 0xda, 0x00, 0x60, + 0x97, 0x07, 0x69, 0xea, 0x86, 0xdd, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x3a, 0x40, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x60, + 0x97, 0xff, 0xfe, 0x07, 0x69, 0xea, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x03, 0x00, + 0xf7, 0x52, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x11, 0x01, 0x3f, 0xfe, + 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x86, 0xff, 0xfe, 0x05, 0x80, 0xda, 0x3f, 0xfe, + 0x05, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02, 0xc0, + 0xdf, 0xff, 0xfe, 0x47, 0x03, 0x3e, 0xa0, 0x75, + 0x82, 0x9b, 0x00, 0x14, 0x82, 0x8b, 0x01, 0x01, + 0x00, 0x00, 0xf9, 0xc8, 0xe7, 0x36, 0xf5, 0xed, + 0x08, 0x01}; + + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; + Packet *p2 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p2 == NULL)) { + SCFree(p1); + return 0; + } ThreadVars th_v; - int result = 0; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 1; - memset(&th_v, 0, sizeof(th_v)); + uint8_t *buf = (uint8_t *)"GET /one/ HTTP/1.0\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); + + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + memset(p2, 0, SIZE_OF_PACKET); + + PACKET_RESET_CHECKSUMS(p1); + p1->ip6h = (IPV6Hdr *)(valid_raw_ipv6 + 14); + p1->icmpv6h = (ICMPV6Hdr *) (valid_raw_ipv6 + 54); + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = buf; + p1->payload_len = buflen; + p1->proto = IPPROTO_ICMPV6; + + PACKET_RESET_CHECKSUMS(p2); + p2->ip6h = (IPV6Hdr *)(invalid_raw_ipv6 + 14); + p2->icmpv6h = (ICMPV6Hdr *) (invalid_raw_ipv6 + 54); + p2->src.family = AF_INET; + p2->dst.family = AF_INET; + p2->payload = buf; + p2->payload_len = buflen; + p2->proto = IPPROTO_ICMPV6; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } + de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert icmpv6 any any -> any any " + "(content:\"/one/\"; icmpv6-csum:invalid; " + "msg:\"icmpv6-csum keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result = 0; + result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); + + de_ctx->sig_list->next = SigInit(de_ctx, + "alert icmpv6 any any -> any any " + "(content:\"/one/\"; icmpv6-csum:valid; " + "msg:\"icmpv6-csum keyword check(1)\"; " + "sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result = 0; + result &= 0; goto end; } SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); -printf("@cleanup\n\n"); - SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) + result &= 0; + else + result &= 1; -printf("@exit\n\n"); - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); - DetectPortPrintMemory(); -printf("@exit\n\n"); - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); - DetectPortPrintMemory(); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + if (PacketAlertCheck(p2, 2)) + result &= 0; + else + result &= 1; - result = 1; + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); end: + SCFree(p1); + SCFree(p2); return result; } -static int SigTestMemory03 (void) +static int SigTest38(void) { + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; ThreadVars th_v; - int result = 0; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 1; + uint8_t raw_eth[] = { + 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00 + }; + uint8_t raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, + 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, + 0x7f, 0x00, 0x00, 0x01 + }; + uint8_t raw_tcp[] = { + 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, + 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, + 0x01, 0x01, 0xfe, 0x71, 0x00, 0x00, 0x01, + 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, + 0x00, 0x22, 0xaa, 0x10 + }; + uint8_t buf[] = { + 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, + 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, + 0x20, 0x38, 0x0d, 0x0a, 0x66, 0x6f, 0x30, 0x30, /* LEN1|20| ends at 17 */ + 0x30, 0x38, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x32, /* "0008" at offset 5 */ + 0x20, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x0d, 0x0a, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, + 0x0a + }; + uint16_t ethlen = sizeof(raw_eth); + uint16_t ipv4len = sizeof(raw_ipv4); + uint16_t tcplen = sizeof(raw_tcp); + uint16_t buflen = sizeof(buf); - memset(&th_v, 0, sizeof(th_v)); + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); + + /* Copy raw data into packet */ + if (PacketCopyData(p1, raw_eth, ethlen) == -1) { + SCFree(p1); + return 1; + } + if (PacketCopyDataOffset(p1, ethlen, raw_ipv4, ipv4len) == -1) { + SCFree(p1); + return 1; + } + if (PacketCopyDataOffset(p1, ethlen + ipv4len, raw_tcp, tcplen) == -1) { + SCFree(p1); + return 1; + } + if (PacketCopyDataOffset(p1, ethlen + ipv4len + tcplen, buf, buflen) == -1) { + SCFree(p1); + return 1; + } + SET_PKT_LEN(p1, ethlen + ipv4len + tcplen + buflen); + + PACKET_RESET_CHECKSUMS(p1); + p1->ethh = (EthernetHdr *)raw_eth; + p1->ip4h = (IPV4Hdr *)raw_ipv4; + p1->tcph = (TCPHdr *)raw_tcp; + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = GET_PKT_DATA(p1) + ethlen + ipv4len + tcplen; + p1->payload_len = buflen; + p1->proto = IPPROTO_TCP; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { @@ -9420,803 +7515,682 @@ static int SigTestMemory03 (void) } de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(content:\"LEN1|20|\"; " + "byte_test:4,=,8,0; " + "msg:\"byte_test keyword check(1)\"; sid:1;)"); if (de_ctx->sig_list == NULL) { - result = 0; + result &= 0; goto end; } - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> 1.2.3.3-1.2.3.6 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any " + "(content:\"LEN1|20|\"; " + "byte_test:4,=,8,5,relative,string,dec; " + "msg:\"byte_test keyword check(2)\"; sid:2;)"); if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> !1.2.3.5 1:990 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; + result &= 0; goto end; } SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) { + result = 1; + } else { + result = 0; + printf("sid 1 didn't alert, but should have: "); + goto cleanup; + } + if (PacketAlertCheck(p1, 2)) { + result = 1; + } else { + result = 0; + printf("sid 2 didn't alert, but should have: "); + goto cleanup; + } -printf("@cleanup\n\n"); +cleanup: SigGroupCleanup(de_ctx); - DetectEngineCtxFree(de_ctx); + SigCleanSignatures(de_ctx); -printf("@exit\n\n"); - DetectSigGroupPrintMemory(); - DetectAddressPrintMemory(); - DetectPortPrintMemory(); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); - result = 1; end: + SCFree(p1); return result; } -static int SigTestSgh01 (void) +static int SigTest39(void) { + Packet *p1 = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p1 == NULL)) + return 0; ThreadVars th_v; - int result = 0; DetectEngineThreadCtx *det_ctx = NULL; - memset(&th_v, 0, sizeof(th_v)); - - Packet *p = NULL; - p = UTHBuildPacketSrcDstPorts((uint8_t *)"a", 1, IPPROTO_TCP, 12345, 80); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"1\"; content:\"one\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - if (de_ctx->sig_list->mpm_content_maxlen != 3) { - printf("de_ctx->sig_list->mpm_content_maxlen %u, expected 3: ", de_ctx->sig_list->mpm_content_maxlen); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two\"; content:\"abcd\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - if (de_ctx->sig_list->next->mpm_content_maxlen != 4) { - printf("de_ctx->sig_list->mpm_content_maxlen %u, expected 4: ", de_ctx->sig_list->next->mpm_content_maxlen); - goto end; - } - - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"3\"; content:\"three\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } - if (de_ctx->sig_list->next->next->mpm_content_maxlen != 5) { - printf("de_ctx->sig_list->next->next->mpm_content_maxlen %u, expected 5: ", de_ctx->sig_list->next->next->mpm_content_maxlen); - goto end; - } + int result = 1; + uint8_t raw_eth[] = { + 0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00 + }; + uint8_t raw_ipv4[] = { + 0x45, 0x00, 0x00, 0x7d, 0xd8, 0xf3, 0x40, 0x00, + 0x40, 0x06, 0x63, 0x85, 0x7f, 0x00, 0x00, 0x01, + 0x7f, 0x00, 0x00, 0x01 + }; + uint8_t raw_tcp[] = { + 0xad, 0x22, 0x04, 0x00, 0x16, 0x39, 0x72, + 0xe2, 0x16, 0x1f, 0x79, 0x84, 0x80, 0x18, + 0x01, 0x01, 0xfe, 0x71, 0x00, 0x00, 0x01, + 0x01, 0x08, 0x0a, 0x00, 0x22, 0xaa, 0x10, + 0x00, 0x22, 0xaa, 0x10 + }; + uint8_t buf[] = { + 0x00, 0x00, 0x00, 0x08, 0x62, 0x6f, 0x6f, 0x65, + 0x65, 0x6b, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x31, + 0x20, 0x38, 0x0d, 0x0a, 0x66, 0x30, 0x30, 0x30, + 0x38, 0x72, 0x0d, 0x0a, 0x4c, 0x45, 0x4e, 0x32, + 0x20, 0x39, 0x39, 0x4c, 0x45, 0x4e, 0x32, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x0d, 0x0a, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, + 0x0a + }; + uint16_t ethlen = sizeof(raw_eth); + uint16_t ipv4len = sizeof(raw_ipv4); + uint16_t tcplen = sizeof(raw_tcp); + uint16_t buflen = sizeof(buf); - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + memset(&th_v, 0, sizeof(ThreadVars)); + memset(p1, 0, SIZE_OF_PACKET); - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); -#endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; + /* Copy raw data into packet */ + if (PacketCopyData(p1, raw_eth, ethlen) == -1) { + SCFree(p1); + return 1; } - - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; + if (PacketCopyDataOffset(p1, ethlen, raw_ipv4, ipv4len) == -1) { + SCFree(p1); + return 1; } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; + if (PacketCopyDataOffset(p1, ethlen + ipv4len, raw_tcp, tcplen) == -1) { + SCFree(p1); + return 1; } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; + if (PacketCopyDataOffset(p1, ethlen + ipv4len + tcplen, buf, buflen) == -1) { + SCFree(p1); + return 1; } + SET_PKT_LEN(p1, ethlen + ipv4len + tcplen + buflen); - p->dp = 81; + PACKET_RESET_CHECKSUMS(p1); + p1->ethh = (EthernetHdr *)raw_eth; + p1->ip4h = (IPV4Hdr *)raw_ipv4; + p1->tcph = (TCPHdr *)raw_tcp; + p1->src.family = AF_INET; + p1->dst.family = AF_INET; + p1->payload = GET_PKT_DATA(p1) + ethlen + ipv4len + tcplen; + p1->payload_len = buflen; + p1->proto = IPPROTO_TCP; - SigGroupHead *sgh2 = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh2 == NULL) { - printf("no sgh2: "); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { goto end; } -#if 0 - if (!(SigGroupHeadContainsSigId(de_ctx, sgh2, 1))) { - printf("sgh2 doesn't have sid 1: "); + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, + "alert tcp any any -> any any " + "(content:\"LEN1|20|\"; " + "byte_test:4,=,8,0; " + "byte_jump:4,0; " + "byte_test:6,=,0x4c454e312038,0,relative; " + "msg:\"byte_jump keyword check(1)\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result &= 0; goto end; } -#endif - if (sgh2->sig_cnt != 1) { - printf("expected one sig, got %u in sgh2: ", sgh2->sig_cnt); + // XXX TODO + de_ctx->sig_list->next = SigInit(de_ctx, + "alert tcp any any -> any any " + "(content:\"LEN1|20|\"; " + "byte_test:4,=,8,4,relative,string,dec; " + "byte_jump:4,4,relative,string,dec,post_offset 2; " + "byte_test:4,=,0x4c454e32,0,relative; " + "msg:\"byte_jump keyword check(2)\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result &= 0; goto end; } - if (sgh2->match_array[0] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 2, should have (sgh2->match_array[0] %p, expected %p): ", - sgh2->match_array[0], de_ctx->sig_list->next); - goto end; - } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); -#if 0 - printf("-\n"); - printf("sgh2->mpm_content_maxlen %u\n", sgh2->mpm_content_maxlen); - printf("sgh2->mpm_uricontent_maxlen %u\n", sgh2->mpm_uricontent_maxlen); - printf("sgh2->sig_cnt %u\n", sgh2->sig_cnt); - printf("sgh2->sig_size %u\n", sgh2->sig_size); -#endif - if (sgh2->mpm_content_maxlen != 4) { - printf("sgh2->mpm_content_maxlen %u, expected 4: ", sgh2->mpm_content_maxlen); - goto end; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + if (PacketAlertCheck(p1, 1)) { + result = 1; + } else { + result = 0; + printf("sid 1 didn't alert, but should have: "); + goto cleanup; } - - if (sgh2->match_array[0] != de_ctx->sig_list->next) { - printf("sgh2 doesn't contain sid 2, should have: "); - goto end; + if (PacketAlertCheck(p1, 2)) { + result = 1; + } else { + result = 0; + printf("sid 2 didn't alert, but should have: "); + goto cleanup; } - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); +cleanup: SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - result = 1; end: + SCFree(p1); return result; } -static int SigTestSgh02 (void) +/** + * \test SigTest36ContentAndIsdataatKeywords01 is a test to check window with constructed packets, + * \brief expecting to match a size + */ + +static int SigTest36ContentAndIsdataatKeywords01 (void) { - ThreadVars th_v; int result = 0; + + // Buid and decode the packet + + uint8_t raw_eth [] = { + 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 + ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 + ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 + ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 + ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 + ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 + ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c + ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e + ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 + ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 + ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d + ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e + ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 + ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 + ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 + ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a + ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 + ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f + ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 + ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 + ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c + ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c + ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 + ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 + ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 + ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c + ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 + ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 + ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 + ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; + + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + DecodeThreadVars dtv; + + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; - Packet *p = NULL; - p = UTHBuildPacketSrcDstPorts((uint8_t *)"a", 1, IPPROTO_TCP, 12345, 80); + memset(p, 0, SIZE_OF_PACKET); + memset(&dtv, 0, sizeof(DecodeThreadVars)); memset(&th_v, 0, sizeof(th_v)); + FlowInitConfig(FLOW_QUIET); + DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } + de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 80:82 (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest36ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:404, relative; sid:101;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 81 (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> any 80:81 (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 101) == 0) { + result = 0; goto end; + } else { + result=1; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + PACKET_RECYCLE(p); + FlowShutdown(); - if (sgh->sig_cnt != 2) { - printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); - goto end; - } + SCFree(p); + return result; - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; +end: + if(de_ctx) + { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dp = 81; - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } + if(det_ctx) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } + //PatternMatchDestroy(mpm_ctx); - if (sgh->sig_cnt != 3) { - printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); - goto end; - } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 2, should have: "); - goto end; - } - if (sgh->match_array[2] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dp = 82; + if(de_ctx) + DetectEngineCtxFree(de_ctx); + + if (p != NULL) + PACKET_RECYCLE(p); + + FlowShutdown(); + + SCFree(p); + return result; +} + + +/** + * \test SigTest37ContentAndIsdataatKeywords02 is a test to check window with constructed packets, + * \brief not expecting to match a size + */ + +static int SigTest37ContentAndIsdataatKeywords02 (void) +{ + int result = 0; + + // Buid and decode the packet + + uint8_t raw_eth [] = { + 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 + ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 + ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 + ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 + ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 + ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 + ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c + ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e + ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 + ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 + ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d + ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e + ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 + ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 + ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 + ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a + ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 + ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f + ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 + ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 + ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c + ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c + ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 + ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 + ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 + ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c + ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 + ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 + ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 + ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; + + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + DecodeThreadVars dtv; + + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(p, 0, SIZE_OF_PACKET); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } + FlowInitConfig(FLOW_QUIET); + DecodeEthernet(&th_v, &dtv, p, raw_eth, sizeof(raw_eth), NULL); - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { goto end; } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->src.family = AF_INET6; - p->dst.family = AF_INET6; + de_ctx->flags |= DE_QUIET; - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); + Signature *s = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest37ContentAndIsdataatKeywords01 \"; content:\"HTTP\"; isdataat:500, relative; sid:101;)"); + if (de_ctx->sig_list == NULL) { + printf("sig parse failed: "); + result = 0; goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + if (s->sm_lists[DETECT_SM_LIST_PMATCH]->type != DETECT_CONTENT) { + printf("type not content: "); goto end; } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 101) == 0) { + result = 1; goto end; + } else { + printf("sig matched, but should not have: "); + result=0; } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - result = 1; + PACKET_RECYCLE(p); + FlowShutdown(); + + SCFree(p); + return result; + end: + if(de_ctx) + { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + } + + if(det_ctx) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + + if(de_ctx) + DetectEngineCtxFree(de_ctx); + + if (p != NULL) + PACKET_RECYCLE(p); + + FlowShutdown(); + + SCFree(p); return result; } -static int SigTestSgh03 (void) +/** + * \test SigTest41NoPacketInspection is a test to check that when PKT_NOPACKET_INSPECTION + * flag is set, we don't need to inspect the packet protocol header or its contents. + */ + +static int SigTest40NoPacketInspection01(void) { - ThreadVars th_v; - int result = 0; + + uint8_t *buf = (uint8_t *) + "220 (vsFTPd 2.0.5)\r\n"; + uint16_t buflen = strlen((char *)buf); Packet *p = SCMalloc(SIZE_OF_PACKET); + TCPHdr tcphdr; if (unlikely(p == NULL)) - return 0; + return 0; + ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; + PacketQueue pq; + Flow f; + int result = 0; memset(&th_v, 0, sizeof(th_v)); memset(p, 0, SIZE_OF_PACKET); + memset(&pq, 0, sizeof(pq)); + memset(&f, 0, sizeof(f)); + memset(&tcphdr, 0, sizeof(tcphdr)); + p->src.family = AF_INET; + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); p->dst.family = AF_INET; - p->payload_len = 1; + p->payload = buf; + p->payload_len = buflen; p->proto = IPPROTO_TCP; - p->dp = 80; - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); + p->dp = 34260; + p->sp = 21; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flags |= PKT_NOPACKET_INSPECTION; + p->tcph = &tcphdr; + p->flow = &f; + + FLOW_INITIALIZE(&f); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } + de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 any (msg:\"No Packet Inspection Test\"; flow:to_server; sid:2; rev:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.5 any (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.5 any (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } - - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } - - if (sgh->sig_cnt != 2) { - printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); - goto end; - } - - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } - - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.5"); - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh %p\n", sgh); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->sig_cnt != 3) { - printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); - goto end; - } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[2] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3 (%x): ", sgh->mpm_content_maxlen, p->dst.addr_data32[0]); - goto end; - } - - - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.6"); - - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } - - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); - goto end; - } + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx,(void *)&det_ctx); + det_ctx->de_ctx = de_ctx; - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } + Detect(&th_v, p, det_ctx, &pq, NULL); + if (PacketAlertCheck(p, 2)) + result = 0; + else + result = 1; - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + //PatternMatchDestroy(mpm_ctx); DetectEngineCtxFree(de_ctx); - - result = 1; end: SCFree(p); return result; } -static int SigTestSgh04 (void) +/** + * \test SigTest42NoPayloadInspection is a test to check that when PKT_NOPAYLOAD_INSPECTION + * flasg is set, we don't need to inspect the packet contents. + */ + +int SigTest40NoPayloadInspection02(void) { - ThreadVars th_v; - int result = 0; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - DetectEngineThreadCtx *det_ctx = NULL; + uint8_t *buf = (uint8_t *) + "220 (vsFTPd 2.0.5)\r\n"; + uint16_t buflen = strlen((char *)buf); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); + + Packet *p = SCMalloc(SIZE_OF_PACKET); + FAIL_IF_NULL(p); memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; p->dst.family = AF_INET; - p->payload_len = 1; + p->payload = buf; + p->payload_len = buflen; p->proto = IPPROTO_TCP; - p->dp = 80; - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); + p->flags |= PKT_NOPAYLOAD_INSPECTION; + DetectEngineThreadCtx *det_ctx = NULL; DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->num != 0) { - printf("internal id != 0: "); - goto end; - } - - de_ctx->sig_list->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.5 any (msg:\"2\"; content:\"two2\"; content:\"abcdef\"; sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->num != 1) { - printf("internal id != 1: "); - goto end; - } - de_ctx->sig_list->next->next = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.5 any (msg:\"3\"; content:\"three\"; content:\"abcdefgh\"; sid:3;)"); - if (de_ctx->sig_list->next->next == NULL) { - result = 0; - goto end; - } - if (de_ctx->sig_list->next->next->num != 2) { - printf("internal id != 2: "); - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"No Payload TEST\"; content:\"220 (vsFTPd 2.0.5)\"; sid:1;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1)); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + SCFree(p); + PASS; +} + +static int SigTestMemory01 (void) +{ + uint8_t *buf = (uint8_t *) + "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n" + "\r\n\r\n" + "GET /two/ HTTP/1.1\r\n" + "Host: two.example.org\r\n" + "\r\n\r\n"; + uint16_t buflen = strlen((char *)buf); + Packet *p = SCMalloc(SIZE_OF_PACKET); + if (unlikely(p == NULL)) + return 0; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; - if (sgh->match_array == NULL) { - printf("sgh->match_array == NULL: "); - goto end; - } + memset(&th_v, 0, sizeof(th_v)); + memset(p, 0, SIZE_OF_PACKET); + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = buf; + p->payload_len = buflen; + p->proto = IPPROTO_TCP; - if (sgh->sig_cnt != 2) { - printf("sgh sig cnt %u, expected 2: ", sgh->sig_cnt); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { goto end; } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have (sgh->match_array[0] %p, expected %p): ", sgh->match_array[0], de_ctx->sig_list); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.5"); + de_ctx->flags |= DE_QUIET; - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result = 0; goto end; } - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - if (sgh->sig_cnt != 3) { - printf("sgh sig cnt %u, expected 3: ", sgh->sig_cnt); - goto end; - } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } - if (sgh->match_array[1] != de_ctx->sig_list->next) { - printf("sgh doesn't contain sid 2, should have: "); - goto end; - } - if (sgh->match_array[2] != de_ctx->sig_list->next->next) { - printf("sgh doesn't contain sid 3, should have: "); - goto end; - } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.6"); + SigGroupCleanup(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } + result = 1; +end: + SCFree(p); + return result; +} - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); - goto end; - } +static int SigTestMemory02 (void) +{ + ThreadVars th_v; + int result = 0; - if (sgh->sig_cnt != 1) { - printf("sgh sig cnt %u, expected 1: ", sgh->sig_cnt); - goto end; - } + memset(&th_v, 0, sizeof(th_v)); - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { goto end; } -#if 0 - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - p->proto = IPPROTO_GRE; + de_ctx->flags |= DE_QUIET; - sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + result = 0; goto end; } -#if 0 - printf("-\n"); - printf("sgh->mpm_content_maxlen %u\n", sgh->mpm_content_maxlen); - printf("sgh->mpm_uricontent_maxlen %u\n", sgh->mpm_uricontent_maxlen); - printf("sgh->sig_cnt %u\n", sgh->sig_cnt); - printf("sgh->sig_size %u\n", sgh->sig_size); - printf("sgh->refcnt %u\n", sgh->refcnt); -#endif - if (sgh->mpm_content_maxlen != 3) { - printf("sgh->mpm_content_maxlen %u, expected 3: ", sgh->mpm_content_maxlen); + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> any 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; goto end; } - if (sgh->match_array[0] != de_ctx->sig_list) { - printf("sgh doesn't contain sid 1, should have: "); - goto end; - } + SigGroupBuild(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: - SCFree(p); return result; } -/** \test setting of mpm type */ -static int SigTestSgh05 (void) +static int SigTestMemory03 (void) { ThreadVars th_v; int result = 0; - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; - DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); - memset(p, 0, SIZE_OF_PACKET); - p->src.family = AF_INET; - p->dst.family = AF_INET; - p->payload_len = 1; - p->proto = IPPROTO_TCP; - p->dp = 80; - p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); if (de_ctx == NULL) { goto end; } de_ctx->flags |= DE_QUIET; - de_ctx->mpm_matcher = MPM_WUMANBER; - de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> 1.2.3.4-1.2.3.6 any (msg:\"1\"; content:\"one\"; content:\"1\"; sid:1;)"); + de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> 1.2.3.4 456 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:1;)"); if (de_ctx->sig_list == NULL) { result = 0; goto end; } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, det_ctx, p); - if (sgh == NULL) { - printf("no sgh: "); - goto end; - } - - if (sgh->mpm_proto_tcp_ctx_ts != NULL || sgh->mpm_proto_tcp_ctx_tc != NULL || - sgh->mpm_proto_udp_ctx_ts != NULL || sgh->mpm_proto_udp_ctx_tc != NULL || - sgh->mpm_proto_other_ctx != NULL) { - printf("sgh->mpm_proto_tcp_ctx_ts != NULL || sgh->mpm_proto_tcp_ctx_tc != NULL" - "sgh->mpm_proto_udp_ctx_ts != NULL || sgh->mpm_proto_udp_ctx_tc != NULL" - "sgh->mpm_proto_other_ctx != NULL: "); + de_ctx->sig_list->next = SigInit(de_ctx,"alert tcp any any -> 1.2.3.3-1.2.3.6 1:1000 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:2;)"); + if (de_ctx->sig_list->next == NULL) { + result = 0; goto end; } - - if (sgh->mpm_stream_ctx_ts == NULL || sgh->mpm_stream_ctx_tc == NULL) { - printf("sgh->mpm_stream_ctx == NULL || sgh->mpm_stream_ctx_tc == NULL: "); + de_ctx->sig_list->next->next = SigInit(de_ctx,"alert tcp any any -> !1.2.3.5 1:990 (msg:\"HTTP URI cap\"; content:\"GET \"; depth:4; pcre:\"/GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; sid:3;)"); + if (de_ctx->sig_list->next->next == NULL) { + result = 0; goto end; } - if (sgh->mpm_stream_ctx_ts->mpm_type != MPM_WUMANBER) { - printf("sgh->mpm_type != MPM_WUMANBER, expected %d, got %d: ", MPM_WUMANBER, sgh->mpm_stream_ctx_ts->mpm_type); - goto end; - } + SigGroupBuild(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); SigGroupCleanup(de_ctx); DetectEngineCtxFree(de_ctx); result = 1; end: - SCFree(p); return result; } -static int SigTestContent01Real (int mpm_type) +static int SigTestContent01 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); @@ -10233,8 +8207,6 @@ static int SigTestContent01Real (int mpm_type) if (de_ctx == NULL) { goto end; } - - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); @@ -10261,20 +8233,8 @@ static int SigTestContent01Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent01B2g (void) -{ - return SigTestContent01Real(MPM_B2G); -} -static int SigTestContent01B3g (void) -{ - return SigTestContent01Real(MPM_B3G); -} -static int SigTestContent01Wm (void) -{ - return SigTestContent01Real(MPM_WUMANBER); -} -static int SigTestContent02Real (int mpm_type) +static int SigTestContent02 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901"; uint16_t buflen = strlen((char *)buf); @@ -10290,8 +8250,6 @@ static int SigTestContent02Real (int mpm_type) if (de_ctx == NULL) { goto end; } - - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; sid:1;)"); @@ -10328,20 +8286,8 @@ static int SigTestContent02Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent02B2g (void) -{ - return SigTestContent02Real(MPM_B2G); -} -static int SigTestContent02B3g (void) -{ - return SigTestContent02Real(MPM_B3G); -} -static int SigTestContent02Wm (void) -{ - return SigTestContent02Real(MPM_WUMANBER); -} -static int SigTestContent03Real (int mpm_type) +static int SigTestContent03 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10358,7 +8304,6 @@ static int SigTestContent03Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; sid:1;)"); @@ -10385,20 +8330,8 @@ static int SigTestContent03Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent03B2g (void) -{ - return SigTestContent03Real(MPM_B2G); -} -static int SigTestContent03B3g (void) -{ - return SigTestContent03Real(MPM_B3G); -} -static int SigTestContent03Wm (void) -{ - return SigTestContent03Real(MPM_WUMANBER); -} -static int SigTestContent04Real (int mpm_type) +static int SigTestContent04 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10416,7 +8349,6 @@ static int SigTestContent04Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); @@ -10443,21 +8375,9 @@ static int SigTestContent04Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent04B2g (void) -{ - return SigTestContent04Real(MPM_B2G); -} -static int SigTestContent04B3g (void) -{ - return SigTestContent04Real(MPM_B3G); -} -static int SigTestContent04Wm (void) -{ - return SigTestContent04Real(MPM_WUMANBER); -} /** \test sigs with patterns at the limit of the pm's size limit */ -static int SigTestContent05Real (int mpm_type) +static int SigTestContent05 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901PADabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10475,7 +8395,6 @@ static int SigTestContent05Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Test 32\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); @@ -10518,20 +8437,8 @@ static int SigTestContent05Real (int mpm_type) } return result; } -static int SigTestContent05B2g (void) -{ - return SigTestContent05Real(MPM_B2G); -} -static int SigTestContent05B3g (void) -{ - return SigTestContent05Real(MPM_B3G); -} -static int SigTestContent05Wm (void) -{ - return SigTestContent05Real(MPM_WUMANBER); -} -static int SigTestContent06Real (int mpm_type) +static int SigTestContent06 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10548,7 +8455,6 @@ static int SigTestContent06Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Test 32 sig1\"; content:\"01234567890123456789012345678901\"; content:\"abcdefghijklmnopqrstuvwxyzABCDEF\"; distance:0; within:32; sid:1;)"); @@ -10589,20 +8495,8 @@ static int SigTestContent06Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestContent06B2g (void) -{ - return SigTestContent06Real(MPM_B2G); -} -static int SigTestContent06B3g (void) -{ - return SigTestContent06Real(MPM_B3G); -} -static int SigTestContent06Wm (void) -{ - return SigTestContent06Real(MPM_WUMANBER); -} -static int SigTestWithinReal01 (int mpm_type) +static int SigTestWithin01 (void) { DecodeThreadVars dtv; ThreadVars th_v; @@ -10712,7 +8606,6 @@ static int SigTestWithinReal01 (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"within test\"; content:\"Hi, this is a big test to check \"; content:\"content matches\"; distance:0; within:15; sid:556;)"); @@ -10816,20 +8709,7 @@ static int SigTestWithinReal01 (int mpm_type) return result; } -static int SigTestWithinReal01B2g (void) -{ - return SigTestWithinReal01(MPM_B2G); -} -static int SigTestWithinReal01B3g (void) -{ - return SigTestWithinReal01(MPM_B3G); -} -static int SigTestWithinReal01Wm (void) -{ - return SigTestWithinReal01(MPM_WUMANBER); -} - -static int SigTestDepthOffset01Real (int mpm_type) +static int SigTestDepthOffset01 (void) { uint8_t *buf = (uint8_t *)"01234567890123456789012345678901abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; uint16_t buflen = strlen((char *)buf); @@ -10847,7 +8727,6 @@ static int SigTestDepthOffset01Real (int mpm_type) goto end; } - de_ctx->mpm_matcher = mpm_type; de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"depth offset\"; content:\"456\"; offset:4; depth:3; sid:1;)"); @@ -10872,76 +8751,49 @@ static int SigTestDepthOffset01Real (int mpm_type) UTHFreePackets(&p, 1); return result; } -static int SigTestDepthOffset01B2g (void) -{ - return SigTestDepthOffset01Real(MPM_B2G); -} -static int SigTestDepthOffset01B3g (void) -{ - return SigTestDepthOffset01Real(MPM_B3G); -} -static int SigTestDepthOffset01Wm (void) -{ - return SigTestDepthOffset01Real(MPM_WUMANBER); -} static int SigTestDetectAlertCounter(void) { Packet *p = NULL; ThreadVars tv; DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - memset(&tv, 0, sizeof(tv)); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - - de_ctx->mpm_matcher = MPM_B2G; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test counter\"; " "content:\"boo\"; sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto end; - } + FAIL_IF(de_ctx->sig_list == NULL); SigGroupBuild(de_ctx); - tv.name = "detect_test"; + strlcpy(tv.name, "detect_test", sizeof(tv.name)); DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); - /* init counters */ - tv.sc_perf_pca = SCPerfGetAllCountersArray(&tv.sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv.thread_group_name != NULL) ? - tv.thread_group_name : tv.name, &tv.sc_perf_pctx); + StatsSetupPrivate(&tv); p = UTHBuildPacket((uint8_t *)"boo", strlen("boo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result = (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 1); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 1); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"roo", strlen("roo"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 2); UTHFreePackets(&p, 1); p = UTHBuildPacket((uint8_t *)"laboosa", strlen("laboosa"), IPPROTO_TCP); Detect(&tv, p, det_ctx, NULL, NULL); - result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 3); + FAIL_IF_NOT(StatsGetLocalCounterValue(&tv, det_ctx->counter_alerts) == 3); UTHFreePackets(&p, 1); -end: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** \test test if the engine set flag to drop pkts of a flow that @@ -10985,7 +8837,6 @@ static int SigTestDropFlow01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop http any any -> any any " @@ -10998,14 +8849,15 @@ static int SigTestDropFlow01(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -11088,7 +8940,6 @@ static int SigTestDropFlow02(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " @@ -11101,14 +8952,15 @@ static int SigTestDropFlow02(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -11210,7 +9062,6 @@ static int SigTestDropFlow03(void) goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " @@ -11232,14 +9083,15 @@ static int SigTestDropFlow03(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -11265,7 +9117,7 @@ static int SigTestDropFlow03(void) SCLogDebug("This flow/stream triggered a drop rule"); FlowSetNoPacketInspectionFlag(p2->flow); DecodeSetNoPacketInspectionFlag(p2); - FlowSetSessionNoApplayerInspectionFlag(p2->flow); + StreamTcpDisableAppLayer(p2->flow); p2->action |= ACTION_DROP; /* return the segments to the pool */ StreamTcpSessionPktFree(p2); @@ -11277,14 +9129,15 @@ static int SigTestDropFlow03(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -11382,7 +9235,6 @@ static int SigTestDropFlow04(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 " @@ -11404,14 +9256,15 @@ static int SigTestDropFlow04(void) SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - SCMutexLock(&f.m); - int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + FLOWLOCK_WRLOCK(&f); + int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf1, http_buf1_len); if (r != 0) { printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); http_state = f.alstate; if (http_state == NULL) { @@ -11448,7 +9301,7 @@ static int SigTestDropFlow04(void) if (StreamTcpCheckFlowDrops(p2) == 1) { FlowSetNoPacketInspectionFlag(p2->flow); DecodeSetNoPacketInspectionFlag(p2); - FlowSetSessionNoApplayerInspectionFlag(p2->flow); + StreamTcpDisableAppLayer(p2->flow); p2->action |= ACTION_DROP; /* return the segments to the pool */ StreamTcpSessionPktFree(p2); @@ -11459,14 +9312,15 @@ static int SigTestDropFlow04(void) goto end; } - SCMutexLock(&f.m); - r = AppLayerParserParse(alp_tctx, &f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len); + FLOWLOCK_WRLOCK(&f); + r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_HTTP, + STREAM_TOSERVER, http_buf2, http_buf2_len); if (r != 0) { printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); goto end; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); /* do detect */ SigMatchSignatures(&tv, de_ctx, det_ctx, p2); @@ -11528,7 +9382,6 @@ static int SigTestPorts01(void) if (de_ctx == NULL) { goto end; } - de_ctx->mpm_matcher = MPM_B2G; de_ctx->flags |= DE_QUIET; s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any 80 " @@ -11561,6 +9414,65 @@ static int SigTestPorts01(void) return result; } +/** \test almost identical patterns */ +static int SigTestBug01(void) +{ + int result = 0; + Packet *p1 = NULL; + Signature *s = NULL; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + uint8_t payload[] = "!mymy"; + + memset(&tv, 0, sizeof(ThreadVars)); + + p1 = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->flags |= DE_QUIET; + + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(content:\"Omymy\"; nocase; sid:1;)"); + if (s == NULL) { + goto end; + } + s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " + "(content:\"!mymy\"; nocase; sid:2;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p1); + + if (PacketAlertCheck(p1, 1)) { + printf("sig 1 alerted on p1, but it should not: "); + goto end; + } + if (!(PacketAlertCheck(p1, 2))) { + printf("sig 2 did not p1, but it should have: "); + goto end; + } + + result = 1; +end: + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&tv, det_ctx); + if (de_ctx != NULL) + SigGroupCleanup(de_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + UTHFreePackets(&p1, 1); + return result; +} + static const char *dummy_conf_string2 = "%YAML 1.1\n" "---\n" @@ -11757,141 +9669,67 @@ void SigRegisterTests(void) SigParseRegisterTests(); IPOnlyRegisterTests(); - UtRegisterTest("SigTest01B2g -- HTTP URI cap", SigTest01B2g, 1); - UtRegisterTest("SigTest01B3g -- HTTP URI cap", SigTest01B3g, 1); - UtRegisterTest("SigTest01Wm -- HTTP URI cap", SigTest01Wm, 1); - - UtRegisterTest("SigTest02B2g -- Offset/Depth match", SigTest02B2g, 1); - UtRegisterTest("SigTest02B3g -- Offset/Depth match", SigTest02B3g, 1); - UtRegisterTest("SigTest02Wm -- Offset/Depth match", SigTest02Wm, 1); - - UtRegisterTest("SigTest03B2g -- offset/depth mismatch", SigTest03B2g, 1); - UtRegisterTest("SigTest03B3g -- offset/depth mismatch", SigTest03B3g, 1); - UtRegisterTest("SigTest03Wm -- offset/depth mismatch", SigTest03Wm, 1); - - UtRegisterTest("SigTest04B2g -- distance/within match", SigTest04B2g, 1); - UtRegisterTest("SigTest04B3g -- distance/within match", SigTest04B3g, 1); - UtRegisterTest("SigTest04Wm -- distance/within match", SigTest04Wm, 1); - - UtRegisterTest("SigTest05B2g -- distance/within mismatch", SigTest05B2g, 1); - UtRegisterTest("SigTest05B3g -- distance/within mismatch", SigTest05B3g, 1); - UtRegisterTest("SigTest05Wm -- distance/within mismatch", SigTest05Wm, 1); - - UtRegisterTest("SigTest06B2g -- uricontent HTTP/1.1 match test", SigTest06B2g, 1); - UtRegisterTest("SigTest06B3g -- uricontent HTTP/1.1 match test", SigTest06B3g, 1); - UtRegisterTest("SigTest06wm -- uricontent HTTP/1.1 match test", SigTest06Wm, 1); - - UtRegisterTest("SigTest07B2g -- uricontent HTTP/1.1 mismatch test", SigTest07B2g, 1); - UtRegisterTest("SigTest07B3g -- uricontent HTTP/1.1 mismatch test", SigTest07B3g, 1); - UtRegisterTest("SigTest07Wm -- uricontent HTTP/1.1 mismatch test", SigTest07Wm, 1); - - UtRegisterTest("SigTest08B2g -- uricontent HTTP/1.0 match test", SigTest08B2g, 1); - UtRegisterTest("SigTest08B3g -- uricontent HTTP/1.0 match test", SigTest08B3g, 1); - UtRegisterTest("SigTest08Wm -- uricontent HTTP/1.0 match test", SigTest08Wm, 1); - - UtRegisterTest("SigTest09B2g -- uricontent HTTP/1.0 mismatch test", SigTest09B2g, 1); - UtRegisterTest("SigTest09B3g -- uricontent HTTP/1.0 mismatch test", SigTest09B3g, 1); - UtRegisterTest("SigTest09Wm -- uricontent HTTP/1.0 mismatch test", SigTest09Wm, 1); - - UtRegisterTest("SigTest10B2g -- long content match, longer than pkt", SigTest10B2g, 1); - UtRegisterTest("SigTest10B3g -- long content match, longer than pkt", SigTest10B3g, 1); - UtRegisterTest("SigTest10Wm -- long content match, longer than pkt", SigTest10Wm, 1); - - UtRegisterTest("SigTest11B2g -- mpm searching", SigTest11B2g, 1); - UtRegisterTest("SigTest11B3g -- mpm searching", SigTest11B3g, 1); - UtRegisterTest("SigTest11Wm -- mpm searching", SigTest11Wm, 1); - - UtRegisterTest("SigTest12B2g -- content order matching, normal", SigTest12B2g, 1); - UtRegisterTest("SigTest12B3g -- content order matching, normal", SigTest12B3g, 1); - UtRegisterTest("SigTest12Wm -- content order matching, normal", SigTest12Wm, 1); - - UtRegisterTest("SigTest13B2g -- content order matching, diff order", SigTest13B2g, 1); - UtRegisterTest("SigTest13B3g -- content order matching, diff order", SigTest13B3g, 1); - UtRegisterTest("SigTest13Wm -- content order matching, diff order", SigTest13Wm, 1); - - UtRegisterTest("SigTest14B2g -- content order matching, distance 0", SigTest14B2g, 1); - UtRegisterTest("SigTest14B3g -- content order matching, distance 0", SigTest14B3g, 1); - UtRegisterTest("SigTest14Wm -- content order matching, distance 0", SigTest14Wm, 1); - - UtRegisterTest("SigTest15B2g -- port negation sig (no match)", SigTest15B2g, 1); - UtRegisterTest("SigTest15B3g -- port negation sig (no match)", SigTest15B3g, 1); - UtRegisterTest("SigTest15Wm -- port negation sig (no match)", SigTest15Wm, 1); - - UtRegisterTest("SigTest16B2g -- port negation sig (match)", SigTest16B2g, 1); - UtRegisterTest("SigTest16B3g -- port negation sig (match)", SigTest16B3g, 1); - UtRegisterTest("SigTest16Wm -- port negation sig (match)", SigTest16Wm, 1); - - UtRegisterTest("SigTest17B2g -- HTTP Host Pkt var capture", SigTest17B2g, 1); - UtRegisterTest("SigTest17B3g -- HTTP Host Pkt var capture", SigTest17B3g, 1); - UtRegisterTest("SigTest17Wm -- HTTP Host Pkt var capture", SigTest17Wm, 1); - - UtRegisterTest("SigTest18B2g -- Ftp negation sig test", SigTest18B2g, 1); - UtRegisterTest("SigTest18B3g -- Ftp negation sig test", SigTest18B3g, 1); - UtRegisterTest("SigTest18Wm -- Ftp negation sig test", SigTest18Wm, 1); - - UtRegisterTest("SigTest19B2g -- IP-ONLY test (1)", SigTest19B2g, 1); - UtRegisterTest("SigTest19B3g -- IP-ONLY test (1)", SigTest19B3g, 1); - UtRegisterTest("SigTest19Wm -- IP-ONLY test (1)", SigTest19Wm, 1); - - UtRegisterTest("SigTest20B2g -- IP-ONLY test (2)", SigTest20B2g, 1); - UtRegisterTest("SigTest20B3g -- IP-ONLY test (2)", SigTest20B3g, 1); - UtRegisterTest("SigTest20Wm -- IP-ONLY test (2)", SigTest20Wm, 1); - - UtRegisterTest("SigTest21B2g -- FLOWBIT test (1)", SigTest21B2g, 1); - UtRegisterTest("SigTest21B3g -- FLOWBIT test (1)", SigTest21B3g, 1); - UtRegisterTest("SigTest21Wm -- FLOWBIT test (1)", SigTest21Wm, 1); - - UtRegisterTest("SigTest22B2g -- FLOWBIT test (2)", SigTest22B2g, 1); - UtRegisterTest("SigTest22B3g -- FLOWBIT test (2)", SigTest22B3g, 1); - UtRegisterTest("SigTest22Wm -- FLOWBIT test (2)", SigTest22Wm, 1); - - UtRegisterTest("SigTest23B2g -- FLOWBIT test (3)", SigTest23B2g, 1); - UtRegisterTest("SigTest23B3g -- FLOWBIT test (3)", SigTest23B3g, 1); - UtRegisterTest("SigTest23Wm -- FLOWBIT test (3)", SigTest23Wm, 1); - - UtRegisterTest("SigTest24IPV4Keyword", SigTest24IPV4Keyword, 1); + UtRegisterTest("SigTest01", SigTest01); + UtRegisterTest("SigTest02 -- Offset/Depth match", SigTest02); + UtRegisterTest("SigTest03 -- offset/depth mismatch", SigTest03); + UtRegisterTest("SigTest04 -- distance/within match", SigTest04); + UtRegisterTest("SigTest05 -- distance/within mismatch", SigTest05); + UtRegisterTest("SigTest06 -- uricontent HTTP/1.1 match test", SigTest06); + UtRegisterTest("SigTest07 -- uricontent HTTP/1.1 mismatch test", + SigTest07); + UtRegisterTest("SigTest08 -- uricontent HTTP/1.0 match test", SigTest08); + UtRegisterTest("SigTest09 -- uricontent HTTP/1.0 mismatch test", + SigTest09); + UtRegisterTest("SigTest10 -- long content match, longer than pkt", + SigTest10); + UtRegisterTest("SigTest11 -- mpm searching", SigTest11); + UtRegisterTest("SigTest12 -- content order matching, normal", SigTest12); + UtRegisterTest("SigTest13 -- content order matching, diff order", + SigTest13); + UtRegisterTest("SigTest14 -- content order matching, distance 0", + SigTest14); + UtRegisterTest("SigTest15 -- port negation sig (no match)", SigTest15); + UtRegisterTest("SigTest16 -- port negation sig (match)", SigTest16); + UtRegisterTest("SigTest17 -- HTTP Host Pkt var capture", SigTest17); + UtRegisterTest("SigTest18 -- Ftp negation sig test", SigTest18); + UtRegisterTest("SigTest19 -- IP-ONLY test (1)", SigTest19); + UtRegisterTest("SigTest20 -- IP-ONLY test (2)", SigTest20); + UtRegisterTest("SigTest21 -- FLOWBIT test (1)", SigTest21); + UtRegisterTest("SigTest22 -- FLOWBIT test (2)", SigTest22); + UtRegisterTest("SigTest23 -- FLOWBIT test (3)", SigTest23); + + UtRegisterTest("SigTest24IPV4Keyword", SigTest24IPV4Keyword); UtRegisterTest("SigTest25NegativeIPV4Keyword", - SigTest25NegativeIPV4Keyword, 1); + SigTest25NegativeIPV4Keyword); - UtRegisterTest("SigTest26TCPV4Keyword", SigTest26TCPV4Keyword, 1); - UtRegisterTest("SigTest26TCPV4AndNegativeIPV4Keyword", SigTest26TCPV4AndNegativeIPV4Keyword, 1); - UtRegisterTest("SigTest26TCPV4AndIPV4Keyword", SigTest26TCPV4AndIPV4Keyword, 1); + UtRegisterTest("SigTest26TCPV4Keyword", SigTest26TCPV4Keyword); + UtRegisterTest("SigTest26TCPV4AndNegativeIPV4Keyword", + SigTest26TCPV4AndNegativeIPV4Keyword); + UtRegisterTest("SigTest26TCPV4AndIPV4Keyword", + SigTest26TCPV4AndIPV4Keyword); UtRegisterTest("SigTest27NegativeTCPV4Keyword", - SigTest27NegativeTCPV4Keyword, 1); + SigTest27NegativeTCPV4Keyword); - UtRegisterTest("SigTest28TCPV6Keyword", SigTest28TCPV6Keyword, 1); + UtRegisterTest("SigTest28TCPV6Keyword", SigTest28TCPV6Keyword); UtRegisterTest("SigTest29NegativeTCPV6Keyword", - SigTest29NegativeTCPV6Keyword, 1); + SigTest29NegativeTCPV6Keyword); - UtRegisterTest("SigTest30UDPV4Keyword", SigTest30UDPV4Keyword, 1); + UtRegisterTest("SigTest30UDPV4Keyword", SigTest30UDPV4Keyword); UtRegisterTest("SigTest31NegativeUDPV4Keyword", - SigTest31NegativeUDPV4Keyword, 1); + SigTest31NegativeUDPV4Keyword); - UtRegisterTest("SigTest32UDPV6Keyword", SigTest32UDPV6Keyword, 1); + UtRegisterTest("SigTest32UDPV6Keyword", SigTest32UDPV6Keyword); UtRegisterTest("SigTest33NegativeUDPV6Keyword", - SigTest33NegativeUDPV6Keyword, 1); + SigTest33NegativeUDPV6Keyword); - UtRegisterTest("SigTest34ICMPV4Keyword", SigTest34ICMPV4Keyword, 1); + UtRegisterTest("SigTest34ICMPV4Keyword", SigTest34ICMPV4Keyword); UtRegisterTest("SigTest35NegativeICMPV4Keyword", - SigTest35NegativeICMPV4Keyword, 1); - - /* The following tests check content options with isdataat options - relative to that content match - */ - - UtRegisterTest("SigTest36ContentAndIsdataatKeywords01B2g", - SigTest36ContentAndIsdataatKeywords01B2g, 1); - UtRegisterTest("SigTest36ContentAndIsdataatKeywords01B3g", - SigTest36ContentAndIsdataatKeywords01B3g, 1); - UtRegisterTest("SigTest36ContentAndIsdataatKeywords01Wm" , - SigTest36ContentAndIsdataatKeywords01Wm, 1); - - UtRegisterTest("SigTest37ContentAndIsdataatKeywords02B2g", - SigTest37ContentAndIsdataatKeywords02B2g, 1); - UtRegisterTest("SigTest37ContentAndIsdataatKeywords02B3g", - SigTest37ContentAndIsdataatKeywords02B3g, 1); - UtRegisterTest("SigTest37ContentAndIsdataatKeywords02Wm" , - SigTest37ContentAndIsdataatKeywords02Wm, 1); + SigTest35NegativeICMPV4Keyword); + + UtRegisterTest("SigTest36ContentAndIsdataatKeywords01", + SigTest36ContentAndIsdataatKeywords01); + UtRegisterTest("SigTest37ContentAndIsdataatKeywords02", + SigTest37ContentAndIsdataatKeywords02); /* We need to enable these tests, as soon as we add the ICMPv6 protocol support in our rules engine */ @@ -11899,74 +9737,50 @@ void SigRegisterTests(void) //UtRegisterTest("SigTest37NegativeICMPV6Keyword", // SigTest37NegativeICMPV6Keyword, 1); - UtRegisterTest("SigTest38B2g -- byte_test test (1)", SigTest38B2g, 1); - UtRegisterTest("SigTest38B3g -- byte_test test (1)", SigTest38B3g, 1); - UtRegisterTest("SigTest38Wm -- byte_test test (1)", SigTest38Wm, 1); - - UtRegisterTest("SigTest39B2g -- byte_jump test (2)", SigTest39B2g, 1); - UtRegisterTest("SigTest39B3g -- byte_jump test (2)", SigTest39B3g, 1); - UtRegisterTest("SigTest39Wm -- byte_jump test (2)", SigTest39Wm, 1); + UtRegisterTest("SigTest38 -- byte_test test (1)", SigTest38); - UtRegisterTest("SigTest40NoPacketInspection01", SigTest40NoPacketInspection01, 1); - UtRegisterTest("SigTest40NoPayloadInspection02", SigTest40NoPayloadInspection02, 1); + UtRegisterTest("SigTest39 -- byte_jump test (2)", SigTest39); - UtRegisterTest("SigTestMemory01", SigTestMemory01, 1); - UtRegisterTest("SigTestMemory02", SigTestMemory02, 1); - UtRegisterTest("SigTestMemory03", SigTestMemory03, 1); + UtRegisterTest("SigTest40NoPacketInspection01", + SigTest40NoPacketInspection01); + UtRegisterTest("SigTest40NoPayloadInspection02", + SigTest40NoPayloadInspection02); - UtRegisterTest("SigTestSgh01", SigTestSgh01, 1); - UtRegisterTest("SigTestSgh02", SigTestSgh02, 1); - UtRegisterTest("SigTestSgh03", SigTestSgh03, 1); - UtRegisterTest("SigTestSgh04", SigTestSgh04, 1); - UtRegisterTest("SigTestSgh05", SigTestSgh05, 1); + UtRegisterTest("SigTestMemory01", SigTestMemory01); + UtRegisterTest("SigTestMemory02", SigTestMemory02); + UtRegisterTest("SigTestMemory03", SigTestMemory03); - UtRegisterTest("SigTestContent01B2g -- 32 byte pattern", SigTestContent01B2g, 1); - UtRegisterTest("SigTestContent01B3g -- 32 byte pattern", SigTestContent01B3g, 1); - UtRegisterTest("SigTestContent01Wm -- 32 byte pattern", SigTestContent01Wm, 1); + UtRegisterTest("SigTestContent01 -- 32 byte pattern", SigTestContent01); + UtRegisterTest("SigTestContent02 -- 32+31 byte pattern", SigTestContent02); + UtRegisterTest("SigTestContent03 -- 32 byte pattern, x2 + distance", + SigTestContent03); + UtRegisterTest("SigTestContent04 -- 32 byte pattern, x2 + distance/within", + SigTestContent04); + UtRegisterTest("SigTestContent05 -- distance/within", SigTestContent05); + UtRegisterTest("SigTestContent06 -- distance/within ip only", + SigTestContent06); - UtRegisterTest("SigTestContent02B2g -- 32+31 byte pattern", SigTestContent02B2g, 1); - UtRegisterTest("SigTestContent02B3g -- 32+31 byte pattern", SigTestContent02B3g, 1); - UtRegisterTest("SigTestContent02Wm -- 32+31 byte pattern", SigTestContent02Wm, 1); + UtRegisterTest("SigTestWithinReal01", SigTestWithin01); + UtRegisterTest("SigTestDepthOffset01", SigTestDepthOffset01); - UtRegisterTest("SigTestContent03B2g -- 32 byte pattern, x2 + distance", SigTestContent03B2g, 1); - UtRegisterTest("SigTestContent03B3g -- 32 byte pattern, x2 + distance", SigTestContent03B3g, 1); - UtRegisterTest("SigTestContent03Wm -- 32 byte pattern, x2 + distance", SigTestContent03Wm, 1); + UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter); - UtRegisterTest("SigTestContent04B2g -- 32 byte pattern, x2 + distance/within", SigTestContent04B2g, 1); - UtRegisterTest("SigTestContent04B3g -- 32 byte pattern, x2 + distance/within", SigTestContent04B3g, 1); - UtRegisterTest("SigTestContent04Wm -- 32 byte pattern, x2 + distance/within", SigTestContent04Wm, 1); + UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01); + UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02); + UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03); + UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04); - UtRegisterTest("SigTestContent05B2g -- distance/within", SigTestContent05B2g, 1); - UtRegisterTest("SigTestContent05B3g -- distance/within", SigTestContent05B3g, 1); - UtRegisterTest("SigTestContent05Wm -- distance/within", SigTestContent05Wm, 1); + UtRegisterTest("DetectAddressYamlParsing01", DetectAddressYamlParsing01); + UtRegisterTest("DetectAddressYamlParsing02", DetectAddressYamlParsing02); + UtRegisterTest("DetectAddressYamlParsing03", DetectAddressYamlParsing03); + UtRegisterTest("DetectAddressYamlParsing04", DetectAddressYamlParsing04); - UtRegisterTest("SigTestContent06B2g -- distance/within ip only", SigTestContent06B2g, 1); - UtRegisterTest("SigTestContent06B3g -- distance/within ip only", SigTestContent06B3g, 1); - UtRegisterTest("SigTestContent06Wm -- distance/within ip only", SigTestContent06Wm, 1); - - UtRegisterTest("SigTestWithinReal01B2g", SigTestWithinReal01B2g, 1); - UtRegisterTest("SigTestWithinReal01B3g", SigTestWithinReal01B3g, 1); - UtRegisterTest("SigTestWithinReal01Wm", SigTestWithinReal01Wm, 1); - - UtRegisterTest("SigTestDepthOffset01B2g", SigTestDepthOffset01B2g, 1); - UtRegisterTest("SigTestDepthOffset01B3g", SigTestDepthOffset01B3g, 1); - UtRegisterTest("SigTestDepthOffset01Wm", SigTestDepthOffset01Wm, 1); - - UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1); - - UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01, 1); - UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02, 1); - UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03, 1); - UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04, 1); - - UtRegisterTest("DetectAddressYamlParsing01", DetectAddressYamlParsing01, 1); - UtRegisterTest("DetectAddressYamlParsing02", DetectAddressYamlParsing02, 1); - UtRegisterTest("DetectAddressYamlParsing03", DetectAddressYamlParsing03, 1); - UtRegisterTest("DetectAddressYamlParsing04", DetectAddressYamlParsing04, 1); - - UtRegisterTest("SigTestPorts01", SigTestPorts01, 1); + UtRegisterTest("SigTestPorts01", SigTestPorts01); + UtRegisterTest("SigTestBug01", SigTestBug01); +#if 0 DetectSimdRegisterTests(); +#endif #endif /* UNITTESTS */ } diff --git a/src/detect.h b/src/detect.h index a3a7d4a7defc..93b52bd3c541 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -30,19 +30,24 @@ #include "detect-engine-proto.h" #include "detect-reference.h" - #include "packet-queue.h" + +#include "util-prefilter.h" #include "util-mpm.h" +#include "util-spm.h" #include "util-hash.h" #include "util-hashlist.h" #include "util-debug.h" #include "util-error.h" #include "util-radix-tree.h" #include "util-file.h" +#include "reputation.h" #include "detect-mark.h" -#define COUNTER_DETECT_ALERTS 1 +#include "stream.h" + +#include "util-var-name.h" #define DETECT_MAX_RULE_SIZE 8192 @@ -84,57 +89,32 @@ struct SCSigSignatureWrapper_; enum DetectSigmatchListEnum { DETECT_SM_LIST_MATCH = 0, DETECT_SM_LIST_PMATCH, - /* list for http_uri keyword and the ones relative to it */ - DETECT_SM_LIST_UMATCH, - /* list for http_raw_uri keyword and the ones relative to it */ - DETECT_SM_LIST_HRUDMATCH, - /* list for http_client_body keyword and the ones relative to it */ - DETECT_SM_LIST_HCBDMATCH, - /* list for http_server_body keyword and the ones relative to it */ - DETECT_SM_LIST_HSBDMATCH, - /* list for http_header keyword and the ones relative to it */ - DETECT_SM_LIST_HHDMATCH, - /* list for http_raw_header keyword and the ones relative to it */ - DETECT_SM_LIST_HRHDMATCH, - /* list for http_stat_msg keyword and the ones relative to it */ - DETECT_SM_LIST_HSMDMATCH, - /* list for http_stat_code keyword and the ones relative to it */ - DETECT_SM_LIST_HSCDMATCH, - /* list for http_host keyword and the ones relative to it */ - DETECT_SM_LIST_HHHDMATCH, - /* list for http_raw_host keyword and the ones relative to it */ - DETECT_SM_LIST_HRHHDMATCH, - /* list for http_method keyword and the ones relative to it */ - DETECT_SM_LIST_HMDMATCH, - /* list for http_cookie keyword and the ones relative to it */ - DETECT_SM_LIST_HCDMATCH, - /* list for http_user_agent keyword and the ones relative to it */ - DETECT_SM_LIST_HUADMATCH, - /* app event engine sm list */ - DETECT_SM_LIST_APP_EVENT, - - DETECT_SM_LIST_AMATCH, - DETECT_SM_LIST_DMATCH, - DETECT_SM_LIST_TMATCH, - - DETECT_SM_LIST_FILEMATCH, - - DETECT_SM_LIST_DNSQUERY_MATCH, + + /* base64_data keyword uses some hardcoded logic so consider + * built-in + * TODO convert to inspect engine */ + DETECT_SM_LIST_BASE64_DATA, /* list for post match actions: flowbit set, flowint increment, etc */ DETECT_SM_LIST_POSTMATCH, + DETECT_SM_LIST_TMATCH, /**< post-detection tagging */ + /* lists for alert thresholding and suppression */ DETECT_SM_LIST_SUPPRESS, DETECT_SM_LIST_THRESHOLD, + DETECT_SM_LIST_MAX, - /* used for Signature->list, which indicates which list - * we're adding keywords to in cases of sticky buffers like - * file_data */ - DETECT_SM_LIST_NOTSET, + /* start of dynamically registered lists */ + DETECT_SM_LIST_DYNAMIC_START = DETECT_SM_LIST_MAX, }; +/* used for Signature->list, which indicates which list + * we're adding keywords to in cases of sticky buffers like + * file_data */ +#define DETECT_SM_LIST_NOTSET INT_MAX + /* a is ... than b */ enum { ADDRESS_ER = -1, /**< error e.g. compare ipv4 and ipv6 */ @@ -150,11 +130,6 @@ enum { #define ADDRESS_FLAG_ANY 0x01 /**< address is "any" */ #define ADDRESS_FLAG_NOT 0x02 /**< address is negated */ -#define ADDRESS_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr to another sgh */ -#define ADDRESS_PORTS_COPY 0x08 /**< ports are a ptr to other ports */ -#define ADDRESS_PORTS_NOTUNIQ 0x10 -#define ADDRESS_HAVEPORT 0x20 /**< address has a ports ptr */ - /** \brief address structure for use in the detection engine. * * Contains the address information and matching information. @@ -163,18 +138,6 @@ typedef struct DetectAddress_ { /** address data for this group */ Address ip; Address ip2; -// uint8_t family; /**< address family, AF_INET (IPv4) or AF_INET6 (IPv6) */ -// uint32_t ip[4]; /**< the address, or lower end of a range */ -// uint32_t ip2[4]; /**< higher end of a range */ - - /** ptr to the next address (dst addr in that case) or to the src port */ - union { - struct DetectAddressHead_ *dst_gh; /**< destination address */ - struct DetectPort_ *port; /**< source port */ - }; - - /** signatures that belong in this group */ - struct SigGroupHead_ *sh; /** flags affecting this address */ uint8_t flags; @@ -183,8 +146,6 @@ typedef struct DetectAddress_ { struct DetectAddress_ *prev; /** ptr to the next address in the list */ struct DetectAddress_ *next; - - uint32_t cnt; } DetectAddress; /** Signature grouping head. Here 'any', ipv4 and ipv6 are split out */ @@ -226,27 +187,23 @@ enum { #define PORT_FLAG_ANY 0x01 /**< 'any' special port */ #define PORT_FLAG_NOT 0x02 /**< negated port */ #define PORT_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr copy */ -#define PORT_GROUP_PORTS_COPY 0x08 /**< dst_ph is a ptr copy */ /** \brief Port structure for detection engine */ typedef struct DetectPort_ { uint16_t port; uint16_t port2; - /* signatures that belong in this group */ - struct SigGroupHead_ *sh; + uint8_t flags; /**< flags for this port */ - struct DetectPort_ *dst_ph; + /* signatures that belong in this group + * + * If the PORT_SIGGROUPHEAD_COPY flag is set, we don't own this pointer + * (memory is freed elsewhere). + */ + struct SigGroupHead_ *sh; - /* double linked list */ - union { - struct DetectPort_ *prev; - struct DetectPort_ *hnext; /* hash next */ - }; + struct DetectPort_ *prev; struct DetectPort_ *next; - - uint32_t cnt; - uint8_t flags; /**< flags for this port */ } DetectPort; /* Signature flags */ @@ -265,12 +222,7 @@ typedef struct DetectPort_ { #define SIG_FLAG_REQUIRE_PACKET (1<<9) /**< signature is requiring packet match */ #define SIG_FLAG_REQUIRE_STREAM (1<<10) /**< signature is requiring stream match */ -#define SIG_FLAG_MPM_PACKET (1<<11) -#define SIG_FLAG_MPM_PACKET_NEG (1<<12) -#define SIG_FLAG_MPM_STREAM (1<<13) -#define SIG_FLAG_MPM_STREAM_NEG (1<<14) -#define SIG_FLAG_MPM_APPLAYER (1<<15) -#define SIG_FLAG_MPM_APPLAYER_NEG (1<<16) +#define SIG_FLAG_MPM_NEG (1<<11) #define SIG_FLAG_REQUIRE_FLOWVAR (1<<17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ @@ -281,13 +233,20 @@ typedef struct DetectPort_ { #define SIG_FLAG_TLSSTORE (1<<21) +#define SIG_FLAG_BYPASS (1<<22) + +#define SIG_FLAG_PREFILTER (1<<23) /**< sig is part of a prefilter engine */ + +/** Proto detect only signature. + * Inspected once per direction when protocol detection is done. */ +#define SIG_FLAG_PDONLY (1<<24) + /* signature init flags */ #define SIG_FLAG_INIT_DEONLY 1 /**< decode event only signature */ #define SIG_FLAG_INIT_PACKET (1<<1) /**< signature has matches against a packet (as opposed to app layer) */ #define SIG_FLAG_INIT_FLOW (1<<2) /**< signature has a flow setting */ #define SIG_FLAG_INIT_BIDIREC (1<<3) /**< signature has bidirectional operator */ -#define SIG_FLAG_INIT_PAYLOAD (1<<4) /**< signature is inspecting the packet payload */ -#define SIG_FLAG_INIT_FIRST_IPPROTO_SEEN (1 << 5) /** < signature has seen the first ip_proto keyword */ +#define SIG_FLAG_INIT_FIRST_IPPROTO_SEEN (1 << 4) /** < signature has seen the first ip_proto keyword */ /* signature mask flags */ #define SIG_MASK_REQUIRE_PAYLOAD (1<<0) @@ -298,21 +257,28 @@ typedef struct DetectPort_ { #define SIG_MASK_REQUIRE_HTTP_STATE (1<<5) #define SIG_MASK_REQUIRE_DCE_STATE (1<<6) #define SIG_MASK_REQUIRE_ENGINE_EVENT (1<<7) +#define SIG_MASK_REQUIRE_SSH_STATE (1<<8) +#define SIG_MASK_REQUIRE_TLS_STATE (1<<9) +#define SIG_MASK_REQUIRE_DNS_STATE (1<<10) +#define SIG_MASK_REQUIRE_FTP_STATE (1<<11) +#define SIG_MASK_REQUIRE_SMTP_STATE (1<<12) +#define SIG_MASK_REQUIRE_TEMPLATE_STATE (1<<13) +#define SIG_MASK_REQUIRE_ENIP_STATE (1<<14) +#define SIG_MASK_REQUIRE_DNP3_STATE (1<<15) /* for now a uint8_t is enough */ -#define SignatureMask uint8_t +#define SignatureMask uint16_t -#define DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET 0x0001 -#define DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM 0x0002 #define DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH 0x0004 #define FILE_SIG_NEED_FILE 0x01 #define FILE_SIG_NEED_FILENAME 0x02 -#define FILE_SIG_NEED_TYPE 0x04 -#define FILE_SIG_NEED_MAGIC 0x08 /**< need the start of the file */ -#define FILE_SIG_NEED_FILECONTENT 0x10 -#define FILE_SIG_NEED_MD5 0x20 -#define FILE_SIG_NEED_SIZE 0x40 +#define FILE_SIG_NEED_MAGIC 0x04 /**< need the start of the file */ +#define FILE_SIG_NEED_FILECONTENT 0x08 +#define FILE_SIG_NEED_MD5 0x10 +#define FILE_SIG_NEED_SHA1 0x20 +#define FILE_SIG_NEED_SHA256 0x40 +#define FILE_SIG_NEED_SIZE 0x80 /* Detection Engine flags */ #define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ @@ -320,12 +286,12 @@ typedef struct DetectPort_ { typedef struct IPOnlyCIDRItem_ { /* address data for this item */ uint8_t family; - uint32_t ip[4]; /* netmask in CIDR values (ex. /16 /18 /24..) */ uint8_t netmask; - /* If this host or net is negated for the signum */ uint8_t negated; + + uint32_t ip[4]; SigIntId signum; /**< our internal id */ /* linked list, the header should be the biggest network */ @@ -333,117 +299,153 @@ typedef struct IPOnlyCIDRItem_ { } IPOnlyCIDRItem; -/** \brief Subset of the Signature for cache efficient prefiltering +/** \brief Used to start a pointer to SigMatch context + * Should never be dereferenced without casting to something else. */ -typedef struct SignatureHeader_ { - union { - struct { - /* coccinelle: SignatureHeader:flags:SIG_FLAG */ - uint32_t flags; - AppProto alproto; - uint16_t dsize_low; - }; - uint64_t hdr_copy1; - }; - union { - struct { - uint16_t dsize_high; - uint16_t mpm_pattern_id_div_8; - }; - uint32_t hdr_copy2; - }; - union { - struct { - uint8_t mpm_pattern_id_mod_8; - SignatureMask mask; - SigIntId num; /**< signature number, internal id */ - }; - uint32_t hdr_copy3; - }; - /** pointer to the full signature */ - struct Signature_ *full_sig; -} SignatureHeader; +typedef struct SigMatchCtx_ { + int foo; +} SigMatchCtx; /** \brief a single match condition for a signature */ typedef struct SigMatch_ { - uint16_t idx; /**< position in the signature */ uint8_t type; /**< match type */ - void *ctx; /**< plugin specific data */ + uint16_t idx; /**< position in the signature */ + SigMatchCtx *ctx; /**< plugin specific data */ struct SigMatch_ *next; struct SigMatch_ *prev; } SigMatch; +/** \brief Data needed for Match() */ +typedef struct SigMatchData_ { + uint8_t type; /**< match type */ + uint8_t is_last; /**< Last element of the list */ + SigMatchCtx *ctx; /**< plugin specific data */ +} SigMatchData; + +struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; + +typedef int (*InspectEngineFuncPtr)(ThreadVars *tv, + struct DetectEngineCtx_ *de_ctx, struct DetectEngineThreadCtx_ *det_ctx, + const struct Signature_ *sig, const SigMatchData *smd, + Flow *f, uint8_t flags, void *alstate, + void *tx, uint64_t tx_id); + +typedef struct DetectEngineAppInspectionEngine_ { + AppProto alproto; + uint8_t dir; + uint8_t id; /**< per sig id used in state keeping */ + int sm_list; + + /* \retval 0 No match. Don't discontinue matching yet. We need more data. + * 1 Match. + * 2 Sig can't match. + * 3 Special value used by filestore sigs to indicate disabling + * filestore for the tx. + */ + InspectEngineFuncPtr Callback; + + SigMatchData *smd; + + struct DetectEngineAppInspectionEngine_ *next; +} DetectEngineAppInspectionEngine; + +#ifdef UNITTESTS +#define sm_lists init_data->smlists +#define sm_lists_tail init_data->smlists_tail +#endif + +typedef struct SignatureInitData_ { + /** Number of sigmatches. Used for assigning SigMatch::idx */ + uint16_t sm_cnt; + + /* used to hold flags that are used during init */ + uint32_t init_flags; + /* coccinelle: SignatureInitData:init_flags:SIG_FLAG_INIT_ */ + + /* used at init to determine max dsize */ + SigMatch *dsize_sm; + + /* the fast pattern added from this signature */ + SigMatch *mpm_sm; + /* used to speed up init of prefilter */ + SigMatch *prefilter_sm; + + /* SigMatch list used for adding content and friends. E.g. file_data; */ + int list; + + /** score to influence rule grouping. A higher value leads to a higher + * likelyhood of a rulegroup with this sig ending up as a contained + * group. */ + int whitelist; + + /** address settings for this signature */ + const DetectAddressHead *src, *dst; + + int prefilter_list; + + /* holds all sm lists */ + struct SigMatch_ **smlists; + /* holds all sm lists' tails */ + struct SigMatch_ **smlists_tail; +} SignatureInitData; + /** \brief Signature container */ typedef struct Signature_ { - union { - struct { - /* coccinelle: Signature:flags:SIG_FLAG */ - uint32_t flags; - AppProto alproto; - uint16_t dsize_low; - }; - uint64_t hdr_copy1; - }; - union { - struct { - uint16_t dsize_high; - uint16_t mpm_pattern_id_div_8; - }; - uint32_t hdr_copy2; - }; - union { - struct { - uint8_t mpm_pattern_id_mod_8; - SignatureMask mask; - SigIntId num; /**< signature number, internal id */ - }; - uint32_t hdr_copy3; - }; + /* coccinelle: Signature:flags:SIG_FLAG */ + uint32_t flags; + + AppProto alproto; + + uint16_t dsize_low; + uint16_t dsize_high; + + SignatureMask mask; + SigIntId num; /**< signature number, internal id */ /** inline -- action */ uint8_t action; uint8_t file_flags; + /** addresses, ports and proto this sig matches on */ + DetectProto proto; + + /** classification id **/ + uint8_t class; + /** ipv4 match arrays */ uint16_t addr_dst_match4_cnt; uint16_t addr_src_match4_cnt; + uint16_t addr_dst_match6_cnt; + uint16_t addr_src_match6_cnt; DetectMatchAddressIPv4 *addr_dst_match4; DetectMatchAddressIPv4 *addr_src_match4; /** ipv6 match arrays */ DetectMatchAddressIPv6 *addr_dst_match6; DetectMatchAddressIPv6 *addr_src_match6; - uint16_t addr_dst_match6_cnt; - uint16_t addr_src_match6_cnt; uint32_t id; /**< sid, set by the 'sid' rule keyword */ + uint32_t gid; /**< generator id */ + uint32_t rev; + int prio; + /** port settings for this signature */ DetectPort *sp, *dp; - /** addresses, ports and proto this sig matches on */ - DetectProto proto; - - /** classification id **/ - uint8_t class; - #ifdef PROFILING uint16_t profiling_id; #endif - uint32_t gid; /**< generator id */ - /** netblocks and hosts specified at the sid, in CIDR format */ IPOnlyCIDRItem *CidrSrc, *CidrDst; - uint32_t rev; - - int prio; + DetectEngineAppInspectionEngine *app_inspect; - /* holds all sm lists */ - struct SigMatch_ *sm_lists[DETECT_SM_LIST_MAX]; - /* holds all sm lists' tails */ - struct SigMatch_ *sm_lists_tail[DETECT_SM_LIST_MAX]; + /* Matching structures for the built-ins. The others are in + * their inspect engines. */ + SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; - SigMatch *filestore_sm; + /* memory is still owned by the sm_lists/sm_arrays entry */ + const struct DetectFilestoreData_ *filestore_ctx; char *msg; @@ -452,33 +454,35 @@ typedef struct Signature_ { /** Reference */ DetectReference *references; - /** address settings for this signature */ - DetectAddressHead src, dst; - - /* used to hold flags that are predominantly used during init */ - uint32_t init_flags; - /* coccinelle: Signature:init_flags:SIG_FLAG_INIT_ */ - - /** number of sigmatches in the match and pmatch list */ - uint16_t sm_cnt; - /* used at init to determine max dsize */ - SigMatch *dsize_sm; - /* the fast pattern added from this signature */ - SigMatch *mpm_sm; - /* helper for init phase */ - uint16_t mpm_content_maxlen; - uint16_t mpm_uricontent_maxlen; - /* Be careful, this pointer is only valid while parsing the sig, * to warn the user about any possible problem */ char *sig_str; - int list; + SignatureInitData *init_data; /** ptr to the next sig in the list */ struct Signature_ *next; } Signature; +/** \brief one time registration of keywords at start up */ +typedef struct DetectMpmAppLayerRegistery_ { + const char *name; + int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ + int sm_list; + + int (*PrefilterRegister)(struct SigGroupHead_ *sgh, MpmCtx *mpm_ctx); + + int id; /**< index into this array and result arrays */ + struct DetectMpmAppLayerRegistery_ *next; +} DetectMpmAppLayerRegistery; + +/** \brief structure for storing per detect engine mpm keyword settings + */ +typedef struct DetectMpmAppLayerKeyword_ { + const DetectMpmAppLayerRegistery *reg; + int32_t sgh_mpm_context; /**< mpm factory id */ +} DetectMpmAppLayerKeyword; + typedef struct DetectReplaceList_ { struct DetectContentData_ *cd; uint8_t *found; @@ -486,28 +490,28 @@ typedef struct DetectReplaceList_ { } DetectReplaceList; /** only execute flowvar storage if rule matched */ -#define DETECT_FLOWVAR_TYPE_POSTMATCH 1 -/** execute flowvar storage even if rule doesn't match (for luajit) */ -#define DETECT_FLOWVAR_TYPE_ALWAYS 2 +#define DETECT_VAR_TYPE_FLOW_POSTMATCH 1 +#define DETECT_VAR_TYPE_PKT_POSTMATCH 2 /** list for flowvar store candidates, to be stored from * post-match function */ -typedef struct DetectFlowvarList_ { - uint16_t idx; /**< flowvar name idx */ +typedef struct DetectVarList_ { + uint32_t idx; /**< flowvar name idx */ uint16_t len; /**< data len */ + uint16_t key_len; + int type; /**< type of store candidate POSTMATCH or ALWAYS */ + uint8_t *key; uint8_t *buffer; /**< alloc'd buffer, may be freed by post-match, post-non-match */ - int type; /**< type of store candidate POSTMATCH or ALWAYS */ - struct DetectFlowvarList_ *next; -} DetectFlowvarList; + struct DetectVarList_ *next; +} DetectVarList; typedef struct DetectEngineIPOnlyThreadCtx_ { uint8_t *sig_match_array; /* bit array of sig nums */ uint32_t sig_match_size; /* size in bytes of the array */ } DetectEngineIPOnlyThreadCtx; -/** \brief IP only rules matching ctx. - * \todo a radix tree would be great here */ +/** \brief IP only rules matching ctx. */ typedef struct DetectEngineIPOnlyCtx_ { /* lookup hashes */ HashListTable *ht16_src, *ht16_dst; @@ -537,8 +541,9 @@ typedef struct DetectEngineIPOnlyCtx_ { } DetectEngineIPOnlyCtx; typedef struct DetectEngineLookupFlow_ { - DetectAddressHead *src_gh[256]; /* a head for each protocol */ - DetectAddressHead *tmp_gh[256]; + DetectPort *tcp; + DetectPort *udp; + struct SigGroupHead_ *sgh[256]; } DetectEngineLookupFlow; /* Flow status @@ -548,15 +553,6 @@ typedef struct DetectEngineLookupFlow_ { */ #define FLOW_STATES 2 -/* mpm pattern id api */ -typedef struct MpmPatternIdStore_ { - HashTable *hash; - PatIntId max_id; - - uint32_t unique_patterns; - uint32_t shared_patterns; -} MpmPatternIdStore; - /** \brief threshold ctx */ typedef struct ThresholdCtx_ { SCMutex threshold_table_lock; /**< Mutex for hash table */ @@ -575,23 +571,38 @@ typedef struct DetectEngineThreadKeywordCtxItem_ { const char *name; /* keyword name, for error printing */ } DetectEngineThreadKeywordCtxItem; +enum DetectEnginePrefilterSetting +{ + DETECT_PREFILTER_MPM = 0, /**< use only mpm / fast_pattern */ + DETECT_PREFILTER_AUTO = 1, /**< use mpm + keyword prefilters */ +}; + /** \brief main detection engine ctx */ typedef struct DetectEngineCtx_ { uint8_t flags; int failure_fatal; + int tenant_id; + Signature *sig_list; uint32_t sig_cnt; /* version of the srep data */ uint32_t srep_version; + /* reputation for netblocks */ + SRepCIDRTree *srepCIDR_ctx; + Signature **sig_array; uint32_t sig_array_size; /* size in bytes */ uint32_t sig_array_len; /* size in array members */ uint32_t signum; + /** Maximum value of all our sgh's non_mpm_store_cnt setting, + * used to alloc det_ctx::non_mpm_id_array */ + uint32_t non_pf_store_cnt_max; + /* used by the signature ordering module */ struct SCSigOrderFunc_ *sc_sig_order_funcs; @@ -603,71 +614,35 @@ typedef struct DetectEngineCtx_ { /* main sigs */ DetectEngineLookupFlow flow_gh[FLOW_STATES]; - uint32_t mpm_unique, mpm_reuse, mpm_none, - mpm_uri_unique, mpm_uri_reuse, mpm_uri_none; uint32_t gh_unique, gh_reuse; - uint32_t mpm_max_patcnt, mpm_min_patcnt, mpm_tot_patcnt, - mpm_uri_max_patcnt, mpm_uri_min_patcnt, mpm_uri_tot_patcnt; - /* init phase vars */ HashListTable *sgh_hash_table; - HashListTable *sgh_mpm_hash_table; - HashListTable *sgh_mpm_uri_hash_table; - HashListTable *sgh_mpm_stream_hash_table; - - HashListTable *sgh_sport_hash_table; - HashListTable *sgh_dport_hash_table; - - HashListTable *sport_hash_table; - HashListTable *dport_hash_table; - - HashListTable *variable_names; - HashListTable *variable_idxs; - uint16_t variable_names_idx; + HashListTable *mpm_hash_table; /* hash table used to cull out duplicate sigs */ HashListTable *dup_sig_hash_table; - /* memory counters */ - uint32_t mpm_memory_size; - DetectEngineIPOnlyCtx io_ctx; ThresholdCtx ths_ctx; uint16_t mpm_matcher; /**< mpm matcher this ctx uses */ + uint16_t spm_matcher; /**< spm matcher this ctx uses */ - /* Config options */ + /* spm thread context prototype, built as spm matchers are constructed and + * later used to construct thread context for each thread. */ + SpmGlobalThreadCtx *spm_global_thread_ctx; - uint16_t max_uniq_toclient_src_groups; - uint16_t max_uniq_toclient_dst_groups; - uint16_t max_uniq_toclient_sp_groups; - uint16_t max_uniq_toclient_dp_groups; + /* Config options */ - uint16_t max_uniq_toserver_src_groups; - uint16_t max_uniq_toserver_dst_groups; - uint16_t max_uniq_toserver_sp_groups; - uint16_t max_uniq_toserver_dp_groups; -/* - uint16_t max_uniq_small_toclient_src_groups; - uint16_t max_uniq_small_toclient_dst_groups; - uint16_t max_uniq_small_toclient_sp_groups; - uint16_t max_uniq_small_toclient_dp_groups; - - uint16_t max_uniq_small_toserver_src_groups; - uint16_t max_uniq_small_toserver_dst_groups; - uint16_t max_uniq_small_toserver_sp_groups; - uint16_t max_uniq_small_toserver_dp_groups; -*/ + uint16_t max_uniq_toclient_groups; + uint16_t max_uniq_toserver_groups; /* specify the configuration for mpm context factory */ uint8_t sgh_mpm_context; - /** hash table for looking up patterns for - * id sharing and id tracking. */ - MpmPatternIdStore *mpm_pattern_id_store; - uint16_t max_fp_id; + uint32_t max_fp_id; MpmCtxFactoryContainer *mpm_ctx_factory_container; @@ -689,52 +664,65 @@ typedef struct DetectEngineCtx_ { int32_t sgh_mpm_context_proto_udp_packet; int32_t sgh_mpm_context_proto_other_packet; int32_t sgh_mpm_context_stream; - int32_t sgh_mpm_context_uri; - int32_t sgh_mpm_context_hcbd; - int32_t sgh_mpm_context_hsbd; - int32_t sgh_mpm_context_hhd; - int32_t sgh_mpm_context_hrhd; - int32_t sgh_mpm_context_hmd; - int32_t sgh_mpm_context_hcd; - int32_t sgh_mpm_context_hrud; - int32_t sgh_mpm_context_hsmd; - int32_t sgh_mpm_context_hscd; - int32_t sgh_mpm_context_huad; - int32_t sgh_mpm_context_hhhd; - int32_t sgh_mpm_context_hrhhd; - int32_t sgh_mpm_context_app_proto_detect; - int32_t sgh_mpm_context_dnsquery; /* the max local id used amongst all sigs */ int32_t byte_extract_max_local_id; - /* id used by every detect engine ctx instance */ - uint32_t id; + /** version of the detect engine */ + uint32_t version; /** sgh for signatures that match against invalid packets. In those cases * we can't lookup by proto, address, port as we don't have these */ struct SigGroupHead_ *decoder_event_sgh; + /* Maximum size of the buffer for decoded base64 data. */ + uint32_t base64_decode_max_len; + /** Store rule file and line so that parsers can use them in errors. */ char *rule_file; int rule_line; - /** Is detect engine using a delayed init */ - int delayed_detect; - /** Did we load the signatures? */ - int delayed_detect_initialized; - /** list of keywords that need thread local ctxs */ DetectEngineThreadKeywordCtxItem *keyword_list; int keyword_id; - int detect_luajit_instances; - #ifdef PROFILING struct SCProfileDetectCtx_ *profile_ctx; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; - struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; + struct SCProfileKeywordDetectCtx_ **profile_keyword_ctx_per_list; + struct SCProfileSghDetectCtx_ *profile_sgh_ctx; + uint32_t profile_match_logging_threshold; #endif + uint32_t prefilter_maxid; + + char config_prefix[64]; + + /** minimal: essentially a stub */ + int minimal; + + /** how many de_ctx' are referencing this */ + uint32_t ref_cnt; + /** list in master: either active or freelist */ + struct DetectEngineCtx_ *next; + + /** id of loader thread 'owning' this de_ctx */ + int loader_id; + + /** are we useing just mpm or also other prefilters */ + enum DetectEnginePrefilterSetting prefilter_setting; + + HashListTable *dport_hash_table; + + DetectPort *tcp_whitelist; + DetectPort *udp_whitelist; + + /** table for storing the string representation with the parsers result */ + HashListTable *address_table; + + /** table with mpms and their registration function + * \todo we only need this at init, so perhaps this + * can move to a DetectEngineCtx 'init' struct */ + DetectMpmAppLayerKeyword *app_mpms; } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ @@ -755,23 +743,52 @@ enum { }; typedef struct HttpReassembledBody_ { - uint8_t *buffer; + const uint8_t *buffer; uint32_t buffer_size; /**< size of the buffer itself */ uint32_t buffer_len; /**< data len in the buffer */ uint64_t offset; /**< data offset */ } HttpReassembledBody; +typedef struct FiledataReassembledBody_ { + const uint8_t *buffer; + uint32_t buffer_size; /**< size of the buffer itself */ + uint32_t buffer_len; /**< data len in the buffer */ + uint64_t offset; /**< data offset */ +} FiledataReassembledBody; + #define DETECT_FILESTORE_MAX 15 -/** \todo review how many we actually need here */ -#define DETECT_SMSG_PMQ_NUM 256 + +typedef struct SignatureNonPrefilterStore_ { + SigIntId id; + SignatureMask mask; +} SignatureNonPrefilterStore; /** * Detection engine thread data. */ -typedef struct DetectionEngineThreadCtx_ { +typedef struct DetectEngineThreadCtx_ { + /** \note multi-tenant hash lookup code from Detect() *depends* + * on this beeing the first member */ + uint32_t tenant_id; + + /** ticker that is incremented once per packet. */ + uint64_t ticker; + /* the thread to which this detection engine thread belongs */ ThreadVars *tv; + SigIntId *non_pf_id_array; + uint32_t non_pf_id_cnt; // size is cnt * sizeof(uint32_t) + + uint32_t mt_det_ctxs_cnt; + struct DetectEngineThreadCtx_ **mt_det_ctxs; + HashTable *mt_det_ctxs_hash; + + struct DetectEngineTenantMapping_ *tenant_array; + uint32_t tenant_array_size; + + uint32_t (*TenantGetId)(const void *, const Packet *p); + /* detection engine variables */ /** offset into the payload of the last match by: @@ -793,14 +810,19 @@ typedef struct DetectionEngineThreadCtx_ { uint16_t hcbd_buffers_size; uint16_t hcbd_buffers_list_len; - uint8_t **hhd_buffers; - uint32_t *hhd_buffers_len; - uint16_t hhd_buffers_size; - uint16_t hhd_buffers_list_len; - uint64_t hhd_start_tx_id; + FiledataReassembledBody *smtp; + uint64_t smtp_start_tx_id; + uint16_t smtp_buffers_size; + uint16_t smtp_buffers_list_len; /** id for alert counter */ uint16_t counter_alerts; +#ifdef PROFILING + uint16_t counter_mpm_list; + uint16_t counter_nonmpm_list; + uint16_t counter_fnonmpm_list; + uint16_t counter_match_list; +#endif /* used to discontinue any more matching */ uint16_t discontinue_matching; @@ -829,15 +851,24 @@ typedef struct DetectionEngineThreadCtx_ { SigIntId de_state_sig_array_len; uint8_t *de_state_sig_array; - struct SigGroupHead_ *sgh; + const struct SigGroupHead_ *sgh; + + SignatureNonPrefilterStore *non_pf_store_ptr; + uint32_t non_pf_store_cnt; + /** pointer to the current mpm ctx that is stored * in a rule group head -- can be either a content * or uricontent ctx. */ MpmThreadCtx mtc; /**< thread ctx for the mpm */ MpmThreadCtx mtcu; /**< thread ctx for uricontent mpm */ MpmThreadCtx mtcs; /**< thread ctx for stream mpm */ - PatternMatcherQueue pmq; - PatternMatcherQueue smsg_pmq[DETECT_SMSG_PMQ_NUM]; + PrefilterRuleStore pmq; + + StreamMsg *smsg; + + /** SPM thread context used for scanning. This has been cloned from the + * prototype held by DetectEngineCtx. */ + SpmThreadCtx *spm_thread_ctx; /** ip only rules ctx */ DetectEngineIPOnlyThreadCtx io_ctx; @@ -847,8 +878,8 @@ typedef struct DetectionEngineThreadCtx_ { /* string to replace */ DetectReplaceList *replist; - /* flowvars to store in post match function */ - DetectFlowvarList *flowvarlist; + /* vars to store in post match function */ + DetectVarList *varlist; /* Array in which the filestore keyword stores file id and tx id. If the * full signature matches, these are processed by a post-match filestore @@ -859,97 +890,163 @@ typedef struct DetectionEngineThreadCtx_ { } filestore[DETECT_FILESTORE_MAX]; DetectEngineCtx *de_ctx; - /** store for keyword contexts that need a per thread storage because of - * thread safety issues */ + /** store for keyword contexts that need a per thread storage. Per de_ctx. */ void **keyword_ctxs_array; int keyword_ctxs_size; + /** store for keyword contexts that need a per thread storage. Global. */ + int global_keyword_ctxs_size; + void **global_keyword_ctxs_array; + + uint8_t *base64_decoded; + int base64_decoded_len; + int base64_decoded_len_max; #ifdef PROFILING struct SCProfileData_ *rule_perf_data; int rule_perf_data_size; struct SCProfileKeywordData_ *keyword_perf_data; - struct SCProfileKeywordData_ *keyword_perf_data_per_list[DETECT_SM_LIST_MAX]; + struct SCProfileKeywordData_ **keyword_perf_data_per_list; int keyword_perf_list; /**< list we're currently inspecting, DETECT_SM_LIST_* */ + struct SCProfileSghData_ *sgh_perf_data; #endif } DetectEngineThreadCtx; /** \brief element in sigmatch type table. - * \note FileMatch pointer below takes a locked flow, AppLayerMatch an unlocked flow */ typedef struct SigTableElmt_ { /** Packet match function pointer */ - int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); + int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); - /** AppLayer match function pointer */ - int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, Signature *, SigMatch *); + /** AppLayer TX match function pointer */ + int (*AppLayerTxMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, + uint8_t flags, void *alstate, void *txv, + const Signature *, const SigMatchCtx *); /** File match function pointer */ int (*FileMatch)(ThreadVars *, /**< thread local vars */ DetectEngineThreadCtx *, Flow *, /**< *LOCKED* flow */ - uint8_t flags, File *, Signature *, SigMatch *); - - /** app layer proto from app-layer-protos.h this match applies to */ - AppProto alproto; + uint8_t flags, File *, const Signature *, const SigMatchCtx *); /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, char *); + _Bool (*SupportsPrefilter)(const Signature *s); + int (*SetupPrefilter)(struct SigGroupHead_ *sgh); + void (*Free)(void *); void (*RegisterTests)(void); uint8_t flags; - char *name; /**< keyword name alias */ - char *alias; /**< name alias */ - char *desc; - char *url; + + const char *name; /**< keyword name alias */ + const char *alias; /**< name alias */ + const char *desc; + const char *url; } SigTableElmt; -#define SIG_GROUP_HEAD_MPM_URI (1) -#define SIG_GROUP_HEAD_MPM_HCBD (1 << 1) -#define SIG_GROUP_HEAD_MPM_HHD (1 << 2) -#define SIG_GROUP_HEAD_MPM_HRHD (1 << 3) -#define SIG_GROUP_HEAD_MPM_HMD (1 << 4) -#define SIG_GROUP_HEAD_MPM_HCD (1 << 5) -#define SIG_GROUP_HEAD_MPM_HRUD (1 << 6) -#define SIG_GROUP_HEAD_MPM_HSBD (1 << 7) -#define SIG_GROUP_HEAD_MPM_HSMD (1 << 8) -#define SIG_GROUP_HEAD_MPM_HSCD (1 << 9) -#define SIG_GROUP_HEAD_MPM_HUAD (1 << 10) -#define SIG_GROUP_HEAD_MPM_HHHD (1 << 11) -#define SIG_GROUP_HEAD_MPM_HRHHD (1 << 12) - -#define SIG_GROUP_HEAD_MPM_COPY (1 << 13) -#define SIG_GROUP_HEAD_MPM_URI_COPY (1 << 14) -#define SIG_GROUP_HEAD_MPM_STREAM_COPY (1 << 15) -#define SIG_GROUP_HEAD_FREE (1 << 16) -#define SIG_GROUP_HEAD_MPM_PACKET (1 << 17) -#define SIG_GROUP_HEAD_MPM_STREAM (1 << 18) -#define SIG_GROUP_HEAD_REFERENCED (1 << 19) /**< sgh is being referenced by others, don't clear */ +#ifdef HAVE_MAGIC #define SIG_GROUP_HEAD_HAVEFILEMAGIC (1 << 20) +#endif #define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21) #define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22) -#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23) +#define SIG_GROUP_HEAD_HAVEFILESHA1 (1 << 23) +#define SIG_GROUP_HEAD_HAVEFILESHA256 (1 << 24) + +enum MpmBuiltinBuffers { + MPMB_TCP_PKT_TS, + MPMB_TCP_PKT_TC, + MPMB_TCP_STREAM_TS, + MPMB_TCP_STREAM_TC, + MPMB_UDP_TS, + MPMB_UDP_TC, + MPMB_OTHERIP, + MPMB_MAX, +}; + +typedef struct MpmStore_ { + uint8_t *sid_array; + uint32_t sid_array_size; + + int direction; + enum MpmBuiltinBuffers buffer; + int sm_list; + int32_t sgh_mpm_context; + + MpmCtx *mpm_ctx; + +} MpmStore; + +typedef struct PrefilterEngineList_ { + uint16_t id; + + /** App Proto this engine applies to: only used with Tx Engines */ + AppProto alproto; + /** Minimal Tx progress we need before running the engine. Only used + * with Tx Engine */ + int tx_min_progress; + + /** Context for matching. Might be MpmCtx for MPM engines, other ctx' + * for other engines. */ + void *pectx; + + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx); + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags); + + struct PrefilterEngineList_ *next; + + /** Free function for pectx data. If NULL the memory is not freed. */ + void (*Free)(void *pectx); + + const char *name; + /* global id for this prefilter */ + uint32_t gid; +} PrefilterEngineList; + +typedef struct PrefilterEngine_ { + uint16_t id; + + /** App Proto this engine applies to: only used with Tx Engines */ + AppProto alproto; + /** Minimal Tx progress we need before running the engine. Only used + * with Tx Engine */ + int tx_min_progress; + + /** Context for matching. Might be MpmCtx for MPM engines, other ctx' + * for other engines. */ + void *pectx; + + union { + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx); + void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx, + Packet *p, Flow *f, void *tx, + const uint64_t idx, const uint8_t flags); + } cb; + + /* global id for this prefilter */ + uint32_t gid; + int is_last; +} PrefilterEngine; typedef struct SigGroupHeadInitData_ { - /* list of content containers - * XXX move into a separate data struct - * with only a ptr to it. Saves some memory - * after initialization - */ - uint8_t *content_array; - uint32_t content_size; - uint8_t *uri_content_array; - uint32_t uri_content_size; - uint8_t *stream_content_array; - uint32_t stream_content_size; - - /* "Normal" detection uses these only at init, but ip-only - * uses it during runtime as well, thus not in init... */ + MpmStore mpm_store[MPMB_MAX]; + uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ uint32_t sig_size; /**< size in bytes */ + uint8_t protos[256]; /**< proto(s) this sgh is for */ + uint32_t direction; /**< set to SIG_FLAG_TOSERVER, SIG_FLAG_TOCLIENT or both */ + int whitelist; /**< try to make this group a unique one */ + + MpmCtx **app_mpms; + + PrefilterEngineList *pkt_engines; + PrefilterEngineList *payload_engines; + PrefilterEngineList *tx_engines; + /* port ptr */ struct DetectPort_ *port; } SigGroupHeadInitData; @@ -960,57 +1057,29 @@ typedef struct SigGroupHead_ { /* number of sigs in this head */ SigIntId sig_cnt; - uint16_t mpm_content_maxlen; - - /** array of masks, used to check multiple masks against - * a packet using SIMD. */ -#if defined(__SSE3__) || defined(__tile__) - SignatureMask *mask_array; -#endif - /** chunk of memory containing the "header" part of each - * signature ordered as an array. Used to pre-filter the - * signatures to be inspected in a cache efficient way. */ - SignatureHeader *head_array; - - /* pattern matcher instances */ - MpmCtx *mpm_proto_other_ctx; - - MpmCtx *mpm_proto_tcp_ctx_ts; - MpmCtx *mpm_proto_udp_ctx_ts; - MpmCtx *mpm_stream_ctx_ts; - MpmCtx *mpm_uri_ctx_ts; - MpmCtx *mpm_hcbd_ctx_ts; - MpmCtx *mpm_hhd_ctx_ts; - MpmCtx *mpm_hrhd_ctx_ts; - MpmCtx *mpm_hmd_ctx_ts; - MpmCtx *mpm_hcd_ctx_ts; - MpmCtx *mpm_hrud_ctx_ts; - MpmCtx *mpm_huad_ctx_ts; - MpmCtx *mpm_hhhd_ctx_ts; - MpmCtx *mpm_hrhhd_ctx_ts; - MpmCtx *mpm_dnsquery_ctx_ts; - - MpmCtx *mpm_proto_tcp_ctx_tc; - MpmCtx *mpm_proto_udp_ctx_tc; - MpmCtx *mpm_stream_ctx_tc; - MpmCtx *mpm_hsbd_ctx_tc; - MpmCtx *mpm_hhd_ctx_tc; - MpmCtx *mpm_hrhd_ctx_tc; - MpmCtx *mpm_hcd_ctx_tc; - MpmCtx *mpm_hsmd_ctx_tc; - MpmCtx *mpm_hscd_ctx_tc; - - uint16_t mpm_uricontent_maxlen; + /* non prefilter list excluding SYN rules */ + uint32_t non_pf_other_store_cnt; + uint32_t non_pf_syn_store_cnt; + SignatureNonPrefilterStore *non_pf_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonPrefilterStore) + /* non mpm list including SYN rules */ + SignatureNonPrefilterStore *non_pf_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonPrefilterStore) /** the number of signatures in this sgh that have the filestore keyword * set. */ uint16_t filestore_cnt; + uint32_t id; /**< unique id used to index sgh_array for stats */ + + PrefilterEngine *pkt_engines; + PrefilterEngine *payload_engines; + PrefilterEngine *tx_engines; + /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ Signature **match_array; /* ptr to our init data we only use at... init :) */ SigGroupHeadInitData *init; + } SigGroupHead; /** sigmatch has no options, so the parser shouldn't expect any */ @@ -1019,13 +1088,64 @@ typedef struct SigGroupHead_ { #define SIGMATCH_IPONLY_COMPAT (1 << 1) /** sigmatch is compatible with a decode event only rule */ #define SIGMATCH_DEONLY_COMPAT (1 << 2) -/**< Flag to indicate that the signature inspects the packet payload */ -#define SIGMATCH_PAYLOAD (1 << 3) /**< Flag to indicate that the signature is not built-in */ -#define SIGMATCH_NOT_BUILT (1 << 4) +#define SIGMATCH_NOT_BUILT (1 << 3) /** sigmatch may have options, so the parser should be ready to * deal with both cases */ -#define SIGMATCH_OPTIONAL_OPT (1 << 5) +#define SIGMATCH_OPTIONAL_OPT (1 << 4) + +enum DetectEngineTenantSelectors +{ + TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ + TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ + TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */ +}; + +typedef struct DetectEngineTenantMapping_ { + uint32_t tenant_id; + + /* traffic id that maps to the tenant id */ + uint32_t traffic_id; + + struct DetectEngineTenantMapping_ *next; +} DetectEngineTenantMapping; + +typedef struct DetectEngineMasterCtx_ { + SCMutex lock; + + /** enable multi tenant mode */ + int multi_tenant_enabled; + + /** version, incremented after each 'apply to threads' */ + uint32_t version; + + /** list of active detection engines. This list is used to generate the + * threads det_ctx's */ + DetectEngineCtx *list; + + /** free list, containing detection engines that will be removed but may + * still be referenced by det_ctx's. Freed as soon as all references are + * gone. */ + DetectEngineCtx *free_list; + + enum DetectEngineTenantSelectors tenant_selector; + + /** list of tenant mappings. Updated under lock. Used to generate lookup + * structures. */ + DetectEngineTenantMapping *tenant_mapping_list; + + /** list of keywords that need thread local ctxs */ + DetectEngineThreadKeywordCtxItem *keyword_list; + int keyword_id; +} DetectEngineMasterCtx; + +/** \brief Signature loader statistics */ +typedef struct SigFileLoaderStat_ { + int bad_files; + int total_files; + int good_sigs_total; + int bad_sigs_total; +} SigFileLoaderStat; /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ @@ -1034,6 +1154,28 @@ enum { DETECT_PRIORITY, DETECT_REV, DETECT_CLASSTYPE, + + /* sorted by prefilter priority. Higher in this list means it will be + * picked over ones lower in the list */ + DETECT_AL_APP_LAYER_PROTOCOL, + DETECT_ACK, + DETECT_SEQ, + DETECT_WINDOW, + DETECT_IPOPTS, + DETECT_FLAGS, + DETECT_FRAGBITS, + DETECT_FRAGOFFSET, + DETECT_TTL, + DETECT_TOS, + DETECT_ITYPE, + DETECT_ICODE, + DETECT_ICMP_ID, + DETECT_ICMP_SEQ, + DETECT_DSIZE, + + DETECT_FLOW, + /* end prefilter sort */ + DETECT_THRESHOLD, DETECT_METADATA, DETECT_REFERENCE, @@ -1042,8 +1184,6 @@ enum { DETECT_CONTENT, DETECT_URICONTENT, DETECT_PCRE, - DETECT_ACK, - DETECT_SEQ, DETECT_DEPTH, DETECT_DISTANCE, DETECT_WITHIN, @@ -1057,19 +1197,17 @@ enum { DETECT_SAMEIP, DETECT_GEOIP, DETECT_IPPROTO, - DETECT_FLOW, - DETECT_WINDOW, DETECT_FTPBOUNCE, DETECT_ISDATAAT, DETECT_ID, DETECT_RPC, - DETECT_DSIZE, DETECT_FLOWVAR, DETECT_FLOWVAR_POSTMATCH, DETECT_FLOWINT, DETECT_PKTVAR, DETECT_NOALERT, DETECT_FLOWBITS, + DETECT_HOSTBITS, DETECT_IPV4_CSUM, DETECT_TCPV4_CSUM, DETECT_TCPV6_CSUM, @@ -1078,34 +1216,31 @@ enum { DETECT_ICMPV4_CSUM, DETECT_ICMPV6_CSUM, DETECT_STREAM_SIZE, - DETECT_TTL, - DETECT_ITYPE, - DETECT_ICODE, - DETECT_TOS, - DETECT_ICMP_ID, - DETECT_ICMP_SEQ, DETECT_DETECTION_FILTER, DETECT_DECODE_EVENT, - DETECT_IPOPTS, - DETECT_FLAGS, - DETECT_FRAGBITS, - DETECT_FRAGOFFSET, DETECT_GID, DETECT_MARK, DETECT_AL_TLS_VERSION, DETECT_AL_TLS_SUBJECT, DETECT_AL_TLS_ISSUERDN, + DETECT_AL_TLS_NOTBEFORE, + DETECT_AL_TLS_NOTAFTER, + DETECT_AL_TLS_EXPIRED, + DETECT_AL_TLS_VALID, DETECT_AL_TLS_FINGERPRINT, DETECT_AL_TLS_STORE, DETECT_AL_HTTP_COOKIE, DETECT_AL_HTTP_METHOD, + DETECT_AL_HTTP_PROTOCOL, + DETECT_AL_HTTP_START, DETECT_AL_URILEN, DETECT_AL_HTTP_CLIENT_BODY, DETECT_AL_HTTP_SERVER_BODY, DETECT_AL_HTTP_HEADER, + DETECT_AL_HTTP_HEADER_NAMES, DETECT_AL_HTTP_RAW_HEADER, DETECT_AL_HTTP_URI, DETECT_AL_HTTP_RAW_URI, @@ -1114,7 +1249,11 @@ enum { DETECT_AL_HTTP_USER_AGENT, DETECT_AL_HTTP_HOST, DETECT_AL_HTTP_RAW_HOST, + DETECT_AL_HTTP_REQUEST_LINE, + DETECT_AL_HTTP_RESPONSE_LINE, + DETECT_AL_SSH_PROTOCOL, DETECT_AL_SSH_PROTOVERSION, + DETECT_AL_SSH_SOFTWARE, DETECT_AL_SSH_SOFTWAREVERSION, DETECT_AL_SSL_VERSION, DETECT_AL_SSL_STATE, @@ -1122,7 +1261,6 @@ enum { DETECT_FILE_DATA, DETECT_PKT_DATA, DETECT_AL_APP_LAYER_EVENT, - DETECT_AL_APP_LAYER_PROTOCOL, DETECT_DCE_IFACE, DETECT_DCE_OPNUM, @@ -1138,6 +1276,8 @@ enum { DETECT_FILESTORE, DETECT_FILEMAGIC, DETECT_FILEMD5, + DETECT_FILESHA1, + DETECT_FILESHA256, DETECT_FILESIZE, DETECT_L3PROTO, @@ -1145,6 +1285,29 @@ enum { DETECT_IPREP, DETECT_AL_DNS_QUERY, + DETECT_AL_TLS_SNI, + DETECT_AL_TLS_CERT_ISSUER, + DETECT_AL_TLS_CERT_SUBJECT, + DETECT_AL_TLS_CERT_SERIAL, + DETECT_AL_MODBUS, + DETECT_CIPSERVICE, + DETECT_ENIPCOMMAND, + + DETECT_AL_DNP3DATA, + DETECT_AL_DNP3FUNC, + DETECT_AL_DNP3IND, + DETECT_AL_DNP3OBJ, + + DETECT_XBITS, + DETECT_BASE64_DECODE, + DETECT_BASE64_DATA, + + DETECT_TEMPLATE, + DETECT_AL_TEMPLATE_BUFFER, + + DETECT_BYPASS, + + DETECT_PREFILTER, /* make sure this stays last */ DETECT_TBLSIZE, @@ -1159,9 +1322,6 @@ Signature *SigFindSignatureBySidGid(DetectEngineCtx *, uint32_t, uint32_t); void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *, Packet *, SignatureMask, uint16_t); -int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThreadCtx *, - Packet *, SignatureHeader *, - uint16_t); void SigMatchFree(SigMatch *sm); void SigCleanSignatures(DetectEngineCtx *); @@ -1174,29 +1334,33 @@ int SigGroupBuild(DetectEngineCtx *); int SigGroupCleanup (DetectEngineCtx *de_ctx); void SigAddressPrepareBidirectionals (DetectEngineCtx *); -char *DetectLoadCompleteSigPath(char *sig_file); +void DisableDetectFlowFileFlags(Flow *f); +char *DetectLoadCompleteSigPath(const DetectEngineCtx *, char *sig_file); int SigLoadSignatures (DetectEngineCtx *, char *, int); void SigTableList(const char *keyword); void SigTableSetup(void); int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p); -int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s); +int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s); SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p); Signature *DetectGetTagSignature(void); -int SignatureIsFilestoring(Signature *); -int SignatureIsFilemagicInspecting(Signature *); -int SignatureIsFileMd5Inspecting(Signature *); -int SignatureIsFilesizeInspecting(Signature *); +int SignatureIsFilestoring(const Signature *); +int SignatureIsFilemagicInspecting(const Signature *); +int SignatureIsFileMd5Inspecting(const Signature *); +int SignatureIsFileSha1Inspecting(const Signature *s); +int SignatureIsFileSha256Inspecting(const Signature *s); +int SignatureIsFilesizeInspecting(const Signature *); int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int); void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *, int); int SigMatchSignaturesRunPostMatch(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p, - Signature *s); + const Signature *s); +void DetectSignatureApplyActions(Packet *p, const Signature *s); #endif /* __DETECT_H__ */ diff --git a/src/flow-bit.c b/src/flow-bit.c index 81fe16413a24..3662611ec8cf 100644 --- a/src/flow-bit.c +++ b/src/flow-bit.c @@ -43,7 +43,7 @@ #include "util-unittest.h" /* get the flowbit with idx from the flow */ -static FlowBit *FlowBitGet(Flow *f, uint16_t idx) +static FlowBit *FlowBitGet(Flow *f, uint32_t idx) { GenericVar *gv = f->flowvar; for ( ; gv != NULL; gv = gv->next) { @@ -56,7 +56,7 @@ static FlowBit *FlowBitGet(Flow *f, uint16_t idx) } /* add a flowbit to the flow */ -static void FlowBitAdd(Flow *f, uint16_t idx) +static void FlowBitAdd(Flow *f, uint32_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { @@ -68,104 +68,60 @@ static void FlowBitAdd(Flow *f, uint16_t idx) fb->idx = idx; fb->next = NULL; GenericVarAppend(&f->flowvar, (GenericVar *)fb); - - //printf("FlowBitAdd: adding flowbit with idx %" PRIu32 "\n", idx); -#ifdef FLOWBITS_STATS - SCMutexLock(&flowbits_mutex); - flowbits_added++; - flowbits_memuse += sizeof(FlowBit); - if (flowbits_memuse > flowbits_memuse_max) - flowbits_memuse_max = flowbits_memuse; - SCMutexUnlock(&flowbits_mutex); -#endif /* FLOWBITS_STATS */ } } -static void FlowBitRemove(Flow *f, uint16_t idx) +static void FlowBitRemove(Flow *f, uint32_t idx) { FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) return; GenericVarRemove(&f->flowvar, (GenericVar *)fb); - - //printf("FlowBitRemove: remove flowbit with idx %" PRIu32 "\n", idx); -#ifdef FLOWBITS_STATS - SCMutexLock(&flowbits_mutex); - flowbits_removed++; - if (flowbits_memuse >= sizeof(FlowBit)) - flowbits_memuse -= sizeof(FlowBit); - else { - printf("ERROR: flowbits memory usage going below 0!\n"); - flowbits_memuse = 0; - } - SCMutexUnlock(&flowbits_mutex); -#endif /* FLOWBITS_STATS */ + FlowBitFree(fb); } -void FlowBitSet(Flow *f, uint16_t idx) +void FlowBitSet(Flow *f, uint32_t idx) { - FLOWLOCK_WRLOCK(f); - - FlowBit *fb = FlowBitGet(f, idx); - if (fb == NULL) { - FlowBitAdd(f, idx); - } - - FLOWLOCK_UNLOCK(f); + FlowBitAdd(f, idx); } -void FlowBitUnset(Flow *f, uint16_t idx) +void FlowBitUnset(Flow *f, uint32_t idx) { - FLOWLOCK_WRLOCK(f); - - FlowBit *fb = FlowBitGet(f, idx); - if (fb != NULL) { - FlowBitRemove(f, idx); - } - - FLOWLOCK_UNLOCK(f); + FlowBitRemove(f, idx); } -void FlowBitToggle(Flow *f, uint16_t idx) +void FlowBitToggle(Flow *f, uint32_t idx) { - FLOWLOCK_WRLOCK(f); - FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { FlowBitRemove(f, idx); } else { FlowBitAdd(f, idx); } - - FLOWLOCK_UNLOCK(f); } -int FlowBitIsset(Flow *f, uint16_t idx) +int FlowBitIsset(Flow *f, uint32_t idx) { int r = 0; - FLOWLOCK_RDLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb != NULL) { r = 1; } - FLOWLOCK_UNLOCK(f); return r; } -int FlowBitIsnotset(Flow *f, uint16_t idx) +int FlowBitIsnotset(Flow *f, uint32_t idx) { int r = 0; - FLOWLOCK_RDLOCK(f); FlowBit *fb = FlowBitGet(f, idx); if (fb == NULL) { r = 1; } - FLOWLOCK_UNLOCK(f); return r; } @@ -175,18 +131,6 @@ void FlowBitFree(FlowBit *fb) return; SCFree(fb); - -#ifdef FLOWBITS_STATS - SCMutexLock(&flowbits_mutex); - flowbits_removed++; - if (flowbits_memuse >= sizeof(FlowBit)) - flowbits_memuse -= sizeof(FlowBit); - else { - printf("ERROR: flowbits memory usage going below 0!\n"); - flowbits_memuse = 0; - } - SCMutexUnlock(&flowbits_mutex); -#endif /* FLOWBITS_STATS */ } @@ -458,17 +402,17 @@ static int FlowBitTest11 (void) void FlowBitRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlowBitTest01", FlowBitTest01, 1); - UtRegisterTest("FlowBitTest02", FlowBitTest02, 1); - UtRegisterTest("FlowBitTest03", FlowBitTest03, 1); - UtRegisterTest("FlowBitTest04", FlowBitTest04, 1); - UtRegisterTest("FlowBitTest05", FlowBitTest05, 1); - UtRegisterTest("FlowBitTest06", FlowBitTest06, 1); - UtRegisterTest("FlowBitTest07", FlowBitTest07, 1); - UtRegisterTest("FlowBitTest08", FlowBitTest08, 1); - UtRegisterTest("FlowBitTest09", FlowBitTest09, 1); - UtRegisterTest("FlowBitTest10", FlowBitTest10, 1); - UtRegisterTest("FlowBitTest11", FlowBitTest11, 1); + UtRegisterTest("FlowBitTest01", FlowBitTest01); + UtRegisterTest("FlowBitTest02", FlowBitTest02); + UtRegisterTest("FlowBitTest03", FlowBitTest03); + UtRegisterTest("FlowBitTest04", FlowBitTest04); + UtRegisterTest("FlowBitTest05", FlowBitTest05); + UtRegisterTest("FlowBitTest06", FlowBitTest06); + UtRegisterTest("FlowBitTest07", FlowBitTest07); + UtRegisterTest("FlowBitTest08", FlowBitTest08); + UtRegisterTest("FlowBitTest09", FlowBitTest09); + UtRegisterTest("FlowBitTest10", FlowBitTest10); + UtRegisterTest("FlowBitTest11", FlowBitTest11); #endif /* UNITTESTS */ } diff --git a/src/flow-bit.h b/src/flow-bit.h index 633b5ee3d9a9..2362d5180795 100644 --- a/src/flow-bit.h +++ b/src/flow-bit.h @@ -29,7 +29,8 @@ typedef struct FlowBit_ { uint8_t type; /* type, DETECT_FLOWBITS in this case */ - uint16_t idx; /* name idx */ + uint8_t pad[3]; + uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ @@ -38,10 +39,10 @@ typedef struct FlowBit_ { void FlowBitFree(FlowBit *); void FlowBitRegisterTests(void); -void FlowBitSet(Flow *, uint16_t); -void FlowBitUnset(Flow *, uint16_t); -void FlowBitToggle(Flow *, uint16_t); -int FlowBitIsset(Flow *, uint16_t); -int FlowBitIsnotset(Flow *, uint16_t); +void FlowBitSet(Flow *, uint32_t); +void FlowBitUnset(Flow *, uint32_t); +void FlowBitToggle(Flow *, uint32_t); +int FlowBitIsset(Flow *, uint32_t); +int FlowBitIsnotset(Flow *, uint32_t); #endif /* __FLOW_BIT_H__ */ diff --git a/src/flow-hash.c b/src/flow-hash.c index 698b5bd7078e..89c1940b33e4 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -35,6 +35,7 @@ #include "flow-util.h" #include "flow-private.h" #include "flow-manager.h" +#include "flow-storage.h" #include "app-layer-parser.h" #include "util-time.h" @@ -53,101 +54,6 @@ SC_ATOMIC_EXTERN(unsigned int, flow_flags); static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv); -#ifdef FLOW_DEBUG_STATS -#define FLOW_DEBUG_STATS_PROTO_ALL 0 -#define FLOW_DEBUG_STATS_PROTO_TCP 1 -#define FLOW_DEBUG_STATS_PROTO_UDP 2 -#define FLOW_DEBUG_STATS_PROTO_ICMP 3 -#define FLOW_DEBUG_STATS_PROTO_OTHER 4 - -static uint64_t flow_hash_count[5] = { 0, 0, 0, 0, 0 }; /* how often are we looking for a hash */ -static uint64_t flow_hash_loop_count[5] = { 0, 0, 0, 0, 0 }; /* how often do we loop through a hash bucket */ -static FILE *flow_hash_count_fp = NULL; -static SCSpinlock flow_hash_count_lock; - -#define FlowHashCountUpdate do { \ - SCSpinLock(&flow_hash_count_lock); \ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL] += _flow_hash_counter; \ - if (f != NULL) { \ - if (p->proto == IPPROTO_TCP) { \ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP] += _flow_hash_counter; \ - } else if (p->proto == IPPROTO_UDP) {\ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP] += _flow_hash_counter; \ - } else if (p->proto == IPPROTO_ICMP) {\ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP] += _flow_hash_counter; \ - } else {\ - flow_hash_count[FLOW_DEBUG_STATS_PROTO_OTHER]++; \ - flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER] += _flow_hash_counter; \ - } \ - } \ - SCSpinUnlock(&flow_hash_count_lock); \ -} while(0); - -#define FlowHashCountInit uint64_t _flow_hash_counter = 0 -#define FlowHashCountIncr _flow_hash_counter++; - -void FlowHashDebugInit(void) -{ -#ifdef FLOW_DEBUG_STATS - SCSpinInit(&flow_hash_count_lock, 0); -#endif - flow_hash_count_fp = fopen("flow-debug.log", "w+"); - if (flow_hash_count_fp != NULL) { - fprintf(flow_hash_count_fp, "ts,all,tcp,udp,icmp,other\n"); - } -} - -void FlowHashDebugPrint(uint32_t ts) -{ -#ifdef FLOW_DEBUG_STATS - if (flow_hash_count_fp == NULL) - return; - - float avg_all = 0, avg_tcp = 0, avg_udp = 0, avg_icmp = 0, avg_other = 0; - SCSpinLock(&flow_hash_count_lock); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL] != 0) - avg_all = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP] != 0) - avg_tcp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP] != 0) - avg_udp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP] != 0) - avg_icmp= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP])); - if (flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER] != 0) - avg_other= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_OTHER]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_OTHER])); - fprintf(flow_hash_count_fp, "%"PRIu32",%02.3f,%02.3f,%02.3f,%02.3f,%02.3f\n", ts, avg_all, avg_tcp, avg_udp, avg_icmp, avg_other); - fflush(flow_hash_count_fp); - memset(&flow_hash_count, 0, sizeof(flow_hash_count)); - memset(&flow_hash_loop_count, 0, sizeof(flow_hash_loop_count)); - SCSpinUnlock(&flow_hash_count_lock); -#endif -} - -void FlowHashDebugDeinit(void) -{ -#ifdef FLOW_DEBUG_STATS - struct timeval ts; - memset(&ts, 0, sizeof(ts)); - TimeGet(&ts); - FlowHashDebugPrint((uint32_t)ts.tv_sec); - if (flow_hash_count_fp != NULL) - fclose(flow_hash_count_fp); - SCSpinDestroy(&flow_hash_count_lock); -#endif -} - -#else - -#define FlowHashCountUpdate -#define FlowHashCountInit -#define FlowHashCountIncr - -#endif /* FLOW_DEBUG_STATS */ - /** \brief compare two raw ipv6 addrs * * \note we don't care about the real ipv6 ip's, this is just @@ -211,9 +117,9 @@ typedef struct FlowHashKey6_ { * * For ICMP we only consider UNREACHABLE errors atm. */ -static inline uint32_t FlowGetKey(const Packet *p) +static inline uint32_t FlowGetHash(const Packet *p) { - uint32_t key; + uint32_t hash = 0; if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { @@ -237,8 +143,7 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); - key = hash % flow_config.hash_size; + hash = hashword(fhk.u32, 5, flow_config.hash_rand); } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); @@ -263,8 +168,7 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); - key = hash % flow_config.hash_size; + hash = hashword(fhk.u32, 5, flow_config.hash_rand); } else { FlowHashKey4 fhk; @@ -282,8 +186,7 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); - key = hash % flow_config.hash_size; + hash = hashword(fhk.u32, 5, flow_config.hash_rand); } } else if (p->ip6h != NULL) { FlowHashKey6 fhk; @@ -318,12 +221,10 @@ static inline uint32_t FlowGetKey(const Packet *p) fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; - uint32_t hash = hashword(fhk.u32, 11, flow_config.hash_rand); - key = hash % flow_config.hash_size; - } else - key = 0; + hash = hashword(fhk.u32, 11, flow_config.hash_rand); + } - return key; + return hash; } /* Since two or more flows can have the same hash key, we need to compare @@ -390,10 +291,28 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) return 0; } +void FlowSetupPacket(Packet *p) +{ + p->flags |= PKT_WANTS_FLOW; + p->flow_hash = FlowGetHash(p); +} + +int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, void *tcp_ssn); + static inline int FlowCompare(Flow *f, const Packet *p) { if (p->proto == IPPROTO_ICMP) { return FlowCompareICMPv4(f, p); + } else if (p->proto == IPPROTO_TCP) { + if (CMP_FLOW(f, p) == 0) + return 0; + + /* if this session is 'reused', we don't return it anymore, + * so return false on the compare */ + if (f->flags & FLOW_TCP_REUSED) + return 0; + + return 1; } else { return CMP_FLOW(f, p); } @@ -443,11 +362,13 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) f = FlowDequeue(&flow_spare_q); if (f == NULL) { /* If we reached the max memcap, we get a used flow */ - if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { + if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) { /* declare state of emergency */ if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) { SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY); + FlowTimeoutsEmergency(); + /* under high load, waking up the flow mgr each time leads * to high cpu usage. Flows are not timed out much faster if * we check a 1000 times a second. */ @@ -456,6 +377,11 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) f = FlowGetUsedFlow(tv, dtv); if (f == NULL) { + /* max memcap reached, so increments the counter */ + if (tv != NULL && dtv != NULL) { + StatsIncr(tv, dtv->counter_flow_memcap); + } + /* very rare, but we can fail. Just giving up */ return NULL; } @@ -465,6 +391,9 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) /* now see if we can alloc a new flow */ f = FlowAlloc(); if (f == NULL) { + if (tv != NULL && dtv != NULL) { + StatsIncr(tv, dtv->counter_flow_memcap); + } return NULL; } @@ -480,6 +409,40 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) return f; } +static Flow *TcpReuseReplace(ThreadVars *tv, DecodeThreadVars *dtv, + FlowBucket *fb, Flow *old_f, + const uint32_t hash, const Packet *p) +{ + /* tag flow as reused so future lookups won't find it */ + old_f->flags |= FLOW_TCP_REUSED; + /* get some settings that we move over to the new flow */ + FlowThreadId thread_id = old_f->thread_id; + + /* since fb lock is still held this flow won't be found until we are done */ + FLOWLOCK_UNLOCK(old_f); + + /* Get a new flow. It will be either a locked flow or NULL */ + Flow *f = FlowGetNew(tv, dtv, p); + if (f == NULL) { + return NULL; + } + + /* flow is locked */ + + /* put at the start of the list */ + f->hnext = fb->head; + fb->head->hprev = f; + fb->head = f; + + /* initialize and return */ + FlowInit(f, p); + f->flow_hash = hash; + f->fb = fb; + + f->thread_id = thread_id; + return f; +} + /** \brief Get Flow for packet * * Hash retrieval function for flows. Looks up the hash bucket containing the @@ -497,27 +460,22 @@ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) * * \retval f *LOCKED* flow or NULL */ -Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) +Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p, Flow **dest) { Flow *f = NULL; - FlowHashCountInit; - /* get the key to our bucket */ - uint32_t key = FlowGetKey(p); /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[key]; + const uint32_t hash = p->flow_hash; + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; FBLOCK_LOCK(fb); SCLogDebug("fb %p fb->head %p", fb, fb->head); - FlowHashCountIncr; - /* see if the bucket already has a flow */ if (fb->head == NULL) { f = FlowGetNew(tv, dtv, p); if (f == NULL) { FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return NULL; } @@ -527,10 +485,13 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* got one, now lock, initialize and return */ FlowInit(f, p); + f->flow_hash = hash; f->fb = fb; + FlowUpdateState(f, FLOW_STATE_NEW); + + FlowReference(dest, f); FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } @@ -542,8 +503,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p Flow *pf = NULL; /* previous flow */ while (f) { - FlowHashCountIncr; - pf = f; f = f->hnext; @@ -551,7 +510,6 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p f = pf->hnext = FlowGetNew(tv, dtv, p); if (f == NULL) { FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return NULL; } fb->tail = f; @@ -562,10 +520,13 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* initialize and return */ FlowInit(f, p); + f->flow_hash = hash; f->fb = fb; + FlowUpdateState(f, FLOW_STATE_NEW); + + FlowReference(dest, f); FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } @@ -589,8 +550,17 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* found our flow, lock & return */ FLOWLOCK_WRLOCK(f); + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { + f = TcpReuseReplace(tv, dtv, fb, f, hash, p); + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + } + + FlowReference(dest, f); + FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } } @@ -598,8 +568,17 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p /* lock & return */ FLOWLOCK_WRLOCK(f); + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) { + f = TcpReuseReplace(tv, dtv, fb, f, hash, p); + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + } + + FlowReference(dest, f); + FBLOCK_UNLOCK(fb); - FlowHashCountUpdate; return f; } @@ -664,15 +643,20 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv) f->hnext = NULL; f->hprev = NULL; f->fb = NULL; + SC_ATOMIC_SET(fb->next_ts, 0); FBLOCK_UNLOCK(fb); - int state = FlowGetFlowState(f); + int state = SC_ATOMIC_GET(f->flow_state); if (state == FLOW_STATE_NEW) f->flow_end_flags |= FLOW_END_FLAG_STATE_NEW; else if (state == FLOW_STATE_ESTABLISHED) f->flow_end_flags |= FLOW_END_FLAG_STATE_ESTABLISHED; else if (state == FLOW_STATE_CLOSED) f->flow_end_flags |= FLOW_END_FLAG_STATE_CLOSED; + else if (state == FLOW_STATE_CAPTURE_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; + else if (state == FLOW_STATE_LOCAL_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; f->flow_end_flags |= FLOW_END_FLAG_FORCED; @@ -685,6 +669,8 @@ static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv) FlowClearMemory(f, f->protomap); + FlowUpdateState(f, FLOW_STATE_NEW); + FLOWLOCK_UNLOCK(f); (void) SC_ATOMIC_ADD(flow_prune_idx, (flow_config.hash_size - cnt)); diff --git a/src/flow-hash.h b/src/flow-hash.h index a5635b06ce19..18a8c324b5a0 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -48,6 +48,12 @@ typedef struct FlowBucket_ { #else #error Enable FBLOCK_SPIN or FBLOCK_MUTEX #endif + /** timestamp in seconds of the earliest possible moment a flow + * will time out in this row. Set by the flow manager. Cleared + * to 0 by workers, either when new flows are added or when a + * flow state changes. The flow manager sets this to INT_MAX for + * empty buckets. */ + SC_ATOMIC_DECLARE(int32_t, next_ts); } __attribute__((aligned(CLS))) FlowBucket; #ifdef FBLOCK_SPIN @@ -68,20 +74,9 @@ typedef struct FlowBucket_ { /* prototypes */ -Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *); +Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *, Flow **); -/** enable to print stats on hash lookups in flow-debug.log */ -//#define FLOW_DEBUG_STATS - -#ifdef FLOW_DEBUG_STATS -void FlowHashDebugInit(void); -void FlowHashDebugDeinit(void); -void FlowHashDebugPrint(uint32_t); -#else -#define FlowHashDebugInit(...) -#define FlowHashDebugPrint(...) -#define FlowHashDebugDeinit(...) -#endif +void FlowDisableTcpReuseHandling(void); #endif /* __FLOW_HASH_H__ */ diff --git a/src/flow-manager.c b/src/flow-manager.c index a42e6590b4f3..4f92ec2c12ad 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -63,6 +63,7 @@ #include "host-timeout.h" #include "defrag-timeout.h" +#include "ippair-timeout.h" #include "output-flow.h" @@ -81,6 +82,20 @@ SC_ATOMIC_DECLARE(uint32_t, flowrec_cnt); SC_ATOMIC_EXTERN(unsigned int, flow_flags); + +typedef FlowProtoTimeout *FlowProtoTimeoutPtr; +SC_ATOMIC_DECLARE(FlowProtoTimeoutPtr, flow_timeouts); + +void FlowTimeoutsInit(void) +{ + SC_ATOMIC_SET(flow_timeouts, flow_timeouts_normal); +} + +void FlowTimeoutsEmergency(void) +{ + SC_ATOMIC_SET(flow_timeouts, flow_timeouts_emerg); +} + /* 1 seconds */ #define FLOW_NORMAL_MODE_UPDATE_DELAY_SEC 1 #define FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC 0 @@ -93,18 +108,34 @@ typedef struct FlowTimeoutCounters_ { uint32_t new; uint32_t est; uint32_t clo; + uint32_t byp; + uint32_t tcp_reuse; + + uint32_t flows_checked; + uint32_t flows_notimeout; + uint32_t flows_timeout; + uint32_t flows_timeout_inuse; + uint32_t flows_removed; + + uint32_t rows_checked; + uint32_t rows_skipped; + uint32_t rows_empty; + uint32_t rows_busy; + uint32_t rows_maxlen; } FlowTimeoutCounters; /** - * \brief Used to kill flow manager thread(s). + * \brief Used to disable flow manager thread(s). * * \todo Kinda hackish since it uses the tv name to identify flow manager * thread. We need an all weather identification scheme. */ -void FlowKillFlowManagerThread(void) +void FlowDisableFlowManagerThread(void) { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif ThreadVars *tv = NULL; - int cnt = 0; /* wake up threads */ uint32_t u; @@ -112,43 +143,56 @@ void FlowKillFlowManagerThread(void) SCCtrlCondSignal(&flow_manager_ctrl_cond); SCMutexLock(&tv_root_lock); - /* flow manager thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; - - while (tv != NULL) { - if (strcasecmp(tv->name, "FlowManagerThread") == 0) { + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_mgr, + strlen(thread_name_flow_mgr)) == 0) + { TmThreadsSetFlag(tv, THV_KILL); - TmThreadsSetFlag(tv, THV_DEINIT); - cnt++; } tv = tv->next; } + SCMutexUnlock(&tv_root_lock); - /* wake up threads, another try */ - for (u = 0; u < flowmgr_number; u++) - SCCtrlCondSignal(&flow_manager_ctrl_cond); + double total_wait_time = 0; + /* value in seconds */ + #define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ + #define WAIT_TIME 100 + +again: + SCMutexLock(&tv_root_lock); tv = tv_root[TVT_MGMT]; - while (tv != NULL) { - if (strcasecmp(tv->name, "FlowManagerThread") == 0) { - /* be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { - usleep(100); + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_mgr, + strlen(thread_name_flow_mgr)) == 0) + { + if (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + SCMutexUnlock(&tv_root_lock); + + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { + SCLogError(SC_ERR_FATAL, "Engine unable to " + "disable detect thread - \"%s\". " + "Killing engine", tv->name); + exit(EXIT_FAILURE); + } + goto again; } } tv = tv->next; } - - - /* not possible, unless someone decides to rename FlowManagerThread */ - if (cnt == 0) { - SCMutexUnlock(&tv_root_lock); - abort(); - } - SCMutexUnlock(&tv_root_lock); + /* wake up threads, another try */ + for (u = 0; u < flowmgr_number; u++) + SCCtrlCondSignal(&flow_manager_ctrl_cond); + /* reset count, so we can kill and respawn (unix socket) */ SC_ATOMIC_SET(flowmgr_cnt, 0); return; @@ -159,42 +203,31 @@ void FlowKillFlowManagerThread(void) * * \param f flow * \param state flow state - * \param emergency bool indicating emergency mode 1 yes, 0 no * * \retval timeout timeout in seconds */ -static inline uint32_t FlowGetFlowTimeout(Flow *f, int state, int emergency) +static inline uint32_t FlowGetFlowTimeout(const Flow *f, enum FlowState state) { uint32_t timeout; - - if (emergency) { - switch(state) { - default: - case FLOW_STATE_NEW: - timeout = flow_proto[f->protomap].emerg_new_timeout; - break; - case FLOW_STATE_ESTABLISHED: - timeout = flow_proto[f->protomap].emerg_est_timeout; - break; - case FLOW_STATE_CLOSED: - timeout = flow_proto[f->protomap].emerg_closed_timeout; - break; - } - } else { /* implies no emergency */ - switch(state) { - default: - case FLOW_STATE_NEW: - timeout = flow_proto[f->protomap].new_timeout; - break; - case FLOW_STATE_ESTABLISHED: - timeout = flow_proto[f->protomap].est_timeout; - break; - case FLOW_STATE_CLOSED: - timeout = flow_proto[f->protomap].closed_timeout; - break; - } + FlowProtoTimeoutPtr flow_timeouts = SC_ATOMIC_GET(flow_timeouts); + switch(state) { + default: + case FLOW_STATE_NEW: + timeout = flow_timeouts[f->protomap].new_timeout; + break; + case FLOW_STATE_ESTABLISHED: + timeout = flow_timeouts[f->protomap].est_timeout; + break; + case FLOW_STATE_CLOSED: + timeout = flow_timeouts[f->protomap].closed_timeout; + break; + case FLOW_STATE_CAPTURE_BYPASSED: + timeout = FLOW_BYPASSED_TIMEOUT; + break; + case FLOW_STATE_LOCAL_BYPASSED: + timeout = flow_timeouts[f->protomap].bypassed_timeout; + break; } - return timeout; } @@ -203,19 +236,22 @@ static inline uint32_t FlowGetFlowTimeout(Flow *f, int state, int emergency) * * \param f flow * \param ts timestamp - * \param emergency bool indicating emergency mode * * \retval 0 not timed out * \retval 1 timed out */ -static int FlowManagerFlowTimeout(Flow *f, int state, struct timeval *ts, int emergency) +static int FlowManagerFlowTimeout(const Flow *f, enum FlowState state, struct timeval *ts, int32_t *next_ts) { /* set the timeout value according to the flow operating mode, * flow's state and protocol.*/ - uint32_t timeout = FlowGetFlowTimeout(f, state, emergency); + uint32_t timeout = FlowGetFlowTimeout(f, state); + + int32_t flow_times_out_at = (int32_t)(f->lastts.tv_sec + timeout); + if (*next_ts == 0 || flow_times_out_at < *next_ts) + *next_ts = flow_times_out_at; /* do the timeout check */ - if ((int32_t)(f->lastts.tv_sec + timeout) >= ts->tv_sec) { + if (flow_times_out_at >= ts->tv_sec) { return 0; } @@ -228,23 +264,23 @@ static int FlowManagerFlowTimeout(Flow *f, int state, struct timeval *ts, int em * * \param f flow * \param ts timestamp - * \param emergency bool indicating emergency mode * * \retval 0 not timed out just yet * \retval 1 fully timed out, lets kill it */ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) { - /** never prune a flow that is used by a packet or stream msg - * we are currently processing in one of the threads */ + /* never prune a flow that is used by a packet we + * are currently processing in one of the threads */ if (SC_ATOMIC_GET(f->use_cnt) > 0) { return 0; } int server = 0, client = 0; + if (!(f->flags & FLOW_TIMEOUT_REASSEMBLY_DONE) && FlowForceReassemblyNeedReassembly(f, &server, &client) == 1) { - FlowForceReassemblyForFlowV2(f, server, client); + FlowForceReassemblyForFlow(f, server, client); return 0; } #ifdef DEBUG @@ -268,27 +304,40 @@ static int FlowManagerFlowTimedOut(Flow *f, struct timeval *ts) * \retval cnt timed out flows */ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, - int emergency, FlowTimeoutCounters *counters) + int emergency, FlowTimeoutCounters *counters, int32_t *next_ts) { uint32_t cnt = 0; + uint32_t checked = 0; do { - if (FLOWLOCK_TRYWRLOCK(f) != 0) { - f = f->hprev; - continue; - } + checked++; - Flow *next_flow = f->hprev; + /* check flow timeout based on lastts and state. Both can be + * accessed w/o Flow lock as we do have the hash row lock (so flow + * can't disappear) and flow_state is atomic. lastts can only + * be modified when we have both the flow and hash row lock */ - int state = FlowGetFlowState(f); + enum FlowState state = SC_ATOMIC_GET(f->flow_state); /* timeout logic goes here */ - if (FlowManagerFlowTimeout(f, state, ts, emergency) == 0) { - FLOWLOCK_UNLOCK(f); + if (FlowManagerFlowTimeout(f, state, ts, next_ts) == 0) { + + counters->flows_notimeout++; + f = f->hprev; continue; } + /* before grabbing the flow lock, make sure we have at least + * 3 packets in the pool */ + PacketPoolWaitForN(3); + + FLOWLOCK_WRLOCK(f); + + Flow *next_flow = f->hprev; + + counters->flows_timeout++; + /* check if the flow is fully timed out and * ready to be discarded. */ if (FlowManagerFlowTimedOut(f, ts) == 1) { @@ -305,25 +354,28 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, f->hnext = NULL; f->hprev = NULL; + if (f->flags & FLOW_TCP_REUSED) + counters->tcp_reuse++; + if (state == FLOW_STATE_NEW) f->flow_end_flags |= FLOW_END_FLAG_STATE_NEW; else if (state == FLOW_STATE_ESTABLISHED) f->flow_end_flags |= FLOW_END_FLAG_STATE_ESTABLISHED; else if (state == FLOW_STATE_CLOSED) f->flow_end_flags |= FLOW_END_FLAG_STATE_CLOSED; + else if (state == FLOW_STATE_LOCAL_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; + else if (state == FLOW_STATE_CAPTURE_BYPASSED) + f->flow_end_flags |= FLOW_END_FLAG_STATE_BYPASSED; if (emergency) f->flow_end_flags |= FLOW_END_FLAG_EMERGENCY; f->flow_end_flags |= FLOW_END_FLAG_TIMEOUT; -// FlowClearMemory (f, f->protomap); - /* no one is referring to this flow, use_cnt 0, removed from hash - * so we can unlock it and move it back to the spare queue. */ + * so we can unlock it and pass it to the flow recycler */ FLOWLOCK_UNLOCK(f); FlowEnqueue(&flow_recycle_q, f); - /* move to spare list */ -// FlowMoveToSpare(f); cnt++; @@ -338,14 +390,24 @@ static uint32_t FlowManagerHashRowTimeout(Flow *f, struct timeval *ts, case FLOW_STATE_CLOSED: counters->clo++; break; + case FLOW_STATE_LOCAL_BYPASSED: + case FLOW_STATE_CAPTURE_BYPASSED: + counters->byp++; + break; } + counters->flows_removed++; } else { + counters->flows_timeout_inuse++; FLOWLOCK_UNLOCK(f); } f = next_flow; } while (f != NULL); + counters->flows_checked += checked; + if (checked > counters->rows_maxlen) + counters->rows_maxlen = checked; + return cnt; } @@ -374,16 +436,37 @@ static uint32_t FlowTimeoutHash(struct timeval *ts, uint32_t try_cnt, for (idx = hash_min; idx < hash_max; idx++) { FlowBucket *fb = &flow_hash[idx]; - if (FBLOCK_TRYLOCK(fb) != 0) + counters->rows_checked++; + + int32_t check_ts = SC_ATOMIC_GET(fb->next_ts); + if (check_ts > (int32_t)ts->tv_sec) { + counters->rows_skipped++; + continue; + } + + /* before grabbing the row lock, make sure we have at least + * 9 packets in the pool */ + PacketPoolWaitForN(9); + + if (FBLOCK_TRYLOCK(fb) != 0) { + counters->rows_busy++; continue; + } /* flow hash bucket is now locked */ - if (fb->tail == NULL) + if (fb->tail == NULL) { + SC_ATOMIC_SET(fb->next_ts, INT_MAX); + counters->rows_empty++; goto next; + } + + int32_t next_ts = 0; /* we have a flow, or more than one */ - cnt += FlowManagerHashRowTimeout(fb->tail, ts, emergency, counters); + cnt += FlowManagerHashRowTimeout(fb->tail, ts, emergency, counters, &next_ts); + + SC_ATOMIC_SET(fb->next_ts, next_ts); next: FBLOCK_UNLOCK(fb); @@ -413,7 +496,7 @@ static uint32_t FlowManagerHashRowCleanup(Flow *f) Flow *next_flow = f->hprev; - int state = FlowGetFlowState(f); + int state = SC_ATOMIC_GET(f->flow_state); /* remove from the hash */ if (f->hprev != NULL) @@ -486,10 +569,24 @@ typedef struct FlowManagerThreadData_ { uint16_t flow_mgr_cnt_clo; uint16_t flow_mgr_cnt_new; uint16_t flow_mgr_cnt_est; - uint16_t flow_mgr_memuse; + uint16_t flow_mgr_cnt_byp; uint16_t flow_mgr_spare; uint16_t flow_emerg_mode_enter; uint16_t flow_emerg_mode_over; + uint16_t flow_tcp_reuse; + + uint16_t flow_mgr_flows_checked; + uint16_t flow_mgr_flows_notimeout; + uint16_t flow_mgr_flows_timeout; + uint16_t flow_mgr_flows_timeout_inuse; + uint16_t flow_mgr_flows_removed; + + uint16_t flow_mgr_rows_checked; + uint16_t flow_mgr_rows_skipped; + uint16_t flow_mgr_rows_empty; + uint16_t flow_mgr_rows_busy; + uint16_t flow_mgr_rows_maxlen; + } FlowManagerThreadData; static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) @@ -520,20 +617,26 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) /* pass thread data back to caller */ *data = ftd; - ftd->flow_mgr_cnt_clo = SCPerfTVRegisterCounter("flow_mgr.closed_pruned", t, - SC_PERF_TYPE_UINT64, "NULL"); - ftd->flow_mgr_cnt_new = SCPerfTVRegisterCounter("flow_mgr.new_pruned", t, - SC_PERF_TYPE_UINT64, "NULL"); - ftd->flow_mgr_cnt_est = SCPerfTVRegisterCounter("flow_mgr.est_pruned", t, - SC_PERF_TYPE_UINT64, "NULL"); - ftd->flow_mgr_memuse = SCPerfTVRegisterCounter("flow.memuse", t, - SC_PERF_TYPE_UINT64, "NULL"); - ftd->flow_mgr_spare = SCPerfTVRegisterCounter("flow.spare", t, - SC_PERF_TYPE_UINT64, "NULL"); - ftd->flow_emerg_mode_enter = SCPerfTVRegisterCounter("flow.emerg_mode_entered", t, - SC_PERF_TYPE_UINT64, "NULL"); - ftd->flow_emerg_mode_over = SCPerfTVRegisterCounter("flow.emerg_mode_over", t, - SC_PERF_TYPE_UINT64, "NULL"); + ftd->flow_mgr_cnt_clo = StatsRegisterCounter("flow_mgr.closed_pruned", t); + ftd->flow_mgr_cnt_new = StatsRegisterCounter("flow_mgr.new_pruned", t); + ftd->flow_mgr_cnt_est = StatsRegisterCounter("flow_mgr.est_pruned", t); + ftd->flow_mgr_cnt_byp = StatsRegisterCounter("flow_mgr.bypassed_pruned", t); + ftd->flow_mgr_spare = StatsRegisterCounter("flow.spare", t); + ftd->flow_emerg_mode_enter = StatsRegisterCounter("flow.emerg_mode_entered", t); + ftd->flow_emerg_mode_over = StatsRegisterCounter("flow.emerg_mode_over", t); + ftd->flow_tcp_reuse = StatsRegisterCounter("flow.tcp_reuse", t); + + ftd->flow_mgr_flows_checked = StatsRegisterCounter("flow_mgr.flows_checked", t); + ftd->flow_mgr_flows_notimeout = StatsRegisterCounter("flow_mgr.flows_notimeout", t); + ftd->flow_mgr_flows_timeout = StatsRegisterCounter("flow_mgr.flows_timeout", t); + ftd->flow_mgr_flows_timeout_inuse = StatsRegisterCounter("flow_mgr.flows_timeout_inuse", t); + ftd->flow_mgr_flows_removed = StatsRegisterCounter("flow_mgr.flows_removed", t); + + ftd->flow_mgr_rows_checked = StatsRegisterCounter("flow_mgr.rows_checked", t); + ftd->flow_mgr_rows_skipped = StatsRegisterCounter("flow_mgr.rows_skipped", t); + ftd->flow_mgr_rows_empty = StatsRegisterCounter("flow_mgr.rows_empty", t); + ftd->flow_mgr_rows_busy = StatsRegisterCounter("flow_mgr.rows_busy", t); + ftd->flow_mgr_rows_maxlen = StatsRegisterCounter("flow_mgr.rows_maxlen", t); PacketPoolInit(); return TM_ECODE_OK; @@ -541,6 +644,7 @@ static TmEcode FlowManagerThreadInit(ThreadVars *t, void *initdata, void **data) static TmEcode FlowManagerThreadDeinit(ThreadVars *t, void *data) { + PacketPoolDestroy(); SCFree(data); return TM_ECODE_OK; } @@ -562,26 +666,17 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) uint32_t established_cnt = 0, new_cnt = 0, closing_cnt = 0; int emerg = FALSE; int prev_emerg = FALSE; - uint32_t last_sec = 0; struct timespec cond_time; int flow_update_delay_sec = FLOW_NORMAL_MODE_UPDATE_DELAY_SEC; int flow_update_delay_nsec = FLOW_NORMAL_MODE_UPDATE_DELAY_NSEC; /* VJ leaving disabled for now, as hosts are only used by tags and the numbers * are really low. Might confuse ppl - uint16_t flow_mgr_host_prune = SCPerfTVRegisterCounter("hosts.pruned", th_v, - SC_PERF_TYPE_UINT64, - "NULL"); - uint16_t flow_mgr_host_active = SCPerfTVRegisterCounter("hosts.active", th_v, - SC_PERF_TYPE_Q_NORMAL, - "NULL"); - uint16_t flow_mgr_host_spare = SCPerfTVRegisterCounter("hosts.spare", th_v, - SC_PERF_TYPE_Q_NORMAL, - "NULL"); + uint16_t flow_mgr_host_prune = StatsRegisterCounter("hosts.pruned", th_v); + uint16_t flow_mgr_host_active = StatsRegisterCounter("hosts.active", th_v); + uint16_t flow_mgr_host_spare = StatsRegisterCounter("hosts.spare", th_v); */ memset(&ts, 0, sizeof(ts)); - FlowHashDebugInit(); - while (1) { if (TmThreadsCheckFlag(th_v, THV_PAUSE)) { @@ -598,7 +693,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCLogDebug("Flow emergency mode entered..."); - SCPerfCounterIncr(ftd->flow_emerg_mode_enter, th_v->sc_perf_pca); + StatsIncr(th_v, ftd->flow_emerg_mode_enter); } } @@ -607,17 +702,12 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) TimeGet(&ts); SCLogDebug("ts %" PRIdMAX "", (intmax_t)ts.tv_sec); - if (((uint32_t)ts.tv_sec - last_sec) > 600) { - FlowHashDebugPrint((uint32_t)ts.tv_sec); - last_sec = (uint32_t)ts.tv_sec; - } - /* see if we still have enough spare flows */ if (ftd->instance == 1) FlowUpdateSpareFlows(); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, }; + FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0}; FlowTimeoutHash(&ts, 0 /* check all */, ftd->min, ftd->max, &counters); @@ -625,25 +715,38 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) DefragTimeoutHash(&ts); //uint32_t hosts_pruned = HostTimeoutHash(&ts); + IPPairTimeoutHash(&ts); } /* - SCPerfCounterAddUI64(flow_mgr_host_prune, th_v->sc_perf_pca, (uint64_t)hosts_pruned); + StatsAddUI64(th_v, flow_mgr_host_prune, (uint64_t)hosts_pruned); uint32_t hosts_active = HostGetActiveCount(); - SCPerfCounterSetUI64(flow_mgr_host_active, th_v->sc_perf_pca, (uint64_t)hosts_active); + StatsSetUI64(th_v, flow_mgr_host_active, (uint64_t)hosts_active); uint32_t hosts_spare = HostGetSpareCount(); - SCPerfCounterSetUI64(flow_mgr_host_spare, th_v->sc_perf_pca, (uint64_t)hosts_spare); + StatsSetUI64(th_v, flow_mgr_host_spare, (uint64_t)hosts_spare); */ - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_clo, th_v->sc_perf_pca, (uint64_t)counters.clo); - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_new, th_v->sc_perf_pca, (uint64_t)counters.new); - SCPerfCounterAddUI64(ftd->flow_mgr_cnt_est, th_v->sc_perf_pca, (uint64_t)counters.est); - long long unsigned int flow_memuse = SC_ATOMIC_GET(flow_memuse); - SCPerfCounterSetUI64(ftd->flow_mgr_memuse, th_v->sc_perf_pca, (uint64_t)flow_memuse); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_clo, (uint64_t)counters.clo); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_new, (uint64_t)counters.new); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_est, (uint64_t)counters.est); + StatsAddUI64(th_v, ftd->flow_mgr_cnt_byp, (uint64_t)counters.byp); + StatsAddUI64(th_v, ftd->flow_tcp_reuse, (uint64_t)counters.tcp_reuse); + + StatsSetUI64(th_v, ftd->flow_mgr_flows_checked, (uint64_t)counters.flows_checked); + StatsSetUI64(th_v, ftd->flow_mgr_flows_notimeout, (uint64_t)counters.flows_notimeout); + StatsSetUI64(th_v, ftd->flow_mgr_flows_timeout, (uint64_t)counters.flows_timeout); + StatsSetUI64(th_v, ftd->flow_mgr_flows_removed, (uint64_t)counters.flows_removed); + StatsSetUI64(th_v, ftd->flow_mgr_flows_timeout_inuse, (uint64_t)counters.flows_timeout_inuse); + + StatsSetUI64(th_v, ftd->flow_mgr_rows_checked, (uint64_t)counters.rows_checked); + StatsSetUI64(th_v, ftd->flow_mgr_rows_skipped, (uint64_t)counters.rows_skipped); + StatsSetUI64(th_v, ftd->flow_mgr_rows_maxlen, (uint64_t)counters.rows_maxlen); + StatsSetUI64(th_v, ftd->flow_mgr_rows_busy, (uint64_t)counters.rows_busy); + StatsSetUI64(th_v, ftd->flow_mgr_rows_empty, (uint64_t)counters.rows_empty); uint32_t len = 0; FQLOCK_LOCK(&flow_spare_q); len = flow_spare_q.len; FQLOCK_UNLOCK(&flow_spare_q); - SCPerfCounterSetUI64(ftd->flow_mgr_spare, th_v->sc_perf_pca, (uint64_t)len); + StatsSetUI64(th_v, ftd->flow_mgr_spare, (uint64_t)len); /* Don't fear, FlowManagerThread is here... * clear emergency bit if we have at least xx flows pruned. */ @@ -656,6 +759,8 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) if (len * 100 / flow_config.prealloc > flow_config.emergency_recovery) { SC_ATOMIC_AND(flow_flags, ~FLOW_EMERGENCY); + FlowTimeoutsReset(); + emerg = FALSE; prev_emerg = FALSE; @@ -667,7 +772,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) "%% flows at the queue", (uintmax_t)ts.tv_sec, (uintmax_t)ts.tv_usec, len * 100 / flow_config.prealloc); - SCPerfCounterIncr(ftd->flow_emerg_mode_over, th_v->sc_perf_pca); + StatsIncr(th_v, ftd->flow_emerg_mode_over); } else { flow_update_delay_sec = FLOW_EMERG_MODE_UPDATE_DELAY_SEC; flow_update_delay_nsec = FLOW_EMERG_MODE_UPDATE_DELAY_NSEC; @@ -675,7 +780,7 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) } if (TmThreadsCheckFlag(th_v, THV_KILL)) { - SCPerfSyncCounters(th_v); + StatsSyncCounters(th_v); break; } @@ -688,21 +793,28 @@ static TmEcode FlowManager(ThreadVars *th_v, void *thread_data) SCLogDebug("woke up... %s", SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY ? "emergency":""); - SCPerfSyncCountersIfSignalled(th_v); + StatsSyncCountersIfSignalled(th_v); } - FlowHashDebugDeinit(); - - SCLogInfo("%" PRIu32 " new flows, %" PRIu32 " established flows were " + SCLogPerf("%" PRIu32 " new flows, %" PRIu32 " established flows were " "timed out, %"PRIu32" flows in closed state", new_cnt, established_cnt, closing_cnt); return TM_ECODE_OK; } +static uint64_t FlowGetMemuse(void) +{ + uint64_t flow_memuse = SC_ATOMIC_GET(flow_memuse); + return flow_memuse; +} + /** \brief spawn the flow manager thread */ void FlowManagerThreadSpawn() { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif intmax_t setting = 1; (void)ConfGetInt("flow.managers", &setting); @@ -713,24 +825,24 @@ void FlowManagerThreadSpawn() } flowmgr_number = (uint32_t)setting; - SCLogInfo("using %u flow manager threads", flowmgr_number); - FlowForceReassemblySetup(g_detect_disabled); + SCLogConfig("using %u flow manager threads", flowmgr_number); SCCtrlCondInit(&flow_manager_ctrl_cond, NULL); SCCtrlMutexInit(&flow_manager_ctrl_mutex, NULL); + StatsRegisterGlobalCounter("flow.memuse", FlowGetMemuse); + uint32_t u; - for (u = 0; u < flowmgr_number; u++) { + for (u = 0; u < flowmgr_number; u++) + { ThreadVars *tv_flowmgr = NULL; - char name[32] = ""; - snprintf(name, sizeof(name), "FlowManagerThread%02u", u+1); + char name[TM_THREAD_NAME_MAX]; + snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_mgr, u+1); - tv_flowmgr = TmThreadCreateMgmtThreadByName("FlowManagerThread", + tv_flowmgr = TmThreadCreateMgmtThreadByName(name, "FlowManager", 0); BUG_ON(tv_flowmgr == NULL); - TmThreadSetCPU(tv_flowmgr, MANAGEMENT_CPU_SET); - if (tv_flowmgr == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); @@ -830,7 +942,7 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) SCLogDebug("%u flows to recycle", len); if (TmThreadsCheckFlag(th_v, THV_KILL)) { - SCPerfSyncCounters(th_v); + StatsSyncCounters(th_v); break; } @@ -843,10 +955,10 @@ static TmEcode FlowRecycler(ThreadVars *th_v, void *thread_data) SCLogDebug("woke up..."); - SCPerfSyncCountersIfSignalled(th_v); + StatsSyncCountersIfSignalled(th_v); } - SCLogInfo("%"PRIu64" flows processed", recycled_cnt); + SCLogPerf("%"PRIu64" flows processed", recycled_cnt); return TM_ECODE_OK; } @@ -864,6 +976,9 @@ int FlowRecyclerReadyToShutdown(void) /** \brief spawn the flow recycler thread */ void FlowRecyclerThreadSpawn() { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif intmax_t setting = 1; (void)ConfGetInt("flow.recyclers", &setting); @@ -874,25 +989,24 @@ void FlowRecyclerThreadSpawn() } flowrec_number = (uint32_t)setting; - SCLogInfo("using %u flow recycler threads", flowrec_number); + SCLogConfig("using %u flow recycler threads", flowrec_number); SCCtrlCondInit(&flow_recycler_ctrl_cond, NULL); SCCtrlMutexInit(&flow_recycler_ctrl_mutex, NULL); uint32_t u; - for (u = 0; u < flowrec_number; u++) { + for (u = 0; u < flowrec_number; u++) + { ThreadVars *tv_flowmgr = NULL; - char name[32] = ""; - snprintf(name, sizeof(name), "FlowRecyclerThread%02u", u+1); + char name[TM_THREAD_NAME_MAX]; + snprintf(name, sizeof(name), "%s#%02u", thread_name_flow_rec, u+1); - tv_flowmgr = TmThreadCreateMgmtThreadByName("FlowRecyclerThread", + tv_flowmgr = TmThreadCreateMgmtThreadByName(name, "FlowRecycler", 0); BUG_ON(tv_flowmgr == NULL); - TmThreadSetCPU(tv_flowmgr, MANAGEMENT_CPU_SET); - if (tv_flowmgr == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); @@ -906,15 +1020,18 @@ void FlowRecyclerThreadSpawn() } /** - * \brief Used to kill flow recycler thread(s). + * \brief Used to disable flow recycler thread(s). * * \note this should only be called when the flow manager is already gone * * \todo Kinda hackish since it uses the tv name to identify flow recycler * thread. We need an all weather identification scheme. */ -void FlowKillFlowRecyclerThread(void) +void FlowDisableFlowRecyclerThread(void) { +#ifdef AFLFUZZ_DISABLE_MGTTHREADS + return; +#endif ThreadVars *tv = NULL; int cnt = 0; @@ -933,40 +1050,53 @@ void FlowKillFlowRecyclerThread(void) SCCtrlCondSignal(&flow_recycler_ctrl_cond); SCMutexLock(&tv_root_lock); - /* flow recycler thread(s) is/are a part of mgmt threads */ tv = tv_root[TVT_MGMT]; - - while (tv != NULL) { - if (strcasecmp(tv->name, "FlowRecyclerThread") == 0) { + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_rec, + strlen(thread_name_flow_rec)) == 0) + { TmThreadsSetFlag(tv, THV_KILL); - TmThreadsSetFlag(tv, THV_DEINIT); cnt++; } tv = tv->next; } + SCMutexUnlock(&tv_root_lock); - /* wake up threads, another try */ - for (u = 0; u < flowrec_number; u++) - SCCtrlCondSignal(&flow_recycler_ctrl_cond); + double total_wait_time = 0; + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 100 +again: + SCMutexLock(&tv_root_lock); tv = tv_root[TVT_MGMT]; - while (tv != NULL) { - if (strcasecmp(tv->name, "FlowRecyclerThread") == 0) { - /* be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { - usleep(100); + while (tv != NULL) + { + if (strncasecmp(tv->name, thread_name_flow_rec, + strlen(thread_name_flow_rec)) == 0) + { + if (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { + SCLogError(SC_ERR_FATAL, "Engine unable to " + "disable detect thread - \"%s\". " + "Killing engine", tv->name); + exit(EXIT_FAILURE); + } + SCMutexUnlock(&tv_root_lock); + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + goto again; } } tv = tv->next; } - - /* not possible, unless someone decides to rename FlowManagerThread */ - if (cnt == 0) { - SCMutexUnlock(&tv_root_lock); - abort(); - } + /* wake up threads, another try */ + for (u = 0; u < flowrec_number; u++) + SCCtrlCondSignal(&flow_recycler_ctrl_cond); SCMutexUnlock(&tv_root_lock); @@ -985,6 +1115,9 @@ void TmModuleFlowManagerRegister (void) tmm_modules[TMM_FLOWMANAGER].cap_flags = 0; tmm_modules[TMM_FLOWMANAGER].flags = TM_FLAG_MANAGEMENT_TM; SCLogDebug("%s registered", tmm_modules[TMM_FLOWMANAGER].name); + + SC_ATOMIC_INIT(flowmgr_cnt); + SC_ATOMIC_INIT(flow_timeouts); } void TmModuleFlowRecyclerRegister (void) @@ -997,6 +1130,8 @@ void TmModuleFlowRecyclerRegister (void) tmm_modules[TMM_FLOWRECYCLER].cap_flags = 0; tmm_modules[TMM_FLOWRECYCLER].flags = TM_FLAG_MANAGEMENT_TM; SCLogDebug("%s registered", tmm_modules[TMM_FLOWRECYCLER].name); + + SC_ATOMIC_INIT(flowrec_cnt); } #ifdef UNITTESTS @@ -1034,8 +1169,9 @@ static int FlowMgrTest01 (void) f.proto = IPPROTO_TCP; - int state = FlowGetFlowState(&f); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + int32_t next_ts = 0; + int state = SC_ATOMIC_GET(f.flow_state); + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1093,8 +1229,9 @@ static int FlowMgrTest02 (void) f.fb = &fb; f.proto = IPPROTO_TCP; - int state = FlowGetFlowState(&f); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + int32_t next_ts = 0; + int state = SC_ATOMIC_GET(f.flow_state); + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1140,8 +1277,9 @@ static int FlowMgrTest03 (void) f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; - int state = FlowGetFlowState(&f); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + int next_ts = 0; + int state = SC_ATOMIC_GET(f.flow_state); + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1200,8 +1338,9 @@ static int FlowMgrTest04 (void) f.proto = IPPROTO_TCP; f.flags |= FLOW_EMERGENCY; - int state = FlowGetFlowState(&f); - if (FlowManagerFlowTimeout(&f, state, &ts, 0) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { + int next_ts = 0; + int state = SC_ATOMIC_GET(f.flow_state); + if (FlowManagerFlowTimeout(&f, state, &ts, &next_ts) != 1 && FlowManagerFlowTimedOut(&f, &ts) != 1) { FBLOCK_DESTROY(&fb); FLOW_DESTROY(&f); FlowQueueDestroy(&flow_spare_q); @@ -1253,7 +1392,7 @@ static int FlowMgrTest05 (void) struct timeval ts; TimeGet(&ts); /* try to time out flows */ - FlowTimeoutCounters counters = { 0, 0, 0, }; + FlowTimeoutCounters counters = { 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0}; FlowTimeoutHash(&ts, 0 /* check all */, 0, flow_config.hash_size, &counters); if (flow_recycle_q.len > 0) { @@ -1262,7 +1401,6 @@ static int FlowMgrTest05 (void) memcpy(&flow_config, &backup, sizeof(FlowConfig)); FlowShutdown(); - return result; } #endif /* UNITTESTS */ @@ -1273,10 +1411,15 @@ static int FlowMgrTest05 (void) void FlowMgrRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("FlowMgrTest01 -- Timeout a flow having fresh TcpSession", FlowMgrTest01, 1); - UtRegisterTest("FlowMgrTest02 -- Timeout a flow having TcpSession with segments", FlowMgrTest02, 1); - UtRegisterTest("FlowMgrTest03 -- Timeout a flow in emergency having fresh TcpSession", FlowMgrTest03, 1); - UtRegisterTest("FlowMgrTest04 -- Timeout a flow in emergency having TcpSession with segments", FlowMgrTest04, 1); - UtRegisterTest("FlowMgrTest05 -- Test flow Allocations when it reach memcap", FlowMgrTest05, 1); + UtRegisterTest("FlowMgrTest01 -- Timeout a flow having fresh TcpSession", + FlowMgrTest01); + UtRegisterTest("FlowMgrTest02 -- Timeout a flow having TcpSession with segments", + FlowMgrTest02); + UtRegisterTest("FlowMgrTest03 -- Timeout a flow in emergency having fresh TcpSession", + FlowMgrTest03); + UtRegisterTest("FlowMgrTest04 -- Timeout a flow in emergency having TcpSession with segments", + FlowMgrTest04); + UtRegisterTest("FlowMgrTest05 -- Test flow Allocations when it reach memcap", + FlowMgrTest05); #endif /* UNITTESTS */ } diff --git a/src/flow-manager.h b/src/flow-manager.h index a2e6f6dc068d..117c98df6d0c 100644 --- a/src/flow-manager.h +++ b/src/flow-manager.h @@ -24,13 +24,17 @@ #ifndef __FLOW_MANAGER_H__ #define __FLOW_MANAGER_H__ +#define FlowTimeoutsReset() FlowTimeoutsInit() +void FlowTimeoutsInit(void); +void FlowTimeoutsEmergency(void); + /** flow manager scheduling condition */ SCCtrlCondT flow_manager_ctrl_cond; SCCtrlMutex flow_manager_ctrl_mutex; #define FlowWakeupFlowManagerThread() SCCtrlCondSignal(&flow_manager_ctrl_cond) void FlowManagerThreadSpawn(void); -void FlowKillFlowManagerThread(void); +void FlowDisableFlowManagerThread(void); void FlowMgrRegisterTests (void); /** flow recycler scheduling condition */ @@ -40,7 +44,7 @@ SCCtrlMutex flow_recycler_ctrl_mutex; SCCtrlCondSignal(&flow_recycler_ctrl_cond) void FlowRecyclerThreadSpawn(void); -void FlowKillFlowRecyclerThread(void); +void FlowDisableFlowRecyclerThread(void); void TmModuleFlowManagerRegister (void); void TmModuleFlowRecyclerRegister (void); diff --git a/src/flow-private.h b/src/flow-private.h index 2c7b8f6dbdd7..9cfcf228637b 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -40,16 +40,21 @@ #define FLOW_DEFAULT_NEW_TIMEOUT 30 #define FLOW_DEFAULT_EST_TIMEOUT 300 #define FLOW_DEFAULT_CLOSED_TIMEOUT 0 +#define FLOW_DEFAULT_BYPASSED_TIMEOUT 100 #define FLOW_IPPROTO_TCP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_TCP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT 100 #define FLOW_IPPROTO_UDP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_UDP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT 100 #define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 30 #define FLOW_IPPROTO_ICMP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT 100 #define FLOW_DEFAULT_EMERG_NEW_TIMEOUT 10 #define FLOW_DEFAULT_EMERG_EST_TIMEOUT 100 #define FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT 0 +#define FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT 50 #define FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT 100 #define FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT 10 @@ -57,6 +62,8 @@ #define FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100 +#define FLOW_BYPASSED_TIMEOUT 6 + enum { FLOW_PROTO_TCP = 0, FLOW_PROTO_UDP, @@ -67,13 +74,18 @@ enum { /* should be last */ FLOW_PROTO_MAX, }; +/* max used in app-layer (counters) */ +#define FLOW_PROTO_APPLAYER_MAX FLOW_PROTO_UDP + 1 /* * Variables */ /** FlowProto specific timeouts and free/state functions */ -FlowProto flow_proto[FLOW_PROTO_MAX]; + +FlowProtoTimeout flow_timeouts_normal[FLOW_PROTO_MAX]; +FlowProtoTimeout flow_timeouts_emerg[FLOW_PROTO_MAX]; +FlowProtoFreeFunc flow_freefuncs[FLOW_PROTO_MAX]; /** spare/unused/prealloced flows live here */ FlowQueue flow_spare_q; @@ -85,35 +97,7 @@ FlowBucket *flow_hash; FlowConfig flow_config; /** flow memuse counter (atomic), for enforcing memcap limit */ -SC_ATOMIC_DECLARE(long long unsigned int, flow_memuse); - -//#define FLOWBITS_STATS -#ifdef FLOWBITS_STATS -uint64_t flowbits_memuse; -uint64_t flowbits_memuse_max; -uint32_t flowbits_added; -uint32_t flowbits_removed; -SCMutex flowbits_mutex; -#endif /* FLOWBITS_STATS */ - -/** \internal - * \brief Get the flow's state - * - * \param f flow - * - * \retval state either FLOW_STATE_NEW, FLOW_STATE_ESTABLISHED or FLOW_STATE_CLOSED - */ -static inline int FlowGetFlowState(Flow *f) -{ - if (flow_proto[f->protomap].GetProtoState != NULL) { - return flow_proto[f->protomap].GetProtoState(f->protoctx); - } else { - if ((f->flags & FLOW_TO_SRC_SEEN) && (f->flags & FLOW_TO_DST_SEEN)) - return FLOW_STATE_ESTABLISHED; - else - return FLOW_STATE_NEW; - } -} +SC_ATOMIC_DECLARE(uint64_t, flow_memuse); #endif /* __FLOW_PRIVATE_H__ */ diff --git a/src/flow-storage.c b/src/flow-storage.c index e4f4f8aeb256..155b3fc10dee 100644 --- a/src/flow-storage.c +++ b/src/flow-storage.c @@ -289,8 +289,8 @@ static int FlowStorageTest03(void) void RegisterFlowStorageTests(void) { #ifdef UNITTESTS - UtRegisterTest("FlowStorageTest01", FlowStorageTest01, 1); - UtRegisterTest("FlowStorageTest02", FlowStorageTest02, 1); - UtRegisterTest("FlowStorageTest03", FlowStorageTest03, 1); + UtRegisterTest("FlowStorageTest01", FlowStorageTest01); + UtRegisterTest("FlowStorageTest02", FlowStorageTest02); + UtRegisterTest("FlowStorageTest03", FlowStorageTest03); #endif } diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 4f62d89d3a4b..eb1400022f89 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -62,39 +62,6 @@ #include "util-profiling.h" -static TmSlot *stream_pseudo_pkt_stream_tm_slot = NULL; -static ThreadVars *stream_pseudo_pkt_stream_TV = NULL; - -static TmSlot *stream_pseudo_pkt_detect_tm_slot = NULL; -static ThreadVars *stream_pseudo_pkt_detect_TV = NULL; -static ThreadVars *stream_pseudo_pkt_detect_prev_TV = NULL; - -static TmSlot *stream_pseudo_pkt_decode_tm_slot = NULL; -static ThreadVars *stream_pseudo_pkt_decode_TV = NULL; - -/** - * \internal - * \brief Flush out if we have any unattended packets. - */ -static inline void FlowForceReassemblyFlushPendingPseudoPackets(void) -{ - /* we don't lock the queue, since flow manager is dead */ - if (stream_pseudo_pkt_decode_tm_slot->slot_post_pq.len == 0) - return; - - SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - Packet *p = PacketDequeue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq); - SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - if (TmThreadsSlotProcessPkt(stream_pseudo_pkt_decode_TV, - stream_pseudo_pkt_decode_tm_slot, - p) != TM_ECODE_OK) { - SCLogError(SC_ERR_TM_THREADS_ERROR, "Received error from FFR on " - "flushing packets through decode->.. TMs"); - } - - return; -} - /** * \internal * \brief Pseudo packet setup for flow forced reassembly. @@ -113,6 +80,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, TcpSession *ssn, int dummy) { + p->tenant_id = f->tenant_id; p->datalink = DLT_RAW; p->proto = IPPROTO_TCP; FlowReference(&p->flow, f); @@ -120,6 +88,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->flags |= PKT_STREAM_EOF; p->flags |= PKT_HAS_FLOW; p->flags |= PKT_PSEUDO_STREAM_END; + + if (f->flags & FLOW_NOPACKET_INSPECTION) { + DecodeSetNoPacketInspectionFlag(p); + } + if (f->flags & FLOW_NOPAYLOAD_INSPECTION) { + DecodeSetNoPayloadInspectionFlag(p); + } + if (direction == 0) p->flowflags |= FLOW_PKT_TOSERVER; else @@ -141,6 +117,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->dp = f->sp; } + /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr. + * Force an allocation if it is not the case. + */ + if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) { + if (PacketCallocExtPkt(p, 40) == -1) { + goto error; + } + } /* set the ip header */ p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); /* version 4 and length 20 bytes for the tcp header */ @@ -178,6 +162,14 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->dp = f->sp; } + /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr. + * Force an allocation if it is not the case. + */ + if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) { + if (PacketCallocExtPkt(p, 60) == -1) { + goto error; + } + } /* set the ip header */ p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p); /* version 6 */ @@ -247,15 +239,15 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, } if (FLOW_IS_IPV4(f)) { - p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, 20); + p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->tcph, 20, 0); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ - p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, - IPV4_GET_RAW_HLEN(p->ip4h)); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, + IPV4_GET_RAW_HLEN(p->ip4h), 0); } else if (FLOW_IS_IPV6(f)) { - p->tcph->th_sum = TCPCalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, 20); + p->tcph->th_sum = TCPChecksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->tcph, 20, 0); } memset(&p->ts, 0, sizeof(struct timeval)); @@ -264,6 +256,10 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, AppLayerParserSetEOF(f->alparser); return p; + +error: + FlowDeReference(&p->flow); + return NULL; } static inline Packet *FlowForceReassemblyPseudoPacketGet(int direction, @@ -271,11 +267,13 @@ static inline Packet *FlowForceReassemblyPseudoPacketGet(int direction, TcpSession *ssn, int dummy) { - Packet *p; - - p = PacketGetFromAlloc(); - if (p == NULL) + PacketPoolWait(); + Packet *p = PacketPoolGetPacket(); + if (p == NULL) { return NULL; + } + + PACKET_PROFILING_START(p); return FlowForceReassemblyPseudoPacketSetup(p, direction, f, ssn, dummy); } @@ -361,7 +359,7 @@ int FlowForceReassemblyNeedReassembly(Flow *f, int *server, int *client) * * \retval 0 This flow doesn't need any reassembly processing; 1 otherwise. */ -int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) +int FlowForceReassemblyForFlow(Flow *f, int server, int client) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; TcpSession *ssn; @@ -391,7 +389,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); @@ -400,7 +398,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); p3 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p3 == NULL) { @@ -410,7 +408,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p2); goto done; } - PKT_SET_SRC(p3, PKT_SRC_FFR_V2); + PKT_SET_SRC(p3, PKT_SRC_FFR); } else { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p2 == NULL) { @@ -418,7 +416,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } } else if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { @@ -427,7 +425,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { @@ -435,13 +433,13 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } else { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); @@ -450,7 +448,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } } @@ -460,7 +458,7 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { @@ -468,28 +466,33 @@ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) TmqhOutputPacketpool(NULL, p1); goto done; } - PKT_SET_SRC(p2, PKT_SRC_FFR_V2); + PKT_SET_SRC(p2, PKT_SRC_FFR); } else if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p1 == NULL) { goto done; } - PKT_SET_SRC(p1, PKT_SRC_FFR_V2); + PKT_SET_SRC(p1, PKT_SRC_FFR); } else { /* impossible */ BUG_ON(1); } } - SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p1); - if (p2 != NULL) - PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p2); - if (p3 != NULL) - PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p3); - SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); - if (stream_pseudo_pkt_decode_TV->inq != NULL) { - SCCondSignal(&trans_q[stream_pseudo_pkt_decode_TV->inq->id].cond_q); + /* inject the packet(s) into the appropriate thread */ + int thread_id = (int)f->thread_id; + Packet *packets[4] = { p1, p2 ? p2 : p3, p2 ? p3 : NULL, NULL }; /**< null terminated array of packets */ + if (unlikely(!(TmThreadsInjectPacketsById(packets, thread_id)))) { + FlowDeReference(&p1->flow); + TmqhOutputPacketpool(NULL, p1); + if (p2) { + FlowDeReference(&p2->flow); + TmqhOutputPacketpool(NULL, p2); + } + if (p3) { + FlowDeReference(&p3->flow); + TmqhOutputPacketpool(NULL, p3); + } } /* done, in case of error (no packet) we still tag flow as complete @@ -518,19 +521,14 @@ static inline void FlowForceReassemblyForHash(void) { Flow *f; TcpSession *ssn; - int client_ok; - int server_ok; - + int client_ok = 0; + int server_ok = 0; uint32_t idx = 0; - /* We use this packet just for reassembly purpose */ - Packet *reassemble_p = PacketGetFromAlloc(); - if (reassemble_p == NULL) - return; - for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; + PacketPoolWaitForN(9); FBLOCK_LOCK(fb); /* get the topmost flow from the QUEUE */ @@ -538,7 +536,7 @@ static inline void FlowForceReassemblyForHash(void) /* we need to loop through all the flows in the queue */ while (f != NULL) { - PACKET_RECYCLE(reassemble_p); + PacketPoolWaitForN(3); FLOWLOCK_WRLOCK(f); @@ -552,111 +550,17 @@ static inline void FlowForceReassemblyForHash(void) continue; } - (void)FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok); - - /* ah ah! We have some unattended toserver segments */ - if (client_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { - StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); - - ssn->client.last_ack = (ssn->client.seg_list_tail->seq + - ssn->client.seg_list_tail->payload_len); - - FlowForceReassemblyPseudoPacketSetup(reassemble_p, 1, f, ssn, 1); - StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, - stt->ra_ctx, ssn, &ssn->server, - reassemble_p, NULL); - FlowDeReference(&reassemble_p->flow); - } - /* oh oh! We have some unattended toclient segments */ - if (server_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { - StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); - - ssn->server.last_ack = (ssn->server.seg_list_tail->seq + - ssn->server.seg_list_tail->payload_len); - - FlowForceReassemblyPseudoPacketSetup(reassemble_p, 0, f, ssn, 1); - StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, - stt->ra_ctx, ssn, &ssn->client, - reassemble_p, NULL); - FlowDeReference(&reassemble_p->flow); + if (FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok) == 1) { + FlowForceReassemblyForFlow(f, server_ok, client_ok); } FLOWLOCK_UNLOCK(f); - /* insert a pseudo packet in the toserver direction */ - if (client_ok) { - FLOWLOCK_WRLOCK(f); - Packet *p = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); - FLOWLOCK_UNLOCK(f); - - if (p == NULL) { - TmqhOutputPacketpool(NULL, reassemble_p); - FBLOCK_UNLOCK(fb); - return; - } - PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); - - if (stream_pseudo_pkt_detect_prev_TV != NULL) { - stream_pseudo_pkt_detect_prev_TV-> - tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); - } else { - TmSlot *s = stream_pseudo_pkt_detect_tm_slot; - while (s != NULL) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, - &s->slot_post_pq); - s = s->slot_next; - } - - if (stream_pseudo_pkt_detect_TV != NULL) { - stream_pseudo_pkt_detect_TV-> - tmqh_out(stream_pseudo_pkt_detect_TV, p); - } else { - TmqhOutputPacketpool(NULL, p); - } - } - } - if (server_ok) { - FLOWLOCK_WRLOCK(f); - Packet *p = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); - FLOWLOCK_UNLOCK(f); - - if (p == NULL) { - TmqhOutputPacketpool(NULL, reassemble_p); - FBLOCK_UNLOCK(fb); - return; - } - PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); - - if (stream_pseudo_pkt_detect_prev_TV != NULL) { - stream_pseudo_pkt_detect_prev_TV-> - tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); - } else { - TmSlot *s = stream_pseudo_pkt_detect_tm_slot; - while (s != NULL) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, - &s->slot_post_pq); - s = s->slot_next; - } - - if (stream_pseudo_pkt_detect_TV != NULL) { - stream_pseudo_pkt_detect_TV-> - tmqh_out(stream_pseudo_pkt_detect_TV, p); - } else { - TmqhOutputPacketpool(NULL, p); - } - } - } - /* next flow in the queue */ f = f->hnext; } FBLOCK_UNLOCK(fb); } - - PKT_SET_SRC(reassemble_p, PKT_SRC_FFR_SHUTDOWN); - TmqhOutputPacketpool(NULL, reassemble_p); return; } @@ -665,141 +569,8 @@ static inline void FlowForceReassemblyForHash(void) */ void FlowForceReassembly(void) { - /* Do remember. We need to have packet acquire disabled by now */ - - /** ----- Part 1 ------*/ - /* Flush out unattended packets */ - FlowForceReassemblyFlushPendingPseudoPackets(); - - /** ----- Part 2 ----- **/ - /* Check if all threads are idle. We need this so that we have all - * packets freeds. As a consequence, no flows are in use */ - - SCMutexLock(&tv_root_lock); - - /* all receive threads are part of packet processing threads */ - ThreadVars *tv = tv_root[TVT_PPT]; - - /* we are doing this in order receive -> decode -> ... -> log */ - while (tv != NULL) { - if (tv->inq != NULL) { - /* we wait till we dry out all the inq packets, before we - * kill this thread. Do note that you should have disabled - * packet acquire by now using TmThreadDisableReceiveThreads()*/ - if (!(strlen(tv->inq->name) == strlen("packetpool") && - strcasecmp(tv->inq->name, "packetpool") == 0)) { - PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { - usleep(100); - } - TmThreadsSetFlag(tv, THV_PAUSE); - if (tv->inq->q_type == 0) - SCCondSignal(&trans_q[tv->inq->id].cond_q); - else - SCCondSignal(&data_queues[tv->inq->id].cond_q); - while (!TmThreadsCheckFlag(tv, THV_PAUSED)) { - if (tv->inq->q_type == 0) - SCCondSignal(&trans_q[tv->inq->id].cond_q); - else - SCCondSignal(&data_queues[tv->inq->id].cond_q); - usleep(100); - } - TmThreadsUnsetFlag(tv, THV_PAUSE); - } - } - tv = tv->next; - } - - SCMutexUnlock(&tv_root_lock); - - /** ----- Part 3 ----- **/ /* Carry out flow reassembly for unattended flows */ FlowForceReassemblyForHash(); - return; } -/** - * \param detect_disabled bool, indicating if we use a detection engine (true) - */ -void FlowForceReassemblySetup(int detect_disabled) -{ - /* get StreamTCP TM's slot and TV containing this slot */ - stream_pseudo_pkt_stream_tm_slot = TmSlotGetSlotForTM(TMM_STREAMTCP); - if (stream_pseudo_pkt_stream_tm_slot == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the slot for STREAMTCP TM"); - exit(EXIT_FAILURE); - } - stream_pseudo_pkt_stream_TV = - TmThreadsGetTVContainingSlot(stream_pseudo_pkt_stream_tm_slot); - if (stream_pseudo_pkt_stream_TV == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the TV containing STREAMTCP TM slot"); - exit(EXIT_FAILURE); - } - - if (!detect_disabled) { - /* get detect TM's slot and TV containing this slot */ - stream_pseudo_pkt_detect_tm_slot = TmSlotGetSlotForTM(TMM_DETECT); - if (stream_pseudo_pkt_detect_tm_slot == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve a slot for DETECT TM"); - exit(EXIT_FAILURE); - } - stream_pseudo_pkt_detect_TV = - TmThreadsGetTVContainingSlot(stream_pseudo_pkt_detect_tm_slot); - if (stream_pseudo_pkt_detect_TV == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the TV containing the Detect TM slot"); - exit(EXIT_FAILURE); - } - if (stream_pseudo_pkt_detect_TV->tm_slots == stream_pseudo_pkt_detect_tm_slot) { - stream_pseudo_pkt_detect_prev_TV = stream_pseudo_pkt_detect_TV->prev; - } - if (strcasecmp(stream_pseudo_pkt_detect_TV->outqh_name, "packetpool") == 0) { - stream_pseudo_pkt_detect_TV = NULL; - } - } - - SCMutexLock(&tv_root_lock); - ThreadVars *tv = tv_root[TVT_PPT]; - int done = 0; - while (tv) { - TmSlot *slots = tv->tm_slots; - while (slots) { - TmModule *tm = TmModuleGetById(slots->tm_id); - if (tm->flags & TM_FLAG_DECODE_TM) { - done = 1; - stream_pseudo_pkt_decode_tm_slot = slots; - break; - } - slots = slots->slot_next; - } - if (done) - break; - tv = tv->next; - } - SCMutexUnlock(&tv_root_lock); - - if (stream_pseudo_pkt_decode_tm_slot == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the slot for DECODE TM"); - exit(EXIT_FAILURE); - } - stream_pseudo_pkt_decode_TV = - TmThreadsGetTVContainingSlot(stream_pseudo_pkt_decode_tm_slot); - if (stream_pseudo_pkt_decode_TV == NULL) { - /* yes, this is fatal! */ - SCLogError(SC_ERR_TM_MODULES_ERROR, "Looks like we have failed to " - "retrieve the TV containing the Decode TM slot"); - exit(EXIT_FAILURE); - } - - return; -} diff --git a/src/flow-timeout.h b/src/flow-timeout.h index 036bd50ce7af..50e007ae066d 100644 --- a/src/flow-timeout.h +++ b/src/flow-timeout.h @@ -24,7 +24,7 @@ #ifndef __FLOW_TIMEOUT_H__ #define __FLOW_TIMEOUT_H__ -int FlowForceReassemblyForFlowV2(Flow *f, int server, int client); +int FlowForceReassemblyForFlow(Flow *f, int server, int client); int FlowForceReassemblyNeedReassembly(Flow *f, int *server, int *client); void FlowForceReassembly(void); void FlowForceReassemblySetup(int detect_disabled); diff --git a/src/flow-util.c b/src/flow-util.c index 7bd685743a41..dae4194bd55d 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -64,6 +64,7 @@ Flow *FlowAlloc(void) } memset(f, 0, size); + /* coverity[missing_lock] */ FLOW_INITIALIZE(f); return f; } @@ -79,7 +80,8 @@ void FlowFree(Flow *f) FLOW_DESTROY(f); SCFree(f); - (void) SC_ATOMIC_SUB(flow_memuse, sizeof(Flow)); + size_t size = sizeof(Flow) + FlowStorageSize(); + (void) SC_ATOMIC_SUB(flow_memuse, size); } /** diff --git a/src/flow-util.h b/src/flow-util.h index 8271c3320798..6258a01959c6 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -40,10 +40,13 @@ (f)->sp = 0; \ (f)->dp = 0; \ (f)->proto = 0; \ + SC_ATOMIC_INIT((f)->flow_state); \ SC_ATOMIC_INIT((f)->use_cnt); \ + (f)->tenant_id = 0; \ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ (f)->flags = 0; \ + (f)->file_flags = 0; \ (f)->lastts.tv_sec = 0; \ (f)->lastts.tv_usec = 0; \ FLOWLOCK_INIT((f)); \ @@ -52,22 +55,17 @@ (f)->alproto = 0; \ (f)->alproto_ts = 0; \ (f)->alproto_tc = 0; \ - (f)->data_al_so_far[0] = 0; \ - (f)->data_al_so_far[1] = 0; \ - (f)->de_ctx_id = 0; \ + (f)->de_ctx_version = 0; \ + (f)->thread_id = 0; \ (f)->alparser = NULL; \ (f)->alstate = NULL; \ - (f)->de_state = NULL; \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ (f)->flowvar = NULL; \ - SCMutexInit(&(f)->de_state_m, NULL); \ (f)->hnext = NULL; \ (f)->hprev = NULL; \ (f)->lnext = NULL; \ (f)->lprev = NULL; \ - SC_ATOMIC_INIT((f)->autofp_tmqh_flow_qid); \ - (void) SC_ATOMIC_SET((f)->autofp_tmqh_flow_qid, -1); \ RESET_COUNTERS((f)); \ } while (0) @@ -81,10 +79,13 @@ (f)->sp = 0; \ (f)->dp = 0; \ (f)->proto = 0; \ + SC_ATOMIC_RESET((f)->flow_state); \ SC_ATOMIC_RESET((f)->use_cnt); \ + (f)->tenant_id = 0; \ (f)->probing_parser_toserver_alproto_masks = 0; \ (f)->probing_parser_toclient_alproto_masks = 0; \ (f)->flags = 0; \ + (f)->file_flags = 0; \ (f)->lastts.tv_sec = 0; \ (f)->lastts.tv_usec = 0; \ (f)->protoctx = NULL; \ @@ -94,37 +95,22 @@ (f)->alproto = 0; \ (f)->alproto_ts = 0; \ (f)->alproto_tc = 0; \ - (f)->data_al_so_far[0] = 0; \ - (f)->data_al_so_far[1] = 0; \ - (f)->de_ctx_id = 0; \ - if ((f)->de_state != NULL) { \ - SCMutexLock(&(f)->de_state_m); \ - DetectEngineStateReset((f)->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); \ - SCMutexUnlock(&(f)->de_state_m); \ - } \ + (f)->de_ctx_version = 0; \ + (f)->thread_id = 0; \ (f)->sgh_toserver = NULL; \ (f)->sgh_toclient = NULL; \ GenericVarFree((f)->flowvar); \ (f)->flowvar = NULL; \ - if (SC_ATOMIC_GET((f)->autofp_tmqh_flow_qid) != -1) { \ - (void) SC_ATOMIC_SET((f)->autofp_tmqh_flow_qid, -1); \ - } \ RESET_COUNTERS((f)); \ } while(0) #define FLOW_DESTROY(f) do { \ FlowCleanupAppLayer((f)); \ + SC_ATOMIC_DESTROY((f)->flow_state); \ SC_ATOMIC_DESTROY((f)->use_cnt); \ \ FLOWLOCK_DESTROY((f)); \ - if ((f)->de_state != NULL) { \ - SCMutexLock(&(f)->de_state_m); \ - DetectEngineStateFree((f)->de_state); \ - SCMutexUnlock(&(f)->de_state_m); \ - } \ GenericVarFree((f)->flowvar); \ - SCMutexDestroy(&(f)->de_state_m); \ - SC_ATOMIC_DESTROY((f)->autofp_tmqh_flow_qid); \ } while(0) /** \brief check if a memory alloc would fit in the memcap diff --git a/src/flow-var.c b/src/flow-var.c index 5262b5a795be..d4506b9b0356 100644 --- a/src/flow-var.c +++ b/src/flow-var.c @@ -51,7 +51,28 @@ static void FlowVarUpdateInt(FlowVar *fv, uint32_t value) * \note flow is not locked by this function, caller is * responsible */ -FlowVar *FlowVarGet(Flow *f, uint16_t idx) +FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, uint16_t keylen) +{ + GenericVar *gv = f->flowvar; + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_FLOWVAR && gv->idx == 0) { + + FlowVar *fv = (FlowVar *)gv; + if (fv->keylen == keylen && memcmp(key, fv->key, keylen) == 0) { + return fv; + } + } + } + + return NULL; +} + +/** \brief get the flowvar with index 'idx' from the flow + * \note flow is not locked by this function, caller is + * responsible + */ +FlowVar *FlowVarGet(Flow *f, uint32_t idx) { GenericVar *gv = f->flowvar; @@ -64,11 +85,30 @@ FlowVar *FlowVarGet(Flow *f, uint16_t idx) } /* add a flowvar to the flow, or update it */ -void FlowVarAddStrNoLock(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) +void FlowVarAddKeyValue(Flow *f, uint8_t *key, uint16_t keysize, uint8_t *value, uint16_t size) +{ + FlowVar *fv = SCCalloc(1, sizeof(FlowVar)); + if (unlikely(fv == NULL)) + return; + + fv->type = DETECT_FLOWVAR; + fv->datatype = FLOWVAR_TYPE_STR; + fv->idx = 0; + fv->data.fv_str.value = value; + fv->data.fv_str.value_len = size; + fv->key = key; + fv->keylen = keysize; + fv->next = NULL; + + GenericVarAppend(&f->flowvar, (GenericVar *)fv); +} + +/* add a flowvar to the flow, or update it */ +void FlowVarAddIdValue(Flow *f, uint32_t idx, uint8_t *value, uint16_t size) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { - fv = SCMalloc(sizeof(FlowVar)); + fv = SCCalloc(1, sizeof(FlowVar)); if (unlikely(fv == NULL)) return; @@ -86,15 +126,7 @@ void FlowVarAddStrNoLock(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) } /* add a flowvar to the flow, or update it */ -void FlowVarAddStr(Flow *f, uint16_t idx, uint8_t *value, uint16_t size) -{ - FLOWLOCK_WRLOCK(f); - FlowVarAddStrNoLock(f, idx, value, size); - FLOWLOCK_UNLOCK(f); -} - -/* add a flowvar to the flow, or update it */ -void FlowVarAddIntNoLock(Flow *f, uint16_t idx, uint32_t value) +void FlowVarAddIntNoLock(Flow *f, uint32_t idx, uint32_t value) { FlowVar *fv = FlowVarGet(f, idx); if (fv == NULL) { @@ -115,11 +147,9 @@ void FlowVarAddIntNoLock(Flow *f, uint16_t idx, uint32_t value) } /* add a flowvar to the flow, or update it */ -void FlowVarAddInt(Flow *f, uint16_t idx, uint32_t value) +void FlowVarAddInt(Flow *f, uint32_t idx, uint32_t value) { - FLOWLOCK_WRLOCK(f); FlowVarAddIntNoLock(f, idx, value); - FLOWLOCK_UNLOCK(f); } void FlowVarFree(FlowVar *fv) @@ -148,7 +178,7 @@ void FlowVarPrint(GenericVar *gv) FlowVar *fv = (FlowVar *)gv; if (fv->datatype == FLOWVAR_TYPE_STR) { - SCLogDebug("Name idx \"%" PRIu16 "\", Value \"", fv->idx); + SCLogDebug("Name idx \"%" PRIu32 "\", Value \"", fv->idx); for (u = 0; u < fv->data.fv_str.value_len; u++) { if (isprint(fv->data.fv_str.value[u])) SCLogDebug("%c", fv->data.fv_str.value[u]); @@ -157,7 +187,7 @@ void FlowVarPrint(GenericVar *gv) } SCLogDebug("\", Len \"%" PRIu16 "\"\n", fv->data.fv_str.value_len); } else if (fv->datatype == FLOWVAR_TYPE_INT) { - SCLogDebug("Name idx \"%" PRIu16 "\", Value \"%" PRIu32 "\"", fv->idx, + SCLogDebug("Name idx \"%" PRIu32 "\", Value \"%" PRIu32 "\"", fv->idx, fv->data.fv_int.value); } else { SCLogDebug("Unknown data type at flowvars\n"); diff --git a/src/flow-var.h b/src/flow-var.h index e45d803043a7..f0bcf3c0c3f6 100644 --- a/src/flow-var.h +++ b/src/flow-var.h @@ -47,25 +47,28 @@ typedef struct FlowVarTypeInt_ { /** Generic Flowvar Structure */ typedef struct FlowVar_ { uint8_t type; /* type, DETECT_FLOWVAR in this case */ - uint16_t idx; /* name idx */ + uint8_t datatype; + uint16_t keylen; + uint32_t idx; /* name idx */ GenericVar *next; /* right now just implement this as a list, * in the long run we have think of something * faster. */ - uint8_t datatype; union { FlowVarTypeStr fv_str; FlowVarTypeInt fv_int; } data; - + uint8_t *key; } FlowVar; /** Flowvar Interface API */ -void FlowVarAddStrNoLock(Flow *, uint16_t, uint8_t *, uint16_t); -void FlowVarAddStr(Flow *, uint16_t, uint8_t *, uint16_t); -void FlowVarAddIntNoLock(Flow *, uint16_t, uint32_t); -void FlowVarAddInt(Flow *, uint16_t, uint32_t); -FlowVar *FlowVarGet(Flow *, uint16_t); +void FlowVarAddIdValue(Flow *, uint32_t id, uint8_t *value, uint16_t size); +void FlowVarAddKeyValue(Flow *f, uint8_t *key, uint16_t keysize, uint8_t *value, uint16_t size); + +void FlowVarAddIntNoLock(Flow *, uint32_t, uint32_t); +void FlowVarAddInt(Flow *, uint32_t, uint32_t); +FlowVar *FlowVarGet(Flow *, uint32_t); +FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, uint16_t keylen); void FlowVarFree(FlowVar *); void FlowVarPrint(GenericVar *); diff --git a/src/flow-worker.c b/src/flow-worker.c new file mode 100644 index 000000000000..b29486e3359e --- /dev/null +++ b/src/flow-worker.c @@ -0,0 +1,319 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Flow Workers are single thread modules taking care of (almost) + * everything related to packets with flows: + * + * - Lookup/creation + * - Stream tracking, reassembly + * - Applayer update + * - Detection + * + * This all while holding the flow lock. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "decode.h" +#include "stream-tcp.h" +#include "app-layer.h" +#include "detect-engine.h" +#include "output.h" + +#include "util-validate.h" + +#include "flow-util.h" + +typedef DetectEngineThreadCtx *DetectEngineThreadCtxPtr; + +typedef struct FlowWorkerThreadData_ { + DecodeThreadVars *dtv; + + union { + StreamTcpThread *stream_thread; + void *stream_thread_ptr; + }; + + SC_ATOMIC_DECLARE(DetectEngineThreadCtxPtr, detect_thread); + + void *output_thread; /* Output thread data. */ + + PacketQueue pq; + +} FlowWorkerThreadData; + +/** \brief handle flow for packet + * + * Handle flow creation/lookup + */ +static inline TmEcode FlowUpdate(Packet *p) +{ + FlowHandlePacketUpdate(p->flow, p); + + int state = SC_ATOMIC_GET(p->flow->flow_state); + switch (state) { + case FLOW_STATE_CAPTURE_BYPASSED: + case FLOW_STATE_LOCAL_BYPASSED: + return TM_ECODE_DONE; + default: + return TM_ECODE_OK; + } +} + +static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data); + +static TmEcode FlowWorkerThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + FlowWorkerThreadData *fw = SCCalloc(1, sizeof(*fw)); + if (fw == NULL) + return TM_ECODE_FAILED; + + SC_ATOMIC_INIT(fw->detect_thread); + SC_ATOMIC_SET(fw->detect_thread, NULL); + + fw->dtv = DecodeThreadVarsAlloc(tv); + if (fw->dtv == NULL) { + FlowWorkerThreadDeinit(tv, fw); + return TM_ECODE_FAILED; + } + + /* setup TCP */ + if (StreamTcpThreadInit(tv, NULL, &fw->stream_thread_ptr) != TM_ECODE_OK) { + FlowWorkerThreadDeinit(tv, fw); + return TM_ECODE_FAILED; + } + + if (DetectEngineEnabled()) { + /* setup DETECT */ + void *detect_thread = NULL; + if (DetectEngineThreadCtxInit(tv, NULL, &detect_thread) != TM_ECODE_OK) { + FlowWorkerThreadDeinit(tv, fw); + return TM_ECODE_FAILED; + } + SC_ATOMIC_SET(fw->detect_thread, detect_thread); + } + + /* Setup outputs for this thread. */ + if (OutputLoggerThreadInit(tv, initdata, &fw->output_thread) != TM_ECODE_OK) { + FlowWorkerThreadDeinit(tv, fw); + return TM_ECODE_FAILED; + } + + AppLayerRegisterThreadCounters(tv); + + /* setup pq for stream end pkts */ + memset(&fw->pq, 0, sizeof(PacketQueue)); + SCMutexInit(&fw->pq.mutex_q, NULL); + + *data = fw; + return TM_ECODE_OK; +} + +static TmEcode FlowWorkerThreadDeinit(ThreadVars *tv, void *data) +{ + FlowWorkerThreadData *fw = data; + + DecodeThreadVarsFree(tv, fw->dtv); + + /* free TCP */ + StreamTcpThreadDeinit(tv, (void *)fw->stream_thread); + + /* free DETECT */ + void *detect_thread = SC_ATOMIC_GET(fw->detect_thread); + if (detect_thread != NULL) { + DetectEngineThreadCtxDeinit(tv, detect_thread); + SC_ATOMIC_SET(fw->detect_thread, NULL); + } + + /* Free output. */ + OutputLoggerThreadDeinit(tv, fw->output_thread); + + /* free pq */ + BUG_ON(fw->pq.len); + SCMutexDestroy(&fw->pq.mutex_q); + + SC_ATOMIC_DESTROY(fw->detect_thread); + SCFree(fw); + return TM_ECODE_OK; +} + +TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq); +TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); + +TmEcode FlowWorker(ThreadVars *tv, Packet *p, void *data, PacketQueue *preq, PacketQueue *unused) +{ + FlowWorkerThreadData *fw = data; + void *detect_thread = SC_ATOMIC_GET(fw->detect_thread); + + SCLogDebug("packet %"PRIu64, p->pcap_cnt); + + /* update time */ + if (!(PKT_IS_PSEUDOPKT(p))) { + TimeSetByThread(tv->id, &p->ts); + } + + /* handle Flow */ + if (p->flags & PKT_WANTS_FLOW) { + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_FLOW); + + FlowHandlePacket(tv, fw->dtv, p); + if (likely(p->flow != NULL)) { + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + if (FlowUpdate(p) == TM_ECODE_DONE) { + FLOWLOCK_UNLOCK(p->flow); + return TM_ECODE_OK; + } + } + /* Flow is now LOCKED */ + + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_FLOW); + + /* if PKT_WANTS_FLOW is not set, but PKT_HAS_FLOW is, then this is a + * pseudo packet created by the flow manager. */ + } else if (p->flags & PKT_HAS_FLOW) { + FLOWLOCK_WRLOCK(p->flow); + } + + SCLogDebug("packet %"PRIu64" has flow? %s", p->pcap_cnt, p->flow ? "yes" : "no"); + + /* handle TCP and app layer */ + if (PKT_IS_TCP(p)) { + SCLogDebug("packet %"PRIu64" is TCP", p->pcap_cnt); + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + + /* if detect is disabled, we need to apply file flags to the flow + * here on the first packet. */ + if (detect_thread == NULL && + ((PKT_IS_TOSERVER(p) && (p->flowflags & FLOW_PKT_TOSERVER_FIRST)) || + (PKT_IS_TOCLIENT(p) && (p->flowflags & FLOW_PKT_TOCLIENT_FIRST)))) + { + DisableDetectFlowFileFlags(p->flow); + } + + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_STREAM); + StreamTcp(tv, p, fw->stream_thread, &fw->pq, NULL); + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_STREAM); + + /* Packets here can safely access p->flow as it's locked */ + SCLogDebug("packet %"PRIu64": extra packets %u", p->pcap_cnt, fw->pq.len); + Packet *x; + while ((x = PacketDequeue(&fw->pq))) { + SCLogDebug("packet %"PRIu64" extra packet %p", p->pcap_cnt, x); + + // TODO do we need to call StreamTcp on these pseudo packets or not? + //StreamTcp(tv, x, fw->stream_thread, &fw->pq, NULL); + if (detect_thread != NULL) { + FLOWWORKER_PROFILING_START(x, PROFILE_FLOWWORKER_DETECT); + Detect(tv, x, detect_thread, NULL, NULL); + FLOWWORKER_PROFILING_END(x, PROFILE_FLOWWORKER_DETECT); + } + + // Outputs + OutputLoggerLog(tv, x, fw->output_thread); + + /* put these packets in the preq queue so that they are + * by the other thread modules before packet 'p'. */ + PacketEnqueue(preq, x); + } + + /* handle the app layer part of the UDP packet payload */ + } else if (p->flow && p->proto == IPPROTO_UDP) { + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_APPLAYERUDP); + AppLayerHandleUdp(tv, fw->stream_thread->ra_ctx->app_tctx, p, p->flow); + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_APPLAYERUDP); + } + + /* handle Detect */ + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + SCLogDebug("packet %"PRIu64" calling Detect", p->pcap_cnt); + + if (detect_thread != NULL) { + FLOWWORKER_PROFILING_START(p, PROFILE_FLOWWORKER_DETECT); + Detect(tv, p, detect_thread, NULL, NULL); + FLOWWORKER_PROFILING_END(p, PROFILE_FLOWWORKER_DETECT); + } + + // Outputs. + OutputLoggerLog(tv, p, fw->output_thread); + + /* Release tcp segments. Done here after alerting can use them. */ + if (p->flow != NULL && p->proto == IPPROTO_TCP) { + StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? + STREAM_TOSERVER : STREAM_TOCLIENT); + } + + if (p->flow) { + DEBUG_ASSERT_FLOW_LOCKED(p->flow); + FLOWLOCK_UNLOCK(p->flow); + } + + return TM_ECODE_OK; +} + +void FlowWorkerReplaceDetectCtx(void *flow_worker, void *detect_ctx) +{ + FlowWorkerThreadData *fw = flow_worker; + + SC_ATOMIC_SET(fw->detect_thread, detect_ctx); +} + +void *FlowWorkerGetDetectCtxPtr(void *flow_worker) +{ + FlowWorkerThreadData *fw = flow_worker; + + return SC_ATOMIC_GET(fw->detect_thread); +} + +const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi) +{ + switch (fwi) { + case PROFILE_FLOWWORKER_FLOW: + return "flow"; + case PROFILE_FLOWWORKER_STREAM: + return "stream"; + case PROFILE_FLOWWORKER_APPLAYERUDP: + return "app-layer"; + case PROFILE_FLOWWORKER_DETECT: + return "detect"; + case PROFILE_FLOWWORKER_SIZE: + return "size"; + } + return "error"; +} + +static void FlowWorkerExitPrintStats(ThreadVars *tv, void *data) +{ + FlowWorkerThreadData *fw = data; + OutputLoggerExitPrintStats(tv, fw->output_thread); +} + +void TmModuleFlowWorkerRegister (void) +{ + tmm_modules[TMM_FLOWWORKER].name = "FlowWorker"; + tmm_modules[TMM_FLOWWORKER].ThreadInit = FlowWorkerThreadInit; + tmm_modules[TMM_FLOWWORKER].Func = FlowWorker; + tmm_modules[TMM_FLOWWORKER].ThreadDeinit = FlowWorkerThreadDeinit; + tmm_modules[TMM_FLOWWORKER].ThreadExitPrintStats = FlowWorkerExitPrintStats; + tmm_modules[TMM_FLOWWORKER].cap_flags = 0; + tmm_modules[TMM_FLOWWORKER].flags = TM_FLAG_STREAM_TM|TM_FLAG_DETECT_TM; +} diff --git a/src/flow-worker.h b/src/flow-worker.h new file mode 100644 index 000000000000..418ea05d6ca8 --- /dev/null +++ b/src/flow-worker.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __FLOW_WORKER_H__ +#define __FLOW_WORKER_H__ + +enum ProfileFlowWorkerId { + PROFILE_FLOWWORKER_FLOW = 0, + PROFILE_FLOWWORKER_STREAM, + PROFILE_FLOWWORKER_APPLAYERUDP, + PROFILE_FLOWWORKER_DETECT, + PROFILE_FLOWWORKER_SIZE +}; +const char *ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi); + +void FlowWorkerReplaceDetectCtx(void *flow_worker, void *detect_ctx); +void *FlowWorkerGetDetectCtxPtr(void *flow_worker); + +void TmModuleFlowWorkerRegister (void); + +#endif /* __FLOW_WORKER_H__ */ diff --git a/src/flow.c b/src/flow.c index 516e684e946f..728145552b85 100644 --- a/src/flow.c +++ b/src/flow.c @@ -84,10 +84,7 @@ SC_ATOMIC_DECLARE(unsigned int, flow_flags); void FlowRegisterTests(void); void FlowInitFlowProto(); -int FlowSetProtoTimeout(uint8_t , uint32_t ,uint32_t ,uint32_t); -int FlowSetProtoEmergencyTimeout(uint8_t , uint32_t ,uint32_t ,uint32_t); int FlowSetProtoFreeFunc(uint8_t, void (*Free)(void *)); -int FlowSetFlowStateFunc(uint8_t , int (*GetProtoState)(void *)); /* Run mode selected at suricata.c */ extern int run_mode; @@ -148,30 +145,40 @@ int FlowUpdateSpareFlows(void) return 1; } -/** \brief Set the IPOnly scanned flag for 'direction'. This function - * handles the locking too. +/** \brief Set the IPOnly scanned flag for 'direction'. + * * \param f Flow to set the flag in * \param direction direction to set the flag in */ -void FlowSetIPOnlyFlag(Flow *f, char direction) +void FlowSetIPOnlyFlag(Flow *f, int direction) { - FLOWLOCK_WRLOCK(f); direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : (f->flags |= FLOW_TOCLIENT_IPONLY_SET); - FLOWLOCK_UNLOCK(f); return; } -/** \brief Set the IPOnly scanned flag for 'direction'. - * - * \param f Flow to set the flag in - * \param direction direction to set the flag in - */ -void FlowSetIPOnlyFlagNoLock(Flow *f, char direction) +/** \brief Set flag to indicate that flow has alerts + * + * \param f flow + */ +void FlowSetHasAlertsFlag(Flow *f) { - direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) : - (f->flags |= FLOW_TOCLIENT_IPONLY_SET); - return; + f->flags |= FLOW_HAS_ALERTS; +} + +/** \brief Check if flow has alerts + * + * \param f flow + * \retval 1 has alerts + * \retval 0 has not alerts + */ +int FlowHasAlerts(const Flow *f) +{ + if (f->flags & FLOW_HAS_ALERTS) { + return 1; + } + + return 0; } /** @@ -179,7 +186,7 @@ void FlowSetIPOnlyFlagNoLock(Flow *f, char direction) * \retval 0 to_server * \retval 1 to_client */ -int FlowGetPacketDirection(Flow *f, const Packet *p) +int FlowGetPacketDirection(const Flow *f, const Packet *p) { if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) { if (!(CMP_PORT(p->sp,p->dp))) { @@ -227,49 +234,73 @@ static inline int FlowUpdateSeenFlag(const Packet *p) return 1; } -/** \brief Entry point for packet flow handling +/** \brief Update Packet and Flow * - * This is called for every packet. + * Updates packet and flow based on the new packet. * - * \param tv threadvars - * \param dtv decode thread vars (for flow output api thread data) - * \param p packet to handle flow for + * \param f locked flow + * \param p packet + * + * \note overwrites p::flowflags */ -void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) +void FlowHandlePacketUpdate(Flow *f, Packet *p) { - /* Get this packet's flow from the hash. FlowHandlePacket() will setup - * a new flow if nescesary. If we get NULL, we're out of flow memory. - * The returned flow is locked. */ - Flow *f = FlowGetFlowFromHash(tv, dtv, p); - if (f == NULL) - return; + SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f); - /* Point the Packet at the Flow */ - FlowReference(&p->flow, f); + int state = SC_ATOMIC_GET(f->flow_state); - /* update the last seen timestamp of this flow */ - COPY_TIMESTAMP(&p->ts,&f->lastts); + if (state != FLOW_STATE_CAPTURE_BYPASSED) { + /* update the last seen timestamp of this flow */ + COPY_TIMESTAMP(&p->ts, &f->lastts); + } else { + /* still seeing packet, we downgrade to local bypass */ + if (p->ts.tv_sec - f->lastts.tv_sec > FLOW_BYPASSED_TIMEOUT / 2) { + SCLogDebug("Downgrading flow to local bypass"); + COPY_TIMESTAMP(&p->ts, &f->lastts); + FlowUpdateState(f, FLOW_STATE_LOCAL_BYPASSED); + } + } /* update flags and counters */ if (FlowGetPacketDirection(f, p) == TOSERVER) { - if (FlowUpdateSeenFlag(p)) { - f->flags |= FLOW_TO_DST_SEEN; - } f->todstpktcnt++; f->todstbytecnt += GET_PKT_LEN(p); - p->flowflags |= FLOW_PKT_TOSERVER; - } else { - if (FlowUpdateSeenFlag(p)) { - f->flags |= FLOW_TO_SRC_SEEN; + p->flowflags = FLOW_PKT_TOSERVER; + if (!(f->flags & FLOW_TO_DST_SEEN)) { + if (FlowUpdateSeenFlag(p)) { + f->flags |= FLOW_TO_DST_SEEN; + p->flowflags |= FLOW_PKT_TOSERVER_FIRST; + } + } + /* xfer proto detect ts flag to first packet in ts dir */ + if (f->flags & FLOW_PROTO_DETECT_TS_DONE) { + f->flags &= ~FLOW_PROTO_DETECT_TS_DONE; + p->flags |= PKT_PROTO_DETECT_TS_DONE; } + } else { f->tosrcpktcnt++; f->tosrcbytecnt += GET_PKT_LEN(p); - p->flowflags |= FLOW_PKT_TOCLIENT; + p->flowflags = FLOW_PKT_TOCLIENT; + if (!(f->flags & FLOW_TO_SRC_SEEN)) { + if (FlowUpdateSeenFlag(p)) { + f->flags |= FLOW_TO_SRC_SEEN; + p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; + } + } + /* xfer proto detect tc flag to first packet in tc dir */ + if (f->flags & FLOW_PROTO_DETECT_TC_DONE) { + f->flags &= ~FLOW_PROTO_DETECT_TC_DONE; + p->flags |= PKT_PROTO_DETECT_TC_DONE; + } } - if ((f->flags & FLOW_TO_DST_SEEN) && (f->flags & FLOW_TO_SRC_SEEN)) { + if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { SCLogDebug("pkt %p FLOW_PKT_ESTABLISHED", p); p->flowflags |= FLOW_PKT_ESTABLISHED; + + if (f->proto != IPPROTO_TCP) { + FlowUpdateState(f, FLOW_STATE_ESTABLISHED); + } } /*set the detection bypass flags*/ @@ -281,8 +312,24 @@ void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) SCLogDebug("setting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f); DecodeSetNoPayloadInspectionFlag(p); } +} - FLOWLOCK_UNLOCK(f); +/** \brief Entry point for packet flow handling + * + * This is called for every packet. + * + * \param tv threadvars + * \param dtv decode thread vars (for flow output api thread data) + * \param p packet to handle flow for + */ +void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) +{ + /* Get this packet's flow from the hash. FlowHandlePacket() will setup + * a new flow if nescesary. If we get NULL, we're out of flow memory. + * The returned flow is locked. */ + Flow *f = FlowGetFlowFromHash(tv, dtv, p, &p->flow); + if (f == NULL) + return; /* set the flow in the packet */ p->flags |= PKT_HAS_FLOW; @@ -302,10 +349,11 @@ void FlowInitConfig(char quiet) FlowQueueInit(&flow_spare_q); FlowQueueInit(&flow_recycle_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ flow_config.hash_rand = (int)( FLOW_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif flow_config.hash_size = FLOW_DEFAULT_HASHSIZE; flow_config.memcap = FLOW_DEFAULT_MEMCAP; flow_config.prealloc = FLOW_DEFAULT_PREALLOC; @@ -368,7 +416,7 @@ void FlowInitConfig(char quiet) (uintmax_t)sizeof(FlowBucket)); exit(EXIT_FAILURE); } - flow_hash = SCCalloc(flow_config.hash_size, sizeof(FlowBucket)); + flow_hash = SCMallocAligned(flow_config.hash_size * sizeof(FlowBucket), CLS); if (unlikely(flow_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in FlowInitConfig. Exiting..."); exit(EXIT_FAILURE); @@ -378,11 +426,12 @@ void FlowInitConfig(char quiet) uint32_t i = 0; for (i = 0; i < flow_config.hash_size; i++) { FBLOCK_INIT(&flow_hash[i]); + SC_ATOMIC_INIT(flow_hash[i].next_ts); } (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the flow hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the flow hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(flow_memuse), flow_config.hash_size, (uintmax_t)sizeof(FlowBucket)); @@ -390,7 +439,7 @@ void FlowInitConfig(char quiet) /* pre allocate flows */ for (i = 0; i < flow_config.prealloc; i++) { - if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { + if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) { SCLogError(SC_ERR_FLOW_INIT, "preallocating flows failed: " "max flow memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", flow_config.memcap, @@ -408,9 +457,9 @@ void FlowInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " flows of size %" PRIuMAX "", - flow_spare_q.len, (uintmax_t)sizeof(Flow)); - SCLogInfo("flow memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("preallocated %" PRIu32 " flows of size %" PRIuMAX "", + flow_spare_q.len, (uintmax_t)(sizeof(Flow) + + FlowStorageSize())); + SCLogConfig("flow memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(flow_memuse), flow_config.memcap); } @@ -423,10 +472,6 @@ void FlowInitConfig(char quiet) * \warning Not thread safe */ static void FlowPrintStats (void) { -#ifdef FLOWBITS_STATS - SCLogInfo("flowbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", - flowbits_added, flowbits_removed, flowbits_memuse_max); -#endif /* FLOWBITS_STATS */ return; } @@ -451,7 +496,7 @@ void FlowShutdown(void) if (flow_hash != NULL) { /* clean up flow mutexes */ for (u = 0; u < flow_config.hash_size; u++) { - Flow *f = flow_hash[u].head; + f = flow_hash[u].head; while (f) { #ifdef DEBUG_VALIDATION BUG_ON(SC_ATOMIC_GET(f->use_cnt) != 0); @@ -464,8 +509,9 @@ void FlowShutdown(void) } FBLOCK_DESTROY(&flow_hash[u]); + SC_ATOMIC_DESTROY(flow_hash[u].next_ts); } - SCFree(flow_hash); + SCFreeAligned(flow_hash); flow_hash = NULL; } (void) SC_ATOMIC_SUB(flow_memuse, flow_config.hash_size * sizeof(FlowBucket)); @@ -485,63 +531,53 @@ void FlowShutdown(void) void FlowInitFlowProto(void) { - /*Default*/ - flow_proto[FLOW_PROTO_DEFAULT].new_timeout = FLOW_DEFAULT_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].est_timeout = FLOW_DEFAULT_EST_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = - FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = - FLOW_DEFAULT_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout = - FLOW_DEFAULT_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_DEFAULT].Freefunc = NULL; - flow_proto[FLOW_PROTO_DEFAULT].GetProtoState = NULL; - /*TCP*/ - flow_proto[FLOW_PROTO_TCP].new_timeout = FLOW_IPPROTO_TCP_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].est_timeout = FLOW_IPPROTO_TCP_EST_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = - FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = - FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_TCP].Freefunc = NULL; - flow_proto[FLOW_PROTO_TCP].GetProtoState = NULL; - /*UDP*/ - flow_proto[FLOW_PROTO_UDP].new_timeout = FLOW_IPPROTO_UDP_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].est_timeout = FLOW_IPPROTO_UDP_EST_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = - FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = - FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_UDP].Freefunc = NULL; - flow_proto[FLOW_PROTO_UDP].GetProtoState = NULL; - /*ICMP*/ - flow_proto[FLOW_PROTO_ICMP].new_timeout = FLOW_IPPROTO_ICMP_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].est_timeout = FLOW_IPPROTO_ICMP_EST_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = - FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = - FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].emerg_closed_timeout = - FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT; - flow_proto[FLOW_PROTO_ICMP].Freefunc = NULL; - flow_proto[FLOW_PROTO_ICMP].GetProtoState = NULL; + FlowTimeoutsInit(); + +#define SET_DEFAULTS(p, n, e, c, b, ne, ee, ce, be) \ + flow_timeouts_normal[(p)].new_timeout = (n); \ + flow_timeouts_normal[(p)].est_timeout = (e); \ + flow_timeouts_normal[(p)].closed_timeout = (c); \ + flow_timeouts_normal[(p)].bypassed_timeout = (b); \ + flow_timeouts_emerg[(p)].new_timeout = (ne); \ + flow_timeouts_emerg[(p)].est_timeout = (ee); \ + flow_timeouts_emerg[(p)].closed_timeout = (ce); \ + flow_timeouts_emerg[(p)].bypassed_timeout = (be); \ + + SET_DEFAULTS(FLOW_PROTO_DEFAULT, + FLOW_DEFAULT_NEW_TIMEOUT, FLOW_DEFAULT_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_DEFAULT_BYPASSED_TIMEOUT, + FLOW_DEFAULT_EMERG_NEW_TIMEOUT, FLOW_DEFAULT_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_TCP, + FLOW_IPPROTO_TCP_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_IPPROTO_TCP_BYPASSED_TIMEOUT, + FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_UDP, + FLOW_IPPROTO_UDP_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_IPPROTO_UDP_BYPASSED_TIMEOUT, + FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + SET_DEFAULTS(FLOW_PROTO_ICMP, + FLOW_IPPROTO_ICMP_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EST_TIMEOUT, + FLOW_DEFAULT_CLOSED_TIMEOUT, FLOW_IPPROTO_ICMP_BYPASSED_TIMEOUT, + FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT, FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT, + FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT, FLOW_DEFAULT_EMERG_BYPASSED_TIMEOUT); + + flow_freefuncs[FLOW_PROTO_DEFAULT].Freefunc = NULL; + flow_freefuncs[FLOW_PROTO_TCP].Freefunc = NULL; + flow_freefuncs[FLOW_PROTO_UDP].Freefunc = NULL; + flow_freefuncs[FLOW_PROTO_ICMP].Freefunc = NULL; /* Let's see if we have custom timeouts defined from config */ const char *new = NULL; const char *established = NULL; const char *closed = NULL; + const char *bypassed = NULL; const char *emergency_new = NULL; const char *emergency_established = NULL; const char *emergency_closed = NULL; + const char *emergency_bypassed = NULL; ConfNode *flow_timeouts = ConfGetNode("flow-timeouts"); if (flow_timeouts != NULL) { @@ -554,48 +590,65 @@ void FlowInitFlowProto(void) new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); closed = ConfNodeLookupChildValue(proto, "closed"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].est_timeout = configval; } if (closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(closed), closed) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_DEFAULT].closed_timeout = configval; + } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_DEFAULT].bypassed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout= configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].est_timeout= configval; } if (emergency_closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > 0) { - flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].closed_timeout = configval; + } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_DEFAULT].bypassed_timeout = configval; } } @@ -605,48 +658,65 @@ void FlowInitFlowProto(void) new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); closed = ConfNodeLookupChildValue(proto, "closed"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); emergency_closed = ConfNodeLookupChildValue(proto, "emergency-closed"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_TCP].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_TCP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_TCP].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_TCP].est_timeout = configval; } if (closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(closed), closed) > 0) { - flow_proto[FLOW_PROTO_TCP].closed_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_TCP].closed_timeout = configval; + } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_TCP].bypassed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_TCP].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_TCP].est_timeout = configval; } if (emergency_closed != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_closed), emergency_closed) > 0) { - flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_TCP].closed_timeout = configval; + } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_TCP].bypassed_timeout = configval; } } @@ -655,32 +725,50 @@ void FlowInitFlowProto(void) if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); + if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_UDP].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_UDP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_UDP].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_UDP].est_timeout = configval; + } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_UDP].bypassed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_UDP].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_UDP].est_timeout = configval; + } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_UDP].bypassed_timeout = configval; } } @@ -689,33 +777,50 @@ void FlowInitFlowProto(void) if (proto != NULL) { new = ConfNodeLookupChildValue(proto, "new"); established = ConfNodeLookupChildValue(proto, "established"); + bypassed = ConfNodeLookupChildValue(proto, "bypassed"); emergency_new = ConfNodeLookupChildValue(proto, "emergency-new"); emergency_established = ConfNodeLookupChildValue(proto, "emergency-established"); + emergency_bypassed = ConfNodeLookupChildValue(proto, + "emergency-bypassed"); if (new != NULL && ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) { - flow_proto[FLOW_PROTO_ICMP].new_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_ICMP].new_timeout = configval; } if (established != NULL && ByteExtractStringUint32(&configval, 10, strlen(established), established) > 0) { - flow_proto[FLOW_PROTO_ICMP].est_timeout = configval; + flow_timeouts_normal[FLOW_PROTO_ICMP].est_timeout = configval; + } + if (bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(bypassed), + bypassed) > 0) { + + flow_timeouts_normal[FLOW_PROTO_ICMP].bypassed_timeout = configval; } if (emergency_new != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_new), emergency_new) > 0) { - flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_ICMP].new_timeout = configval; } if (emergency_established != NULL && ByteExtractStringUint32(&configval, 10, strlen(emergency_established), emergency_established) > 0) { - flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = configval; + flow_timeouts_emerg[FLOW_PROTO_ICMP].est_timeout = configval; + } + if (emergency_bypassed != NULL && + ByteExtractStringUint32(&configval, 10, + strlen(emergency_bypassed), + emergency_bypassed) > 0) { + + flow_timeouts_emerg[FLOW_PROTO_UDP].bypassed_timeout = configval; } } } @@ -736,8 +841,8 @@ int FlowClearMemory(Flow* f, uint8_t proto_map) SCEnter(); /* call the protocol specific free function if we have one */ - if (flow_proto[proto_map].Freefunc != NULL) { - flow_proto[proto_map].Freefunc(f->protoctx); + if (flow_freefuncs[proto_map].Freefunc != NULL) { + flow_freefuncs[proto_map].Freefunc(f->protoctx); } FlowFreeStorage(f); @@ -760,87 +865,66 @@ int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *)) uint8_t proto_map; proto_map = FlowGetProtoMapping(proto); - flow_proto[proto_map].Freefunc = Free; + flow_freefuncs[proto_map].Freefunc = Free; return 1; } -/** - * \brief Function to set the function to get protocol specific flow state. - * - * \param proto protocol of which function is needed to be set. - * \param GetFlowState Function pointer which will be called to get state. - */ - -int FlowSetFlowStateFunc (uint8_t proto, int (*GetProtoState)(void *)) +AppProto FlowGetAppProtocol(const Flow *f) { - uint8_t proto_map; - proto_map = FlowGetProtoMapping(proto); - - flow_proto[proto_map].GetProtoState = GetProtoState; - return 1; + return f->alproto; } -/** - * \brief Function to set the timeout values for the specified protocol. - * - * \param proto protocol of which timeout value is needed to be set. - * \param new_timeout timeout value for the new flows. - * \param est_timeout timeout value for the established flows. - * \param closed_timeout timeout value for the closed flows. - */ - -int FlowSetProtoTimeout(uint8_t proto, uint32_t new_timeout, - uint32_t est_timeout, uint32_t closed_timeout) +void *FlowGetAppState(const Flow *f) { - uint8_t proto_map; - proto_map = FlowGetProtoMapping(proto); - - flow_proto[proto_map].new_timeout = new_timeout; - flow_proto[proto_map].est_timeout = est_timeout; - flow_proto[proto_map].closed_timeout = closed_timeout; - - return 1; + return f->alstate; } /** - * \brief Function to set the emergency timeout values for the specified - * protocol. - * - * \param proto protocol of which timeout value is needed to be set. - * \param emerg_new_timeout timeout value for the new flows. - * \param emerg_est_timeout timeout value for the established flows. - * \param emerg_closed_timeout timeout value for the closed flows. + * \brief get 'disruption' flags: GAP/DEPTH/PASS + * \param f locked flow + * \param flags existing flags to be ammended + * \retval flags original flags + disrupt flags (if any) + * \TODO handle UDP */ - -int FlowSetProtoEmergencyTimeout(uint8_t proto, uint32_t emerg_new_timeout, - uint32_t emerg_est_timeout, - uint32_t emerg_closed_timeout) +uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags) { + if (f->proto != IPPROTO_TCP) { + return flags; + } + if (f->protoctx == NULL) { + return flags; + } - uint8_t proto_map; - proto_map = FlowGetProtoMapping(proto); + uint8_t newflags = flags; + TcpSession *ssn = f->protoctx; + TcpStream *stream = flags & STREAM_TOSERVER ? &ssn->client : &ssn->server; - flow_proto[proto_map].emerg_new_timeout = emerg_new_timeout; - flow_proto[proto_map].emerg_est_timeout = emerg_est_timeout; - flow_proto[proto_map].emerg_closed_timeout = emerg_closed_timeout; + if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { + newflags |= STREAM_DEPTH; + } + if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { + newflags |= STREAM_GAP; + } + /* todo: handle pass case (also for UDP!) */ - return 1; + return newflags; } -AppProto FlowGetAppProtocol(Flow *f) +void FlowUpdateState(Flow *f, enum FlowState s) { - return f->alproto; -} + /* set the state */ + SC_ATOMIC_SET(f->flow_state, s); -void *FlowGetAppState(Flow *f) -{ - return f->alstate; + if (f->fb) { + /* and reset the flow buckup next_ts value so that the flow manager + * has to revisit this row */ + SC_ATOMIC_SET(f->fb->next_ts, 0); + } } /************************************Unittests*******************************/ #ifdef UNITTESTS -#include "stream-tcp-private.h" #include "threads.h" /** @@ -855,40 +939,35 @@ static int FlowTest01 (void) FlowInitFlowProto(); proto_map = FlowGetProtoMapping(IPPROTO_TCP); - - if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_TCP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_TCP_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT)){ - printf ("failed in setting TCP flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_IPPROTO_TCP_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_IPPROTO_TCP_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT); proto_map = FlowGetProtoMapping(IPPROTO_UDP); - if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_UDP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_UDP_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT)){ - printf ("failed in setting UDP flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_IPPROTO_UDP_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_IPPROTO_UDP_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT); proto_map = FlowGetProtoMapping(IPPROTO_ICMP); - if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_ICMP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT)){ - printf ("failed in setting ICMP flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_IPPROTO_ICMP_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT); proto_map = FlowGetProtoMapping(IPPROTO_DCCP); - if ((flow_proto[proto_map].new_timeout != FLOW_DEFAULT_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_DEFAULT_EST_TIMEOUT) - && (flow_proto[proto_map].emerg_new_timeout != FLOW_DEFAULT_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_DEFAULT_EMERG_EST_TIMEOUT)){ - printf ("failed in setting default flow timeout"); - return 0; - } + FAIL_IF(flow_timeouts_normal[proto_map].new_timeout != FLOW_DEFAULT_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_normal[proto_map].est_timeout != FLOW_DEFAULT_EST_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].new_timeout != FLOW_DEFAULT_EMERG_NEW_TIMEOUT); + FAIL_IF(flow_timeouts_emerg[proto_map].est_timeout != FLOW_DEFAULT_EMERG_EST_TIMEOUT); - return 1; + PASS; } /*Test function for the unit test FlowTest02*/ -void test(void *f) {} +static void test(void *f) {} /** * \test Test the setting of the per protocol free function to free the @@ -904,23 +983,12 @@ static int FlowTest02 (void) FlowSetProtoFreeFunc(IPPROTO_UDP, test); FlowSetProtoFreeFunc(IPPROTO_ICMP, test); - if (flow_proto[FLOW_PROTO_DEFAULT].Freefunc != test) { - printf("Failed in setting default free function\n"); - return 0; - } - if (flow_proto[FLOW_PROTO_TCP].Freefunc != test) { - printf("Failed in setting TCP free function\n"); - return 0; - } - if (flow_proto[FLOW_PROTO_UDP].Freefunc != test) { - printf("Failed in setting UDP free function\n"); - return 0; - } - if (flow_proto[FLOW_PROTO_ICMP].Freefunc != test) { - printf("Failed in setting ICMP free function\n"); - return 0; - } - return 1; + FAIL_IF(flow_freefuncs[FLOW_PROTO_DEFAULT].Freefunc != test); + FAIL_IF(flow_freefuncs[FLOW_PROTO_TCP].Freefunc != test); + FAIL_IF(flow_freefuncs[FLOW_PROTO_UDP].Freefunc != test); + FAIL_IF(flow_freefuncs[FLOW_PROTO_ICMP].Freefunc != test); + + PASS; } /** @@ -1071,11 +1139,15 @@ static int FlowTest09 (void) void FlowRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01, 1); - UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", FlowTest02, 1); - UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", FlowTest07, 1); - UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", FlowTest08, 1); - UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", FlowTest09, 1); + UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01); + UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", + FlowTest02); + UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", + FlowTest07); + UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", + FlowTest08); + UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", + FlowTest09); FlowMgrRegisterTests(); RegisterFlowStorageTests(); diff --git a/src/flow.h b/src/flow.h index 802f61fd2a85..a490a82427cb 100644 --- a/src/flow.h +++ b/src/flow.h @@ -43,67 +43,82 @@ typedef struct AppLayerParserState_ AppLayerParserState; /* per flow flags */ /** At least on packet from the source address was seen */ -#define FLOW_TO_SRC_SEEN 0x00000001 +#define FLOW_TO_SRC_SEEN BIT_U32(0) /** At least on packet from the destination address was seen */ -#define FLOW_TO_DST_SEEN 0x00000002 - -// vacany 1x - -/** no magic on files in this flow */ -#define FLOW_FILE_NO_MAGIC_TS 0x00000008 -#define FLOW_FILE_NO_MAGIC_TC 0x00000010 +#define FLOW_TO_DST_SEEN BIT_U32(1) +/** Don't return this from the flow hash. It has been replaced. */ +#define FLOW_TCP_REUSED BIT_U32(2) /** Flow was inspected against IP-Only sigs in the toserver direction */ -#define FLOW_TOSERVER_IPONLY_SET 0x00000020 +#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3) /** Flow was inspected against IP-Only sigs in the toclient direction */ -#define FLOW_TOCLIENT_IPONLY_SET 0x00000040 +#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4) /** Packet belonging to this flow should not be inspected at all */ -#define FLOW_NOPACKET_INSPECTION 0x00000080 +#define FLOW_NOPACKET_INSPECTION BIT_U32(5) /** Packet payloads belonging to this flow should not be inspected */ -#define FLOW_NOPAYLOAD_INSPECTION 0x00000100 +#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6) /** All packets in this flow should be dropped */ -#define FLOW_ACTION_DROP 0x00000200 +#define FLOW_ACTION_DROP BIT_U32(7) /** Sgh for toserver direction set (even if it's NULL) */ -#define FLOW_SGH_TOSERVER 0x00000800 +#define FLOW_SGH_TOSERVER BIT_U32(8) /** Sgh for toclient direction set (even if it's NULL) */ -#define FLOW_SGH_TOCLIENT 0x00001000 +#define FLOW_SGH_TOCLIENT BIT_U32(9) /** packet to server direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOSERVER_DROP_LOGGED 0x00002000 +#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10) /** packet to client direction has been logged in drop file (only in IPS mode) */ -#define FLOW_TOCLIENT_DROP_LOGGED 0x00004000 -/** alproto detect done. Right now we need it only for udp */ -#define FLOW_ALPROTO_DETECT_DONE 0x00008000 -#define FLOW_NO_APPLAYER_INSPECTION 0x00010000 +#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11) + +/** flow has alerts */ +#define FLOW_HAS_ALERTS BIT_U32(12) /** Pattern matcher alproto detection done */ -#define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00020000 +#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13) /** Probing parser alproto detection done */ -#define FLOW_TS_PP_ALPROTO_DETECT_DONE 0x00040000 +#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14) /** Pattern matcher alproto detection done */ -#define FLOW_TC_PM_ALPROTO_DETECT_DONE 0x00100000 +#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(15) /** Probing parser alproto detection done */ -#define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00200000 -#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000 -/** even if the flow has files, don't store 'm */ -#define FLOW_FILE_NO_STORE_TS 0x01000000 -#define FLOW_FILE_NO_STORE_TC 0x02000000 +#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(16) +#define FLOW_TIMEOUT_REASSEMBLY_DONE BIT_U32(17) /** flow is ipv4 */ -#define FLOW_IPV4 0x04000000 +#define FLOW_IPV4 BIT_U32(18) /** flow is ipv6 */ -#define FLOW_IPV6 0x08000000 +#define FLOW_IPV6 BIT_U32(19) +#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(20) +#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(21) + + +/* File flags */ + +/** no magic on files in this flow */ +#define FLOWFILE_NO_MAGIC_TS BIT_U16(0) +#define FLOWFILE_NO_MAGIC_TC BIT_U16(1) + +/** even if the flow has files, don't store 'm */ +#define FLOWFILE_NO_STORE_TS BIT_U16(2) +#define FLOWFILE_NO_STORE_TC BIT_U16(3) /** no md5 on files in this flow */ -#define FLOW_FILE_NO_MD5_TS 0x10000000 -#define FLOW_FILE_NO_MD5_TC 0x20000000 +#define FLOWFILE_NO_MD5_TS BIT_U16(4) +#define FLOWFILE_NO_MD5_TC BIT_U16(5) + +/** no sha1 on files in this flow */ +#define FLOWFILE_NO_SHA1_TS BIT_U16(6) +#define FLOWFILE_NO_SHA1_TC BIT_U16(7) + +/** no sha256 on files in this flow */ +#define FLOWFILE_NO_SHA256_TS BIT_U16(8) +#define FLOWFILE_NO_SHA256_TC BIT_U16(9) /** no size tracking of files in this flow */ -#define FLOW_FILE_NO_SIZE_TS 0x40000000 -#define FLOW_FILE_NO_SIZE_TC 0x80000000 +#define FLOWFILE_NO_SIZE_TS BIT_U16(10) +#define FLOWFILE_NO_SIZE_TC BIT_U16(11) + #define FLOW_IS_IPV4(f) \ (((f)->flags & FLOW_IPV4) == FLOW_IPV4) @@ -170,13 +185,10 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_PKT_TOSERVER 0x01 #define FLOW_PKT_TOCLIENT 0x02 #define FLOW_PKT_ESTABLISHED 0x04 -#define FLOW_PKT_STATELESS 0x08 -#define FLOW_PKT_TOSERVER_IPONLY_SET 0x10 -#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x20 -/** \todo only used by flow keyword internally. */ -#define FLOW_PKT_NOSTREAM 0x40 -/** \todo only used by flow keyword internally. */ -#define FLOW_PKT_ONLYSTREAM 0x80 +#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08 +#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10 +#define FLOW_PKT_TOSERVER_FIRST 0x20 +#define FLOW_PKT_TOCLIENT_FIRST 0x40 #define FLOW_END_FLAG_STATE_NEW 0x01 #define FLOW_END_FLAG_STATE_ESTABLISHED 0x02 @@ -185,6 +197,7 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_END_FLAG_TIMEOUT 0x10 #define FLOW_END_FLAG_FORCED 0x20 #define FLOW_END_FLAG_SHUTDOWN 0x40 +#define FLOW_END_FLAG_STATE_BYPASSED 0x80 /** Mutex or RWLocks for the flow. */ //#define FLOWLOCK_RWLOCK @@ -272,6 +285,16 @@ typedef unsigned int FlowRefCount; typedef unsigned short FlowRefCount; #endif +#ifdef __tile__ +/* Atomic Ints performance better on Tile. */ +typedef unsigned int FlowStateType; +#else +typedef unsigned short FlowStateType; +#endif + +/** Local Thread ID */ +typedef uint16_t FlowThreadId; + /** * \brief Flow data structure. * @@ -307,8 +330,18 @@ typedef struct Flow_ uint8_t recursion_level; uint16_t vlan_id[2]; + /** flow hash - the flow hash before hash table size mod. */ + uint32_t flow_hash; + + /* time stamp of last update (last packet). Set/updated under the + * flow and flow hash row locks, safe to read under either the + * flow lock or flow hash row lock. */ + struct timeval lastts; + /* end of flow "header" */ + SC_ATOMIC_DECLARE(FlowStateType, flow_state); + /** how many pkts and stream msgs are using the flow *right now*. This * variable is atomic so not protected by the Flow mutex "m". * @@ -317,16 +350,17 @@ typedef struct Flow_ */ SC_ATOMIC_DECLARE(FlowRefCount, use_cnt); - /** flow queue id, used with autofp */ - SC_ATOMIC_DECLARE(int, autofp_tmqh_flow_qid); + /** flow tenant id, used to setup flow timeout and stream pseudo + * packets with the correct tenant id set */ + uint32_t tenant_id; uint32_t probing_parser_toserver_alproto_masks; uint32_t probing_parser_toclient_alproto_masks; - uint32_t flags; + uint32_t flags; /**< generic flags */ - /* time stamp of last update (last packet) */ - struct timeval lastts; + uint16_t file_flags; /**< file tracking/extraction flags */ + /* coccinelle: Flow:file_flags:FLOWFILE_ */ #ifdef FLOWLOCK_RWLOCK SCRWLock r; @@ -350,12 +384,13 @@ typedef struct Flow_ AppProto alproto_ts; AppProto alproto_tc; - uint32_t data_al_so_far[2]; - - /** detection engine ctx id used to inspect this flow. Set at initial + /** detection engine ctx version used to inspect this flow. Set at initial * inspection. If it doesn't match the currently in use de_ctx, the - * de_state and stored sgh ptrs are reset. */ - uint32_t de_ctx_id; + * stored sgh ptrs are reset. */ + uint32_t de_ctx_version; + + /** Thread ID for the stream/detect portion of this flow */ + FlowThreadId thread_id; /** application level storage ptrs. * @@ -363,21 +398,16 @@ typedef struct Flow_ AppLayerParserState *alparser; /**< parser internal state */ void *alstate; /**< application layer state */ - /** detection engine state */ - struct DetectEngineState_ *de_state; - /** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag * has been set. */ - struct SigGroupHead_ *sgh_toclient; + const struct SigGroupHead_ *sgh_toclient; /** toserver sgh for this flow. Only use when FLOW_SGH_TOSERVER flow flag * has been set. */ - struct SigGroupHead_ *sgh_toserver; + const struct SigGroupHead_ *sgh_toserver; /* pointer to the var list */ GenericVar *flowvar; - SCMutex de_state_m; /**< mutex lock for the de_state object */ - /** hash list pointers, protected by fb->s */ struct Flow_ *hnext; /* hash list */ struct Flow_ *hprev; @@ -394,68 +424,58 @@ typedef struct Flow_ uint64_t tosrcbytecnt; } Flow; -enum { +enum FlowState { FLOW_STATE_NEW = 0, FLOW_STATE_ESTABLISHED, FLOW_STATE_CLOSED, + FLOW_STATE_LOCAL_BYPASSED, + FLOW_STATE_CAPTURE_BYPASSED, }; -typedef struct FlowProto_ { +typedef struct FlowProtoTimeout_ { uint32_t new_timeout; uint32_t est_timeout; uint32_t closed_timeout; - uint32_t emerg_new_timeout; - uint32_t emerg_est_timeout; - uint32_t emerg_closed_timeout; + uint32_t bypassed_timeout; +} FlowProtoTimeout; + +typedef struct FlowProtoFreeFunc_ { void (*Freefunc)(void *); - int (*GetProtoState)(void *); -} FlowProto; +} FlowProtoFreeFunc; +/** \brief prepare packet for a life with flow + * Set PKT_WANTS_FLOW flag to incidate workers should do a flow lookup + * and calc the hash value to be used in the lookup and autofp flow + * balancing. */ +void FlowSetupPacket(Packet *p); void FlowHandlePacket (ThreadVars *, DecodeThreadVars *, Packet *); void FlowInitConfig (char); void FlowPrintQueueInfo (void); void FlowShutdown(void); -void FlowSetIPOnlyFlag(Flow *, char); -void FlowSetIPOnlyFlagNoLock(Flow *, char); +void FlowSetIPOnlyFlag(Flow *, int); +void FlowSetHasAlertsFlag(Flow *); +int FlowHasAlerts(const Flow *); void FlowRegisterTests (void); int FlowSetProtoTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); int FlowSetProtoEmergencyTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); int FlowSetProtoFreeFunc (uint8_t , void (*Free)(void *)); -int FlowSetFlowStateFunc (uint8_t , int (*GetProtoState)(void *)); void FlowUpdateQueue(Flow *); struct FlowQueue_; int FlowUpdateSpareFlows(void); -static inline void FlowLockSetNoPacketInspectionFlag(Flow *); static inline void FlowSetNoPacketInspectionFlag(Flow *); -static inline void FlowLockSetNoPayloadInspectionFlag(Flow *); static inline void FlowSetNoPayloadInspectionFlag(Flow *); -static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *); -int FlowGetPacketDirection(Flow *, const Packet *); +int FlowGetPacketDirection(const Flow *, const Packet *); void FlowCleanupAppLayer(Flow *); -/** ----- Inline functions ----- */ +void FlowUpdateState(Flow *f, enum FlowState s); -/** \brief Set the No Packet Inspection Flag after locking the flow. - * - * \param f Flow to set the flag in - */ -static inline void FlowLockSetNoPacketInspectionFlag(Flow *f) -{ - SCEnter(); - - SCLogDebug("flow %p", f); - FLOWLOCK_WRLOCK(f); - f->flags |= FLOW_NOPACKET_INSPECTION; - FLOWLOCK_UNLOCK(f); - - SCReturn; -} +/** ----- Inline functions ----- */ /** \brief Set the No Packet Inspection Flag without locking the flow. * @@ -471,22 +491,6 @@ static inline void FlowSetNoPacketInspectionFlag(Flow *f) SCReturn; } -/** \brief Set the No payload inspection Flag after locking the flow. - * - * \param f Flow to set the flag in - */ -static inline void FlowLockSetNoPayloadInspectionFlag(Flow *f) -{ - SCEnter(); - - SCLogDebug("flow %p", f); - FLOWLOCK_WRLOCK(f); - f->flags |= FLOW_NOPAYLOAD_INSPECTION; - FLOWLOCK_UNLOCK(f); - - SCReturn; -} - /** \brief Set the No payload inspection Flag without locking the flow. * * \param f Flow to set the flag in @@ -501,15 +505,6 @@ static inline void FlowSetNoPayloadInspectionFlag(Flow *f) SCReturn; } -/** \brief set flow flag to disable app layer inspection - * - * \param f *LOCKED* flow - */ -static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *f) -{ - f->flags |= FLOW_NO_APPLAYER_INSPECTION; -} - /** * \brief increase the use count of a flow * @@ -561,12 +556,25 @@ static inline void FlowDeReference(Flow **d) } } -int FlowClearMemory(Flow *,uint8_t ); +/** \brief create a flow id that is as unique as possible + * \retval flow_id signed 64bit id + * \note signed because of the signedness of json_integer_t in + * the json output + */ +static inline int64_t FlowGetId(const Flow *f) +{ + return (int64_t)f->flow_hash << 31 | + (int64_t)(f->startts.tv_sec & 0x0000FFFF) << 16 | + (int64_t)(f->startts.tv_usec & 0x0000FFFF); +} -AppProto FlowGetAppProtocol(Flow *f); -void *FlowGetAppState(Flow *f); +int FlowClearMemory(Flow *,uint8_t ); +AppProto FlowGetAppProtocol(const Flow *f); +void *FlowGetAppState(const Flow *f); +uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags); +void FlowHandlePacketUpdate(Flow *f, Packet *p); #endif /* __FLOW_H__ */ diff --git a/src/host-bit.c b/src/host-bit.c new file mode 100644 index 000000000000..6710caebf113 --- /dev/null +++ b/src/host-bit.c @@ -0,0 +1,523 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements per host bits. Actually, not a bit, + * but called that way because of Snort's flowbits. + * It's a binary storage. + * + * \todo move away from a linked list implementation + * \todo use different datatypes, such as string, int, etc. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "host-bit.h" +#include "host.h" +#include "detect.h" +#include "util-var.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "host-storage.h" + +static int host_bit_id = -1; /**< Host storage id for bits */ + +void HostBitFreeAll(void *store) { + GenericVar *gv = store; + GenericVarFree(gv); +} + +void HostBitInitCtx(void) +{ + host_bit_id = HostStorageRegister("bit", sizeof(void *), NULL, HostBitFreeAll); + if (host_bit_id == -1) { + SCLogError(SC_ERR_HOST_INIT, "Can't initiate host storage for bits"); + exit(EXIT_FAILURE); + } +} + +/* lock before using this */ +int HostHasHostBits(Host *host) +{ + if (host == NULL) + return 0; + return HostGetStorageById(host, host_bit_id) ? 1 : 0; +} + +/** \retval 1 host timed out wrt xbits + * \retval 0 host still has active (non-expired) xbits */ +int HostBitsTimedoutCheck(Host *h, struct timeval *ts) +{ + GenericVar *gv = HostGetStorageById(h, host_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS) { + XBit *xb = (XBit *)gv; + if (xb->expire > (uint32_t)ts->tv_sec) + return 0; + } + } + return 1; +} + +/* get the bit with idx from the host */ +static XBit *HostBitGet(Host *h, uint32_t idx) +{ + GenericVar *gv = HostGetStorageById(h, host_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS && gv->idx == idx) { + return (XBit *)gv; + } + } + + return NULL; +} + +/* add a flowbit to the flow */ +static void HostBitAdd(Host *h, uint32_t idx, uint32_t expire) +{ + XBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + fb = SCMalloc(sizeof(XBit)); + if (unlikely(fb == NULL)) + return; + + fb->type = DETECT_XBITS; + fb->idx = idx; + fb->next = NULL; + fb->expire = expire; + + GenericVar *gv = HostGetStorageById(h, host_bit_id); + GenericVarAppend(&gv, (GenericVar *)fb); + HostSetStorageById(h, host_bit_id, gv); + + // bit already set, lets update it's time + } else { + fb->expire = expire; + } +} + +static void HostBitRemove(Host *h, uint32_t idx) +{ + XBit *fb = HostBitGet(h, idx); + if (fb == NULL) + return; + + GenericVar *gv = HostGetStorageById(h, host_bit_id); + if (gv) { + GenericVarRemove(&gv, (GenericVar *)fb); + XBitFree(fb); + HostSetStorageById(h, host_bit_id, gv); + } +} + +void HostBitSet(Host *h, uint32_t idx, uint32_t expire) +{ + XBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + HostBitAdd(h, idx, expire); + } +} + +void HostBitUnset(Host *h, uint32_t idx) +{ + XBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + HostBitRemove(h, idx); + } +} + +void HostBitToggle(Host *h, uint32_t idx, uint32_t expire) +{ + XBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + HostBitRemove(h, idx); + } else { + HostBitAdd(h, idx, expire); + } +} + +int HostBitIsset(Host *h, uint32_t idx, uint32_t ts) +{ + XBit *fb = HostBitGet(h, idx); + if (fb != NULL) { + if (fb->expire < ts) { + HostBitRemove(h,idx); + return 0; + } + return 1; + } + return 0; +} + +int HostBitIsnotset(Host *h, uint32_t idx, uint32_t ts) +{ + XBit *fb = HostBitGet(h, idx); + if (fb == NULL) { + return 1; + } + + if (fb->expire < ts) { + HostBitRemove(h,idx); + return 1; + } + return 0; +} + +int HostBitList(Host *h, XBit **iter) +{ + GenericVar *gv = (GenericVar *)*iter; + if (gv == NULL) { + gv = HostGetStorageById(h, host_bit_id); + } else { + gv = gv->next; + } + + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS) { + *iter = (XBit *)gv; + return 1; + } + } + *iter = NULL; + return 0; +} + +/* TESTS */ +#ifdef UNITTESTS +static int HostBitTest01 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 0); + + XBit *fb = HostBitGet(h,0); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest02 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + XBit *fb = HostBitGet(h,0); + if (fb == NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest03 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 30); + + XBit *fb = HostBitGet(h,0); + if (fb == NULL) { + printf("fb == NULL although it was just added: "); + goto end; + } + + HostBitRemove(h, 0); + + fb = HostBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL although it was just removed: "); + goto end; + } else { + ret = 1; + } + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest04 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 30); + HostBitAdd(h, 1, 30); + HostBitAdd(h, 2, 30); + HostBitAdd(h, 3, 30); + + XBit *fb = HostBitGet(h,0); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest05 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 30); + HostBitAdd(h, 1, 30); + HostBitAdd(h, 2, 30); + HostBitAdd(h, 3, 30); + + XBit *fb = HostBitGet(h,1); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest06 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); + + XBit *fb = HostBitGet(h,2); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest07 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); + + XBit *fb = HostBitGet(h,3); + if (fb != NULL) + ret = 1; + + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest08 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); + + XBit *fb = HostBitGet(h,0); + if (fb == NULL) + goto end; + + HostBitRemove(h,0); + + fb = HostBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest09 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); + + XBit *fb = HostBitGet(h,1); + if (fb == NULL) + goto end; + + HostBitRemove(h,1); + + fb = HostBitGet(h,1); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest10 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); + + XBit *fb = HostBitGet(h,2); + if (fb == NULL) + goto end; + + HostBitRemove(h,2); + + fb = HostBitGet(h,2); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +static int HostBitTest11 (void) +{ + int ret = 0; + + HostInitConfig(TRUE); + Host *h = HostAlloc(); + if (h == NULL) + goto end; + + HostBitAdd(h, 0, 90); + HostBitAdd(h, 1, 90); + HostBitAdd(h, 2, 90); + HostBitAdd(h, 3, 90); + + XBit *fb = HostBitGet(h,3); + if (fb == NULL) + goto end; + + HostBitRemove(h,3); + + fb = HostBitGet(h,3); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + HostFree(h); +end: + HostCleanup(); + return ret; +} + +#endif /* UNITTESTS */ + +void HostBitRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("HostBitTest01", HostBitTest01); + UtRegisterTest("HostBitTest02", HostBitTest02); + UtRegisterTest("HostBitTest03", HostBitTest03); + UtRegisterTest("HostBitTest04", HostBitTest04); + UtRegisterTest("HostBitTest05", HostBitTest05); + UtRegisterTest("HostBitTest06", HostBitTest06); + UtRegisterTest("HostBitTest07", HostBitTest07); + UtRegisterTest("HostBitTest08", HostBitTest08); + UtRegisterTest("HostBitTest09", HostBitTest09); + UtRegisterTest("HostBitTest10", HostBitTest10); + UtRegisterTest("HostBitTest11", HostBitTest11); +#endif /* UNITTESTS */ +} diff --git a/src/host-bit.h b/src/host-bit.h new file mode 100644 index 000000000000..388147dad58c --- /dev/null +++ b/src/host-bit.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __HOST_BIT_H__ +#define __HOST_BIT_H__ + +#include "host.h" +#include "util-var.h" + +void HostBitInitCtx(void); +void HostBitRegisterTests(void); + +int HostHasHostBits(Host *host); +int HostBitsTimedoutCheck(Host *h, struct timeval *ts); + +void HostBitSet(Host *, uint32_t, uint32_t); +void HostBitUnset(Host *, uint32_t); +void HostBitToggle(Host *, uint32_t, uint32_t); +int HostBitIsset(Host *, uint32_t, uint32_t); +int HostBitIsnotset(Host *, uint32_t, uint32_t); +int HostBitList(Host *, XBit **); + +#endif /* __HOST_BIT_H__ */ diff --git a/src/host-storage.c b/src/host-storage.c index 6748089cd7ae..ba1f812a466d 100644 --- a/src/host-storage.c +++ b/src/host-storage.c @@ -32,16 +32,66 @@ unsigned int HostStorageSize(void) return StorageGetSize(STORAGE_HOST); } -void *HostGetStorageById(Host *h, int id) -{ - return StorageGetById((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id); +/** \defgroup hoststorage Host storage API + * + * The Host storage API is a per-host storage. It is a mean to extend + * the Host structure with arbitrary data. + * + * You have first to register the storage via HostStorageRegister() during + * the init of your module. Then you can attach data via HostSetStorageById() + * and access them via HostGetStorageById(). + * @{ + */ + +/** + * \brief Register a Host storage + * + * \param name the name of the storage + * \param size integer coding the size of the stored value (sizeof(void *) is best choice here) + * \param Alloc allocation function for the storage (can be null) + * \param Free free function for the new storage + * + * \retval The ID of the newly register storage that will be used to access data + * + * It has to be called once during the init of the sub system + */ + +int HostStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) { + return StorageRegister(STORAGE_HOST, name, size, Alloc, Free); } +/** + * \brief Store a pointer in a given Host storage + * + * \param h a pointer to the Host + * \param id the id of the storage (return of HostStorageRegister() call) + * \param ptr pointer to the data to store + */ + int HostSetStorageById(Host *h, int id, void *ptr) { return StorageSetById((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id, ptr); } +/** + * \brief Get a value from a given Host storage + * + * \param h a pointer to the Host + * \param id the id of the storage (return of HostStorageRegister() call) + * + */ + +void *HostGetStorageById(Host *h, int id) +{ + return StorageGetById((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id); +} + +/** + * @} + */ + +/* Start of "private" function */ + void *HostAllocStorageById(Host *h, int id) { return StorageAllocByIdPrealloc((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST, id); @@ -58,9 +108,6 @@ void HostFreeStorage(Host *h) StorageFreeAll((Storage *)((void *)h + sizeof(Host)), STORAGE_HOST); } -int HostStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) { - return StorageRegister(STORAGE_HOST, name, size, Alloc, Free); -} #ifdef UNITTESTS @@ -283,8 +330,8 @@ static int HostStorageTest03(void) void RegisterHostStorageTests(void) { #ifdef UNITTESTS - UtRegisterTest("HostStorageTest01", HostStorageTest01, 1); - UtRegisterTest("HostStorageTest02", HostStorageTest02, 1); - UtRegisterTest("HostStorageTest03", HostStorageTest03, 1); + UtRegisterTest("HostStorageTest01", HostStorageTest01); + UtRegisterTest("HostStorageTest02", HostStorageTest02); + UtRegisterTest("HostStorageTest03", HostStorageTest03); #endif } diff --git a/src/host-timeout.c b/src/host-timeout.c index a8b08b8d8591..c8be4e05a75e 100644 --- a/src/host-timeout.c +++ b/src/host-timeout.c @@ -26,6 +26,9 @@ #include "detect-engine-tag.h" #include "detect-engine-threshold.h" + +#include "host-bit.h" + #include "reputation.h" uint32_t HostGetSpareCount(void) @@ -51,6 +54,7 @@ static int HostHostTimedOut(Host *h, struct timeval *ts) { int tags = 0; int thresholds = 0; + int vars = 0; /** never prune a host that is used by a packet * we are currently processing in one of the threads */ @@ -71,8 +75,11 @@ static int HostHostTimedOut(Host *h, struct timeval *ts) if (ThresholdHostHasThreshold(h) && ThresholdTimeoutCheck(h, ts) == 0) { thresholds = 1; } + if (HostHasHostBits(h) && HostBitsTimedoutCheck(h, ts) == 0) { + vars = 1; + } - if (tags || thresholds) + if (tags || thresholds || vars) return 0; SCLogDebug("host %p timed out", h); diff --git a/src/host.c b/src/host.c index c3831c757ef7..276d1b42ee17 100644 --- a/src/host.c +++ b/src/host.c @@ -29,6 +29,7 @@ #include "util-debug.h" #include "host.h" #include "host-storage.h" +#include "host-bit.h" #include "util-random.h" #include "util-misc.h" @@ -47,6 +48,10 @@ static Host *HostGetUsedHost(void); /** queue with spare hosts */ static HostQueue host_spare_q; +/** size of the host object. Maybe updated in HostInitConfig to include + * the storage APIs additions. */ +static uint16_t g_host_size = sizeof(Host); + uint32_t HostSpareQueueGetSize(void) { return HostQueueLen(&host_spare_q); @@ -60,19 +65,16 @@ void HostMoveToSpare(Host *h) Host *HostAlloc(void) { - size_t size = sizeof(Host) + HostStorageSize(); - - if (!(HOST_CHECK_MEMCAP(size))) { + if (!(HOST_CHECK_MEMCAP(g_host_size))) { return NULL; } + (void) SC_ATOMIC_ADD(host_memuse, g_host_size); - (void) SC_ATOMIC_ADD(host_memuse, size); - - Host *h = SCMalloc(size); + Host *h = SCMalloc(g_host_size); if (unlikely(h == NULL)) goto error; - memset(h, 0x00, size); + memset(h, 0x00, g_host_size); SCMutexInit(&h->m, NULL); SC_ATOMIC_INIT(h->use_cnt); @@ -90,7 +92,7 @@ void HostFree(Host *h) SC_ATOMIC_DESTROY(h->use_cnt); SCMutexDestroy(&h->m); SCFree(h); - (void) SC_ATOMIC_SUB(host_memuse, (sizeof(Host) + HostStorageSize())); + (void) SC_ATOMIC_SUB(host_memuse, g_host_size); } } @@ -129,6 +131,8 @@ void HostClearMemory(Host *h) void HostInitConfig(char quiet) { SCLogDebug("initializing host engine..."); + if (HostStorageSize() > 0) + g_host_size = sizeof(Host) + HostStorageSize(); memset(&host_config, 0, sizeof(host_config)); //SC_ATOMIC_INIT(flow_flags); @@ -137,10 +141,11 @@ void HostInitConfig(char quiet) SC_ATOMIC_INIT(host_prune_idx); HostQueueInit(&host_spare_q); +#ifndef AFLFUZZ_NO_RANDOM unsigned int seed = RandomTimePreseed(); /* set defaults */ host_config.hash_rand = (int)( HOST_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); - +#endif host_config.hash_size = HOST_DEFAULT_HASHSIZE; host_config.memcap = HOST_DEFAULT_MEMCAP; host_config.prealloc = HOST_DEFAULT_PREALLOC; @@ -191,7 +196,7 @@ void HostInitConfig(char quiet) (uintmax_t)sizeof(HostHashRow)); exit(EXIT_FAILURE); } - host_hash = SCCalloc(host_config.hash_size, sizeof(HostHashRow)); + host_hash = SCMallocAligned(host_config.hash_size * sizeof(HostHashRow), CLS); if (unlikely(host_hash == NULL)) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in HostInitConfig. Exiting..."); exit(EXIT_FAILURE); @@ -205,7 +210,7 @@ void HostInitConfig(char quiet) (void) SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow))); if (quiet == FALSE) { - SCLogInfo("allocated %llu bytes of memory for the host hash... " + SCLogConfig("allocated %"PRIu64" bytes of memory for the host hash... " "%" PRIu32 " buckets of size %" PRIuMAX "", SC_ATOMIC_GET(host_memuse), host_config.hash_size, (uintmax_t)sizeof(HostHashRow)); @@ -213,11 +218,11 @@ void HostInitConfig(char quiet) /* pre allocate hosts */ for (i = 0; i < host_config.prealloc; i++) { - if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { + if (!(HOST_CHECK_MEMCAP(g_host_size))) { SCLogError(SC_ERR_HOST_INIT, "preallocating hosts failed: " "max host memcap reached. Memcap %"PRIu64", " "Memuse %"PRIu64".", host_config.memcap, - ((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)sizeof(Host))); + ((uint64_t)SC_ATOMIC_GET(host_memuse) + g_host_size)); exit(EXIT_FAILURE); } @@ -230,9 +235,9 @@ void HostInitConfig(char quiet) } if (quiet == FALSE) { - SCLogInfo("preallocated %" PRIu32 " hosts of size %" PRIuMAX "", - host_spare_q.len, (uintmax_t)sizeof(Host)); - SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, + SCLogConfig("preallocated %" PRIu32 " hosts of size %" PRIu16 "", + host_spare_q.len, g_host_size); + SCLogConfig("host memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); } @@ -244,10 +249,10 @@ void HostInitConfig(char quiet) void HostPrintStats (void) { #ifdef HOSTBITS_STATS - SCLogInfo("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", + SCLogPerf("hostbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", hostbits_added, hostbits_removed, hostbits_memuse_max); #endif /* HOSTBITS_STATS */ - SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64, + SCLogPerf("host memory usage: %"PRIu64" bytes, maximum: %"PRIu64, SC_ATOMIC_GET(host_memuse), host_config.memcap); return; } @@ -270,7 +275,7 @@ void HostShutdown(void) /* clear and free the hash */ if (host_hash != NULL) { for (u = 0; u < host_config.hash_size; u++) { - Host *h = host_hash[u].head; + h = host_hash[u].head; while (h) { Host *n = h->hnext; HostFree(h); @@ -279,7 +284,7 @@ void HostShutdown(void) HRLOCK_DESTROY(&host_hash[u]); } - SCFree(host_hash); + SCFreeAligned(host_hash); host_hash = NULL; } (void) SC_ATOMIC_SUB(host_memuse, host_config.hash_size * sizeof(HostHashRow)); @@ -385,7 +390,7 @@ static Host *HostGetNew(Address *a) h = HostDequeue(&host_spare_q); if (h == NULL) { /* If we reached the max memcap, we get a used host */ - if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) { + if (!(HOST_CHECK_MEMCAP(g_host_size))) { /* declare state of emergency */ //if (!(SC_ATOMIC_GET(host_flags) & HOST_EMERGENCY)) { // SC_ATOMIC_OR(host_flags, HOST_EMERGENCY); @@ -439,6 +444,12 @@ void HostLock(Host *h) SCMutexLock(&h->m); } +void HostUnlock(Host *h) +{ + SCMutexUnlock(&h->m); +} + + /* HostGetHostFromHash * * Hash retrieval function for hosts. Looks up the hash bucket containing the diff --git a/src/host.h b/src/host.h index 2616b4b35b00..d22f6f32f017 100644 --- a/src/host.h +++ b/src/host.h @@ -129,9 +129,9 @@ typedef struct HostConfig_ { } while (0) HostConfig host_config; -SC_ATOMIC_DECLARE(unsigned long long int,host_memuse); -SC_ATOMIC_DECLARE(unsigned int,host_counter); -SC_ATOMIC_DECLARE(unsigned int,host_prune_idx); +SC_ATOMIC_DECLARE(uint64_t,host_memuse); +SC_ATOMIC_DECLARE(uint32_t,host_counter); +SC_ATOMIC_DECLARE(uint32_t,host_prune_idx); void HostInitConfig(char quiet); void HostShutdown(void); @@ -146,5 +146,12 @@ void HostMoveToSpare(Host *); uint32_t HostSpareQueueGetSize(void); void HostPrintStats (void); +void HostRegisterUnittests(void); + +Host *HostAlloc(); +void HostFree(); + +void HostUnlock(Host *h); + #endif /* __HOST_H__ */ diff --git a/src/ippair-bit.c b/src/ippair-bit.c new file mode 100644 index 000000000000..8ea1bc4d6ba1 --- /dev/null +++ b/src/ippair-bit.c @@ -0,0 +1,507 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implements per ippair bits. Actually, not a bit, + * but called that way because of Snort's flowbits. + * It's a binary storage. + * + * \todo move away from a linked list implementation + * \todo use different datatypes, such as string, int, etc. + */ + +#include "suricata-common.h" +#include "threads.h" +#include "ippair-bit.h" +#include "ippair.h" +#include "detect.h" +#include "util-var.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "ippair-storage.h" + +static int ippair_bit_id = -1; /**< IPPair storage id for bits */ + +void XBitFreeAll(void *store) { + GenericVar *gv = store; + GenericVarFree(gv); +} + +void IPPairBitInitCtx(void) +{ + ippair_bit_id = IPPairStorageRegister("bit", sizeof(void *), NULL, XBitFreeAll); + if (ippair_bit_id == -1) { + SCLogError(SC_ERR_IPPAIR_INIT, "Can't initiate ippair storage for bits"); + exit(EXIT_FAILURE); + } +} + +/* lock before using this */ +int IPPairHasBits(IPPair *ippair) +{ + if (ippair == NULL) + return 0; + return IPPairGetStorageById(ippair, ippair_bit_id) ? 1 : 0; +} + +/** \retval 1 ippair timed out wrt xbits + * \retval 0 ippair still has active (non-expired) xbits */ +int IPPairBitsTimedoutCheck(IPPair *h, struct timeval *ts) +{ + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS) { + XBit *xb = (XBit *)gv; + if (xb->expire > (uint32_t)ts->tv_sec) + return 0; + } + } + return 1; +} + +/* get the bit with idx from the ippair */ +static XBit *IPPairBitGet(IPPair *h, uint32_t idx) +{ + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + for ( ; gv != NULL; gv = gv->next) { + if (gv->type == DETECT_XBITS && gv->idx == idx) { + return (XBit *)gv; + } + } + + return NULL; +} + +/* add a flowbit to the flow */ +static void IPPairBitAdd(IPPair *h, uint32_t idx, uint32_t expire) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) { + fb = SCMalloc(sizeof(XBit)); + if (unlikely(fb == NULL)) + return; + + fb->type = DETECT_XBITS; + fb->idx = idx; + fb->next = NULL; + fb->expire = expire; + + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + GenericVarAppend(&gv, (GenericVar *)fb); + IPPairSetStorageById(h, ippair_bit_id, gv); + + // bit already set, lets update it's timer + } else { + fb->expire = expire; + } +} + +static void IPPairBitRemove(IPPair *h, uint32_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) + return; + + GenericVar *gv = IPPairGetStorageById(h, ippair_bit_id); + if (gv) { + GenericVarRemove(&gv, (GenericVar *)fb); + XBitFree(fb); + IPPairSetStorageById(h, ippair_bit_id, gv); + } +} + +void IPPairBitSet(IPPair *h, uint32_t idx, uint32_t expire) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) { + IPPairBitAdd(h, idx, expire); + } +} + +void IPPairBitUnset(IPPair *h, uint32_t idx) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb != NULL) { + IPPairBitRemove(h, idx); + } +} + +void IPPairBitToggle(IPPair *h, uint32_t idx, uint32_t expire) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb != NULL) { + IPPairBitRemove(h, idx); + } else { + IPPairBitAdd(h, idx, expire); + } +} + +int IPPairBitIsset(IPPair *h, uint32_t idx, uint32_t ts) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb != NULL) { + if (fb->expire < ts) { + IPPairBitRemove(h, idx); + return 0; + } + + return 1; + } + return 0; +} + +int IPPairBitIsnotset(IPPair *h, uint32_t idx, uint32_t ts) +{ + XBit *fb = IPPairBitGet(h, idx); + if (fb == NULL) { + return 1; + } + + if (fb->expire < ts) { + IPPairBitRemove(h, idx); + return 1; + } + + return 0; +} + + +/* TESTS */ +#ifdef UNITTESTS +static int IPPairBitTest01 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0, 0); + + XBit *fb = IPPairBitGet(h,0); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest02 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + XBit *fb = IPPairBitGet(h,0); + if (fb == NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest03 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0, 30); + + XBit *fb = IPPairBitGet(h,0); + if (fb == NULL) { + printf("fb == NULL although it was just added: "); + goto end; + } + + IPPairBitRemove(h, 0); + + fb = IPPairBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL although it was just removed: "); + goto end; + } else { + ret = 1; + } + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest04 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,30); + IPPairBitAdd(h, 1,30); + IPPairBitAdd(h, 2,30); + IPPairBitAdd(h, 3,30); + + XBit *fb = IPPairBitGet(h,0); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest05 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,1); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest06 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,2); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest07 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,3); + if (fb != NULL) + ret = 1; + + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest08 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,0); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,0); + + fb = IPPairBitGet(h,0); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest09 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,1); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,1); + + fb = IPPairBitGet(h,1); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest10 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,2); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,2); + + fb = IPPairBitGet(h,2); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +static int IPPairBitTest11 (void) +{ + int ret = 0; + + IPPairInitConfig(TRUE); + IPPair *h = IPPairAlloc(); + if (h == NULL) + goto end; + + IPPairBitAdd(h, 0,90); + IPPairBitAdd(h, 1,90); + IPPairBitAdd(h, 2,90); + IPPairBitAdd(h, 3,90); + + XBit *fb = IPPairBitGet(h,3); + if (fb == NULL) + goto end; + + IPPairBitRemove(h,3); + + fb = IPPairBitGet(h,3); + if (fb != NULL) { + printf("fb != NULL even though it was removed: "); + goto end; + } + + ret = 1; + IPPairFree(h); +end: + IPPairCleanup(); + return ret; +} + +#endif /* UNITTESTS */ + +void IPPairBitRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("IPPairBitTest01", IPPairBitTest01); + UtRegisterTest("IPPairBitTest02", IPPairBitTest02); + UtRegisterTest("IPPairBitTest03", IPPairBitTest03); + UtRegisterTest("IPPairBitTest04", IPPairBitTest04); + UtRegisterTest("IPPairBitTest05", IPPairBitTest05); + UtRegisterTest("IPPairBitTest06", IPPairBitTest06); + UtRegisterTest("IPPairBitTest07", IPPairBitTest07); + UtRegisterTest("IPPairBitTest08", IPPairBitTest08); + UtRegisterTest("IPPairBitTest09", IPPairBitTest09); + UtRegisterTest("IPPairBitTest10", IPPairBitTest10); + UtRegisterTest("IPPairBitTest11", IPPairBitTest11); +#endif /* UNITTESTS */ +} diff --git a/src/ippair-bit.h b/src/ippair-bit.h new file mode 100644 index 000000000000..cbc7cb739be8 --- /dev/null +++ b/src/ippair-bit.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __IPPAIR_BIT_H__ +#define __IPPAIR_BIT_H__ + +#include "ippair.h" +#include "util-var.h" + +void IPPairBitInitCtx(void); +void IPPairBitRegisterTests(void); + +int IPPairHasBits(IPPair *host); +int IPPairBitsTimedoutCheck(IPPair *h, struct timeval *ts); + +void IPPairBitSet(IPPair *, uint32_t, uint32_t); +void IPPairBitUnset(IPPair *, uint32_t); +void IPPairBitToggle(IPPair *, uint32_t, uint32_t); +int IPPairBitIsset(IPPair *, uint32_t, uint32_t); +int IPPairBitIsnotset(IPPair *, uint32_t, uint32_t); + +#endif /* __IPPAIR_BIT_H__ */ diff --git a/src/ippair-queue.c b/src/ippair-queue.c new file mode 100644 index 000000000000..0f68200dd947 --- /dev/null +++ b/src/ippair-queue.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * IPPair queue handler functions + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "ippair-queue.h" +#include "util-error.h" +#include "util-debug.h" +#include "util-print.h" + +IPPairQueue *IPPairQueueInit (IPPairQueue *q) +{ + if (q != NULL) { + memset(q, 0, sizeof(IPPairQueue)); + HQLOCK_INIT(q); + } + return q; +} + +IPPairQueue *IPPairQueueNew() +{ + IPPairQueue *q = (IPPairQueue *)SCMalloc(sizeof(IPPairQueue)); + if (q == NULL) { + SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPPairQueueNew. Exiting..."); + exit(EXIT_SUCCESS); + } + q = IPPairQueueInit(q); + return q; +} + +/** + * \brief Destroy a ippair queue + * + * \param q the ippair queue to destroy + */ +void IPPairQueueDestroy (IPPairQueue *q) +{ + HQLOCK_DESTROY(q); +} + +/** + * \brief add a ippair to a queue + * + * \param q queue + * \param h ippair + */ +void IPPairEnqueue (IPPairQueue *q, IPPair *h) +{ +#ifdef DEBUG + BUG_ON(q == NULL || h == NULL); +#endif + + HQLOCK_LOCK(q); + + /* more ippairs in queue */ + if (q->top != NULL) { + h->lnext = q->top; + q->top->lprev = h; + q->top = h; + /* only ippair */ + } else { + q->top = h; + q->bot = h; + } + q->len++; +#ifdef DBG_PERF + if (q->len > q->dbg_maxlen) + q->dbg_maxlen = q->len; +#endif /* DBG_PERF */ + HQLOCK_UNLOCK(q); +} + +/** + * \brief remove a ippair from the queue + * + * \param q queue + * + * \retval h ippair or NULL if empty list. + */ +IPPair *IPPairDequeue (IPPairQueue *q) +{ + HQLOCK_LOCK(q); + + IPPair *h = q->bot; + if (h == NULL) { + HQLOCK_UNLOCK(q); + return NULL; + } + + /* more packets in queue */ + if (q->bot->lprev != NULL) { + q->bot = q->bot->lprev; + q->bot->lnext = NULL; + /* just the one we remove, so now empty */ + } else { + q->top = NULL; + q->bot = NULL; + } + +#ifdef DEBUG + BUG_ON(q->len == 0); +#endif + if (q->len > 0) + q->len--; + + h->lnext = NULL; + h->lprev = NULL; + + HQLOCK_UNLOCK(q); + return h; +} + +uint32_t IPPairQueueLen(IPPairQueue *q) +{ + uint32_t len; + HQLOCK_LOCK(q); + len = q->len; + HQLOCK_UNLOCK(q); + return len; +} diff --git a/src/ippair-queue.h b/src/ippair-queue.h new file mode 100644 index 000000000000..5c80cf3917da --- /dev/null +++ b/src/ippair-queue.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __IPPAIR_QUEUE_H__ +#define __IPPAIR_QUEUE_H__ + +#include "suricata-common.h" +#include "ippair.h" + +/** Spinlocks or Mutex for the ippair queues. */ +//#define HQLOCK_SPIN +#define HQLOCK_MUTEX + +#ifdef HQLOCK_SPIN + #ifdef HQLOCK_MUTEX + #error Cannot enable both HQLOCK_SPIN and HQLOCK_MUTEX + #endif +#endif + +/* Define a queue for storing ippairs */ +typedef struct IPPairQueue_ +{ + IPPair *top; + IPPair *bot; + uint32_t len; +#ifdef DBG_PERF + uint32_t dbg_maxlen; +#endif /* DBG_PERF */ +#ifdef HQLOCK_MUTEX + SCMutex m; +#elif defined HQLOCK_SPIN + SCSpinlock s; +#else + #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#endif +} IPPairQueue; + +#ifdef HQLOCK_SPIN + #define HQLOCK_INIT(q) SCSpinInit(&(q)->s, 0) + #define HQLOCK_DESTROY(q) SCSpinDestroy(&(q)->s) + #define HQLOCK_LOCK(q) SCSpinLock(&(q)->s) + #define HQLOCK_TRYLOCK(q) SCSpinTrylock(&(q)->s) + #define HQLOCK_UNLOCK(q) SCSpinUnlock(&(q)->s) +#elif defined HQLOCK_MUTEX + #define HQLOCK_INIT(q) SCMutexInit(&(q)->m, NULL) + #define HQLOCK_DESTROY(q) SCMutexDestroy(&(q)->m) + #define HQLOCK_LOCK(q) SCMutexLock(&(q)->m) + #define HQLOCK_TRYLOCK(q) SCMutexTrylock(&(q)->m) + #define HQLOCK_UNLOCK(q) SCMutexUnlock(&(q)->m) +#else + #error Enable HQLOCK_SPIN or HQLOCK_MUTEX +#endif + +/* prototypes */ +IPPairQueue *IPPairQueueNew(); +IPPairQueue *IPPairQueueInit(IPPairQueue *); +void IPPairQueueDestroy (IPPairQueue *); + +void IPPairEnqueue (IPPairQueue *, IPPair *); +IPPair *IPPairDequeue (IPPairQueue *); +uint32_t IPPairQueueLen(IPPairQueue *); + +#endif /* __IPPAIR_QUEUE_H__ */ diff --git a/src/ippair-storage.c b/src/ippair-storage.c new file mode 100644 index 000000000000..890b0c9c18ac --- /dev/null +++ b/src/ippair-storage.c @@ -0,0 +1,299 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * IPPair wrapper around storage api + */ + +#include "suricata-common.h" +#include "ippair-storage.h" +#include "util-unittest.h" + +unsigned int IPPairStorageSize(void) +{ + return StorageGetSize(STORAGE_IPPAIR); +} + +void *IPPairGetStorageById(IPPair *h, int id) +{ + return StorageGetById((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id); +} + +int IPPairSetStorageById(IPPair *h, int id, void *ptr) +{ + return StorageSetById((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id, ptr); +} + +void *IPPairAllocStorageById(IPPair *h, int id) +{ + return StorageAllocByIdPrealloc((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id); +} + +void IPPairFreeStorageById(IPPair *h, int id) +{ + StorageFreeById((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR, id); +} + +void IPPairFreeStorage(IPPair *h) +{ + if (IPPairStorageSize() > 0) + StorageFreeAll((Storage *)((void *)h + sizeof(IPPair)), STORAGE_IPPAIR); +} + +int IPPairStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)) { + return StorageRegister(STORAGE_IPPAIR, name, size, Alloc, Free); +} + +#ifdef UNITTESTS + +static void *StorageTestAlloc(unsigned int size) +{ + void *x = SCMalloc(size); + return x; +} +static void StorageTestFree(void *x) +{ + if (x) + SCFree(x); +} + +static int IPPairStorageTest01(void) +{ + StorageInit(); + + int id1 = IPPairStorageRegister("test", 8, StorageTestAlloc, StorageTestFree); + if (id1 < 0) + goto error; + int id2 = IPPairStorageRegister("variable", 24, StorageTestAlloc, StorageTestFree); + if (id2 < 0) + goto error; + int id3 = IPPairStorageRegister("store", sizeof(void *), StorageTestAlloc, StorageTestFree); + if (id3 < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + IPPairInitConfig(1); + + Address a, b; + memset(&a, 0x00, sizeof(a)); + memset(&b, 0x00, sizeof(b)); + a.addr_data32[0] = 0x01020304; + b.addr_data32[0] = 0x04030201; + a.family = AF_INET; + b.family = AF_INET; + IPPair *h = IPPairGetIPPairFromHash(&a, &b); + if (h == NULL) { + printf("failed to get ippair: "); + goto error; + } + + void *ptr = IPPairGetStorageById(h, id1); + if (ptr != NULL) { + goto error; + } + ptr = IPPairGetStorageById(h, id2); + if (ptr != NULL) { + goto error; + } + ptr = IPPairGetStorageById(h, id3); + if (ptr != NULL) { + goto error; + } + + void *ptr1a = IPPairAllocStorageById(h, id1); + if (ptr1a == NULL) { + goto error; + } + void *ptr2a = IPPairAllocStorageById(h, id2); + if (ptr2a == NULL) { + goto error; + } + void *ptr3a = IPPairAllocStorageById(h, id3); + if (ptr3a == NULL) { + goto error; + } + + void *ptr1b = IPPairGetStorageById(h, id1); + if (ptr1a != ptr1b) { + goto error; + } + void *ptr2b = IPPairGetStorageById(h, id2); + if (ptr2a != ptr2b) { + goto error; + } + void *ptr3b = IPPairGetStorageById(h, id3); + if (ptr3a != ptr3b) { + goto error; + } + + IPPairRelease(h); + + IPPairShutdown(); + StorageCleanup(); + return 1; +error: + IPPairShutdown(); + StorageCleanup(); + return 0; +} + +static int IPPairStorageTest02(void) +{ + StorageInit(); + + int id1 = IPPairStorageRegister("test", sizeof(void *), NULL, StorageTestFree); + if (id1 < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + IPPairInitConfig(1); + + Address a, b; + memset(&a, 0x00, sizeof(a)); + memset(&b, 0x00, sizeof(b)); + a.addr_data32[0] = 0x01020304; + b.addr_data32[0] = 0x04030201; + a.family = AF_INET; + b.family = AF_INET; + IPPair *h = IPPairGetIPPairFromHash(&a, &b); + if (h == NULL) { + printf("failed to get ippair: "); + goto error; + } + + void *ptr = IPPairGetStorageById(h, id1); + if (ptr != NULL) { + goto error; + } + + void *ptr1a = SCMalloc(128); + if (unlikely(ptr1a == NULL)) { + goto error; + } + IPPairSetStorageById(h, id1, ptr1a); + + void *ptr1b = IPPairGetStorageById(h, id1); + if (ptr1a != ptr1b) { + goto error; + } + + IPPairRelease(h); + + IPPairShutdown(); + StorageCleanup(); + return 1; +error: + IPPairShutdown(); + StorageCleanup(); + return 0; +} + +static int IPPairStorageTest03(void) +{ + StorageInit(); + + int id1 = IPPairStorageRegister("test1", sizeof(void *), NULL, StorageTestFree); + if (id1 < 0) + goto error; + int id2 = IPPairStorageRegister("test2", sizeof(void *), NULL, StorageTestFree); + if (id2 < 0) + goto error; + int id3 = IPPairStorageRegister("test3", 32, StorageTestAlloc, StorageTestFree); + if (id3 < 0) + goto error; + + if (StorageFinalize() < 0) + goto error; + + IPPairInitConfig(1); + + Address a, b; + memset(&a, 0x00, sizeof(a)); + memset(&b, 0x00, sizeof(b)); + a.addr_data32[0] = 0x01020304; + b.addr_data32[0] = 0x04030201; + a.family = AF_INET; + b.family = AF_INET; + IPPair *h = IPPairGetIPPairFromHash(&a, &b); + if (h == NULL) { + printf("failed to get ippair: "); + goto error; + } + + void *ptr = IPPairGetStorageById(h, id1); + if (ptr != NULL) { + goto error; + } + + void *ptr1a = SCMalloc(128); + if (unlikely(ptr1a == NULL)) { + goto error; + } + IPPairSetStorageById(h, id1, ptr1a); + + void *ptr2a = SCMalloc(256); + if (unlikely(ptr2a == NULL)) { + goto error; + } + IPPairSetStorageById(h, id2, ptr2a); + + void *ptr3a = IPPairAllocStorageById(h, id3); + if (ptr3a == NULL) { + goto error; + } + + void *ptr1b = IPPairGetStorageById(h, id1); + if (ptr1a != ptr1b) { + goto error; + } + void *ptr2b = IPPairGetStorageById(h, id2); + if (ptr2a != ptr2b) { + goto error; + } + void *ptr3b = IPPairGetStorageById(h, id3); + if (ptr3a != ptr3b) { + goto error; + } + + IPPairRelease(h); + + IPPairShutdown(); + StorageCleanup(); + return 1; +error: + IPPairShutdown(); + StorageCleanup(); + return 0; +} +#endif + +void RegisterIPPairStorageTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("IPPairStorageTest01", IPPairStorageTest01); + UtRegisterTest("IPPairStorageTest02", IPPairStorageTest02); + UtRegisterTest("IPPairStorageTest03", IPPairStorageTest03); +#endif +} diff --git a/src/detect-engine-apt-event.h b/src/ippair-storage.h similarity index 51% rename from src/detect-engine-apt-event.h rename to src/ippair-storage.h index c264efe94563..0671ac9196c9 100644 --- a/src/detect-engine-apt-event.h +++ b/src/ippair-storage.h @@ -15,20 +15,31 @@ * 02110-1301, USA. */ -/** \file +/** + * \file * - * \author Anoop Saldanha + * \author Victor Julien + * + * IPPair wrapper around storage api */ -#ifndef __DETECT_ENGINE_APT_EVENT__H__ -#define __DETECT_ENGINE_APT_EVENT__H__ +#ifndef __IPPAIR_STORAGE_H__ +#define __IPPAIR_STORAGE_H__ + +#include "util-storage.h" +#include "ippair.h" + +unsigned int IPPairStorageSize(void); + +void *IPPairGetStorageById(IPPair *h, int id); +int IPPairSetStorageById(IPPair *h, int id, void *ptr); +void *IPPairAllocStorageById(IPPair *h, int id); + +void IPPairFreeStorageById(IPPair *h, int id); +void IPPairFreeStorage(IPPair *h); + +void RegisterIPPairStorageTests(void); -int DetectEngineAptEventInspect(ThreadVars *tv, - DetectEngineCtx *de_ctx, - DetectEngineThreadCtx *det_ctx, - Signature *s, Flow *f, uint8_t flags, - void *alstate, - void *tx, uint64_t tx_id); -void DetectEngineAptEventRegisterTests(void); +int IPPairStorageRegister(const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *)); -#endif /* __DETECT_ENGINE_APT_EVENT__H__ */ +#endif /* __IPPAIR_STORAGE_H__ */ diff --git a/src/ippair-timeout.c b/src/ippair-timeout.c new file mode 100644 index 000000000000..1225f82511c5 --- /dev/null +++ b/src/ippair-timeout.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "ippair.h" +#include "ippair-bit.h" + +uint32_t IPPairGetSpareCount(void) +{ + return IPPairSpareQueueGetSize(); +} + +uint32_t IPPairGetActiveCount(void) +{ + return SC_ATOMIC_GET(ippair_counter); +} + +/** \internal + * \brief See if we can really discard this ippair. Check use_cnt reference. + * + * \param h ippair + * \param ts timestamp + * + * \retval 0 not timed out just yet + * \retval 1 fully timed out, lets kill it + */ +static int IPPairTimedOut(IPPair *h, struct timeval *ts) +{ + int vars = 0; + + /** never prune a ippair that is used by a packet + * we are currently processing in one of the threads */ + if (SC_ATOMIC_GET(h->use_cnt) > 0) { + return 0; + } + + if (IPPairHasBits(h) && IPPairBitsTimedoutCheck(h, ts) == 0) { + vars = 1; + } + + if (vars) { + return 0; + } + + SCLogDebug("ippair %p timed out", h); + return 1; +} + +/** + * \internal + * + * \brief check all ippairs in a hash row for timing out + * + * \param hb ippair hash row *LOCKED* + * \param h last ippair in the hash row + * \param ts timestamp + * + * \retval cnt timed out ippairs + */ +static uint32_t IPPairHashRowTimeout(IPPairHashRow *hb, IPPair *h, struct timeval *ts) +{ + uint32_t cnt = 0; + + do { + if (SCMutexTrylock(&h->m) != 0) { + h = h->hprev; + continue; + } + + IPPair *next_ippair = h->hprev; + + /* check if the ippair is fully timed out and + * ready to be discarded. */ + if (IPPairTimedOut(h, ts) == 1) { + /* remove from the hash */ + if (h->hprev != NULL) + h->hprev->hnext = h->hnext; + if (h->hnext != NULL) + h->hnext->hprev = h->hprev; + if (hb->head == h) + hb->head = h->hnext; + if (hb->tail == h) + hb->tail = h->hprev; + + h->hnext = NULL; + h->hprev = NULL; + + IPPairClearMemory (h); + + /* no one is referring to this ippair, use_cnt 0, removed from hash + * so we can unlock it and move it back to the spare queue. */ + SCMutexUnlock(&h->m); + + /* move to spare list */ + IPPairMoveToSpare(h); + + cnt++; + } else { + SCMutexUnlock(&h->m); + } + + h = next_ippair; + } while (h != NULL); + + return cnt; +} + +/** + * \brief time out ippairs from the hash + * + * \param ts timestamp + * + * \retval cnt number of timed out ippair + */ +uint32_t IPPairTimeoutHash(struct timeval *ts) +{ + uint32_t idx = 0; + uint32_t cnt = 0; + + for (idx = 0; idx < ippair_config.hash_size; idx++) { + IPPairHashRow *hb = &ippair_hash[idx]; + + if (HRLOCK_TRYLOCK(hb) != 0) + continue; + + /* ippair hash bucket is now locked */ + + if (hb->tail == NULL) { + HRLOCK_UNLOCK(hb); + continue; + } + + /* we have a ippair, or more than one */ + cnt += IPPairHashRowTimeout(hb, hb->tail, ts); + HRLOCK_UNLOCK(hb); + } + + return cnt; +} diff --git a/src/ippair-timeout.h b/src/ippair-timeout.h new file mode 100644 index 000000000000..15d8e96a9890 --- /dev/null +++ b/src/ippair-timeout.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __IPPAIR_TIMEOUT_H__ +#define __IPPAIR_TIMEOUT_H__ + +uint32_t IPPairTimeoutHash(struct timeval *ts); + +uint32_t IPPairGetSpareCount(void); +uint32_t IPPairGetActiveCount(void); + +#endif diff --git a/src/ippair.c b/src/ippair.c new file mode 100644 index 000000000000..29335996d044 --- /dev/null +++ b/src/ippair.c @@ -0,0 +1,739 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Information about ippairs. + */ + +#include "suricata-common.h" +#include "conf.h" + +#include "util-debug.h" +#include "ippair.h" +#include "ippair-storage.h" + +#include "util-random.h" +#include "util-misc.h" +#include "util-byte.h" + +#include "ippair-queue.h" + +#include "detect-tag.h" +#include "detect-engine-tag.h" +#include "detect-engine-threshold.h" + +#include "util-hash-lookup3.h" + +static IPPair *IPPairGetUsedIPPair(void); + +/** queue with spare ippairs */ +static IPPairQueue ippair_spare_q; + +/** size of the ippair object. Maybe updated in IPPairInitConfig to include + * the storage APIs additions. */ +static uint16_t g_ippair_size = sizeof(IPPair); + +uint32_t IPPairSpareQueueGetSize(void) +{ + return IPPairQueueLen(&ippair_spare_q); +} + +void IPPairMoveToSpare(IPPair *h) +{ + IPPairEnqueue(&ippair_spare_q, h); + (void) SC_ATOMIC_SUB(ippair_counter, 1); +} + +IPPair *IPPairAlloc(void) +{ + if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { + return NULL; + } + + (void) SC_ATOMIC_ADD(ippair_memuse, g_ippair_size); + + IPPair *h = SCMalloc(g_ippair_size); + if (unlikely(h == NULL)) + goto error; + + memset(h, 0x00, g_ippair_size); + + SCMutexInit(&h->m, NULL); + SC_ATOMIC_INIT(h->use_cnt); + return h; + +error: + return NULL; +} + +void IPPairFree(IPPair *h) +{ + if (h != NULL) { + IPPairClearMemory(h); + + SC_ATOMIC_DESTROY(h->use_cnt); + SCMutexDestroy(&h->m); + SCFree(h); + (void) SC_ATOMIC_SUB(ippair_memuse, g_ippair_size); + } +} + +IPPair *IPPairNew(Address *a, Address *b) +{ + IPPair *p = IPPairAlloc(); + if (p == NULL) + goto error; + + /* copy addresses */ + COPY_ADDRESS(a, &p->a[0]); + COPY_ADDRESS(b, &p->a[1]); + + return p; + +error: + return NULL; +} + +void IPPairClearMemory(IPPair *h) +{ + if (IPPairStorageSize() > 0) + IPPairFreeStorage(h); +} + +#define IPPAIR_DEFAULT_HASHSIZE 4096 +#define IPPAIR_DEFAULT_MEMCAP 16777216 +#define IPPAIR_DEFAULT_PREALLOC 1000 + +/** \brief initialize the configuration + * \warning Not thread safe */ +void IPPairInitConfig(char quiet) +{ + SCLogDebug("initializing ippair engine..."); + if (IPPairStorageSize() > 0) + g_ippair_size = sizeof(IPPair) + IPPairStorageSize(); + + memset(&ippair_config, 0, sizeof(ippair_config)); + //SC_ATOMIC_INIT(flow_flags); + SC_ATOMIC_INIT(ippair_counter); + SC_ATOMIC_INIT(ippair_memuse); + SC_ATOMIC_INIT(ippair_prune_idx); + IPPairQueueInit(&ippair_spare_q); + +#ifndef AFLFUZZ_NO_RANDOM + unsigned int seed = RandomTimePreseed(); + /* set defaults */ + ippair_config.hash_rand = (int)( IPPAIR_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0)); +#endif + ippair_config.hash_size = IPPAIR_DEFAULT_HASHSIZE; + ippair_config.memcap = IPPAIR_DEFAULT_MEMCAP; + ippair_config.prealloc = IPPAIR_DEFAULT_PREALLOC; + + /* Check if we have memcap and hash_size defined at config */ + char *conf_val; + uint32_t configval = 0; + + /** set config values for memcap, prealloc and hash_size */ + if ((ConfGet("ippair.memcap", &conf_val)) == 1) + { + if (ParseSizeStringU64(conf_val, &ippair_config.memcap) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ippair.memcap " + "from conf file - %s. Killing engine", + conf_val); + exit(EXIT_FAILURE); + } + } + if ((ConfGet("ippair.hash-size", &conf_val)) == 1) + { + if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), + conf_val) > 0) { + ippair_config.hash_size = configval; + } + } + + if ((ConfGet("ippair.prealloc", &conf_val)) == 1) + { + if (ByteExtractStringUint32(&configval, 10, strlen(conf_val), + conf_val) > 0) { + ippair_config.prealloc = configval; + } else { + WarnInvalidConfEntry("ippair.prealloc", "%"PRIu32, ippair_config.prealloc); + } + } + SCLogDebug("IPPair config from suricata.yaml: memcap: %"PRIu64", hash-size: " + "%"PRIu32", prealloc: %"PRIu32, ippair_config.memcap, + ippair_config.hash_size, ippair_config.prealloc); + + /* alloc hash memory */ + uint64_t hash_size = ippair_config.hash_size * sizeof(IPPairHashRow); + if (!(IPPAIR_CHECK_MEMCAP(hash_size))) { + SCLogError(SC_ERR_IPPAIR_INIT, "allocating ippair hash failed: " + "max ippair memcap is smaller than projected hash size. " + "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate " + "total hash size by multiplying \"ippair.hash-size\" with %"PRIuMAX", " + "which is the hash bucket size.", ippair_config.memcap, hash_size, + (uintmax_t)sizeof(IPPairHashRow)); + exit(EXIT_FAILURE); + } + ippair_hash = SCMallocAligned(ippair_config.hash_size * sizeof(IPPairHashRow), CLS); + if (unlikely(ippair_hash == NULL)) { + SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPPairInitConfig. Exiting..."); + exit(EXIT_FAILURE); + } + memset(ippair_hash, 0, ippair_config.hash_size * sizeof(IPPairHashRow)); + + uint32_t i = 0; + for (i = 0; i < ippair_config.hash_size; i++) { + HRLOCK_INIT(&ippair_hash[i]); + } + (void) SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow))); + + if (quiet == FALSE) { + SCLogConfig("allocated %"PRIu64" bytes of memory for the ippair hash... " + "%" PRIu32 " buckets of size %" PRIuMAX "", + SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size, + (uintmax_t)sizeof(IPPairHashRow)); + } + + /* pre allocate ippairs */ + for (i = 0; i < ippair_config.prealloc; i++) { + if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { + SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippairs failed: " + "max ippair memcap reached. Memcap %"PRIu64", " + "Memuse %"PRIu64".", ippair_config.memcap, + ((uint64_t)SC_ATOMIC_GET(ippair_memuse) + g_ippair_size)); + exit(EXIT_FAILURE); + } + + IPPair *h = IPPairAlloc(); + if (h == NULL) { + SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippair failed: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + IPPairEnqueue(&ippair_spare_q,h); + } + + if (quiet == FALSE) { + SCLogConfig("preallocated %" PRIu32 " ippairs of size %" PRIu16 "", + ippair_spare_q.len, g_ippair_size); + SCLogConfig("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); + } + + return; +} + +/** \brief print some ippair stats + * \warning Not thread safe */ +void IPPairPrintStats (void) +{ +#ifdef IPPAIRBITS_STATS + SCLogPerf("ippairbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "", + ippairbits_added, ippairbits_removed, ippairbits_memuse_max); +#endif /* IPPAIRBITS_STATS */ + SCLogPerf("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64, + SC_ATOMIC_GET(ippair_memuse), ippair_config.memcap); + return; +} + +/** \brief shutdown the flow engine + * \warning Not thread safe */ +void IPPairShutdown(void) +{ + IPPair *h; + uint32_t u; + + IPPairPrintStats(); + + /* free spare queue */ + while((h = IPPairDequeue(&ippair_spare_q))) { + BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0); + IPPairFree(h); + } + + /* clear and free the hash */ + if (ippair_hash != NULL) { + for (u = 0; u < ippair_config.hash_size; u++) { + h = ippair_hash[u].head; + while (h) { + IPPair *n = h->hnext; + IPPairFree(h); + h = n; + } + + HRLOCK_DESTROY(&ippair_hash[u]); + } + SCFreeAligned(ippair_hash); + ippair_hash = NULL; + } + (void) SC_ATOMIC_SUB(ippair_memuse, ippair_config.hash_size * sizeof(IPPairHashRow)); + IPPairQueueDestroy(&ippair_spare_q); + + SC_ATOMIC_DESTROY(ippair_prune_idx); + SC_ATOMIC_DESTROY(ippair_memuse); + SC_ATOMIC_DESTROY(ippair_counter); + //SC_ATOMIC_DESTROY(flow_flags); + return; +} + +/** \brief Cleanup the ippair engine + * + * Cleanup the ippair engine from tag and threshold. + * + */ +void IPPairCleanup(void) +{ + IPPair *h; + uint32_t u; + + if (ippair_hash != NULL) { + for (u = 0; u < ippair_config.hash_size; u++) { + h = ippair_hash[u].head; + IPPairHashRow *hb = &ippair_hash[u]; + HRLOCK_LOCK(hb); + while (h) { + if ((SC_ATOMIC_GET(h->use_cnt) > 0)) { + /* iprep is attached to ippair only clear local storage */ + IPPairFreeStorage(h); + h = h->hnext; + } else { + IPPair *n = h->hnext; + /* remove from the hash */ + if (h->hprev != NULL) + h->hprev->hnext = h->hnext; + if (h->hnext != NULL) + h->hnext->hprev = h->hprev; + if (hb->head == h) + hb->head = h->hnext; + if (hb->tail == h) + hb->tail = h->hprev; + h->hnext = NULL; + h->hprev = NULL; + IPPairClearMemory(h); + IPPairMoveToSpare(h); + h = n; + } + } + HRLOCK_UNLOCK(hb); + } + } + + return; +} + +/** \brief compare two raw ipv6 addrs + * + * \note we don't care about the real ipv6 ip's, this is just + * to consistently fill the FlowHashKey6 struct, without all + * the ntohl calls. + * + * \warning do not use elsewhere unless you know what you're doing. + * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely + * what you are looking for. + * Copied from FlowHashRawAddressIPv6GtU32 + */ +static inline int IPPairHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b) +{ + int i; + + for (i = 0; i < 4; i++) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + break; + } + + return 0; +} + +/* calculate the hash key for this packet + * + * we're using: + * hash_rand -- set at init time + * source address + */ +static uint32_t IPPairGetKey(Address *a, Address *b) +{ + uint32_t key; + + if (a->family == AF_INET) { + uint32_t addrs[2] = { MIN(a->addr_data32[0], b->addr_data32[0]), + MAX(a->addr_data32[0], b->addr_data32[0]) }; + uint32_t hash = hashword(addrs, 2, ippair_config.hash_rand); + key = hash % ippair_config.hash_size; + } else if (a->family == AF_INET6) { + uint32_t addrs[8]; + if (IPPairHashRawAddressIPv6GtU32(&a->addr_data32[0],&b->addr_data32[0])) { + addrs[0] = b->addr_data32[0]; + addrs[1] = b->addr_data32[1]; + addrs[2] = b->addr_data32[2]; + addrs[3] = b->addr_data32[3]; + addrs[4] = a->addr_data32[0]; + addrs[5] = a->addr_data32[1]; + addrs[6] = a->addr_data32[2]; + addrs[7] = a->addr_data32[3]; + } else { + addrs[0] = a->addr_data32[0]; + addrs[1] = a->addr_data32[1]; + addrs[2] = a->addr_data32[2]; + addrs[3] = a->addr_data32[3]; + addrs[4] = b->addr_data32[0]; + addrs[5] = b->addr_data32[1]; + addrs[6] = b->addr_data32[2]; + addrs[7] = b->addr_data32[3]; + } + uint32_t hash = hashword(addrs, 8, ippair_config.hash_rand); + key = hash % ippair_config.hash_size; + } else + key = 0; + + return key; +} + +/* Since two or more ippairs can have the same hash key, we need to compare + * the ippair with the current addresses. */ +static inline int IPPairCompare(IPPair *p, Address *a, Address *b) +{ + /* compare in both directions */ + if ((CMP_ADDR(&p->a[0], a) && CMP_ADDR(&p->a[1], b)) || + (CMP_ADDR(&p->a[0], b) && CMP_ADDR(&p->a[1], a))) + return 1; + return 0; +} + +/** + * \brief Get a new ippair + * + * Get a new ippair. We're checking memcap first and will try to make room + * if the memcap is reached. + * + * \retval h *LOCKED* ippair on succes, NULL on error. + */ +static IPPair *IPPairGetNew(Address *a, Address *b) +{ + IPPair *h = NULL; + + /* get a ippair from the spare queue */ + h = IPPairDequeue(&ippair_spare_q); + if (h == NULL) { + /* If we reached the max memcap, we get a used ippair */ + if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) { + /* declare state of emergency */ + //if (!(SC_ATOMIC_GET(ippair_flags) & IPPAIR_EMERGENCY)) { + // SC_ATOMIC_OR(ippair_flags, IPPAIR_EMERGENCY); + + /* under high load, waking up the flow mgr each time leads + * to high cpu usage. Flows are not timed out much faster if + * we check a 1000 times a second. */ + // FlowWakeupFlowManagerThread(); + //} + + h = IPPairGetUsedIPPair(); + if (h == NULL) { + return NULL; + } + + /* freed a ippair, but it's unlocked */ + } else { + /* now see if we can alloc a new ippair */ + h = IPPairNew(a,b); + if (h == NULL) { + return NULL; + } + + /* ippair is initialized but *unlocked* */ + } + } else { + /* ippair has been recycled before it went into the spare queue */ + + /* ippair is initialized (recylced) but *unlocked* */ + } + + (void) SC_ATOMIC_ADD(ippair_counter, 1); + SCMutexLock(&h->m); + return h; +} + +void IPPairInit(IPPair *h, Address *a, Address *b) +{ + COPY_ADDRESS(a, &h->a[0]); + COPY_ADDRESS(b, &h->a[1]); + (void) IPPairIncrUsecnt(h); +} + +void IPPairRelease(IPPair *h) +{ + (void) IPPairDecrUsecnt(h); + SCMutexUnlock(&h->m); +} + +void IPPairLock(IPPair *h) +{ + SCMutexLock(&h->m); +} + +void IPPairUnlock(IPPair *h) +{ + SCMutexUnlock(&h->m); +} + +/* IPPairGetIPPairFromHash + * + * Hash retrieval function for ippairs. Looks up the hash bucket containing the + * ippair pointer. Then compares the packet with the found ippair to see if it is + * the ippair we need. If it isn't, walk the list until the right ippair is found. + * + * returns a *LOCKED* ippair or NULL + */ +IPPair *IPPairGetIPPairFromHash (Address *a, Address *b) +{ + IPPair *h = NULL; + + /* get the key to our bucket */ + uint32_t key = IPPairGetKey(a, b); + /* get our hash bucket and lock it */ + IPPairHashRow *hb = &ippair_hash[key]; + HRLOCK_LOCK(hb); + + /* see if the bucket already has a ippair */ + if (hb->head == NULL) { + h = IPPairGetNew(a,b); + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return NULL; + } + + /* ippair is locked */ + hb->head = h; + hb->tail = h; + + /* got one, now lock, initialize and return */ + IPPairInit(h,a,b); + + HRLOCK_UNLOCK(hb); + return h; + } + + /* ok, we have a ippair in the bucket. Let's find out if it is our ippair */ + h = hb->head; + + /* see if this is the ippair we are looking for */ + if (IPPairCompare(h, a, b) == 0) { + IPPair *ph = NULL; /* previous ippair */ + + while (h) { + ph = h; + h = h->hnext; + + if (h == NULL) { + h = ph->hnext = IPPairGetNew(a,b); + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return NULL; + } + hb->tail = h; + + /* ippair is locked */ + + h->hprev = ph; + + /* initialize and return */ + IPPairInit(h,a,b); + + HRLOCK_UNLOCK(hb); + return h; + } + + if (IPPairCompare(h, a, b) != 0) { + /* we found our ippair, lets put it on top of the + * hash list -- this rewards active ippairs */ + if (h->hnext) { + h->hnext->hprev = h->hprev; + } + if (h->hprev) { + h->hprev->hnext = h->hnext; + } + if (h == hb->tail) { + hb->tail = h->hprev; + } + + h->hnext = hb->head; + h->hprev = NULL; + hb->head->hprev = h; + hb->head = h; + + /* found our ippair, lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; + } + } + } + + /* lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; +} + +/** \brief look up a ippair in the hash + * + * \param a address to look up + * + * \retval h *LOCKED* ippair or NULL + */ +IPPair *IPPairLookupIPPairFromHash (Address *a, Address *b) +{ + IPPair *h = NULL; + + /* get the key to our bucket */ + uint32_t key = IPPairGetKey(a, b); + /* get our hash bucket and lock it */ + IPPairHashRow *hb = &ippair_hash[key]; + HRLOCK_LOCK(hb); + + /* see if the bucket already has a ippair */ + if (hb->head == NULL) { + HRLOCK_UNLOCK(hb); + return h; + } + + /* ok, we have a ippair in the bucket. Let's find out if it is our ippair */ + h = hb->head; + + /* see if this is the ippair we are looking for */ + if (IPPairCompare(h, a, b) == 0) { + while (h) { + h = h->hnext; + + if (h == NULL) { + HRLOCK_UNLOCK(hb); + return h; + } + + if (IPPairCompare(h, a, b) != 0) { + /* we found our ippair, lets put it on top of the + * hash list -- this rewards active ippairs */ + if (h->hnext) { + h->hnext->hprev = h->hprev; + } + if (h->hprev) { + h->hprev->hnext = h->hnext; + } + if (h == hb->tail) { + hb->tail = h->hprev; + } + + h->hnext = hb->head; + h->hprev = NULL; + hb->head->hprev = h; + hb->head = h; + + /* found our ippair, lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; + } + } + } + + /* lock & return */ + SCMutexLock(&h->m); + (void) IPPairIncrUsecnt(h); + HRLOCK_UNLOCK(hb); + return h; +} + +/** \internal + * \brief Get a ippair from the hash directly. + * + * Called in conditions where the spare queue is empty and memcap is reached. + * + * Walks the hash until a ippair can be freed. "ippair_prune_idx" atomic int makes + * sure we don't start at the top each time since that would clear the top of + * the hash leading to longer and longer search times under high pressure (observed). + * + * \retval h ippair or NULL + */ +static IPPair *IPPairGetUsedIPPair(void) +{ + uint32_t idx = SC_ATOMIC_GET(ippair_prune_idx) % ippair_config.hash_size; + uint32_t cnt = ippair_config.hash_size; + + while (cnt--) { + if (++idx >= ippair_config.hash_size) + idx = 0; + + IPPairHashRow *hb = &ippair_hash[idx]; + + if (HRLOCK_TRYLOCK(hb) != 0) + continue; + + IPPair *h = hb->tail; + if (h == NULL) { + HRLOCK_UNLOCK(hb); + continue; + } + + if (SCMutexTrylock(&h->m) != 0) { + HRLOCK_UNLOCK(hb); + continue; + } + + /** never prune a ippair that is used by a packets + * we are currently processing in one of the threads */ + if (SC_ATOMIC_GET(h->use_cnt) > 0) { + HRLOCK_UNLOCK(hb); + SCMutexUnlock(&h->m); + continue; + } + + /* remove from the hash */ + if (h->hprev != NULL) + h->hprev->hnext = h->hnext; + if (h->hnext != NULL) + h->hnext->hprev = h->hprev; + if (hb->head == h) + hb->head = h->hnext; + if (hb->tail == h) + hb->tail = h->hprev; + + h->hnext = NULL; + h->hprev = NULL; + HRLOCK_UNLOCK(hb); + + IPPairClearMemory (h); + + SCMutexUnlock(&h->m); + + (void) SC_ATOMIC_ADD(ippair_prune_idx, (ippair_config.hash_size - cnt)); + return h; + } + + return NULL; +} + +void IPPairRegisterUnittests(void) +{ + RegisterIPPairStorageTests(); +} diff --git a/src/ippair.h b/src/ippair.h new file mode 100644 index 000000000000..812319e6f8bd --- /dev/null +++ b/src/ippair.h @@ -0,0 +1,154 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __IPPAIR_H__ +#define __IPPAIR_H__ + +#include "decode.h" +#include "util-storage.h" + +/** Spinlocks or Mutex for the flow buckets. */ +//#define HRLOCK_SPIN +#define HRLOCK_MUTEX + +#ifdef HRLOCK_SPIN + #ifdef HRLOCK_MUTEX + #error Cannot enable both HRLOCK_SPIN and HRLOCK_MUTEX + #endif +#endif + +#ifdef HRLOCK_SPIN + #define HRLOCK_TYPE SCSpinlock + #define HRLOCK_INIT(fb) SCSpinInit(&(fb)->lock, 0) + #define HRLOCK_DESTROY(fb) SCSpinDestroy(&(fb)->lock) + #define HRLOCK_LOCK(fb) SCSpinLock(&(fb)->lock) + #define HRLOCK_TRYLOCK(fb) SCSpinTrylock(&(fb)->lock) + #define HRLOCK_UNLOCK(fb) SCSpinUnlock(&(fb)->lock) +#elif defined HRLOCK_MUTEX + #define HRLOCK_TYPE SCMutex + #define HRLOCK_INIT(fb) SCMutexInit(&(fb)->lock, NULL) + #define HRLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->lock) + #define HRLOCK_LOCK(fb) SCMutexLock(&(fb)->lock) + #define HRLOCK_TRYLOCK(fb) SCMutexTrylock(&(fb)->lock) + #define HRLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->lock) +#else + #error Enable HRLOCK_SPIN or HRLOCK_MUTEX +#endif + +typedef struct IPPair_ { + /** ippair mutex */ + SCMutex m; + + /** ippair addresses -- ipv4 or ipv6 */ + Address a[2]; + + /** use cnt, reference counter */ + SC_ATOMIC_DECLARE(unsigned int, use_cnt); + + /** storage api handle */ + Storage *storage; + + /** hash pointers, protected by hash row mutex/spin */ + struct IPPair_ *hnext; + struct IPPair_ *hprev; + + /** list pointers, protected by ippair-queue mutex/spin */ + struct IPPair_ *lnext; + struct IPPair_ *lprev; +} IPPair; + +typedef struct IPPairHashRow_ { + HRLOCK_TYPE lock; + IPPair *head; + IPPair *tail; +} __attribute__((aligned(CLS))) IPPairHashRow; + +/** ippair hash table */ +IPPairHashRow *ippair_hash; + +#define IPPAIR_VERBOSE 0 +#define IPPAIR_QUIET 1 + +typedef struct IPPairConfig_ { + uint64_t memcap; + uint32_t hash_rand; + uint32_t hash_size; + uint32_t prealloc; +} IPPairConfig; + +/** \brief check if a memory alloc would fit in the memcap + * + * \param size memory allocation size to check + * + * \retval 1 it fits + * \retval 0 no fit + */ +#define IPPAIR_CHECK_MEMCAP(size) \ + ((((uint64_t)SC_ATOMIC_GET(ippair_memuse) + (uint64_t)(size)) <= ippair_config.memcap)) + +#define IPPairIncrUsecnt(h) \ + (void)SC_ATOMIC_ADD((h)->use_cnt, 1) +#define IPPairDecrUsecnt(h) \ + (void)SC_ATOMIC_SUB((h)->use_cnt, 1) + +#define IPPairReference(dst_h_ptr, h) do { \ + if ((h) != NULL) { \ + IPPairIncrUsecnt((h)); \ + *(dst_h_ptr) = h; \ + } \ + } while (0) + +#define IPPairDeReference(src_h_ptr) do { \ + if (*(src_h_ptr) != NULL) { \ + IPPairDecrUsecnt(*(src_h_ptr)); \ + *(src_h_ptr) = NULL; \ + } \ + } while (0) + +IPPairConfig ippair_config; +SC_ATOMIC_DECLARE(uint64_t,ippair_memuse); +SC_ATOMIC_DECLARE(uint32_t,ippair_counter); +SC_ATOMIC_DECLARE(uint32_t,ippair_prune_idx); + +void IPPairInitConfig(char quiet); +void IPPairShutdown(void); +void IPPairCleanup(void); + +IPPair *IPPairLookupIPPairFromHash (Address *, Address *); +IPPair *IPPairGetIPPairFromHash (Address *, Address *); +void IPPairRelease(IPPair *); +void IPPairLock(IPPair *); +void IPPairClearMemory(IPPair *); +void IPPairMoveToSpare(IPPair *); +uint32_t IPPairSpareQueueGetSize(void); +void IPPairPrintStats (void); + +void IPPairRegisterUnittests(void); + +IPPair *IPPairAlloc(void); +void IPPairFree(IPPair *); + +void IPPairLock(IPPair *); +void IPPairUnlock(IPPair *); + +#endif /* __IPPAIR_H__ */ diff --git a/src/log-cf-common.c b/src/log-cf-common.c new file mode 100644 index 000000000000..9a4efb3219c4 --- /dev/null +++ b/src/log-cf-common.c @@ -0,0 +1,274 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Paulo Pacheco + * \author Victor Julien + * \author Ignacio Sanchez + * + * Common custom logging format + */ + +#include "log-cf-common.h" +#include "util-print.h" +#include "util-unittest.h" + +/** + * \brief Creates a custom format node + * \retval LogCustomFormatNode * ptr if created + * \retval NULL if failed to allocate + */ +LogCustomFormatNode * LogCustomFormatNodeAlloc() +{ + LogCustomFormatNode * node = SCCalloc(1, sizeof(LogCustomFormatNode)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format node"); + return NULL; + } + return node; +} + +/** + * \brief Creates a custom format. + * \retval LogCustomFormat * ptr if created + * \retval NULL if failed to allocate + */ +LogCustomFormat * LogCustomFormatAlloc() +{ + LogCustomFormat * cf = SCCalloc(1, sizeof(LogCustomFormat)); + if (unlikely(cf == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to alloc custom format"); + return NULL; + } + return cf; +} + +/** + * \brief Frees memory held by a custom format node + * \param LogCustomFormatNode * node - node to relaease + */ +void LogCustomFormatNodeFree(LogCustomFormatNode *node) +{ + if (node==NULL) + return; + + SCFree(node); +} + +/** + * \brief Frees memory held by a custom format + * \param LogCustomFormat * cf - format to relaease + */ +void LogCustomFormatFree(LogCustomFormat *cf) +{ + if (cf==NULL) + return; + + for (size_t i = 0; i < cf->cf_n; ++i) { + LogCustomFormatNodeFree(cf->cf_nodes[i]); + } + SCFree(cf); +} + +/** + * \brief Parses and saves format nodes for custom format + * \param LogCustomFormat * cf - custom format to build + * \param const char * format - string with format specification + */ +int LogCustomFormatParse(LogCustomFormat *cf, const char *format) +{ + const char *p, *np; + uint32_t n; + LogCustomFormatNode *node = NULL; + + if (cf==NULL) + return 0; + + if (format==NULL) + return 0; + + p=format; + + for (cf->cf_n = 0; cf->cf_n < LOG_MAXN_NODES-1 && p && *p != '\0';){ + + node = LogCustomFormatNodeAlloc(); + if (node == NULL) { + goto parsererror; + } + node->maxlen = 0; + + if (*p != '%'){ + /* Literal found in format string */ + node->type = LOG_CF_LITERAL; + np = strchr(p, '%'); + if (np == NULL){ + n = LOG_NODE_STRLEN-2; + np = NULL; /* End */ + }else{ + n = np-p; + } + strlcpy(node->data,p,n+1); + p = np; + } else { + /* Non Literal found in format string */ + p++; + if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */ + p++; + np = strchr(p, ']'); + if (np != NULL) { + if (np-p > 0 && np-p < 10){ + long maxlen = strtol(p,NULL,10); + if (maxlen > 0 && maxlen < LOG_NODE_MAXOUTPUTLEN) { + node->maxlen = (uint32_t) maxlen; + } + } else { + goto parsererror; + } + p = np + 1; + } else { + goto parsererror; + } + } + if (*p == '{') { /* Simple format char */ + np = strchr(p, '}'); + if (np != NULL && np-p > 1 && np-p < LOG_NODE_STRLEN-2) { + p++; + n = np-p; + strlcpy(node->data, p, n+1); + p = np; + } else { + goto parsererror; + } + p++; + } else { + node->data[0] = '\0'; + } + node->type = *p; + if (*p == '%'){ + node->type = LOG_CF_LITERAL; + strlcpy(node->data, "%", 2); + } + p++; + } + LogCustomFormatAddNode(cf, node); + } + return 1; + +parsererror: + LogCustomFormatNodeFree(node); + return 0; +} + +/** + * \brief Adds a node to custom format + * \param LogCustomFormat * cf - custom format + * \param LogCustomFormatNode * node - node to add + */ +void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node) +{ + if (cf == NULL || node == NULL) + return; + + if (cf->cf_n == LOG_MAXN_NODES) { + SCLogWarning(SC_WARN_LOG_CF_TOO_MANY_NODES, "Too many options for custom format"); + return; + } + +#ifdef DEBUG + SCLogDebug("%d-> n.type=[%d] n.maxlen=[%d] n.data=[%s]", + cf->cf_n, node->type, node->maxlen, node->data); +#endif + + cf->cf_nodes[cf->cf_n] = node; + cf->cf_n++; +} + +/** + * \brief Writes a timestamp with given format into a MemBuffer + * \param MemBuffer * buffer - where to write + * \param const char * fmt - format to be used write timestamp + * \param const struct timeveal *ts - the timetstamp + * + */ +void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts) { + + time_t time = ts->tv_sec; + struct tm local_tm; + struct tm *timestamp = SCLocalTime(time, &local_tm); + char buf[128] = {0}; + const char * fmt_to_use = TIMESTAMP_DEFAULT_FORMAT; + + if (fmt && *fmt != '\0') { + fmt_to_use = fmt; + } + + CreateFormattedTimeString (timestamp, fmt_to_use, buf, sizeof(buf)); + PrintRawUriBuf((char *)buffer->buffer, &buffer->offset, + buffer->size, (uint8_t *)buf,strlen(buf)); +} + +#ifdef UNITTESTS +/** + * \internal + * \brief This test tests default timestamp format + */ +static int LogCustomFormatTest01(void) +{ + struct tm tm; + tm.tm_sec = 0; + tm.tm_min = 30; + tm.tm_hour = 4; + tm.tm_mday = 13; + tm.tm_mon = 0; + tm.tm_year = 114; + tm.tm_wday = 1; + tm.tm_yday = 13; + tm.tm_isdst = 0; + time_t secs = mktime(&tm); + struct timeval ts = {secs, 0}; + + MemBuffer *buffer = MemBufferCreateNew(62); + if (!buffer) { + return 0; + } + + LogCustomFormatWriteTimestamp(buffer, "", &ts); + /* + * {buffer = "01/13/14-04:30:00", size = 62, offset = 17} + */ + FAIL_IF_NOT( buffer->offset == 17); + FAIL_IF(strcmp((char *)buffer->buffer, "01/13/14-04:30:00") != 0); + + MemBufferFree(buffer); + + return 1; +} + +void LogCustomFormatRegisterTests(void) +{ + UtRegisterTest("LogCustomFormatTest01", LogCustomFormatTest01); +} +#endif /* UNITTESTS */ + +void LogCustomFormatRegister(void) +{ +#ifdef UNITTESTS + LogCustomFormatRegisterTests(); +#endif /* UNITTESTS */ +} diff --git a/src/log-cf-common.h b/src/log-cf-common.h new file mode 100644 index 000000000000..f871a3de35d2 --- /dev/null +++ b/src/log-cf-common.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * \author Ignacio Sanchez + * \author Paulo Pacheco + * + * Common custom loggging format + */ + +#ifndef __LOG_CF_COMMON_H__ +#define __LOG_CF_COMMON_H__ + +#define LOG_MAXN_NODES 64 +#define LOG_NODE_STRLEN 256 +#define LOG_NODE_MAXOUTPUTLEN 8192 + +#define TIMESTAMP_DEFAULT_FORMAT "%D-%H:%M:%S" +#define TIMESTAMP_DEFAULT_FORMAT_LEN 62 + +/* Common format nodes */ +#define LOG_CF_NONE "-" +#define LOG_CF_LITERAL '%' +#define LOG_CF_TIMESTAMP 't' +#define LOG_CF_TIMESTAMP_U 'z' +#define LOG_CF_CLIENT_IP 'a' +#define LOG_CF_SERVER_IP 'A' +#define LOG_CF_CLIENT_PORT 'p' +#define LOG_CF_SERVER_PORT 'P' + +/* Line log common separators **/ +#define LOG_CF_STAR_SEPARATOR "[**]" +#define LOG_CF_SPACE_SEPARATOR " " +#define LOG_CF_UNKNOWN_VALUE "-" + +#define LOG_CF_WRITE_STAR_SEPATATOR(buffer) \ + MemBufferWriteString(buffer, LOG_CF_STAR_SEPARATOR); + +#define LOG_CF_WRITE_SPACE_SEPARATOR(buffer) \ + MemBufferWriteString(buffer, LOG_CF_SPACE_SEPARATOR); + +#define LOG_CF_WRITE_UNKNOWN_VALUE(buffer) \ + MemBufferWriteString(buffer, LOG_CF_UNKNOWN_VALUE); + +/* Include */ +#include "suricata-common.h" +#include "util-buffer.h" + +typedef struct LogCustomFormatNode_ { + uint32_t type; /**< Node format type. ie: LOG_CF_LITERAL, ... */ + uint32_t maxlen; /**< Maximun length of the data */ + char data[LOG_NODE_STRLEN]; /**< optional data. ie: http header name */ +} LogCustomFormatNode; + + +typedef struct LogCustomFormat_ { + uint32_t cf_n; /**< Total number of custom string format nodes */ + LogCustomFormatNode *cf_nodes[LOG_MAXN_NODES]; /**< Custom format string nodes */ +} LogCustomFormat; + +LogCustomFormatNode * LogCustomFormatNodeAlloc(void); +LogCustomFormat * LogCustomFormatAlloc(void); + +void LogCustomFormatNodeFree(LogCustomFormatNode *node); +void LogCustomFormatFree(LogCustomFormat *cf); + +void LogCustomFormatAddNode(LogCustomFormat *cf, LogCustomFormatNode *node); +int LogCustomFormatParse(LogCustomFormat *cf, const char *format); + +void LogCustomFormatWriteTimestamp(MemBuffer *buffer, const char *fmt, const struct timeval *ts); +void LogCustomFormatRegister(void); + +#endif /* __LOG_CF_COMMON_H__ */ diff --git a/src/log-dnslog.c b/src/log-dnslog.c index 7d226e8b8a20..2b3658d2e788 100644 --- a/src/log-dnslog.c +++ b/src/log-dnslog.c @@ -40,6 +40,7 @@ #include "output.h" #include "log-dnslog.h" +#include "app-layer-dns-common.h" #include "app-layer-dns-udp.h" #include "app-layer.h" #include "util-privs.h" @@ -95,10 +96,8 @@ static void LogQuery(LogDnsLogThread *aft, char *timebuf, char *srcip, char *dst " [**] %s [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", record, srcip, sp, dstip, dp); - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); } static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *dstip, Port sp, Port dp, DNSTransaction *tx, DNSAnswerEntry *entry) @@ -109,16 +108,18 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds /* reset */ MemBufferReset(aft->buffer); - /* time & tx*/ MemBufferWriteString(aft->buffer, "%s [**] Response TX %04x [**] ", timebuf, tx->tx_id); if (entry == NULL) { - if (tx->no_such_name) - MemBufferWriteString(aft->buffer, "No Such Name"); - else if (tx->recursion_desired) + if (tx->rcode) { + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + MemBufferWriteString(aft->buffer, "%s", rcode); + } else if (tx->recursion_desired) { MemBufferWriteString(aft->buffer, "Recursion Desired"); + } } else { /* query */ if (entry->fqdn_len > 0) { @@ -135,11 +136,11 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds " [**] %s [**] TTL %u [**] ", record, entry->ttl); uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry) + entry->fqdn_len); - if (entry->type == DNS_RECORD_TYPE_A) { + if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) { char a[16] = ""; PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); MemBufferWriteString(aft->buffer, "%s", a); - } else if (entry->type == DNS_RECORD_TYPE_AAAA) { + } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) { char a[46]; PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); MemBufferWriteString(aft->buffer, "%s", a); @@ -156,18 +157,16 @@ static void LogAnswer(LogDnsLogThread *aft, char *timebuf, char *srcip, char *ds " [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", srcip, sp, dstip, dp); - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); } -static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, - void *state, void *tx, uint64_t tx_id) +static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id, uint8_t direction) { LogDnsLogThread *aft = (LogDnsLogThread *)data; DNSTransaction *dns_tx = (DNSTransaction *)tx; - SCLogDebug("pcap_cnt %ju", p->pcap_cnt); + SCLogDebug("pcap_cnt %"PRIu64, p->pcap_cnt); char timebuf[64]; CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); @@ -211,24 +210,26 @@ static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, dp = p->sp; } - DNSQueryEntry *query = NULL; - TAILQ_FOREACH(query, &dns_tx->query_list, next) { - LogQuery(aft, timebuf, dstip, srcip, dp, sp, dns_tx, query); - } - - if (dns_tx->no_such_name) - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); - if (dns_tx->recursion_desired) - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); - - DNSAnswerEntry *entry = NULL; - TAILQ_FOREACH(entry, &dns_tx->answer_list, next) { - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); - } + if (direction == STREAM_TOSERVER) { + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &dns_tx->query_list, next) { + LogQuery(aft, timebuf, dstip, srcip, dp, sp, dns_tx, query); + } + } else if (direction == STREAM_TOCLIENT) { + if (dns_tx->rcode) + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); + if (dns_tx->recursion_desired) + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, NULL); + + DNSAnswerEntry *entry = NULL; + TAILQ_FOREACH(entry, &dns_tx->answer_list, next) { + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); + } - entry = NULL; - TAILQ_FOREACH(entry, &dns_tx->authority_list, next) { - LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); + entry = NULL; + TAILQ_FOREACH(entry, &dns_tx->authority_list, next) { + LogAnswer(aft, timebuf, srcip, dstip, sp, dp, dns_tx, entry); + } } aft->dns_cnt++; @@ -236,6 +237,18 @@ static int LogDnsLogger(ThreadVars *tv, void *data, const Packet *p, Flow *f, return 0; } +static int LogDnsRequestLogger(ThreadVars *tv, void *data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) +{ + return LogDnsLogger(tv, data, p, f, state, tx, tx_id, STREAM_TOSERVER); +} + +static int LogDnsResponseLogger(ThreadVars *tv, void *data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) +{ + return LogDnsLogger(tv, data, p, f, state, tx, tx_id, STREAM_TOCLIENT); +} + static TmEcode LogDnsLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogDnsLogThread *aft = SCMalloc(sizeof(LogDnsLogThread)); @@ -245,7 +258,7 @@ static TmEcode LogDnsLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for DNSLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogDNSLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -291,7 +304,6 @@ static void LogDnsLogExitPrintStats(ThreadVars *tv, void *data) static void LogDnsLogDeInitCtx(OutputCtx *output_ctx) { LogDnsFileCtx *dnslog_ctx = (LogDnsFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&dnslog_ctx->file_ctx->rotation_flag); LogFileFreeCtx(dnslog_ctx->file_ctx); SCFree(dnslog_ctx); SCFree(output_ctx); @@ -310,11 +322,10 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx)); if (unlikely(dnslog_ctx == NULL)) { @@ -343,18 +354,17 @@ static OutputCtx *LogDnsLogInitCtx(ConfNode *conf) return output_ctx; } -void TmModuleLogDnsLogRegister (void) +void LogDnsLogRegister (void) { - tmm_modules[TMM_LOGDNSLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGDNSLOG].ThreadInit = LogDnsLogThreadInit; - tmm_modules[TMM_LOGDNSLOG].ThreadExitPrintStats = LogDnsLogExitPrintStats; - tmm_modules[TMM_LOGDNSLOG].ThreadDeinit = LogDnsLogThreadDeinit; - tmm_modules[TMM_LOGDNSLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGDNSLOG].cap_flags = 0; - tmm_modules[TMM_LOGDNSLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterTxModule(MODULE_NAME, "dns-log", LogDnsLogInitCtx, - ALPROTO_DNS, LogDnsLogger); + /* Request logger. */ + OutputRegisterTxModuleWithProgress(LOGGER_DNS, MODULE_NAME, "dns-log", + LogDnsLogInitCtx, ALPROTO_DNS, LogDnsRequestLogger, 0, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, LogDnsLogExitPrintStats); + + /* Response logger. */ + OutputRegisterTxModuleWithProgress(LOGGER_DNS, MODULE_NAME, "dns-log", + LogDnsLogInitCtx, ALPROTO_DNS, LogDnsResponseLogger, 1, 1, + LogDnsLogThreadInit, LogDnsLogThreadDeinit, LogDnsLogExitPrintStats); /* enable the logger for the app layer */ SCLogDebug("registered %s", MODULE_NAME); diff --git a/src/log-dnslog.h b/src/log-dnslog.h index acd00bc40285..eefac42248f8 100644 --- a/src/log-dnslog.h +++ b/src/log-dnslog.h @@ -24,6 +24,6 @@ #ifndef __LOG_DNSLOG_H__ #define __LOG_DNSLOG_H__ -void TmModuleLogDnsLogRegister (void); +void LogDnsLogRegister(void); #endif /* __LOG_DNSLOG_H__ */ diff --git a/src/log-droplog.c b/src/log-droplog.c index 34447ae2171e..027425754d1b 100644 --- a/src/log-droplog.c +++ b/src/log-droplog.c @@ -37,7 +37,6 @@ #include "util-debug.h" #include "decode-ipv4.h" -#include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -125,7 +124,6 @@ static void LogDropLogDeInitCtx(OutputCtx *output_ctx) if (output_ctx != NULL) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; if (logfile_ctx != NULL) { - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); } SCFree(output_ctx); @@ -151,11 +149,10 @@ static OutputCtx *LogDropLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } - OutputRegisterFileRotationFlag(&logfile_ctx->rotation_flag); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { @@ -226,31 +223,35 @@ static int LogDropLogNetFilter (ThreadVars *tv, const Packet *p, void *data) switch (proto) { case IPPROTO_TCP: - fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16" " - "SEQ=%"PRIu32" ACK=%"PRIu32" WINDOW=%"PRIu32"", - GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_SEQ(p), - TCP_GET_ACK(p), TCP_GET_WINDOW(p)); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_SYN(p) ? " SYN" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_ACK(p) ? " ACK" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_PUSH(p) ? " PSH" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_RST(p) ? " RST" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_URG(p) ? " URG" : ""); - fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_FIN(p) ? " FIN" : ""); - fprintf(dlt->file_ctx->fp, " RES=0x%02"PRIu8" URGP=%"PRIu16"", - TCP_GET_RAW_X2(p->tcph), TCP_GET_URG_POINTER(p)); + if (PKT_IS_TCP(p)) { + fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16" " + "SEQ=%"PRIu32" ACK=%"PRIu32" WINDOW=%"PRIu32"", + GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_SEQ(p), + TCP_GET_ACK(p), TCP_GET_WINDOW(p)); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_SYN(p) ? " SYN" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_ACK(p) ? " ACK" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_PUSH(p) ? " PSH" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_RST(p) ? " RST" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_URG(p) ? " URG" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_FIN(p) ? " FIN" : ""); + fprintf(dlt->file_ctx->fp, " RES=0x%02"PRIu8" URGP=%"PRIu16"", + TCP_GET_RAW_X2(p->tcph), TCP_GET_URG_POINTER(p)); + } break; case IPPROTO_UDP: - fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16"" - " LEN=%"PRIu16"", UDP_GET_SRC_PORT(p), - UDP_GET_DST_PORT(p), UDP_GET_LEN(p)); + if (PKT_IS_UDP(p)) { + fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16"" + " LEN=%"PRIu16"", UDP_GET_SRC_PORT(p), + UDP_GET_DST_PORT(p), UDP_GET_LEN(p)); + } break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { - fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" + fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu8" CODE=%"PRIu8"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV4_GET_TYPE(p), ICMPV4_GET_CODE(p), ICMPV4_GET_ID(p), ICMPV4_GET_SEQ(p)); - } else if(PKT_IS_ICMPV6(p)) { - fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" + } else if (PKT_IS_ICMPV6(p)) { + fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu8" CODE=%"PRIu8"" " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV6_GET_TYPE(p), ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); } @@ -291,14 +292,12 @@ static int LogDropCondition(ThreadVars *tv, const Packet *p) if (p->flow != NULL) { int ret = FALSE; - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) ret = TRUE; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) ret = TRUE; } - FLOWLOCK_UNLOCK(p->flow); return ret; } else if (PACKET_TEST_ACTION(p, ACTION_DROP)) { return TRUE; @@ -324,14 +323,12 @@ static int LogDropLogger(ThreadVars *tv, void *thread_data, const Packet *p) return -1; if (p->flow) { - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) p->flow->flags |= FLOW_TOSERVER_DROP_LOGGED; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) p->flow->flags |= FLOW_TOCLIENT_DROP_LOGGED; } - FLOWLOCK_UNLOCK(p->flow); } return 0; } @@ -384,23 +381,18 @@ int LogDropLogTest01() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); - SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1 && (PACKET_TEST_ACTION(p, ACTION_DROP))) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); - else - result = 0; if (LogDropCondition(NULL, p) == TRUE) LogDropLogger(NULL, &dlt, p); @@ -453,23 +445,18 @@ int LogDropLogTest02() de_ctx->flags |= DE_QUIET; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " "(msg:\"LogDropLog test\"; content:\"GET\"; Classtype:unknown; sid:1;)"); - result = (de_ctx->sig_list != NULL); - SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); if (p->alerts.cnt == 1 && p->alerts.alerts[0].action != ACTION_DROP) result = (strcmp(p->alerts.alerts[0].s->class_msg, "Unknown are we") == 0); - else - result = 0; if (LogDropCondition(NULL, p) == TRUE) LogDropLogger(NULL, &dlt, p); @@ -495,25 +482,18 @@ int LogDropLogTest02() */ static void LogDropLogRegisterTests(void) { - UtRegisterTest("LogDropLogTest01", LogDropLogTest01, 1); - UtRegisterTest("LogDropLogTest02", LogDropLogTest02, 1); + UtRegisterTest("LogDropLogTest01", LogDropLogTest01); + UtRegisterTest("LogDropLogTest02", LogDropLogTest02); } #endif /** \brief function to register the drop log module */ -void TmModuleLogDropLogRegister (void) +void LogDropLogRegister (void) { - - tmm_modules[TMM_LOGDROPLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGDROPLOG].ThreadInit = LogDropLogThreadInit; - tmm_modules[TMM_LOGDROPLOG].ThreadExitPrintStats = LogDropLogExitPrintStats; - tmm_modules[TMM_LOGDROPLOG].ThreadDeinit = LogDropLogThreadDeinit; + OutputRegisterPacketModule(LOGGER_DROP, MODULE_NAME, "drop", + LogDropLogInitCtx, LogDropLogger, LogDropCondition, + LogDropLogThreadInit, LogDropLogThreadDeinit, LogDropLogExitPrintStats); #ifdef UNITTESTS - tmm_modules[TMM_LOGDROPLOG].RegisterTests = LogDropLogRegisterTests; + LogDropLogRegisterTests(); #endif - tmm_modules[TMM_LOGDROPLOG].cap_flags = 0; - tmm_modules[TMM_LOGDROPLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "drop", LogDropLogInitCtx, - LogDropLogger, LogDropCondition); } diff --git a/src/log-droplog.h b/src/log-droplog.h index 2b266ad55c37..e37d8e73f989 100644 --- a/src/log-droplog.h +++ b/src/log-droplog.h @@ -26,6 +26,6 @@ #ifndef ALERT_DROPLOG_H #define ALERT_DROPLOG_H -void TmModuleLogDropLogRegister(void); +void LogDropLogRegister(void); #endif /* ALERT_DROPLOG_H */ diff --git a/src/log-file.c b/src/log-file.c index 8cb7a662bb2c..3ddf8643b1bf 100644 --- a/src/log-file.c +++ b/src/log-file.c @@ -55,6 +55,8 @@ #include "util-logopenfile.h" #include "app-layer-htp.h" +#include "app-layer-smtp.h" +#include "util-decode-mime.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" @@ -144,6 +146,34 @@ static void LogFileMetaGetUserAgent(FILE *fp, const Packet *p, const File *ff) fprintf(fp, ""); } +static void LogFileMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) +{ + SMTPState *state = (SMTPState *) p->flow->alstate; + if (state != NULL) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, state, ff->txid); + if (tx == NULL || tx->msg_tail == NULL) + return; + + /* Message Id */ + if (tx->msg_tail->msg_id != NULL) { + + fprintf(fp, "\"message-id\": \""); + PrintRawJsonFp(fp, (uint8_t *) tx->msg_tail->msg_id, + (int) tx->msg_tail->msg_id_len); + fprintf(fp, "\", "); + } + + /* Sender */ + MimeDecField *field = MimeDecFindField(tx->msg_tail, "from"); + if (field != NULL) { + fprintf(fp, "\"sender\": \""); + PrintRawJsonFp(fp, (uint8_t *) field->value, + (int) field->value_len); + fprintf(fp, "\", "); + } + } +} + /** * \internal * \brief Write meta data on a single line json record @@ -231,12 +261,15 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const fprintf(fp, "\"http_user_agent\": \""); LogFileMetaGetUserAgent(fp, p, ff); fprintf(fp, "\", "); + } else if (p->flow->alproto == ALPROTO_SMTP) { + /* Only applicable to SMTP */ + LogFileMetaGetSmtp(fp, p, ff); } fprintf(fp, "\"filename\": \""); PrintRawJsonFp(fp, ff->name, ff->name_len); fprintf(fp, "\", "); - +#ifdef HAVE_MAGIC fprintf(fp, "\"magic\": \""); if (ff->magic) { PrintRawJsonFp(fp, (uint8_t *)ff->magic, strlen(ff->magic)); @@ -244,7 +277,7 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const fprintf(fp, "unknown"); } fprintf(fp, "\", "); - +#endif switch (ff->state) { case FILE_STATE_CLOSED: fprintf(fp, "\"state\": \"CLOSED\", "); @@ -257,6 +290,22 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const } fprintf(fp, "\", "); } + if (ff->flags & FILE_SHA1) { + fprintf(fp, "\"sha1\": \""); + size_t x; + for (x = 0; x < sizeof(ff->sha1); x++) { + fprintf(fp, "%02x", ff->sha1[x]); + } + fprintf(fp, "\", "); + } + if (ff->flags & FILE_SHA256) { + fprintf(fp, "\"sha256\": \""); + size_t x; + for (x = 0; x < sizeof(ff->sha256); x++) { + fprintf(fp, "%02x", ff->sha256[x]); + } + fprintf(fp, "\", "); + } #endif break; case FILE_STATE_TRUNCATED: @@ -270,7 +319,7 @@ static void LogFileWriteJsonRecord(LogFileLogThread *aft, const Packet *p, const break; } fprintf(fp, "\"stored\": %s, ", ff->flags & FILE_STORED ? "true" : "false"); - fprintf(fp, "\"size\": %"PRIu64" ", ff->size); + fprintf(fp, "\"size\": %"PRIu64" ", FileTrackedSize(ff)); fprintf(fp, "}\n"); fflush(fp); SCMutexUnlock(&aft->file_ctx->fp_mutex); @@ -355,7 +404,6 @@ void LogFileLogExitPrintStats(ThreadVars *tv, void *data) static void LogFileLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); LogFileFreeCtx(logfile_ctx); free(output_ctx); } @@ -372,11 +420,10 @@ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } - OutputRegisterFileRotationFlag(&logfile_ctx->rotation_flag); OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) @@ -385,22 +432,19 @@ static OutputCtx *LogFileLogInitCtx(ConfNode *conf) output_ctx->data = logfile_ctx; output_ctx->DeInit = LogFileLogDeInitCtx; + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); + if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { + FileForceFilestoreEnable(); + SCLogInfo("forcing filestore of all files"); + } + const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for logged files"); } - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL && ConfValIsTrue(force_md5)) { -#ifdef HAVE_NSS - FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for logged files"); -#else - SCLogInfo("md5 calculation requires linking against libnss"); -#endif - } - + FileForceHashParseCfg(conf); FileForceTrackingEnable(); SCReturnPtr(output_ctx, "OutputCtx"); } @@ -416,19 +460,11 @@ int LogFileLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, const return 0; } -void TmModuleLogFileLogRegister (void) +void LogFileLogRegister (void) { - tmm_modules[TMM_FILELOG].name = MODULE_NAME; - tmm_modules[TMM_FILELOG].ThreadInit = LogFileLogThreadInit; - tmm_modules[TMM_FILELOG].Func = NULL; - tmm_modules[TMM_FILELOG].ThreadExitPrintStats = LogFileLogExitPrintStats; - tmm_modules[TMM_FILELOG].ThreadDeinit = LogFileLogThreadDeinit; - tmm_modules[TMM_FILELOG].RegisterTests = NULL; - tmm_modules[TMM_FILELOG].cap_flags = 0; - tmm_modules[TMM_FILELOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterFileModule(MODULE_NAME, "file-log", LogFileLogInitCtx, - LogFileLogger); + OutputRegisterFileModule(LOGGER_FILE, MODULE_NAME, "file-log", + LogFileLogInitCtx, LogFileLogger, LogFileLogThreadInit, + LogFileLogThreadDeinit, LogFileLogExitPrintStats); SCLogDebug("registered"); } diff --git a/src/log-file.h b/src/log-file.h index 08e0785b21e4..b856204bd688 100644 --- a/src/log-file.h +++ b/src/log-file.h @@ -24,6 +24,6 @@ #ifndef __LOG_FILELOG_H__ #define __LOG_FILELOG_H__ -void TmModuleLogFileLogRegister (void); +void LogFileLogRegister(void); #endif /* __LOG_FILELOG_H__ */ diff --git a/src/log-filestore.c b/src/log-filestore.c index 989b51dee512..5fca12d203dc 100644 --- a/src/log-filestore.c +++ b/src/log-filestore.c @@ -46,6 +46,7 @@ #include "util-atomic.h" #include "util-file.h" #include "util-time.h" +#include "util-misc.h" #include "output.h" @@ -53,6 +54,8 @@ #include "util-logopenfile.h" #include "app-layer-htp.h" +#include "app-layer-smtp.h" +#include "util-decode-mime.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" @@ -139,8 +142,32 @@ static void LogFilestoreMetaGetUserAgent(FILE *fp, const Packet *p, const File * fprintf(fp, ""); } -static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, const char *filename, int ipver) +static void LogFilestoreMetaGetSmtp(FILE *fp, const Packet *p, const File *ff) { + SMTPState *state = (SMTPState *) p->flow->alstate; + if (state != NULL) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, state, ff->txid); + if (tx == NULL || tx->msg_tail == NULL) + return; + + /* Message Id */ + if (tx->msg_tail->msg_id != NULL) { + fprintf(fp, "MESSAGE-ID: "); + PrintRawUriFp(fp, (uint8_t *) tx->msg_tail->msg_id, tx->msg_tail->msg_id_len); + fprintf(fp, "\n"); + } + + /* Sender */ + MimeDecField *field = MimeDecFindField(tx->msg_tail, "from"); + if (field != NULL) { + fprintf(fp, "SENDER: "); + PrintRawUriFp(fp, (uint8_t *) field->value, field->value_len); + fprintf(fp, "\n"); + } + } +} + +static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, char *filename, int ipver) { char metafilename[PATH_MAX] = ""; snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); FILE *fp = fopen(metafilename, "w+"); @@ -180,18 +207,29 @@ static void LogFilestoreLogCreateMetaFile(const Packet *p, const File *ff, const fprintf(fp, "SRC PORT: %" PRIu16 "\n", sp); fprintf(fp, "DST PORT: %" PRIu16 "\n", dp); } - fprintf(fp, "HTTP URI: "); - LogFilestoreMetaGetUri(fp, p, ff); - fprintf(fp, "\n"); - fprintf(fp, "HTTP HOST: "); - LogFilestoreMetaGetHost(fp, p, ff); - fprintf(fp, "\n"); - fprintf(fp, "HTTP REFERER: "); - LogFilestoreMetaGetReferer(fp, p, ff); - fprintf(fp, "\n"); - fprintf(fp, "HTTP USER AGENT: "); - LogFilestoreMetaGetUserAgent(fp, p, ff); - fprintf(fp, "\n"); + + fprintf(fp, "APP PROTO: %s\n", + AppProtoToString(p->flow->alproto)); + + /* Only applicable to HTTP traffic */ + if (p->flow->alproto == ALPROTO_HTTP) { + fprintf(fp, "HTTP URI: "); + LogFilestoreMetaGetUri(fp, p, ff); + fprintf(fp, "\n"); + fprintf(fp, "HTTP HOST: "); + LogFilestoreMetaGetHost(fp, p, ff); + fprintf(fp, "\n"); + fprintf(fp, "HTTP REFERER: "); + LogFilestoreMetaGetReferer(fp, p, ff); + fprintf(fp, "\n"); + fprintf(fp, "HTTP USER AGENT: "); + LogFilestoreMetaGetUserAgent(fp, p, ff); + fprintf(fp, "\n"); + } else if (p->flow->alproto == ALPROTO_SMTP) { + /* Only applicable to SMTP */ + LogFilestoreMetaGetSmtp(fp, p, ff); + } + fprintf(fp, "FILENAME: "); PrintRawUriFp(fp, ff->name, ff->name_len); fprintf(fp, "\n"); @@ -209,9 +247,10 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); FILE *fp = fopen(metafilename, "a"); if (fp != NULL) { +#ifdef HAVE_MAGIC fprintf(fp, "MAGIC: %s\n", ff->magic ? ff->magic : ""); - +#endif switch (ff->state) { case FILE_STATE_CLOSED: fprintf(fp, "STATE: CLOSED\n"); @@ -224,6 +263,22 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) } fprintf(fp, "\n"); } + if (ff->flags & FILE_SHA1) { + fprintf(fp, "SHA1: "); + size_t x; + for (x = 0; x < sizeof(ff->sha1); x++) { + fprintf(fp, "%02x", ff->sha1[x]); + } + fprintf(fp, "\n"); + } + if (ff->flags & FILE_SHA256) { + fprintf(fp, "SHA256: "); + size_t x; + for (x = 0; x < sizeof(ff->sha256); x++) { + fprintf(fp, "%02x", ff->sha256[x]); + } + fprintf(fp, "\n"); + } #endif break; case FILE_STATE_TRUNCATED: @@ -236,7 +291,7 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) fprintf(fp, "STATE: UNKNOWN\n"); break; } - fprintf(fp, "SIZE: %"PRIu64"\n", ff->size); + fprintf(fp, "SIZE: %"PRIu64"\n", FileTrackedSize(ff)); fclose(fp); } else { @@ -244,7 +299,8 @@ static void LogFilestoreLogCloseMetaFile(const File *ff) } } -static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, const File *ff, const FileData *ffd, uint8_t flags) +static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, + const File *ff, const uint8_t *data, uint32_t data_len, uint8_t flags) { SCEnter(); LogFilestoreLogThread *aft = (LogFilestoreLogThread *)thread_data; @@ -265,7 +321,7 @@ static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p return 0; } - SCLogDebug("ff %p, ffd %p", ff, ffd); + SCLogDebug("ff %p, data %p, data_len %u", ff, data, data_len); snprintf(filename, sizeof(filename), "%s/file.%u", g_logfile_base_dir, ff->file_id); @@ -282,7 +338,7 @@ static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p return -1; } /* we can get called with a NULL ffd when we need to close */ - } else if (ffd != NULL) { + } else if (data != NULL) { file_fd = open(filename, O_APPEND | O_NOFOLLOW | O_WRONLY); if (file_fd == -1) { SCLogDebug("failed to open file %s: %s", filename, strerror(errno)); @@ -291,7 +347,7 @@ static int LogFilestoreLogger(ThreadVars *tv, void *thread_data, const Packet *p } if (file_fd != -1) { - ssize_t r = write(file_fd, (const void *)ffd->data, (size_t)ffd->len); + ssize_t r = write(file_fd, (const void *)data, (size_t)data_len); if (r == -1) { SCLogDebug("write failed: %s", strerror(errno)); } @@ -314,7 +370,7 @@ static TmEcode LogFilestoreLogThreadInit(ThreadVars *t, void *initdata, void **d if (initdata == NULL) { - SCLogDebug("Error getting context for LogFilestore. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogFileStore. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -380,7 +436,7 @@ static void LogFilestoreLogDeInitCtx(OutputCtx *output_ctx) { LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; LogFileFreeCtx(logfile_ctx); - free(output_ctx); + SCFree(output_ctx); } @@ -390,12 +446,6 @@ static void LogFilestoreLogDeInitCtx(OutputCtx *output_ctx) * */ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) { - LogFileCtx *logfile_ctx = LogFileNewCtx(); - if (logfile_ctx == NULL) { - SCLogDebug("Could not create new LogFilestoreCtx"); - return NULL; - } - OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; @@ -421,41 +471,47 @@ static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf) } } + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); + if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { + FileForceFilestoreEnable(); + SCLogInfo("forcing filestore of all files"); + } + const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); SCLogInfo("forcing magic lookup for stored files"); } - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL && ConfValIsTrue(force_md5)) { -#ifdef HAVE_NSS - FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for stored files"); -#else - SCLogInfo("md5 calculation requires linking against libnss"); -#endif - } + FileForceHashParseCfg(conf); SCLogInfo("storing files in %s", g_logfile_base_dir); + const char *stream_depth_str = ConfNodeLookupChildValue(conf, "stream-depth"); + if (stream_depth_str != NULL && strcmp(stream_depth_str, "no")) { + uint32_t stream_depth = 0; + if (ParseSizeStringU32(stream_depth_str, + &stream_depth) < 0) { + SCLogError(SC_ERR_SIZE_PARSE, "Error parsing " + "file-store.stream-depth " + "from conf file - %s. Killing engine", + stream_depth_str); + exit(EXIT_FAILURE); + } else { + FileReassemblyDepthEnable(stream_depth); + } + } + SCReturnPtr(output_ctx, "OutputCtx"); } -void TmModuleLogFilestoreRegister (void) +void LogFilestoreRegister (void) { - tmm_modules[TMM_FILESTORE].name = MODULE_NAME; - tmm_modules[TMM_FILESTORE].ThreadInit = LogFilestoreLogThreadInit; - tmm_modules[TMM_FILESTORE].Func = NULL; - tmm_modules[TMM_FILESTORE].ThreadExitPrintStats = LogFilestoreLogExitPrintStats; - tmm_modules[TMM_FILESTORE].ThreadDeinit = LogFilestoreLogThreadDeinit; - tmm_modules[TMM_FILESTORE].RegisterTests = NULL; - tmm_modules[TMM_FILESTORE].cap_flags = 0; - tmm_modules[TMM_FILESTORE].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterFiledataModule(MODULE_NAME, "file", LogFilestoreLogInitCtx, - LogFilestoreLogger); - OutputRegisterFiledataModule(MODULE_NAME, "file-store", LogFilestoreLogInitCtx, - LogFilestoreLogger); + OutputRegisterFiledataModule(LOGGER_FILE_STORE, MODULE_NAME, "file", + LogFilestoreLogInitCtx, LogFilestoreLogger, LogFilestoreLogThreadInit, + LogFilestoreLogThreadDeinit, LogFilestoreLogExitPrintStats); + OutputRegisterFiledataModule(LOGGER_FILE_STORE, MODULE_NAME, "file-store", + LogFilestoreLogInitCtx, LogFilestoreLogger, LogFilestoreLogThreadInit, + LogFilestoreLogThreadDeinit, LogFilestoreLogExitPrintStats); SCLogDebug("registered"); } diff --git a/src/log-filestore.h b/src/log-filestore.h index bfbfd5fcfa85..d477506fc590 100644 --- a/src/log-filestore.h +++ b/src/log-filestore.h @@ -24,6 +24,6 @@ #ifndef __LOG_FILESTORE_H__ #define __LOG_FILESTORE_H__ -void TmModuleLogFilestoreRegister (void); +void LogFilestoreRegister(void); #endif /* __LOG_FILELOG_H__ */ diff --git a/src/log-httplog.c b/src/log-httplog.c index 609157808bc9..a26a2f673023 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -49,6 +49,7 @@ #include "util-logopenfile.h" #include "util-time.h" +#include "log-cf-common.h" #define DEFAULT_LOG_FILENAME "http.log" @@ -58,32 +59,17 @@ TmEcode LogHttpLogThreadInit(ThreadVars *, void *, void **); TmEcode LogHttpLogThreadDeinit(ThreadVars *, void *); -void LogHttpLogExitPrintStats(ThreadVars *, void *); static void LogHttpLogDeInitCtx(OutputCtx *); int LogHttpLogger(ThreadVars *tv, void *thread_data, const Packet *, Flow *f, void *state, void *tx, uint64_t tx_id); -void TmModuleLogHttpLogRegister (void) +void LogHttpLogRegister (void) { - tmm_modules[TMM_LOGHTTPLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGHTTPLOG].ThreadInit = LogHttpLogThreadInit; - tmm_modules[TMM_LOGHTTPLOG].ThreadExitPrintStats = LogHttpLogExitPrintStats; - tmm_modules[TMM_LOGHTTPLOG].ThreadDeinit = LogHttpLogThreadDeinit; - tmm_modules[TMM_LOGHTTPLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGHTTPLOG].cap_flags = 0; - tmm_modules[TMM_LOGHTTPLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterTxModule(MODULE_NAME, "http-log", LogHttpLogInitCtx, - ALPROTO_HTTP, LogHttpLogger); + OutputRegisterTxModule(LOGGER_HTTP, MODULE_NAME, "http-log", + LogHttpLogInitCtx, ALPROTO_HTTP, LogHttpLogger, LogHttpLogThreadInit, + LogHttpLogThreadDeinit, NULL); } -#define LOG_HTTP_MAXN_NODES 64 -#define LOG_HTTP_NODE_STRLEN 256 -#define LOG_HTTP_NODE_MAXOUTPUTLEN 8192 - -#define TIMESTAMP_DEFAULT_FORMAT "%b %d, %Y; %H:%M:%S" -#define LOG_HTTP_CF_NONE "-" -#define LOG_HTTP_CF_LITERAL '%' #define LOG_HTTP_CF_REQUEST_HOST 'h' #define LOG_HTTP_CF_REQUEST_PROTOCOL 'H' #define LOG_HTTP_CF_REQUEST_METHOD 'm' @@ -95,24 +81,12 @@ void TmModuleLogHttpLogRegister (void) #define LOG_HTTP_CF_RESPONSE_STATUS 's' #define LOG_HTTP_CF_RESPONSE_HEADER 'o' #define LOG_HTTP_CF_RESPONSE_LEN 'B' -#define LOG_HTTP_CF_TIMESTAMP 't' -#define LOG_HTTP_CF_TIMESTAMP_U 'z' -#define LOG_HTTP_CF_CLIENT_IP 'a' -#define LOG_HTTP_CF_SERVER_IP 'A' -#define LOG_HTTP_CF_CLIENT_PORT 'p' -#define LOG_HTTP_CF_SERVER_PORT 'P' - -typedef struct LogHttpCustomFormatNode_ { - uint32_t type; /** Node format type. ie: LOG_HTTP_CF_LITERAL, LOG_HTTP_CF_REQUEST_HEADER */ - uint32_t maxlen; /** Maximun length of the data */ - char data[LOG_HTTP_NODE_STRLEN]; /** optional data. ie: http header name */ -} LogHttpCustomFormatNode; + typedef struct LogHttpFileCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ - uint32_t cf_n; /** Total number of custom string format nodes */ - LogHttpCustomFormatNode *cf_nodes[LOG_HTTP_MAXN_NODES]; /** Custom format string nodes */ + LogCustomFormat *cf; } LogHttpFileCtx; #define LOG_HTTP_DEFAULT 0 @@ -168,49 +142,44 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t htp_header_t *h_request_hdr; htp_header_t *h_response_hdr; - time_t time = ts->tv_sec; - struct tm local_tm; - struct tm *timestamp = SCLocalTime(time, &local_tm); - - for (i = 0; i < httplog_ctx->cf_n; i++) { + for (i = 0; i < httplog_ctx->cf->cf_n; i++) { h_request_hdr = NULL; h_response_hdr = NULL; - switch (httplog_ctx->cf_nodes[i]->type){ - case LOG_HTTP_CF_LITERAL: + + LogCustomFormatNode * node = httplog_ctx->cf->cf_nodes[i]; + if (! node) /* Should never happen */ + continue; + + switch (node->type){ + case LOG_CF_LITERAL: /* LITERAL */ - MemBufferWriteString(aft->buffer, "%s", httplog_ctx->cf_nodes[i]->data); + MemBufferWriteString(aft->buffer, "%s", node->data); break; - case LOG_HTTP_CF_TIMESTAMP: + case LOG_CF_TIMESTAMP: /* TIMESTAMP */ - if (httplog_ctx->cf_nodes[i]->data[0] == '\0') { - strftime(buf, 62, TIMESTAMP_DEFAULT_FORMAT, timestamp); - } else { - strftime(buf, 62, httplog_ctx->cf_nodes[i]->data, timestamp); - } - PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, - aft->buffer->size, (uint8_t *)buf,strlen(buf)); + LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); break; - case LOG_HTTP_CF_TIMESTAMP_U: + case LOG_CF_TIMESTAMP_U: /* TIMESTAMP USECONDS */ - snprintf(buf, 62, "%06u", (unsigned int) ts->tv_usec); + snprintf(buf, 6, "%06u", (unsigned int) ts->tv_usec); PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)buf,strlen(buf)); break; - case LOG_HTTP_CF_CLIENT_IP: + case LOG_CF_CLIENT_IP: /* CLIENT IP ADDRESS */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)srcip,strlen(srcip)); break; - case LOG_HTTP_CF_SERVER_IP: + case LOG_CF_SERVER_IP: /* SERVER IP ADDRESS */ PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)dstip,strlen(dstip)); break; - case LOG_HTTP_CF_CLIENT_PORT: + case LOG_CF_CLIENT_PORT: /* CLIENT PORT */ MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); break; - case LOG_HTTP_CF_SERVER_PORT: + case LOG_CF_SERVER_PORT: /* SERVER PORT */ MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); break; @@ -221,13 +190,13 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_URI: /* URI */ if (tx->request_uri != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(tx->request_uri)) { datalen = bstr_len(tx->request_uri); } @@ -235,14 +204,14 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_uri), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_HOST: /* HOSTNAME */ if (tx->request_hostname != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(tx->request_hostname)) { datalen = bstr_len(tx->request_hostname); } @@ -250,7 +219,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_hostname), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_PROTOCOL: @@ -260,16 +229,16 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_HEADER: /* REQUEST HEADER */ if (tx->request_headers != NULL) { - h_request_hdr = htp_table_get_c(tx->request_headers, httplog_ctx->cf_nodes[i]->data); + h_request_hdr = htp_table_get_c(tx->request_headers, node->data); } if (h_request_hdr != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(h_request_hdr->value)) { datalen = bstr_len(h_request_hdr->value); } @@ -277,7 +246,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(h_request_hdr->value), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_COOKIE: @@ -286,19 +255,19 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t h_request_hdr = htp_table_get_c(tx->request_headers, "Cookie"); if (h_request_hdr != NULL) { cvalue_len = GetCookieValue((uint8_t *) bstr_ptr(h_request_hdr->value), - bstr_len(h_request_hdr->value), (char *) httplog_ctx->cf_nodes[i]->data, + bstr_len(h_request_hdr->value), (char *) node->data, &cvalue); } } if (cvalue_len > 0 && cvalue != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > cvalue_len) { datalen = cvalue_len; } PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, cvalue, datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_REQUEST_LEN: @@ -312,17 +281,17 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_HEADER: /* RESPONSE HEADER */ if (tx->response_headers != NULL) { h_response_hdr = htp_table_get_c(tx->response_headers, - httplog_ctx->cf_nodes[i]->data); + node->data); } if (h_response_hdr != NULL) { - datalen = httplog_ctx->cf_nodes[i]->maxlen; + datalen = node->maxlen; if (datalen == 0 || datalen > bstr_len(h_response_hdr->value)) { datalen = bstr_len(h_response_hdr->value); } @@ -330,7 +299,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t aft->buffer->size, (uint8_t *)bstr_ptr(h_response_hdr->value), datalen); } else { - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); } break; case LOG_HTTP_CF_RESPONSE_LEN: @@ -339,8 +308,8 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t break; default: /* NO MATCH */ - MemBufferWriteString(aft->buffer, LOG_HTTP_CF_NONE); - SCLogDebug("No matching parameter %%%c for custom http log.", httplog_ctx->cf_nodes[i]->type); + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + SCLogDebug("No matching parameter %%%c for custom http log.", node->type); break; } } @@ -349,7 +318,7 @@ static void LogHttpLogCustom(LogHttpLogThread *aft, htp_tx_t *tx, const struct t static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) { - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* referer */ htp_header_t *h_referer = NULL; @@ -363,7 +332,8 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) } else { MemBufferWriteString(aft->buffer, ""); } - MemBufferWriteString(aft->buffer, " [**] "); + + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* method */ if (tx->request_method != NULL) { @@ -371,7 +341,7 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) (uint8_t *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* protocol */ if (tx->request_protocol != NULL) { @@ -381,7 +351,7 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) } else { MemBufferWriteString(aft->buffer, ""); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* response status */ if (tx->response_status != NULL) { @@ -404,7 +374,8 @@ static void LogHttpLogExtended(LogHttpLogThread *aft, htp_tx_t *tx) } /* length */ - MemBufferWriteString(aft->buffer, " [**] %"PRIuMAX" bytes", (uintmax_t)tx->response_message_len); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); + MemBufferWriteString(aft->buffer, "%"PRIuMAX" bytes", (uintmax_t)tx->response_message_len); } static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, Flow *f, HtpState *htp_state, htp_tx_t *tx, uint64_t tx_id, int ipproto) @@ -471,7 +442,7 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, } else { MemBufferWriteString(aft->buffer, ""); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* uri */ if (tx->request_uri != NULL) { @@ -479,7 +450,7 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, (uint8_t *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); } - MemBufferWriteString(aft->buffer, " [**] "); + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); /* user agent */ htp_header_t *h_user_agent = NULL; @@ -498,17 +469,16 @@ static TmEcode LogHttpLogIPWrapper(ThreadVars *tv, void *data, const Packet *p, } /* ip/tcp header info */ + LOG_CF_WRITE_STAR_SEPATATOR(aft->buffer); MemBufferWriteString(aft->buffer, - " [**] %s:%" PRIu16 " -> %s:%" PRIu16 "\n", + "%s:%" PRIu16 " -> %s:%" PRIu16 "\n", srcip, sp, dstip, dp); } aft->uri_cnt ++; - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); end: SCReturnInt(0); @@ -542,7 +512,7 @@ TmEcode LogHttpLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogHTTPLog. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -575,16 +545,6 @@ TmEcode LogHttpLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void LogHttpLogExitPrintStats(ThreadVars *tv, void *data) -{ - LogHttpLogThread *aft = (LogHttpLogThread *)data; - if (aft == NULL) { - return; - } - - SCLogInfo("HTTP logger logged %" PRIu32 " requests", aft->uri_cnt); -} - /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful @@ -592,18 +552,15 @@ void LogHttpLogExitPrintStats(ThreadVars *tv, void *data) OutputCtx *LogHttpLogInitCtx(ConfNode *conf) { LogFileCtx* file_ctx = LogFileNewCtx(); - const char *p, *np; - uint32_t n; if(file_ctx == NULL) { SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); LogHttpFileCtx *httplog_ctx = SCMalloc(sizeof(LogHttpFileCtx)); if (unlikely(httplog_ctx == NULL)) { @@ -613,7 +570,6 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) memset(httplog_ctx, 0x00, sizeof(LogHttpFileCtx)); httplog_ctx->file_ctx = file_ctx; - httplog_ctx->cf_n=0; const char *extended = ConfNodeLookupChildValue(conf, "extended"); const char *custom = ConfNodeLookupChildValue(conf, "custom"); @@ -621,74 +577,17 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) /* If custom logging format is selected, lets parse it */ if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { - p=customformat; + + httplog_ctx->cf = LogCustomFormatAlloc(); + if (!httplog_ctx->cf) { + goto errorfree; + } + httplog_ctx->flags |= LOG_HTTP_CUSTOM; - for (httplog_ctx->cf_n = 0; httplog_ctx->cf_n < LOG_HTTP_MAXN_NODES-1 && p && *p != '\0'; - httplog_ctx->cf_n++){ - httplog_ctx->cf_nodes[httplog_ctx->cf_n] = SCMalloc(sizeof(LogHttpCustomFormatNode)); - if (httplog_ctx->cf_nodes[httplog_ctx->cf_n] == NULL) { - for (n = 0; n < httplog_ctx->cf_n; n++) { - SCFree(httplog_ctx->cf_nodes[n]); - } - LogFileFreeCtx(file_ctx); - SCFree(httplog_ctx); - return NULL; - } - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->maxlen = 0; - - if (*p != '%'){ - /* Literal found in format string */ - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL; - np = strchr(p, '%'); - if (np == NULL){ - n = LOG_HTTP_NODE_STRLEN-2; - np = NULL; /* End */ - }else{ - n = np-p; - } - strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data,p,n+1); - p = np; - } else { - /* Non Literal found in format string */ - p++; - if (*p == '[') { /* Check if maxlength has been specified (ie: [25]) */ - p++; - np = strchr(p, ']'); - if (np != NULL) { - if (np-p > 0 && np-p < 10){ - long maxlen = strtol(p,NULL,10); - if (maxlen > 0 && maxlen < LOG_HTTP_NODE_MAXOUTPUTLEN) { - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->maxlen = (uint32_t) maxlen; - } - } else { - goto parsererror; - } - p = np + 1; - } else { - goto parsererror; - } - } - if (*p == '{') { /* Simple format char */ - np = strchr(p, '}'); - if (np != NULL && np-p > 1 && np-p < LOG_HTTP_NODE_STRLEN-2) { - p++; - n = np-p; - strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, p, n+1); - p = np; - } else { - goto parsererror; - } - p++; - } else { - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data[0] = '\0'; - } - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = *p; - if (*p == '%'){ - httplog_ctx->cf_nodes[httplog_ctx->cf_n]->type = LOG_HTTP_CF_LITERAL; - strlcpy(httplog_ctx->cf_nodes[httplog_ctx->cf_n]->data, "%", 2); - } - p++; - } + + /* Parsing */ + if ( ! LogCustomFormatParse(httplog_ctx->cf, customformat)) { + goto parsererror; } } else { if (extended == NULL) { @@ -716,12 +615,11 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) return output_ctx; parsererror: - for (n = 0;n < httplog_ctx->cf_n;n++) { - SCFree(httplog_ctx->cf_nodes[n]); - } + SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string."); +errorfree: + LogCustomFormatFree(httplog_ctx->cf); LogFileFreeCtx(file_ctx); SCFree(httplog_ctx); - SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom http log format string."); return NULL; } @@ -729,11 +627,7 @@ OutputCtx *LogHttpLogInitCtx(ConfNode *conf) static void LogHttpLogDeInitCtx(OutputCtx *output_ctx) { LogHttpFileCtx *httplog_ctx = (LogHttpFileCtx *)output_ctx->data; - uint32_t i; - for (i = 0; i < httplog_ctx->cf_n; i++) { - SCFree(httplog_ctx->cf_nodes[i]); - } - OutputUnregisterFileRotationFlag(&httplog_ctx->file_ctx->rotation_flag); + LogCustomFormatFree(httplog_ctx->cf); LogFileFreeCtx(httplog_ctx->file_ctx); SCFree(httplog_ctx); SCFree(output_ctx); diff --git a/src/log-httplog.h b/src/log-httplog.h index c02d0d9d612b..e8fccb65dab4 100644 --- a/src/log-httplog.h +++ b/src/log-httplog.h @@ -24,7 +24,7 @@ #ifndef __LOG_HTTPLOG_H__ #define __LOG_HTTPLOG_H__ -void TmModuleLogHttpLogRegister (void); +void LogHttpLogRegister(void); void TmModuleLogHttpLogIPv4Register (void); void TmModuleLogHttpLogIPv6Register (void); OutputCtx *LogHttpLogInitCtx(ConfNode *); diff --git a/src/log-pcap.c b/src/log-pcap.c index 21d41e8bd3b1..0d1a2f776a38 100644 --- a/src/log-pcap.c +++ b/src/log-pcap.c @@ -26,6 +26,13 @@ */ #include "suricata-common.h" + +#if defined(HAVE_DIRENT_H) && defined(HAVE_FNMATCH_H) +#define INIT_RING_BUFFER +#include +#include +#endif + #include "debug.h" #include "detect.h" #include "flow.h" @@ -75,11 +82,21 @@ #define HONOR_PASS_RULES_DISABLED 0 #define HONOR_PASS_RULES_ENABLED 1 +#define PCAP_SNAPLEN 262144 + SC_ATOMIC_DECLARE(uint32_t, thread_cnt); typedef struct PcapFileName_ { char *filename; char *dirname; + + /* Like a struct timeval, but with fixed size. This is only used when + * seeding the ring buffer on start. */ + struct { + uint64_t secs; + uint32_t usecs; + }; + TAILQ_ENTRY(PcapFileName_) next; /**< Pointer to next Pcap File for tailq. */ } PcapFileName; @@ -138,28 +155,30 @@ typedef struct PcapLogThreadData_ { PcapLogData *pcap_log; } PcapLogThreadData; +/* Pattern for extracting timestamp from pcap log files. */ +static const char timestamp_pattern[] = ".*?(\\d+)(\\.(\\d+))?"; +static pcre *pcre_timestamp_code = NULL; +static pcre_extra *pcre_timestamp_extra = NULL; + /* global pcap data for when we're using multi mode. At exit we'll * merge counters into this one and then report counters. */ static PcapLogData *g_pcap_data = NULL; static int PcapLogOpenFileCtx(PcapLogData *); -static TmEcode PcapLog(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +static int PcapLog(ThreadVars *, void *, const Packet *); static TmEcode PcapLogDataInit(ThreadVars *, void *, void **); static TmEcode PcapLogDataDeinit(ThreadVars *, void *); static void PcapLogFileDeInitCtx(OutputCtx *); static OutputCtx *PcapLogInitCtx(ConfNode *); static void PcapLogProfilingDump(PcapLogData *); +static int PcapLogCondition(ThreadVars *, const Packet *); -void TmModulePcapLogRegister(void) +void PcapLogRegister(void) { - tmm_modules[TMM_PCAPLOG].name = MODULE_NAME; - tmm_modules[TMM_PCAPLOG].ThreadInit = PcapLogDataInit; - tmm_modules[TMM_PCAPLOG].Func = PcapLog; - tmm_modules[TMM_PCAPLOG].ThreadDeinit = PcapLogDataDeinit; - tmm_modules[TMM_PCAPLOG].RegisterTests = NULL; - - OutputRegisterModule(MODULE_NAME, "pcap-log", PcapLogInitCtx); - + OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", + PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit, + PcapLogDataDeinit, NULL); + PcapLogProfileSetup(); SC_ATOMIC_INIT(thread_cnt); return; } @@ -171,6 +190,17 @@ void TmModulePcapLogRegister(void) (prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \ (prof).cnt++ +static int PcapLogCondition(ThreadVars *tv, const Packet *p) +{ + if (p->flags & PKT_PSEUDO_STREAM_END) { + return FALSE; + } + if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) { + return FALSE; + } + return TRUE; +} + /** * \brief Function to close pcaplog file * @@ -281,7 +311,7 @@ static int PcapLogRotateFile(ThreadVars *t, PcapLogData *pl) return 0; } -static int PcapLogOpenHandles(PcapLogData *pl, Packet *p) +static int PcapLogOpenHandles(PcapLogData *pl, const Packet *p) { PCAPLOG_PROFILE_START; @@ -289,7 +319,7 @@ static int PcapLogOpenHandles(PcapLogData *pl, Packet *p) if (pl->pcap_dead_handle == NULL) { if ((pl->pcap_dead_handle = pcap_open_dead(p->datalink, - -1)) == NULL) { + PCAP_SNAPLEN)) == NULL) { SCLogDebug("Error opening dead pcap handle"); return TM_ECODE_FAILED; } @@ -345,8 +375,7 @@ static void PcapLogUnlock(PcapLogData *pl) * \retval TM_ECODE_OK on succes * \retval TM_ECODE_FAILED on serious error */ -static TmEcode PcapLog (ThreadVars *t, Packet *p, void *thread_data, PacketQueue *pq, - PacketQueue *postpq) +static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p) { size_t len; int rotate = 0; @@ -468,10 +497,199 @@ static PcapLogData *PcapLogDataCopy(const PcapLogData *pl) return copy; } +#ifdef INIT_RING_BUFFER +static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs, + uint32_t *usecs) +{ + int pcre_ovecsize = 4 * 3; + int pcre_ovec[pcre_ovecsize]; + char buf[PATH_MAX]; + + int n = pcre_exec(pcre_timestamp_code, pcre_timestamp_extra, + filename, strlen(filename), 0, 0, pcre_ovec, + pcre_ovecsize); + if (n != 2 && n != 4) { + /* No match. */ + return 0; + } + + if (n >= 2) { + /* Extract seconds. */ + if (pcre_copy_substring(filename, pcre_ovec, pcre_ovecsize, + 1, buf, sizeof(buf)) < 0) { + return 0; + } + if (ByteExtractStringUint64(secs, 10, 0, buf) < 0) { + return 0; + } + } + if (n == 4) { + /* Extract microseconds. */ + if (pcre_copy_substring(filename, pcre_ovec, pcre_ovecsize, + 3, buf, sizeof(buf)) < 0) { + return 0; + } + if (ByteExtractStringUint32(usecs, 10, 0, buf) < 0) { + return 0; + } + } + + return 1; +} + +static TmEcode PcapLogInitRingBuffer(PcapLogData *pl) +{ + char pattern[PATH_MAX]; + + SCLogInfo("Initializing PCAP ring buffer for %s/%s.", + pl->dir, pl->prefix); + + strlcpy(pattern, pl->dir, PATH_MAX); + if (pattern[strlen(pattern) - 1] != '/') { + strlcat(pattern, "/", PATH_MAX); + } + if (pl->mode == LOGMODE_MULTI) { + for (int i = 0; i < pl->filename_part_cnt; i++) { + char *part = pl->filename_parts[i]; + if (part == NULL || strlen(part) == 0) { + continue; + } + if (part[0] != '%' || strlen(part) < 2) { + strlcat(pattern, part, PATH_MAX); + continue; + } + switch (part[1]) { + case 'i': + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Thread ID not allowed inring buffer mode."); + return TM_ECODE_FAILED; + case 'n': { + char tmp[PATH_MAX]; + snprintf(tmp, PATH_MAX, "%"PRIu32, pl->thread_number); + strlcat(pattern, tmp, PATH_MAX); + break; + } + case 't': + strlcat(pattern, "*", PATH_MAX); + break; + default: + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Unsupported format character: %%%s", part); + return TM_ECODE_FAILED; + } + } + } else { + strlcat(pattern, pl->prefix, PATH_MAX); + strlcat(pattern, ".*", PATH_MAX); + } + + char *basename = strrchr(pattern, '/'); + *basename++ = '\0'; + + /* Pattern is now just the directory name. */ + DIR *dir = opendir(pattern); + if (dir == NULL) { + SCLogWarning(SC_ERR_DIR_OPEN, "Failed to open directory %s: %s", + pattern, strerror(errno)); + return TM_ECODE_FAILED; + } + + for (;;) { + struct dirent *entry = readdir(dir); + if (entry == NULL) { + break; + } + if (fnmatch(basename, entry->d_name, 0) != 0) { + continue; + } + + uint64_t secs = 0; + uint32_t usecs = 0; + + if (!PcapLogGetTimeOfFile(entry->d_name, &secs, &usecs)) { + /* Failed to get time stamp out of file name. Not necessarily a + * failure as the file might just not be a pcap log file. */ + continue; + } + + PcapFileName *pf = SCCalloc(sizeof(*pf), 1); + if (unlikely(pf == NULL)) { + goto fail; + } + char path[PATH_MAX]; + snprintf(path, PATH_MAX - 1, "%s/%s", pattern, entry->d_name); + if ((pf->filename = SCStrdup(path)) == NULL) { + goto fail; + } + if ((pf->dirname = SCStrdup(pattern)) == NULL) { + goto fail; + } + pf->secs = secs; + pf->usecs = usecs; + + if (TAILQ_EMPTY(&pl->pcap_file_list)) { + TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next); + } else { + /* Ordered insert. */ + PcapFileName *it = NULL; + TAILQ_FOREACH(it, &pl->pcap_file_list, next) { + if (pf->secs < it->secs) { + break; + } else if (pf->secs == it->secs && pf->usecs < it->usecs) { + break; + } + } + if (it == NULL) { + TAILQ_INSERT_TAIL(&pl->pcap_file_list, pf, next); + } else { + TAILQ_INSERT_BEFORE(it, pf, next); + } + } + pl->file_cnt++; + continue; + + fail: + if (pf != NULL) { + if (pf->filename != NULL) { + SCFree(pf->filename); + } + if (pf->dirname != NULL) { + SCFree(pf->dirname); + } + SCFree(pf); + } + break; + } + + if (pl->file_cnt > pl->max_files) { + PcapFileName *pf = TAILQ_FIRST(&pl->pcap_file_list); + while (pf != NULL && pl->file_cnt > pl->max_files) { + SCLogDebug("Removing PCAP file %s", pf->filename); + if (remove(pf->filename) != 0) { + SCLogWarning(SC_WARN_REMOVE_FILE, + "Failed to remove PCAP file %s: %s", pf->filename, + strerror(errno)); + } + TAILQ_REMOVE(&pl->pcap_file_list, pf, next); + PcapFileNameFree(pf); + pf = TAILQ_FIRST(&pl->pcap_file_list); + pl->file_cnt--; + } + } + + closedir(dir); + + /* For some reason file count is initialized at one, instead of 0. */ + SCLogNotice("Ring buffer initialized with %d files.", pl->file_cnt - 1); + + return TM_ECODE_OK; +} +#endif /* INIT_RING_BUFFER */ + static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) { if (initdata == NULL) { - SCLogDebug("Error getting context for PcapLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for LogPcap. \"initdata\" argument NULL"); return TM_ECODE_FAILED; } @@ -493,7 +711,9 @@ static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) td->pcap_log->pkt_cnt = 0; td->pcap_log->pcap_dead_handle = NULL; td->pcap_log->pcap_dumper = NULL; - td->pcap_log->file_cnt = 1; + if (td->pcap_log->file_cnt < 1) { + td->pcap_log->file_cnt = 1; + } struct timeval ts; memset(&ts, 0x00, sizeof(struct timeval)); @@ -511,6 +731,16 @@ static TmEcode PcapLogDataInit(ThreadVars *t, void *initdata, void **data) *data = (void *)td; + if (pl->max_files && (pl->mode == LOGMODE_MULTI || pl->threads == 1)) { +#ifdef INIT_RING_BUFFER + if (PcapLogInitRingBuffer(td->pcap_log) == TM_ECODE_FAILED) { + return TM_ECODE_FAILED; + } +#else + SCLogInfo("Unable to initialize ring buffer on this platform."); +#endif /* INIT_RING_BUFFER */ + } + return TM_ECODE_OK; } @@ -540,6 +770,27 @@ static void StatsMerge(PcapLogData *dst, PcapLogData *src) dst->profile_data_size += src->profile_data_size; } +static void PcapLogDataFree(PcapLogData *pl) +{ + + PcapFileName *pf; + while ((pf = TAILQ_FIRST(&pl->pcap_file_list)) != NULL) { + TAILQ_REMOVE(&pl->pcap_file_list, pf, next); + PcapFileNameFree(pf); + } + if (pl == g_pcap_data) { + for (int i = 0; i < MAX_TOKS; i++) { + if (pl->filename_parts[i] != NULL) { + SCFree(pl->filename_parts[i]); + } + } + } + SCFree(pl->h); + SCFree(pl->filename); + SCFree(pl->prefix); + SCFree(pl); +} + /** * \brief Thread deinit function. * @@ -572,6 +823,12 @@ static TmEcode PcapLogDataDeinit(ThreadVars *t, void *thread_data) pl->reported = 1; } } + + if (pl != g_pcap_data) { + PcapLogDataFree(pl); + } + + SCFree(td); return TM_ECODE_OK; } @@ -667,6 +924,9 @@ static int ParseFilename(PcapLogData *pl, const char *filename) * */ static OutputCtx *PcapLogInitCtx(ConfNode *conf) { + const char *pcre_errbuf; + int pcre_erroffset; + PcapLogData *pl = SCMalloc(sizeof(PcapLogData)); if (unlikely(pl == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate Memory for PcapLogData"); @@ -693,6 +953,19 @@ static OutputCtx *PcapLogInitCtx(ConfNode *conf) SCMutexInit(&pl->plog_lock, NULL); + /* Initialize PCREs. */ + pcre_timestamp_code = pcre_compile(timestamp_pattern, 0, &pcre_errbuf, + &pcre_erroffset, NULL); + if (pcre_timestamp_code == NULL) { + FatalError(SC_ERR_PCRE_COMPILE, + "Failed to compile \"%s\" at offset %"PRIu32": %s", + timestamp_pattern, pcre_erroffset, pcre_errbuf); + } + pcre_timestamp_extra = pcre_study(pcre_timestamp_code, 0, &pcre_errbuf); + if (pcre_errbuf != NULL) { + FatalError(SC_ERR_PCRE_STUDY, "Fail to study pcre: %s", pcre_errbuf); + } + /* conf params */ const char *filename = NULL; @@ -894,7 +1167,8 @@ static void PcapLogFileDeInitCtx(OutputCtx *output_ctx) TAILQ_FOREACH(pf, &pl->pcap_file_list, next) { SCLogDebug("PCAP files left at exit: %s\n", pf->filename); } - + PcapLogDataFree(pl); + SCFree(output_ctx); return; } diff --git a/src/log-pcap.h b/src/log-pcap.h index 0c6e7011bade..8b68d4332929 100644 --- a/src/log-pcap.h +++ b/src/log-pcap.h @@ -28,7 +28,7 @@ #ifndef __LOG_PCAP_H__ #define __LOG_PCAP_H__ -void TmModulePcapLogRegister (void); +void PcapLogRegister(void); void PcapLogProfileSetup(void); #endif /* __LOG_PCAP_H__ */ diff --git a/src/log-stats.c b/src/log-stats.c new file mode 100644 index 000000000000..69fe82d2053c --- /dev/null +++ b/src/log-stats.c @@ -0,0 +1,291 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "log-stats.h" +#include "util-privs.h" +#include "util-buffer.h" + +#include "util-logopenfile.h" +#include "util-time.h" + +#define DEFAULT_LOG_FILENAME "stats.log" +#define MODULE_NAME "LogStatsLog" +#define OUTPUT_BUFFER_SIZE 16384 + +#define LOG_STATS_TOTALS (1<<0) +#define LOG_STATS_THREADS (1<<1) +#define LOG_STATS_NULLS (1<<2) + +TmEcode LogStatsLogThreadInit(ThreadVars *, void *, void **); +TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *); +static void LogStatsLogDeInitCtx(OutputCtx *); + +typedef struct LogStatsFileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ +} LogStatsFileCtx; + +typedef struct LogStatsLogThread_ { + LogStatsFileCtx *statslog_ctx; + MemBuffer *buffer; +} LogStatsLogThread; + +int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +{ + SCEnter(); + LogStatsLogThread *aft = (LogStatsLogThread *)thread_data; + + struct timeval tval; + struct tm *tms; + + gettimeofday(&tval, NULL); + struct tm local_tm; + tms = SCLocalTime(tval.tv_sec, &local_tm); + + /* Calculate the Engine uptime */ + int up_time = (int)difftime(tval.tv_sec, st->start_time); + int sec = up_time % 60; // Seconds in a minute + int in_min = up_time / 60; + int min = in_min % 60; // Minutes in a hour + int in_hours = in_min / 60; + int hours = in_hours % 24; // Hours in a day + int days = in_hours / 24; + + MemBufferWriteString(aft->buffer, "----------------------------------------------" + "--------------------------------------\n"); + MemBufferWriteString(aft->buffer, "Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n", + tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour, + tms->tm_min, tms->tm_sec, days, hours, min, sec); + MemBufferWriteString(aft->buffer, "----------------------------------------------" + "--------------------------------------\n"); + MemBufferWriteString(aft->buffer, "%-42s | %-25s | %-s\n", "Counter", "TM Name", + "Value"); + MemBufferWriteString(aft->buffer, "----------------------------------------------" + "--------------------------------------\n"); + + /* global stats */ + uint32_t u = 0; + if (aft->statslog_ctx->flags & LOG_STATS_TOTALS) { + for (u = 0; u < st->nstats; u++) { + if (st->stats[u].name == NULL) + continue; + + if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->stats[u].value == 0) + continue; + + char line[256]; + size_t len = snprintf(line, sizeof(line), "%-42s | %-25s | %-" PRIu64 "\n", + st->stats[u].name, st->stats[u].tm_name, st->stats[u].value); + + /* since we can have many threads, the buffer might not be big enough. + * Expand if necessary. */ + if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) { + MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); + } + + MemBufferWriteString(aft->buffer, "%s", line); + } + } + + /* per thread stats */ + if (st->tstats != NULL && aft->statslog_ctx->flags & LOG_STATS_THREADS) { + /* for each thread (store) */ + uint32_t x; + for (x = 0; x < st->ntstats; x++) { + uint32_t offset = x * st->nstats; + + /* for each counter */ + for (u = offset; u < (offset + st->nstats); u++) { + if (st->tstats[u].name == NULL) + continue; + + if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->tstats[u].value == 0) + continue; + + char line[256]; + size_t len = snprintf(line, sizeof(line), "%-42s | %-25s | %-" PRIu64 "\n", + st->tstats[u].name, st->tstats[u].tm_name, st->tstats[u].value); + + /* since we can have many threads, the buffer might not be big enough. + * Expand if necessary. */ + if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) { + MemBufferExpand(&aft->buffer, OUTPUT_BUFFER_SIZE); + } + + MemBufferWriteString(aft->buffer, "%s", line); + } + } + } + + aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), + MEMBUFFER_OFFSET(aft->buffer), aft->statslog_ctx->file_ctx); + + MemBufferReset(aft->buffer); + + SCReturnInt(0); +} + +TmEcode LogStatsLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogStatsLogThread *aft = SCMalloc(sizeof(LogStatsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(LogStatsLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for LogStats. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Ouptut Context (file pointer and mutex) */ + aft->statslog_ctx= ((OutputCtx *)initdata)->data; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +TmEcode LogStatsLogThreadDeinit(ThreadVars *t, void *data) +{ + LogStatsLogThread *aft = (LogStatsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + /* clear memory */ + memset(aft, 0, sizeof(LogStatsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +/** \brief Create a new http log LogFileCtx. + * \param conf Pointer to ConfNode containing this loggers configuration. + * \return NULL if failure, LogFileCtx* to the file_ctx if succesful + * */ +OutputCtx *LogStatsLogInitCtx(ConfNode *conf) +{ + LogFileCtx *file_ctx = LogFileNewCtx(); + if (file_ctx == NULL) { + SCLogError(SC_ERR_STATS_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + LogStatsFileCtx *statslog_ctx = SCMalloc(sizeof(LogStatsFileCtx)); + if (unlikely(statslog_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return NULL; + } + memset(statslog_ctx, 0x00, sizeof(LogStatsFileCtx)); + + statslog_ctx->flags = LOG_STATS_TOTALS; + + if (conf != NULL) { + const char *totals = ConfNodeLookupChildValue(conf, "totals"); + const char *threads = ConfNodeLookupChildValue(conf, "threads"); + const char *nulls = ConfNodeLookupChildValue(conf, "null-values"); + SCLogDebug("totals %s threads %s", totals, threads); + + if ((totals != NULL && ConfValIsFalse(totals)) && + (threads != NULL && ConfValIsFalse(threads))) { + LogFileFreeCtx(file_ctx); + SCFree(statslog_ctx); + SCLogError(SC_ERR_STATS_LOG_NEGATED, + "Cannot disable both totals and threads in stats logging"); + return NULL; + } + + if (totals != NULL && ConfValIsFalse(totals)) { + statslog_ctx->flags &= ~LOG_STATS_TOTALS; + } + if (threads != NULL && ConfValIsTrue(threads)) { + statslog_ctx->flags |= LOG_STATS_THREADS; + } + if (nulls != NULL && ConfValIsTrue(nulls)) { + statslog_ctx->flags |= LOG_STATS_NULLS; + } + SCLogDebug("statslog_ctx->flags %08x", statslog_ctx->flags); + } + + statslog_ctx->file_ctx = file_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + SCFree(statslog_ctx); + return NULL; + } + + output_ctx->data = statslog_ctx; + output_ctx->DeInit = LogStatsLogDeInitCtx; + + SCLogDebug("STATS log output initialized"); + + return output_ctx; +} + +static void LogStatsLogDeInitCtx(OutputCtx *output_ctx) +{ + LogStatsFileCtx *statslog_ctx = (LogStatsFileCtx *)output_ctx->data; + LogFileFreeCtx(statslog_ctx->file_ctx); + SCFree(statslog_ctx); + SCFree(output_ctx); +} + +void LogStatsLogRegister (void) +{ + OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", + LogStatsLogInitCtx, LogStatsLogger, LogStatsLogThreadInit, + LogStatsLogThreadDeinit, NULL); +} diff --git a/src/log-stats.h b/src/log-stats.h new file mode 100644 index 000000000000..f7f536c6ddb0 --- /dev/null +++ b/src/log-stats.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __LOG_STATS_H__ +#define __LOG_STATS_H__ + +void LogStatsLogRegister(void); + +#endif /* __LOG_HTTPLOG_H__ */ diff --git a/src/log-tcp-data.c b/src/log-tcp-data.c index 2133f9de4a01..c2faa046ee26 100644 --- a/src/log-tcp-data.c +++ b/src/log-tcp-data.c @@ -55,24 +55,17 @@ TmEcode LogTcpDataLogThreadInit(ThreadVars *, void *, void **); TmEcode LogTcpDataLogThreadDeinit(ThreadVars *, void *); -void LogTcpDataLogExitPrintStats(ThreadVars *, void *); static void LogTcpDataLogDeInitCtx(OutputCtx *); int LogTcpDataLogger(ThreadVars *tv, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); -void TmModuleLogTcpDataLogRegister (void) { - tmm_modules[TMM_LOGTCPDATALOG].name = MODULE_NAME; - tmm_modules[TMM_LOGTCPDATALOG].ThreadInit = LogTcpDataLogThreadInit; - tmm_modules[TMM_LOGTCPDATALOG].ThreadExitPrintStats = LogTcpDataLogExitPrintStats; - tmm_modules[TMM_LOGTCPDATALOG].ThreadDeinit = LogTcpDataLogThreadDeinit; - tmm_modules[TMM_LOGTCPDATALOG].RegisterTests = NULL; - tmm_modules[TMM_LOGTCPDATALOG].cap_flags = 0; - tmm_modules[TMM_LOGTCPDATALOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterStreamingModule(MODULE_NAME, "tcp-data", LogTcpDataLogInitCtx, - LogTcpDataLogger, STREAMING_TCP_DATA); - OutputRegisterStreamingModule(MODULE_NAME, "http-body-data", LogTcpDataLogInitCtx, - LogTcpDataLogger, STREAMING_HTTP_BODIES); +void LogTcpDataLogRegister (void) { + OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "tcp-data", + LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_TCP_DATA, + LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, NULL); + OutputRegisterStreamingModule(LOGGER_TCP_DATA, MODULE_NAME, "http-body-data", + LogTcpDataLogInitCtx, LogTcpDataLogger, STREAMING_HTTP_BODIES, + LogTcpDataLogThreadInit, LogTcpDataLogThreadDeinit, NULL); } typedef struct LogTcpDataFileCtx_ { @@ -112,9 +105,10 @@ static int LogTcpDataLoggerDir(ThreadVars *tv, void *thread_data, const Flow *f, char name[PATH_MAX]; - char tx[64] = ""; - if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) + char tx[64] = { 0 }; + if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) { snprintf(tx, sizeof(tx), "%"PRIu64, tx_id); + } snprintf(name, sizeof(name), "%s/%s/%s_%u-%s_%u-%s-%s.data", td->log_dir, @@ -164,10 +158,8 @@ static int LogTcpDataLoggerFile(ThreadVars *tv, void *thread_data, const Flow *f PrintRawDataToBuffer(aft->buffer->buffer, &aft->buffer->offset, aft->buffer->size, (uint8_t *)data,data_len); - SCMutexLock(&td->file_ctx->fp_mutex); td->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), td->file_ctx); - SCMutexUnlock(&td->file_ctx->fp_mutex); } SCReturnInt(TM_ECODE_OK); } @@ -229,13 +221,6 @@ TmEcode LogTcpDataLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void LogTcpDataLogExitPrintStats(ThreadVars *tv, void *data) { - LogTcpDataLogThread *aft = (LogTcpDataLogThread *)data; - if (aft == NULL) { - return; - } -} - /** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful @@ -248,7 +233,7 @@ OutputCtx *LogTcpDataLogInitCtx(ConfNode *conf) LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_TCPDATA_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } @@ -293,7 +278,7 @@ OutputCtx *LogTcpDataLogInitCtx(ConfNode *conf) if (tcpdatalog_ctx->file == 1) { SCLogInfo("opening logfile"); - if (SCConfLogOpenGeneric(conf, file_ctx, filename) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, filename, 1) < 0) { LogFileFreeCtx(file_ctx); SCFree(tcpdatalog_ctx); return NULL; diff --git a/src/log-tcp-data.h b/src/log-tcp-data.h index 5123c3b2dda5..fcfe19442b59 100644 --- a/src/log-tcp-data.h +++ b/src/log-tcp-data.h @@ -24,7 +24,7 @@ #ifndef __LOG_TCPDATALOG_H__ #define __LOG_TCPDATALOG_H__ -void TmModuleLogTcpDataLogRegister (void); +void LogTcpDataLogRegister(void); OutputCtx *LogTcpDataLogInitCtx(ConfNode *); #endif /* __LOG_TCPDATALOG_H__ */ diff --git a/src/log-tlslog.c b/src/log-tlslog.c index 580b0a20226c..97158b9daf12 100644 --- a/src/log-tlslog.c +++ b/src/log-tlslog.c @@ -21,6 +21,7 @@ * \author Roliers Jean-Paul * \author Eric Leblond * \author Victor Julien + * \author Paulo Pacheco * * Implements TLS logging portion of the engine. The TLS logger is * implemented as a packet logger, as the TLS parser is not transaction @@ -53,12 +54,10 @@ #include "util-logopenfile.h" #include "util-crypt.h" #include "util-time.h" +#include "log-cf-common.h" #define DEFAULT_LOG_FILENAME "tls.log" -static char tls_logfile_base_dir[PATH_MAX] = "/tmp"; -SC_ATOMIC_DECLARE(unsigned int, cert_id); - #define MODULE_NAME "LogTlsLog" #define OUTPUT_BUFFER_SIZE 65535 @@ -66,10 +65,21 @@ SC_ATOMIC_DECLARE(unsigned int, cert_id); #define LOG_TLS_DEFAULT 0 #define LOG_TLS_EXTENDED 1 +#define LOG_TLS_CUSTOM 2 + +#define LOG_TLS_CF_VERSION 'v' +#define LOG_TLS_CF_DATE_NOT_BEFORE 'd' +#define LOG_TLS_CF_DATE_NOT_AFTER 'D' +#define LOG_TLS_CF_SHA1 'f' +#define LOG_TLS_CF_SNI 'n' +#define LOG_TLS_CF_SUBJECT 's' +#define LOG_TLS_CF_ISSUER 'i' +#define LOG_TLS_CF_EXTENDED 'E' typedef struct LogTlsFileCtx_ { LogFileCtx *file_ctx; uint32_t flags; /** Store mode */ + LogCustomFormat *cf; } LogTlsFileCtx; typedef struct LogTlsLogThread_ { @@ -79,43 +89,79 @@ typedef struct LogTlsLogThread_ { uint32_t tls_cnt; MemBuffer *buffer; - uint8_t* enc_buf; - size_t enc_buf_len; } LogTlsLogThread; -static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) +static void LogTlsLogVersion(MemBuffer *buffer, uint16_t version) { - if (state->server_connp.cert0_fingerprint != NULL) { - MemBufferWriteString(aft->buffer, " SHA1='%s'", state->server_connp.cert0_fingerprint); - } - switch (state->server_connp.version) { + switch (version) { case TLS_VERSION_UNKNOWN: - MemBufferWriteString(aft->buffer, " VERSION='UNDETERMINED'"); + MemBufferWriteString(buffer, "VERSION='UNDETERMINED'"); break; case SSL_VERSION_2: - MemBufferWriteString(aft->buffer, " VERSION='SSLv2'"); + MemBufferWriteString(buffer, "VERSION='SSLv2'"); break; case SSL_VERSION_3: - MemBufferWriteString(aft->buffer, " VERSION='SSLv3'"); + MemBufferWriteString(buffer, "VERSION='SSLv3'"); break; case TLS_VERSION_10: - MemBufferWriteString(aft->buffer, " VERSION='TLSv1'"); + MemBufferWriteString(buffer, "VERSION='TLSv1'"); break; case TLS_VERSION_11: - MemBufferWriteString(aft->buffer, " VERSION='TLS 1.1'"); + MemBufferWriteString(buffer, "VERSION='TLS 1.1'"); break; case TLS_VERSION_12: - MemBufferWriteString(aft->buffer, " VERSION='TLS 1.2'"); + MemBufferWriteString(buffer, "VERSION='TLS 1.2'"); break; default: - MemBufferWriteString(aft->buffer, " VERSION='0x%04x'", - state->server_connp.version); + MemBufferWriteString(buffer, "VERSION='0x%04x'", version); break; } - MemBufferWriteString(aft->buffer, "\n"); } -static int GetIPInformations(const Packet *p, char* srcip, size_t srcip_len, +static void LogTlsLogDate(MemBuffer *buffer, const char *title, time_t *date) +{ + char timebuf[64] = {0}; + struct timeval tv; + tv.tv_sec = *date; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + MemBufferWriteString(buffer, "%s='%s'", title, timebuf); +} + +static void LogTlsLogString(MemBuffer *buffer, const char *title, const char *value) +{ + MemBufferWriteString(buffer, "%s='%s'", title, value); +} + +static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state) +{ + if (state->server_connp.cert0_fingerprint != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SHA1", state->server_connp.cert0_fingerprint); + } + if (state->client_connp.sni != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SNI", state->client_connp.sni); + } + if (state->server_connp.cert0_serial != NULL) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogString(aft->buffer, "SERIAL", state->server_connp.cert0_serial); + } + + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogVersion(aft->buffer, state->server_connp.version); + + if (state->server_connp.cert0_not_before != 0) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogDate(aft->buffer, "NOTBEFORE", &state->server_connp.cert0_not_before); + } + if (state->server_connp.cert0_not_after != 0) { + LOG_CF_WRITE_SPACE_SEPARATOR(aft->buffer); + LogTlsLogDate(aft->buffer, "NOTAFTER", &state->server_connp.cert0_not_after); + } +} + +int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, Port* sp, char* dstip, size_t dstip_len, Port* dp, int ipproto) { @@ -153,162 +199,6 @@ static int GetIPInformations(const Packet *p, char* srcip, size_t srcip_len, return 1; } -static int CreateFileName(LogTlsFileCtx *log, const Packet *p, SSLState *state, char *filename) -{ -#define FILELEN 64 //filename len + extention + ending path / + some space - - int filenamelen = FILELEN + strlen(tls_logfile_base_dir); - int file_id = SC_ATOMIC_ADD(cert_id, 1); - - if (filenamelen + 1 > PATH_MAX) { - return 0; - } - - /* Use format : packet time + incremental ID - * When running on same pcap it will overwrite - * On a live device, we will not be able to overwrite */ - snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem", - tls_logfile_base_dir, - (long int)p->ts.tv_sec, - (long int)p->ts.tv_usec, - file_id); - return 1; -} - -static void LogTlsLogPem(LogTlsLogThread *aft, const Packet *p, SSLState *state, LogTlsFileCtx *log, int ipproto) -{ -#define PEMHEADER "-----BEGIN CERTIFICATE-----\n" -#define PEMFOOTER "-----END CERTIFICATE-----\n" - //Logging pem certificate - char filename[PATH_MAX] = ""; - FILE* fp = NULL; - FILE* fpmeta = NULL; - unsigned long pemlen; - unsigned char* pembase64ptr = NULL; - int ret; - uint8_t *ptmp; - SSLCertsChain *cert; - - if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0)) - SCReturn; - - CreateFileName(log, p, state, filename); - if (strlen(filename) == 0) { - SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename"); - SCReturn; - } - - fp = fopen(filename, "w"); - if (fp == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename); - SCReturn; - } - - TAILQ_FOREACH(cert, &state->server_connp.certs, next) { - pemlen = (4 * (cert->cert_len + 2) / 3) +1; - if (pemlen > aft->enc_buf_len) { - ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); - if (ptmp == NULL) { - SCFree(aft->enc_buf); - aft->enc_buf = NULL; - SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding"); - goto end_fp; - } - aft->enc_buf = ptmp; - aft->enc_buf_len = pemlen; - } - - memset(aft->enc_buf, 0, aft->enc_buf_len); - - ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); - if (ret != SC_BASE64_OK) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function"); - goto end_fwrite_fp; - } - - if (fprintf(fp, PEMHEADER) < 0) - goto end_fwrite_fp; - - pembase64ptr = aft->enc_buf; - while (pemlen > 0) { - size_t loffset = pemlen >= 64 ? 64 : pemlen; - if (fwrite(pembase64ptr, 1, loffset, fp) != loffset) - goto end_fwrite_fp; - if (fwrite("\n", 1, 1, fp) != 1) - goto end_fwrite_fp; - pembase64ptr += 64; - if (pemlen < 64) - break; - pemlen -= 64; - } - - if (fprintf(fp, PEMFOOTER) < 0) - goto end_fwrite_fp; - } - fclose(fp); - - //Logging certificate informations - memcpy(filename + (strlen(filename) - 3), "meta", 4); - fpmeta = fopen(filename, "w"); - if (fpmeta != NULL) { - #define PRINT_BUF_LEN 46 - char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; - char timebuf[64]; - Port sp, dp; - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); - if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "TIME: %s\n", timebuf) < 0) - goto end_fwrite_fpmeta; - if (p->pcap_cnt > 0) { - if (fprintf(fpmeta, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt) < 0) - goto end_fwrite_fpmeta; - } - if (fprintf(fpmeta, "SRC IP: %s\n", srcip) < 0) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "DST IP: %s\n", dstip) < 0) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "PROTO: %" PRIu32 "\n", p->proto) < 0) - goto end_fwrite_fpmeta; - if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { - if (fprintf(fpmeta, "SRC PORT: %" PRIu16 "\n", sp) < 0) - goto end_fwrite_fpmeta; - if (fprintf(fpmeta, "DST PORT: %" PRIu16 "\n", dp) < 0) - goto end_fwrite_fpmeta; - } - - if (fprintf(fpmeta, "TLS SUBJECT: %s\n" - "TLS ISSUERDN: %s\n" - "TLS FINGERPRINT: %s\n", - state->server_connp.cert0_subject, - state->server_connp.cert0_issuerdn, - state->server_connp.cert0_fingerprint) < 0) - goto end_fwrite_fpmeta; - - fclose(fpmeta); - } else { - SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s", - filename); - SCReturn; - } - - /* Reset the store flag */ - state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM; - SCReturn; - -end_fwrite_fp: - fclose(fp); - SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); -end_fwrite_fpmeta: - if (fpmeta) { - fclose(fpmeta); - SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); - } - SCReturn; -end_fp: - fclose(fp); -} - static TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) { LogTlsLogThread *aft = SCMalloc(sizeof(LogTlsLogThread)); @@ -322,39 +212,12 @@ static TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) return TM_ECODE_FAILED; } - struct stat stat_buf; - if (stat(tls_logfile_base_dir, &stat_buf) != 0) { - int ret; - ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); - if (ret != 0) { - int err = errno; - if (err != EEXIST) { - SCLogError(SC_ERR_LOGDIR_CONFIG, - "Cannot create certs drop directory %s: %s", - tls_logfile_base_dir, strerror(err)); - exit(EXIT_FAILURE); - } - } else { - SCLogInfo("Created certs drop directory %s", - tls_logfile_base_dir); - } - - } - aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); if (aft->buffer == NULL) { SCFree(aft); return TM_ECODE_FAILED; } - aft->enc_buf = SCMalloc(CERT_ENC_BUFFER_SIZE); - if (aft->enc_buf == NULL) { - SCFree(aft); - return TM_ECODE_FAILED; - } - aft->enc_buf_len = CERT_ENC_BUFFER_SIZE; - memset(aft->enc_buf, 0, aft->enc_buf_len); - /* Use the Ouptut Context (file pointer and mutex) */ aft->tlslog_ctx = ((OutputCtx *) initdata)->data; @@ -379,11 +242,9 @@ static TmEcode LogTlsLogThreadDeinit(ThreadVars *t, void *data) static void LogTlsLogDeInitCtx(OutputCtx *output_ctx) { - OutputTlsLoggerDisable(); - LogTlsFileCtx *tlslog_ctx = (LogTlsFileCtx *) output_ctx->data; - OutputUnregisterFileRotationFlag(&tlslog_ctx->file_ctx->rotation_flag); LogFileFreeCtx(tlslog_ctx->file_ctx); + LogCustomFormatFree(tlslog_ctx->cf); SCFree(tlslog_ctx); SCFree(output_ctx); } @@ -404,12 +265,6 @@ static void LogTlsLogExitPrintStats(ThreadVars *tv, void *data) * */ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) { - if (OutputTlsLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " - "can be enabled"); - return NULL; - } - LogFileCtx* file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { @@ -418,28 +273,9 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) return NULL; } - char *s_default_log_dir = NULL; - s_default_log_dir = ConfigGetLogDirectory(); - - const char *s_base_dir = NULL; - s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir"); - if (s_base_dir == NULL || strlen(s_base_dir) == 0) { - strlcpy(tls_logfile_base_dir, - s_default_log_dir, sizeof(tls_logfile_base_dir)); - } else { - if (PathIsAbsolute(s_base_dir)) { - strlcpy(tls_logfile_base_dir, - s_base_dir, sizeof(tls_logfile_base_dir)); - } else { - snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), - "%s/%s", s_default_log_dir, s_base_dir); - } - } - - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { goto filectx_error; } - OutputRegisterFileRotationFlag(&file_ctx->rotation_flag); LogTlsFileCtx *tlslog_ctx = SCCalloc(1, sizeof(LogTlsFileCtx)); if (unlikely(tlslog_ctx == NULL)) @@ -447,11 +283,28 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) tlslog_ctx->file_ctx = file_ctx; const char *extended = ConfNodeLookupChildValue(conf, "extended"); - if (extended == NULL) { - tlslog_ctx->flags |= LOG_TLS_DEFAULT; + const char *custom = ConfNodeLookupChildValue(conf, "custom"); + const char *customformat = ConfNodeLookupChildValue(conf, "customformat"); + + /* If custom logging format is selected, lets parse it */ + if (custom != NULL && customformat != NULL && ConfValIsTrue(custom)) { + tlslog_ctx->cf = LogCustomFormatAlloc(); + if (!tlslog_ctx->cf) { + goto tlslog_error; + } + + tlslog_ctx->flags |= LOG_TLS_CUSTOM; + /* Parsing */ + if ( ! LogCustomFormatParse(tlslog_ctx->cf, customformat)) { + goto parser_error; + } } else { - if (ConfValIsTrue(extended)) { - tlslog_ctx->flags |= LOG_TLS_EXTENDED; + if (extended == NULL) { + tlslog_ctx->flags |= LOG_TLS_DEFAULT; + } else { + if (ConfValIsTrue(extended)) { + tlslog_ctx->flags |= LOG_TLS_EXTENDED; + } } } @@ -467,141 +320,178 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf) AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); return output_ctx; - +parser_error: + SCLogError(SC_ERR_INVALID_ARGUMENT,"Syntax error in custom tls log format string."); tlslog_error: + LogCustomFormatFree(tlslog_ctx->cf); SCFree(tlslog_ctx); filectx_error: LogFileFreeCtx(file_ctx); return NULL; } -/** \internal - * \brief Condition function for TLS logger - * \retval bool true or false -- log now? - */ -static int LogTlsCondition(ThreadVars *tv, const Packet *p) +/* Custom format logging */ +static void LogTlsLogCustom(LogTlsLogThread *aft, SSLState *ssl_state, const struct timeval *ts, + char *srcip, Port sp, char *dstip, Port dp) { - if (p->flow == NULL) { - return FALSE; - } + LogTlsFileCtx *tlslog_ctx = aft->tlslog_ctx; + uint32_t i; + char buf[6]; - if (!(PKT_IS_TCP(p))) { - return FALSE; - } + for (i = 0; i < tlslog_ctx->cf->cf_n; i++) { - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto dontlog; + LogCustomFormatNode * node = tlslog_ctx->cf->cf_nodes[i]; + if (! node) /* Should never happen */ + continue; - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, so no request logging"); - goto dontlog; + switch (node->type){ + case LOG_CF_LITERAL: + /* LITERAL */ + MemBufferWriteString(aft->buffer, "%s", node->data); + break; + case LOG_CF_TIMESTAMP: + /* TIMESTAMP */ + LogCustomFormatWriteTimestamp(aft->buffer, node->data, ts); + break; + case LOG_CF_TIMESTAMP_U: + /* TIMESTAMP USECONDS */ + snprintf(buf, 6, "%06u", (unsigned int) ts->tv_usec); + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)buf,strlen(buf)); + break; + case LOG_CF_CLIENT_IP: + /* CLIENT IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)srcip,strlen(srcip)); + break; + case LOG_CF_SERVER_IP: + /* SERVER IP ADDRESS */ + PrintRawUriBuf((char *)aft->buffer->buffer, &aft->buffer->offset, + aft->buffer->size, (uint8_t *)dstip,strlen(dstip)); + break; + case LOG_CF_CLIENT_PORT: + /* CLIENT PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", sp); + break; + case LOG_CF_SERVER_PORT: + /* SERVER PORT */ + MemBufferWriteString(aft->buffer, "%" PRIu16 "", dp); + break; + case LOG_TLS_CF_VERSION: + LogTlsLogVersion(aft->buffer, ssl_state->server_connp.version); + break; + case LOG_TLS_CF_DATE_NOT_BEFORE: + LogTlsLogDate(aft->buffer, "NOTBEFORE", &ssl_state->server_connp.cert0_not_before); + break; + case LOG_TLS_CF_DATE_NOT_AFTER: + LogTlsLogDate(aft->buffer, "NOTAFTER", &ssl_state->server_connp.cert0_not_after); + break; + case LOG_TLS_CF_SHA1: + if (ssl_state->server_connp.cert0_fingerprint != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->server_connp.cert0_fingerprint); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_SNI: + if (ssl_state->client_connp.sni != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->client_connp.sni); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_SUBJECT: + if (ssl_state->server_connp.cert0_subject != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->server_connp.cert0_subject); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_ISSUER: + if (ssl_state->server_connp.cert0_issuerdn != NULL) { + MemBufferWriteString(aft->buffer, "%s", + ssl_state->server_connp.cert0_issuerdn); + } else { + LOG_CF_WRITE_UNKNOWN_VALUE(aft->buffer); + } + break; + case LOG_TLS_CF_EXTENDED: + /* Extended format */ + LogTlsLogExtended(aft, ssl_state); + break; + default: + /* NO MATCH */ + MemBufferWriteString(aft->buffer, LOG_CF_NONE); + SCLogDebug("No matching parameter %%%c for custom tls log.", node->type); + break; + } } - - /* we only log the state once if we don't have to write - * the cert due to tls.store keyword. */ - if (!(ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) && - (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED)) - goto dontlog; - - if (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) - goto dontlog; - - /* todo: logic to log once */ - - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; + MemBufferWriteString(aft->buffer, "\n"); } -static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) + +static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) { LogTlsLogThread *aft = (LogTlsLogThread *)thread_data; LogTlsFileCtx *hlog = aft->tlslog_ctx; char timebuf[64]; int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; - if (unlikely(p->flow == NULL)) { - return 0; - } - - /* check if we have TLS state or not */ - FLOWLOCK_WRLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto end; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + SSLState *ssl_state = (SSLState *)state; if (unlikely(ssl_state == NULL)) { - goto end; + return 0; } - if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) - goto end; - - if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) { - LogTlsLogPem(aft, p, ssl_state, hlog, ipproto); + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) { + return 0; } - /* Don't log again the state. If we are here it was because we had - * to store the cert. */ - if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED) - goto end; - - CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); #define PRINT_BUF_LEN 46 char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; Port sp, dp; - if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, - &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) { - goto end; + if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, + PRINT_BUF_LEN, &dp, ipproto)) { + return 0; } - MemBufferReset(aft->buffer); - MemBufferWriteString(aft->buffer, - "%s %s:%d -> %s:%d TLS: Subject='%s' Issuerdn='%s'", - timebuf, srcip, sp, dstip, dp, - ssl_state->server_connp.cert0_subject, - ssl_state->server_connp.cert0_issuerdn); - - if (hlog->flags & LOG_TLS_EXTENDED) { - LogTlsLogExtended(aft, ssl_state); + /* Custom format */ + if (hlog->flags & LOG_TLS_CUSTOM) { + LogTlsLogCustom(aft, ssl_state, &p->ts, srcip, sp, dstip, dp); } else { - MemBufferWriteString(aft->buffer, "\n"); + + MemBufferReset(aft->buffer); + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + MemBufferWriteString(aft->buffer, + "%s %s:%d -> %s:%d TLS: Subject='%s' Issuerdn='%s'", + timebuf, srcip, sp, dstip, dp, + ssl_state->server_connp.cert0_subject, + ssl_state->server_connp.cert0_issuerdn); + + if (hlog->flags & LOG_TLS_EXTENDED) { + LogTlsLogExtended(aft, ssl_state); + MemBufferWriteString(aft->buffer, "\n"); + } else { + MemBufferWriteString(aft->buffer, "\n"); + } } aft->tls_cnt++; - SCMutexLock(&hlog->file_ctx->fp_mutex); hlog->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer), MEMBUFFER_OFFSET(aft->buffer), hlog->file_ctx); - SCMutexUnlock(&hlog->file_ctx->fp_mutex); - /* we only log the state once */ - ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED; -end: - FLOWLOCK_UNLOCK(p->flow); return 0; } -void TmModuleLogTlsLogRegister(void) +void LogTlsLogRegister(void) { - tmm_modules[TMM_LOGTLSLOG].name = MODULE_NAME; - tmm_modules[TMM_LOGTLSLOG].ThreadInit = LogTlsLogThreadInit; - tmm_modules[TMM_LOGTLSLOG].Func = NULL; - tmm_modules[TMM_LOGTLSLOG].ThreadExitPrintStats = LogTlsLogExitPrintStats; - tmm_modules[TMM_LOGTLSLOG].ThreadDeinit = LogTlsLogThreadDeinit; - tmm_modules[TMM_LOGTLSLOG].RegisterTests = NULL; - tmm_modules[TMM_LOGTLSLOG].cap_flags = 0; - tmm_modules[TMM_LOGTLSLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "tls-log", LogTlsLogInitCtx, - LogTlsLogger, LogTlsCondition); - - SC_ATOMIC_INIT(cert_id); + OutputRegisterTxModuleWithProgress(LOGGER_TLS, MODULE_NAME, "tls-log", + LogTlsLogInitCtx, ALPROTO_TLS, LogTlsLogger, TLS_HANDSHAKE_DONE, + TLS_HANDSHAKE_DONE, LogTlsLogThreadInit, LogTlsLogThreadDeinit, + LogTlsLogExitPrintStats); } diff --git a/src/log-tlslog.h b/src/log-tlslog.h index f339d5d81fb2..87c2fbcf5db7 100644 --- a/src/log-tlslog.h +++ b/src/log-tlslog.h @@ -25,7 +25,11 @@ #ifndef __LOG_TLSLOG_H__ #define __LOG_TLSLOG_H__ -void TmModuleLogTlsLogRegister (void); +void LogTlsLogRegister(void); + +int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len, + Port* sp, char* dstip, size_t dstip_len, + Port* dp, int ipproto); #endif /* __LOG_TLSLOG_H__ */ diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c new file mode 100644 index 000000000000..861a2da69aef --- /dev/null +++ b/src/log-tlsstore.c @@ -0,0 +1,422 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Roliers Jean-Paul + * \author Eric Leblond + * \author Victor Julien + * + * Implements TLS store portion of the engine. + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "log-tlslog.h" +#include "app-layer-ssl.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util-privs.h" +#include "util-buffer.h" + +#include "util-logopenfile.h" +#include "util-crypt.h" +#include "util-time.h" + +#define MODULE_NAME "LogTlsStoreLog" + +static char tls_logfile_base_dir[PATH_MAX] = "/tmp"; +SC_ATOMIC_DECLARE(unsigned int, cert_id); +static char logging_dir_not_writable; + +#define LOGGING_WRITE_ISSUE_LIMIT 6 + +typedef struct LogTlsStoreLogThread_ { + uint32_t tls_cnt; + + uint8_t* enc_buf; + size_t enc_buf_len; +} LogTlsStoreLogThread; + +static int CreateFileName(const Packet *p, SSLState *state, char *filename) +{ +#define FILELEN 64 //filename len + extention + ending path / + some space + + int filenamelen = FILELEN + strlen(tls_logfile_base_dir); + int file_id = SC_ATOMIC_ADD(cert_id, 1); + + if (filenamelen + 1 > PATH_MAX) { + return 0; + } + + /* Use format : packet time + incremental ID + * When running on same pcap it will overwrite + * On a live device, we will not be able to overwrite */ + snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem", + tls_logfile_base_dir, + (long int)p->ts.tv_sec, + (long int)p->ts.tv_usec, + file_id); + return 1; +} + +static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *state, int ipproto) +{ +#define PEMHEADER "-----BEGIN CERTIFICATE-----\n" +#define PEMFOOTER "-----END CERTIFICATE-----\n" + //Logging pem certificate + char filename[PATH_MAX] = ""; + FILE* fp = NULL; + FILE* fpmeta = NULL; + unsigned long pemlen; + unsigned char* pembase64ptr = NULL; + int ret; + uint8_t *ptmp; + SSLCertsChain *cert; + + if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0)) + SCReturn; + + CreateFileName(p, state, filename); + if (strlen(filename) == 0) { + SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename"); + SCReturn; + } + + fp = fopen(filename, "w"); + if (fp == NULL) { + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FOPEN, + "Can't create PEM file '%s' in '%s' directory", + filename, tls_logfile_base_dir); + logging_dir_not_writable++; + } + SCReturn; + } + + TAILQ_FOREACH(cert, &state->server_connp.certs, next) { + pemlen = (4 * (cert->cert_len + 2) / 3) +1; + if (pemlen > aft->enc_buf_len) { + ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen); + if (ptmp == NULL) { + SCFree(aft->enc_buf); + aft->enc_buf = NULL; + SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding"); + goto end_fp; + } + aft->enc_buf = ptmp; + aft->enc_buf_len = pemlen; + } + + memset(aft->enc_buf, 0, aft->enc_buf_len); + + ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen); + if (ret != SC_BASE64_OK) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function"); + goto end_fwrite_fp; + } + + if (fprintf(fp, PEMHEADER) < 0) + goto end_fwrite_fp; + + pembase64ptr = aft->enc_buf; + while (pemlen > 0) { + size_t loffset = pemlen >= 64 ? 64 : pemlen; + if (fwrite(pembase64ptr, 1, loffset, fp) != loffset) + goto end_fwrite_fp; + if (fwrite("\n", 1, 1, fp) != 1) + goto end_fwrite_fp; + pembase64ptr += 64; + if (pemlen < 64) + break; + pemlen -= 64; + } + + if (fprintf(fp, PEMFOOTER) < 0) + goto end_fwrite_fp; + } + fclose(fp); + + //Logging certificate informations + memcpy(filename + (strlen(filename) - 3), "meta", 4); + fpmeta = fopen(filename, "w"); + if (fpmeta != NULL) { + #define PRINT_BUF_LEN 46 + char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN]; + char timebuf[64]; + Port sp, dp; + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "TIME: %s\n", timebuf) < 0) + goto end_fwrite_fpmeta; + if (p->pcap_cnt > 0) { + if (fprintf(fpmeta, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt) < 0) + goto end_fwrite_fpmeta; + } + if (fprintf(fpmeta, "SRC IP: %s\n", srcip) < 0) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "DST IP: %s\n", dstip) < 0) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "PROTO: %" PRIu32 "\n", p->proto) < 0) + goto end_fwrite_fpmeta; + if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) { + if (fprintf(fpmeta, "SRC PORT: %" PRIu16 "\n", sp) < 0) + goto end_fwrite_fpmeta; + if (fprintf(fpmeta, "DST PORT: %" PRIu16 "\n", dp) < 0) + goto end_fwrite_fpmeta; + } + + if (fprintf(fpmeta, "TLS SUBJECT: %s\n" + "TLS ISSUERDN: %s\n" + "TLS FINGERPRINT: %s\n", + state->server_connp.cert0_subject, + state->server_connp.cert0_issuerdn, + state->server_connp.cert0_fingerprint) < 0) + goto end_fwrite_fpmeta; + + fclose(fpmeta); + } else { + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FOPEN, + "Can't create meta file '%s' in '%s' directory", + filename, tls_logfile_base_dir); + logging_dir_not_writable++; + } + SCReturn; + } + + /* Reset the store flag */ + state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM; + SCReturn; + +end_fwrite_fp: + fclose(fp); + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate"); + logging_dir_not_writable++; + } +end_fwrite_fpmeta: + if (fpmeta) { + fclose(fpmeta); + if (logging_dir_not_writable < LOGGING_WRITE_ISSUE_LIMIT) { + SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile"); + logging_dir_not_writable++; + } + } + SCReturn; +end_fp: + fclose(fp); + SCReturn; +} + +/** \internal + * \brief Condition function for TLS logger + * \retval bool true or false -- log now? + */ +static int LogTlsStoreCondition(ThreadVars *tv, const Packet *p, void *state, + void *tx, uint64_t tx_id) +{ + if (p->flow == NULL) { + return FALSE; + } + + if (!(PKT_IS_TCP(p))) { + return FALSE; + } + + SSLState *ssl_state = (SSLState *)state; + if (ssl_state == NULL) { + SCLogDebug("no tls state, so no request logging"); + goto dontlog; + } + + if ((ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) == 0) + goto dontlog; + + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) + goto dontlog; + + return TRUE; +dontlog: + return FALSE; +} + +static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *tx, uint64_t tx_id) +{ + LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)thread_data; + int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6; + + SSLState *ssl_state = (SSLState *)state; + if (unlikely(ssl_state == NULL)) { + return 0; + } + + if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) { + LogTlsLogPem(aft, p, ssl_state, ipproto); + } + + return 0; +} + +static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogTlsStoreLogThread *aft = SCMalloc(sizeof(LogTlsStoreLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(LogTlsStoreLogThread)); + + if (initdata == NULL) { + SCLogDebug("Error getting context for LogTLSStore. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + struct stat stat_buf; + /* coverity[toctou] */ + if (stat(tls_logfile_base_dir, &stat_buf) != 0) { + int ret; + /* coverity[toctou] */ + ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP); + if (ret != 0) { + int err = errno; + if (err != EEXIST) { + SCLogError(SC_ERR_LOGDIR_CONFIG, + "Cannot create certs drop directory %s: %s", + tls_logfile_base_dir, strerror(err)); + exit(EXIT_FAILURE); + } + } else { + SCLogInfo("Created certs drop directory %s", + tls_logfile_base_dir); + } + + } + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode LogTlsStoreLogThreadDeinit(ThreadVars *t, void *data) +{ + LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + if (aft->enc_buf != NULL) + SCFree(aft->enc_buf); + + /* clear memory */ + memset(aft, 0, sizeof(LogTlsStoreLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void LogTlsStoreLogExitPrintStats(ThreadVars *tv, void *data) +{ + LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)data; + if (aft == NULL) { + return; + } + + SCLogInfo("(%s) certificates extracted %" PRIu32 "", tv->name, aft->tls_cnt); +} + +/** + * \internal + * + * \brief deinit the log ctx and write out the waldo + * + * \param output_ctx output context to deinit + */ +static void LogTlsStoreLogDeInitCtx(OutputCtx *output_ctx) +{ + SCFree(output_ctx); +} + +/** \brief Create a new http log LogFilestoreCtx. + * \param conf Pointer to ConfNode containing this loggers configuration. + * \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful + * */ +static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf) +{ + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + + output_ctx->data = NULL; + output_ctx->DeInit = LogTlsStoreLogDeInitCtx; + + /* FIXME we need to implement backward compability here */ + char *s_default_log_dir = NULL; + s_default_log_dir = ConfigGetLogDirectory(); + + const char *s_base_dir = NULL; + s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir"); + if (s_base_dir == NULL || strlen(s_base_dir) == 0) { + strlcpy(tls_logfile_base_dir, + s_default_log_dir, sizeof(tls_logfile_base_dir)); + } else { + if (PathIsAbsolute(s_base_dir)) { + strlcpy(tls_logfile_base_dir, + s_base_dir, sizeof(tls_logfile_base_dir)); + } else { + snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir), + "%s/%s", s_default_log_dir, s_base_dir); + } + } + + SCLogInfo("storing certs in %s", tls_logfile_base_dir); + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); + + SCReturnPtr(output_ctx, "OutputCtx"); +} + +void LogTlsStoreRegister (void) +{ + OutputRegisterTxModuleWithCondition(LOGGER_TLS_STORE, MODULE_NAME, + "tls-store", LogTlsStoreLogInitCtx, ALPROTO_TLS, LogTlsStoreLogger, + LogTlsStoreCondition, LogTlsStoreLogThreadInit, + LogTlsStoreLogThreadDeinit, LogTlsStoreLogExitPrintStats); + + SC_ATOMIC_INIT(cert_id); + + SCLogDebug("registered"); +} diff --git a/src/log-tlsstore.h b/src/log-tlsstore.h new file mode 100644 index 000000000000..c80975bee132 --- /dev/null +++ b/src/log-tlsstore.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __LOG_TLSSTORE_H__ +#define __LOG_TLSSTORE_H__ + +void LogTlsStoreRegister(void); + +#endif /* __LOG_TLSSTORE_H__ */ diff --git a/src/output-file.c b/src/output-file.c index 0f1e85210672..020be8e28288 100644 --- a/src/output-file.c +++ b/src/output-file.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-file.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -50,17 +51,19 @@ typedef struct OutputFileLogger_ { OutputCtx *output_ctx; struct OutputFileLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputFileLogger; static OutputFileLogger *list = NULL; -int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputFileLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -69,7 +72,10 @@ int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *ou op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->logger_id = id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -80,14 +86,18 @@ int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *ou t->next = op; } - SCLogDebug("OutputRegisterTxLogger happy"); + SCLogDebug("OutputRegisterFileLogger happy"); return 0; } -static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputFileLogger *logger = list; @@ -113,7 +123,6 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, Packe int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0; int file_trunc = 0; - FLOWLOCK_WRLOCK(f); // < need write lock for FilePrune below file_trunc = StreamTcpReassembleDepthReached(p); FileContainer *ffc = AppLayerParserGetFiles(p->proto, f->alproto, @@ -138,20 +147,20 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, Packe ff->state == FILE_STATE_ERROR) { int file_logged = 0; - +#ifdef HAVE_MAGIC if (FileForceMagic() && ff->magic == NULL) { FilemagicGlobalLookup(ff); } - +#endif logger = list; store = op_thread_data->store; while (logger && store) { BUG_ON(logger->LogFunc == NULL); SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Packet *)p, (const File *)ff); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); file_logged = 1; logger = logger->next; @@ -170,7 +179,6 @@ static TmEcode OutputFileLog(ThreadVars *tv, Packet *p, void *thread_data, Packe FilePrune(ffc); } - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } @@ -190,16 +198,9 @@ static TmEcode OutputFileLogThreadInit(ThreadVars *tv, void *initdata, void **da OutputFileLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -233,15 +234,8 @@ static TmEcode OutputFileLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputFileLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -249,6 +243,8 @@ static TmEcode OutputFileLogThreadDeinit(ThreadVars *tv, void *thread_data) store = next_store; logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } @@ -259,15 +255,8 @@ static void OutputFileLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputFileLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; @@ -275,14 +264,10 @@ static void OutputFileLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleFileLoggerRegister (void) +void OutputFileLoggerRegister(void) { - tmm_modules[TMM_FILELOGGER].name = "__file_logger__"; - tmm_modules[TMM_FILELOGGER].ThreadInit = OutputFileLogThreadInit; - tmm_modules[TMM_FILELOGGER].Func = OutputFileLog; - tmm_modules[TMM_FILELOGGER].ThreadExitPrintStats = OutputFileLogExitPrintStats; - tmm_modules[TMM_FILELOGGER].ThreadDeinit = OutputFileLogThreadDeinit; - tmm_modules[TMM_FILELOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputFileLogThreadInit, + OutputFileLogThreadDeinit, OutputFileLogExitPrintStats, OutputFileLog); } void OutputFileShutdown(void) diff --git a/src/output-file.h b/src/output-file.h index 8b203e267c1d..d27d26eec47f 100644 --- a/src/output-file.h +++ b/src/output-file.h @@ -37,9 +37,11 @@ typedef int (*FileLogger)(ThreadVars *, void *thread_data, const Packet *, const */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFileLogger(const char *name, FileLogger LogFunc, OutputCtx *); +int OutputRegisterFileLogger(LoggerId id, const char *name, FileLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleFileLoggerRegister (void); +void OutputFileLoggerRegister(void); void OutputFileShutdown(void); diff --git a/src/output-filedata.c b/src/output-filedata.c index cd624437a09a..7beca04acad9 100644 --- a/src/output-filedata.c +++ b/src/output-filedata.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-filedata.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -51,7 +52,10 @@ typedef struct OutputFiledataLogger_ { OutputCtx *output_ctx; struct OutputFiledataLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputFiledataLogger; static OutputFiledataLogger *list = NULL; @@ -60,12 +64,11 @@ static SCMutex g_waldo_mutex = SCMUTEX_INITIALIZER; static int g_waldo_init = 0; static int g_waldo_deinit = 0; -int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterFiledataLogger(LoggerId id, const char *name, + FiledataLogger LogFunc, OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputFiledataLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -74,7 +77,10 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, Outpu op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->logger_id = id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -85,16 +91,47 @@ int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, Outpu t->next = op; } - SCLogDebug("OutputRegisterTxLogger happy"); + SCLogDebug("OutputRegisterFiledataLogger happy"); return 0; } SC_ATOMIC_DECLARE(unsigned int, file_id); -static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static int CallLoggers(ThreadVars *tv, OutputLoggerThreadStore *store_list, + Packet *p, const File *ff, + const uint8_t *data, uint32_t data_len, uint8_t flags) +{ + OutputFiledataLogger *logger = list; + OutputLoggerThreadStore *store = store_list; + int file_logged = 0; + + while (logger && store) { + BUG_ON(logger->LogFunc == NULL); + + SCLogDebug("logger %p", logger); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); + logger->LogFunc(tv, store->thread_data, (const Packet *)p, ff, data, data_len, flags); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); + + file_logged = 1; + + logger = logger->next; + store = store->next; + + BUG_ON(logger == NULL && store != NULL); + BUG_ON(logger != NULL && store == NULL); + } + return file_logged; +} + +static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputFiledataLogger *logger = list; @@ -120,7 +157,6 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P int file_close = (p->flags & PKT_PSEUDO_STREAM_END) ? 1 : 0; int file_trunc = 0; - FLOWLOCK_WRLOCK(f); // < need write lock for FiledataPrune below file_trunc = StreamTcpReassembleDepthReached(p); FileContainer *ffc = AppLayerParserGetFiles(p->proto, f->alproto, @@ -129,10 +165,11 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P if (ffc != NULL) { File *ff; for (ff = ffc->head; ff != NULL; ff = ff->next) { +#ifdef HAVE_MAGIC if (FileForceMagic() && ff->magic == NULL) { FilemagicGlobalLookup(ff); } - +#endif SCLogDebug("ff %p", ff); if (ff->flags & FILE_STORED) { SCLogDebug("stored flag set"); @@ -144,78 +181,51 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P continue; } - FileData *ffd; - for (ffd = ff->chunks_head; ffd != NULL; ffd = ffd->next) { - uint8_t flags = 0; - int file_logged = 0; - FileData *write_ffd = ffd; - - SCLogDebug("ffd %p", ffd); - - /* special case: on stream end we may inform the - * loggers that the file is truncated. In this - * case we already logged the current ffd, which - * is the last in our list. */ - if (ffd->stored == 1) { - if (!(file_close == 1 || ffd->next == NULL)) { - continue; - } - - // call writer with NULL ffd, so it can 'close' - // so really a 'close' msg - write_ffd = NULL; - flags |= OUTPUT_FILEDATA_FLAG_CLOSE; - } + /* if we have no data chunks left to log, we should still + * close the logger(s) */ + if (FileDataSize(ff) == ff->content_stored && + (file_trunc || file_close)) { + CallLoggers(tv, store, p, ff, NULL, 0, OUTPUT_FILEDATA_FLAG_CLOSE); + ff->flags |= FILE_STORED; + continue; + } - /* store */ + /* store */ - /* if file_id == 0, this is the first store of this file */ - if (ff->file_id == 0) { - /* new file */ - ff->file_id = SC_ATOMIC_ADD(file_id, 1); - flags |= OUTPUT_FILEDATA_FLAG_OPEN; - } else { - /* existing file */ - } + /* if file_id == 0, this is the first store of this file */ + if (ff->file_id == 0) { + /* new file */ + ff->file_id = SC_ATOMIC_ADD(file_id, 1); + flags |= OUTPUT_FILEDATA_FLAG_OPEN; + } else { + /* existing file */ + } - /* if file needs to be closed or truncated, inform - * loggers */ - if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) { - ff->state = FILE_STATE_TRUNCATED; - } + /* if file needs to be closed or truncated, inform + * loggers */ + if ((file_close || file_trunc) && ff->state < FILE_STATE_CLOSED) { + ff->state = FILE_STATE_TRUNCATED; + } - /* for the last data chunk we have, also tell the logger - * we're closing up */ - if (ffd->next == NULL && ff->state >= FILE_STATE_CLOSED) - flags |= OUTPUT_FILEDATA_FLAG_CLOSE; + /* tell the logger we're closing up */ + if (ff->state >= FILE_STATE_CLOSED) + flags |= OUTPUT_FILEDATA_FLAG_CLOSE; - logger = list; - store = op_thread_data->store; - while (logger && store) { - BUG_ON(logger->LogFunc == NULL); + /* do the actual logging */ + const uint8_t *data = NULL; + uint32_t data_len = 0; - SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); - logger->LogFunc(tv, store->thread_data, (const Packet *)p, (const File *)ff, - (const FileData *)write_ffd, flags); - PACKET_PROFILING_TMM_END(p, logger->module_id); - file_logged = 1; + StreamingBufferGetDataAtOffset(ff->sb, + &data, &data_len, + ff->content_stored); - logger = logger->next; - store = store->next; + int file_logged = CallLoggers(tv, store, p, ff, data, data_len, flags); + if (file_logged) { + ff->content_stored += data_len; - BUG_ON(logger == NULL && store != NULL); - BUG_ON(logger != NULL && store == NULL); - } - - if (file_logged) { - ffd->stored = 1; - - /* all done */ - if (flags & OUTPUT_FILEDATA_FLAG_CLOSE) { - ff->flags |= FILE_STORED; - break; - } + /* all done */ + if (flags & OUTPUT_FILEDATA_FLAG_CLOSE) { + ff->flags |= FILE_STORED; } } } @@ -223,7 +233,6 @@ static TmEcode OutputFiledataLog(ThreadVars *tv, Packet *p, void *thread_data, P FilePrune(ffc); } - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } @@ -298,16 +307,9 @@ static TmEcode OutputFiledataLogThreadInit(ThreadVars *tv, void *initdata, void OutputFiledataLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -390,15 +392,8 @@ static TmEcode OutputFiledataLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputFiledataLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -416,6 +411,8 @@ static TmEcode OutputFiledataLogThreadDeinit(ThreadVars *tv, void *thread_data) g_waldo_deinit = 1; } SCMutexUnlock(&g_waldo_mutex); + + SCFree(op_thread_data); return TM_ECODE_OK; } @@ -426,15 +423,8 @@ static void OutputFiledataLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputFiledataLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; @@ -442,15 +432,11 @@ static void OutputFiledataLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleFiledataLoggerRegister (void) +void OutputFiledataLoggerRegister(void) { - tmm_modules[TMM_FILEDATALOGGER].name = "__filedata_logger__"; - tmm_modules[TMM_FILEDATALOGGER].ThreadInit = OutputFiledataLogThreadInit; - tmm_modules[TMM_FILEDATALOGGER].Func = OutputFiledataLog; - tmm_modules[TMM_FILEDATALOGGER].ThreadExitPrintStats = OutputFiledataLogExitPrintStats; - tmm_modules[TMM_FILEDATALOGGER].ThreadDeinit = OutputFiledataLogThreadDeinit; - tmm_modules[TMM_FILEDATALOGGER].cap_flags = 0; - + OutputRegisterRootLogger(OutputFiledataLogThreadInit, + OutputFiledataLogThreadDeinit, OutputFiledataLogExitPrintStats, + OutputFiledataLog); SC_ATOMIC_INIT(file_id); } diff --git a/src/output-filedata.h b/src/output-filedata.h index 8900cd489df6..4c661b2de1cc 100644 --- a/src/output-filedata.h +++ b/src/output-filedata.h @@ -34,16 +34,19 @@ /** filedata logger function pointer type */ typedef int (*FiledataLogger)(ThreadVars *, void *thread_data, const Packet *, - const File *, const FileData *, uint8_t); + const File *, const uint8_t *, uint32_t, uint8_t); /** packet logger condition function pointer type, * must return true for packets that should be logged */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFiledataLogger(const char *name, FiledataLogger LogFunc, OutputCtx *); +int OutputRegisterFiledataLogger(LoggerId id, const char *name, + FiledataLogger LogFunc, OutputCtx *, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleFiledataLoggerRegister (void); +void OutputFiledataLoggerRegister(void); void OutputFiledataShutdown(void); diff --git a/src/output-flow.c b/src/output-flow.c index 20d5d7d423bd..235c6578e63e 100644 --- a/src/output-flow.c +++ b/src/output-flow.c @@ -47,17 +47,18 @@ typedef struct OutputFlowLogger_ { OutputCtx *output_ctx; struct OutputFlowLogger_ *next; const char *name; - TmmId module_id; + TmEcode (*ThreadInit)(ThreadVars *, void *, void **); + TmEcode (*ThreadDeinit)(ThreadVars *, void *); + void (*ThreadExitPrintStats)(ThreadVars *, void *); } OutputFlowLogger; static OutputFlowLogger *list = NULL; -int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputFlowLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -66,7 +67,9 @@ int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *ou op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -90,7 +93,6 @@ TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f) if (list == NULL) return TM_ECODE_OK; - //BUG_ON(list == NULL); OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputFlowLogger *logger = list; @@ -106,9 +108,9 @@ TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f) BUG_ON(logger->LogFunc == NULL); SCLogDebug("logger %p", logger); - //PACKET_PROFILING_TMM_START(p, logger->module_id); + //PACKET_PROFILING_LOGGER_START(p, logger->module_id); logger->LogFunc(tv, store->thread_data, f); - //PACKET_PROFILING_TMM_END(p, logger->module_id); + //PACKET_PROFILING_LOGGER_END(p, logger->module_id); logger = logger->next; store = store->next; @@ -136,16 +138,9 @@ TmEcode OutputFlowLogThreadInit(ThreadVars *tv, void *initdata, void **data) OutputFlowLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -179,15 +174,8 @@ TmEcode OutputFlowLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputFlowLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -207,15 +195,8 @@ void OutputFlowLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputFlowLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; diff --git a/src/output-flow.h b/src/output-flow.h index af093e3eb0d9..26bfc32450b2 100644 --- a/src/output-flow.h +++ b/src/output-flow.h @@ -36,7 +36,9 @@ typedef int (*FlowLogger)(ThreadVars *, void *thread_data, Flow *f); */ //typedef int (*TxLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, OutputCtx *); +int OutputRegisterFlowLogger(const char *name, FlowLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); void OutputFlowShutdown(void); diff --git a/src/output-json-alert.c b/src/output-json-alert.c index d4d9f72d43d7..89a582cf5068 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -35,21 +35,30 @@ #include "threadvars.h" #include "util-debug.h" +#include "util-misc.h" #include "util-unittest.h" #include "util-unittest-helper.h" -#include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-reference.h" #include "app-layer-parser.h" +#include "app-layer-dnp3.h" +#include "app-layer-htp.h" +#include "app-layer-htp-xff.h" #include "util-classification-config.h" #include "util-syslog.h" +#include "util-logopenfile.h" #include "output.h" #include "output-json.h" +#include "output-json-dnp3.h" #include "output-json-http.h" +#include "output-json-tls.h" +#include "output-json-ssh.h" +#include "output-json-smtp.h" +#include "output-json-email-common.h" #include "util-byte.h" #include "util-privs.h" @@ -57,23 +66,30 @@ #include "util-proto-name.h" #include "util-optimize.h" #include "util-buffer.h" -#include "util-logopenfile.h" #include "util-crypt.h" #define MODULE_NAME "JsonAlertLog" #ifdef HAVE_LIBJANSSON -#define LOG_JSON_PAYLOAD 1 -#define LOG_JSON_PACKET 2 -#define LOG_JSON_PAYLOAD_BASE64 4 -#define LOG_JSON_HTTP 8 +#define LOG_JSON_PAYLOAD 0x001 +#define LOG_JSON_PACKET 0x002 +#define LOG_JSON_PAYLOAD_BASE64 0x004 +#define LOG_JSON_HTTP 0x008 +#define LOG_JSON_TLS 0x010 +#define LOG_JSON_SSH 0x020 +#define LOG_JSON_SMTP 0x040 +#define LOG_JSON_TAGGED_PACKETS 0x080 +#define LOG_JSON_DNP3 0x100 +#define LOG_JSON_VARS 0x200 #define JSON_STREAM_BUFFER_SIZE 4096 typedef struct AlertJsonOutputCtx_ { LogFileCtx* file_ctx; - uint8_t flags; + uint16_t flags; + uint32_t payload_buffer_size; + HttpXFFCfg *xff_cfg; } AlertJsonOutputCtx; typedef struct JsonAlertLogThread_ { @@ -86,53 +102,173 @@ typedef struct JsonAlertLogThread_ { /* Callback function to pack payload contents from a stream into a buffer * so we can report them in JSON output. */ -static int AlertJsonPrintStreamSegmentCallback(const Packet *p, void *data, uint8_t *buf, uint32_t buflen) +static int AlertJsonDumpStreamSegmentCallback(const Packet *p, void *data, const uint8_t *buf, uint32_t buflen) { MemBuffer *payload = (MemBuffer *)data; - - PrintStringsToBuffer(payload->buffer, &payload->offset, payload->size, - buf, buflen); + MemBufferWriteRaw(payload, buf, buflen); return 1; } -/** Handle the case where no JSON support is compiled in. - * - */ -static void AlertJsonHttp(const Flow *f, json_t *js) +static void AlertJsonTls(const Flow *f, json_t *js) { - HtpState *htp_state = (HtpState *)f->alstate; - if (htp_state) { - uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, tx_id); + SSLState *ssl_state = (SSLState *)FlowGetAppState(f); + if (ssl_state) { + json_t *tjs = json_object(); + if (unlikely(tjs == NULL)) + return; - if (tx) { - json_t *hjs = json_object(); - if (unlikely(hjs == NULL)) - return; + JsonTlsLogJSONBasic(tjs, ssl_state); + JsonTlsLogJSONExtended(tjs, ssl_state); + + json_object_set_new(js, "tls", tjs); + } + + return; +} + +static void AlertJsonSsh(const Flow *f, json_t *js) +{ + SshState *ssh_state = (SshState *)FlowGetAppState(f); + if (ssh_state) { + json_t *tjs = json_object(); + if (unlikely(tjs == NULL)) + return; + + JsonSshLogJSON(tjs, ssh_state); - JsonHttpLogJSONBasic(hjs, tx); - JsonHttpLogJSONExtended(hjs, tx); + json_object_set_new(js, "ssh", tjs); + } + + return; +} - json_object_set_new(js, "http", hjs); +static void AlertJsonDnp3(const Flow *f, json_t *js) +{ + DNP3State *dnp3_state = (DNP3State *)FlowGetAppState(f); + if (dnp3_state) { + uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); + DNP3Transaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_DNP3, + dnp3_state, tx_id); + if (tx) { + json_t *dnp3js = json_object(); + if (likely(dnp3js != NULL)) { + if (tx->has_request && tx->request_done) { + json_t *request = JsonDNP3LogRequest(tx); + if (request != NULL) { + json_object_set_new(dnp3js, "request", request); + } + } + if (tx->has_response && tx->response_done) { + json_t *response = JsonDNP3LogResponse(tx); + if (response != NULL) { + json_object_set_new(dnp3js, "response", response); + } + } + json_object_set_new(js, "dnp3", dnp3js); + } } } return; } +void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js) +{ + char *action = "allowed"; + /* use packet action if rate_filter modified the action */ + if (unlikely(pa->flags & PACKET_ALERT_RATE_FILTER_MODIFIED)) { + if (PACKET_TEST_ACTION(p, (ACTION_DROP|ACTION_REJECT| + ACTION_REJECT_DST|ACTION_REJECT_BOTH))) { + action = "blocked"; + } + } else { + if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { + action = "blocked"; + } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { + action = "blocked"; + } + } + + /* Add tx_id to root element for correlation with other events. */ + json_object_del(js, "tx_id"); + if (pa->flags & PACKET_ALERT_FLAG_TX) + json_object_set_new(js, "tx_id", json_integer(pa->tx_id)); + + json_t *ajs = json_object(); + if (ajs == NULL) { + json_decref(js); + return; + } + + json_object_set_new(ajs, "action", json_string(action)); + json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); + json_object_set_new(ajs, "signature_id", json_integer(pa->s->id)); + json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); + json_object_set_new(ajs, "signature", + json_string((pa->s->msg) ? pa->s->msg : "")); + json_object_set_new(ajs, "category", + json_string((pa->s->class_msg) ? pa->s->class_msg : "")); + json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); + + if (p->tenant_id > 0) + json_object_set_new(ajs, "tenant_id", json_integer(p->tenant_id)); + + /* alert */ + json_object_set_new(js, "alert", ajs); +} + +static void AlertJsonTunnel(const Packet *p, json_t *js) +{ + json_t *tunnel = json_object(); + if (tunnel == NULL) + return; + + if (p->root == NULL) { + json_decref(tunnel); + return; + } + + /* get a lock to access root packet fields */ + SCMutex *m = &p->root->tunnel_mutex; + + SCMutexLock(m); + JsonFiveTuple((const Packet *)p->root, 0, tunnel); + SCMutexUnlock(m); + + json_object_set_new(tunnel, "depth", json_integer(p->recursion_level)); + + json_object_set_new(js, "tunnel", tunnel); +} + +static void AlertJsonPacket(const Packet *p, json_t *js) +{ + unsigned long len = GET_PKT_LEN(p) * 2; + uint8_t encoded_packet[len]; + Base64Encode((unsigned char*) GET_PKT_DATA(p), GET_PKT_LEN(p), + encoded_packet, &len); + json_object_set_new(js, "packet", json_string((char *)encoded_packet)); + + /* Create packet info. */ + json_t *packetinfo_js = json_object(); + if (unlikely(packetinfo_js == NULL)) { + return; + } + json_object_set_new(packetinfo_js, "linktype", json_integer(p->datalink)); + json_object_set_new(js, "packet_info", packetinfo_js); +} + static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { MemBuffer *payload = aft->payload_buffer; AlertJsonOutputCtx *json_output_ctx = aft->json_output_ctx; + json_t *hjs = NULL; int i; - if (p->alerts.cnt == 0) + if (p->alerts.cnt == 0 && !(p->flags & PKT_HAS_TAG)) return TM_ECODE_OK; - MemBufferReset(aft->json_buffer); - json_t *js = CreateJSONHeader((Packet *)p, 0, "alert"); if (unlikely(js == NULL)) return TM_ECODE_OK; @@ -143,48 +279,80 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) continue; } - char *action = "allowed"; - if (pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) { - action = "blocked"; - } else if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) { - action = "blocked"; + MemBufferReset(aft->json_buffer); + + /* alert */ + AlertJsonHeader(p, pa, js); + + if (IS_TUNNEL_PKT(p)) { + AlertJsonTunnel(p, js); } - json_t *ajs = json_object(); - if (ajs == NULL) { - json_decref(js); - return TM_ECODE_OK; + if (json_output_ctx->flags & LOG_JSON_HTTP) { + if (p->flow != NULL) { + uint16_t proto = FlowGetAppProtocol(p->flow); + + /* http alert */ + if (proto == ALPROTO_HTTP) { + hjs = JsonHttpAddMetadata(p->flow, pa->tx_id); + if (hjs) + json_object_set_new(js, "http", hjs); + } + } } - json_object_set_new(ajs, "action", json_string(action)); - json_object_set_new(ajs, "gid", json_integer(pa->s->gid)); - json_object_set_new(ajs, "signature_id", json_integer(pa->s->id)); - json_object_set_new(ajs, "rev", json_integer(pa->s->rev)); - json_object_set_new(ajs, "signature", - json_string((pa->s->msg) ? pa->s->msg : "")); - json_object_set_new(ajs, "category", - json_string((pa->s->class_msg) ? pa->s->class_msg : "")); - json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); + if (json_output_ctx->flags & LOG_JSON_TLS) { + if (p->flow != NULL) { + uint16_t proto = FlowGetAppProtocol(p->flow); - if (pa->flags & PACKET_ALERT_FLAG_TX) - json_object_set_new(ajs, "tx_id", json_integer(pa->tx_id)); + /* tls alert */ + if (proto == ALPROTO_TLS) + AlertJsonTls(p->flow, js); + } + } - /* alert */ - json_object_set_new(js, "alert", ajs); + if (json_output_ctx->flags & LOG_JSON_SSH) { + if (p->flow != NULL) { + uint16_t proto = FlowGetAppProtocol(p->flow); - if (json_output_ctx->flags & LOG_JSON_HTTP) { + /* ssh alert */ + if (proto == ALPROTO_SSH) + AlertJsonSsh(p->flow, js); + } + } + + if (json_output_ctx->flags & LOG_JSON_SMTP) { if (p->flow != NULL) { - FLOWLOCK_RDLOCK(p->flow); uint16_t proto = FlowGetAppProtocol(p->flow); - /* http alert */ - if (proto == ALPROTO_HTTP) - AlertJsonHttp(p->flow, js); + /* smtp alert */ + if (proto == ALPROTO_SMTP) { + hjs = JsonSMTPAddMetadata(p->flow, pa->tx_id); + if (hjs) + json_object_set_new(js, "smtp", hjs); + + hjs = JsonEmailAddMetadata(p->flow, pa->tx_id); + if (hjs) + json_object_set_new(js, "email", hjs); + } + } + } + + if (json_output_ctx->flags & LOG_JSON_DNP3) { + if (p->flow != NULL) { + uint16_t proto = FlowGetAppProtocol(p->flow); - FLOWLOCK_UNLOCK(p->flow); + /* dnp3 alert */ + if (proto == ALPROTO_DNP3) { + AlertJsonDnp3(p->flow, js); + } } } + if (json_output_ctx->flags & LOG_JSON_VARS) { + JsonAddVars(p, p->flow, js); + } + /* payload */ if (json_output_ctx->flags & (LOG_JSON_PAYLOAD | LOG_JSON_PAYLOAD_BASE64)) { int stream = (p->proto == IPPROTO_TCP) ? @@ -204,38 +372,43 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) } StreamSegmentForEach((const Packet *)p, flag, - AlertJsonPrintStreamSegmentCallback, + AlertJsonDumpStreamSegmentCallback, (void *)payload); if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { - unsigned long len = JSON_STREAM_BUFFER_SIZE * 2; - unsigned char encoded[len]; - Base64Encode((unsigned char *)payload, payload->offset, encoded, &len); + unsigned long len = json_output_ctx->payload_buffer_size * 2; + uint8_t encoded[len]; + Base64Encode(payload->buffer, payload->offset, encoded, &len); json_object_set_new(js, "payload", json_string((char *)encoded)); } if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { + uint8_t printable_buf[payload->offset + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + payload->buffer, payload->offset); json_object_set_new(js, "payload_printable", - json_string((char *)payload->buffer)); + json_string((char *)printable_buf)); } } else { /* This is a single packet and not a stream */ - unsigned char packet_buf[p->payload_len + 1]; - uint32_t offset = 0; - - PrintStringsToBuffer(packet_buf, &offset, - p->payload_len + 1, - p->payload, p->payload_len); - if (json_output_ctx->flags & LOG_JSON_PAYLOAD_BASE64) { - unsigned long len = sizeof(packet_buf) * 2; - unsigned char encoded[len]; - Base64Encode(packet_buf, offset, encoded, &len); - json_object_set_new(js, "payload", json_string((char *)encoded)); + unsigned long len = p->payload_len * 2 + 1; + uint8_t encoded[len]; + if (Base64Encode(p->payload, p->payload_len, encoded, &len) == SC_BASE64_OK) { + json_object_set_new(js, "payload", json_string((char *)encoded)); + } } if (json_output_ctx->flags & LOG_JSON_PAYLOAD) { - json_object_set_new(js, "payload_printable", json_string((char *)packet_buf)); + uint8_t printable_buf[p->payload_len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + p->payload_len + 1, + p->payload, p->payload_len); + printable_buf[p->payload_len] = '\0'; + json_object_set_new(js, "payload_printable", json_string((char *)printable_buf)); } } @@ -244,24 +417,60 @@ static int AlertJson(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) /* base64-encoded full packet */ if (json_output_ctx->flags & LOG_JSON_PACKET) { - unsigned long len = GET_PKT_LEN(p) * 2; - unsigned char encoded_packet[len]; - Base64Encode((unsigned char*) GET_PKT_DATA(p), GET_PKT_LEN(p), encoded_packet, &len); - json_object_set_new(js, "packet", json_string((char *)encoded_packet)); + AlertJsonPacket(p, js); } - OutputJSONBuffer(js, aft->file_ctx, aft->json_buffer); + HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; + + /* xff header */ + if ((xff_cfg != NULL) && !(xff_cfg->flags & XFF_DISABLED) && p->flow != NULL) { + int have_xff_ip = 0; + char buffer[XFF_MAXLEN]; + + if (FlowGetAppProtocol(p->flow) == ALPROTO_HTTP) { + if (pa->flags & PACKET_ALERT_FLAG_TX) { + have_xff_ip = HttpXFFGetIPFromTx(p, pa->tx_id, xff_cfg, buffer, XFF_MAXLEN); + } else { + have_xff_ip = HttpXFFGetIP(p, xff_cfg, buffer, XFF_MAXLEN); + } + } + + if (have_xff_ip) { + if (xff_cfg->flags & XFF_EXTRADATA) { + json_object_set_new(js, "xff", json_string(buffer)); + } + else if (xff_cfg->flags & XFF_OVERWRITE) { + if (p->flowflags & FLOW_PKT_TOCLIENT) { + json_object_set(js, "dest_ip", json_string(buffer)); + } else { + json_object_set(js, "src_ip", json_string(buffer)); + } + } + } + } + + OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); json_object_del(js, "alert"); } json_object_clear(js); json_decref(js); + if ((p->flags & PKT_HAS_TAG) && (json_output_ctx->flags & + LOG_JSON_TAGGED_PACKETS)) { + MemBufferReset(aft->json_buffer); + json_t *packetjs = CreateJSONHeader((Packet *)p, 0, "packet"); + if (unlikely(packetjs != NULL)) { + AlertJsonPacket(p, packetjs); + OutputJSONBuffer(packetjs, aft->file_ctx, &aft->json_buffer); + json_decref(packetjs); + } + } + return TM_ECODE_OK; } static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const Packet *p) { - MemBuffer *buffer = (MemBuffer *)aft->json_buffer; int i; char timebuf[64]; json_t *js; @@ -269,11 +478,11 @@ static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const if (p->alerts.cnt == 0) return TM_ECODE_OK; - MemBufferReset(buffer); - CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); for (i = 0; i < p->alerts.cnt; i++) { + MemBufferReset(aft->json_buffer); + const PacketAlert *pa = &p->alerts.alerts[i]; if (unlikely(pa->s == NULL)) { continue; @@ -319,9 +528,12 @@ static int AlertJsonDecoderEvent(ThreadVars *tv, JsonAlertLogThread *aft, const json_string((pa->s->class_msg) ? pa->s->class_msg : "")); json_object_set_new(ajs, "severity", json_integer(pa->s->prio)); + if (p->tenant_id > 0) + json_object_set_new(ajs, "tenant_id", json_integer(p->tenant_id)); + /* alert */ json_object_set_new(js, "alert", ajs); - OutputJSONBuffer(js, aft->file_ctx, buffer); + OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); json_object_clear(js); json_decref(js); } @@ -343,7 +555,10 @@ static int JsonAlertLogger(ThreadVars *tv, void *thread_data, const Packet *p) static int JsonAlertLogCondition(ThreadVars *tv, const Packet *p) { - return (p->alerts.cnt ? TRUE : FALSE); + if (p->alerts.cnt || (p->flags & PKT_HAS_TAG)) { + return TRUE; + } + return FALSE; } #define OUTPUT_BUFFER_SIZE 65535 @@ -355,7 +570,7 @@ static TmEcode JsonAlertLogThreadInit(ThreadVars *t, void *initdata, void **data memset(aft, 0, sizeof(JsonAlertLogThread)); if(initdata == NULL) { - SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogAlert. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -366,17 +581,17 @@ static TmEcode JsonAlertLogThreadInit(ThreadVars *t, void *initdata, void **data return TM_ECODE_FAILED; } - aft->payload_buffer = MemBufferCreateNew(JSON_STREAM_BUFFER_SIZE); - if (aft->payload_buffer == NULL) { - SCFree(aft); - return TM_ECODE_FAILED; - } - /** Use the Output Context (file pointer and mutex) */ AlertJsonOutputCtx *json_output_ctx = ((OutputCtx *)initdata)->data; aft->file_ctx = json_output_ctx->file_ctx; aft->json_output_ctx = json_output_ctx; + aft->payload_buffer = MemBufferCreateNew(json_output_ctx->payload_buffer_size); + if (aft->payload_buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + *data = (void *)aft; return TM_ECODE_OK; } @@ -400,9 +615,15 @@ static TmEcode JsonAlertLogThreadDeinit(ThreadVars *t, void *data) static void JsonAlertLogDeInitCtx(OutputCtx *output_ctx) { - SCLogDebug("cleaning up output_ctx"); - LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - LogFileFreeCtx(logfile_ctx); + AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *) output_ctx->data; + if (json_output_ctx != NULL) { + HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } + LogFileFreeCtx(json_output_ctx->file_ctx); + SCFree(json_output_ctx); + } SCFree(output_ctx); } @@ -413,6 +634,11 @@ static void JsonAlertLogDeInitCtxSub(OutputCtx *output_ctx) AlertJsonOutputCtx *json_output_ctx = (AlertJsonOutputCtx *) output_ctx->data; if (json_output_ctx != NULL) { + HttpXFFCfg *xff_cfg = json_output_ctx->xff_cfg; + if (xff_cfg != NULL) { + SCFree(xff_cfg); + } + SCFree(json_output_ctx); } SCFree(output_ctx); @@ -420,6 +646,100 @@ static void JsonAlertLogDeInitCtxSub(OutputCtx *output_ctx) #define DEFAULT_LOG_FILENAME "alert.json" +static void XffSetup(AlertJsonOutputCtx *json_output_ctx, ConfNode *conf) +{ + HttpXFFCfg *xff_cfg = NULL; + + xff_cfg = SCMalloc(sizeof(HttpXFFCfg)); + if (unlikely(xff_cfg == NULL)) { + return; + } + memset(xff_cfg, 0, sizeof(HttpXFFCfg)); + + json_output_ctx->xff_cfg = xff_cfg; + + uint32_t payload_buffer_size = JSON_STREAM_BUFFER_SIZE; + + if (conf != NULL) { + const char *payload = ConfNodeLookupChildValue(conf, "payload"); + const char *payload_buffer_value = ConfNodeLookupChildValue(conf, "payload-buffer-size"); + const char *packet = ConfNodeLookupChildValue(conf, "packet"); + const char *payload_printable = ConfNodeLookupChildValue(conf, "payload-printable"); + const char *http = ConfNodeLookupChildValue(conf, "http"); + const char *tls = ConfNodeLookupChildValue(conf, "tls"); + const char *ssh = ConfNodeLookupChildValue(conf, "ssh"); + const char *smtp = ConfNodeLookupChildValue(conf, "smtp"); + const char *tagged_packets = ConfNodeLookupChildValue(conf, "tagged-packets"); + const char *dnp3 = ConfNodeLookupChildValue(conf, "dnp3"); + const char *vars = ConfNodeLookupChildValue(conf, "vars"); + + if (vars != NULL) { + if (ConfValIsTrue(vars)) { + json_output_ctx->flags |= LOG_JSON_VARS; + } + } + if (ssh != NULL) { + if (ConfValIsTrue(ssh)) { + json_output_ctx->flags |= LOG_JSON_SSH; + } + } + if (tls != NULL) { + if (ConfValIsTrue(tls)) { + json_output_ctx->flags |= LOG_JSON_TLS; + } + } + if (http != NULL) { + if (ConfValIsTrue(http)) { + json_output_ctx->flags |= LOG_JSON_HTTP; + } + } + if (smtp != NULL) { + if (ConfValIsTrue(smtp)) { + json_output_ctx->flags |= LOG_JSON_SMTP; + } + } + if (payload_printable != NULL) { + if (ConfValIsTrue(payload_printable)) { + json_output_ctx->flags |= LOG_JSON_PAYLOAD; + } + } + if (payload != NULL) { + if (ConfValIsTrue(payload)) { + json_output_ctx->flags |= LOG_JSON_PAYLOAD_BASE64; + } + } + if (payload_buffer_value != NULL) { + uint32_t value; + if (ParseSizeStringU32(payload_buffer_value, &value) < 0) { + SCLogError(SC_ERR_ALERT_PAYLOAD_BUFFER, "Error parsing " + "payload-buffer-size - %s. Killing engine", + payload_buffer_value); + exit(EXIT_FAILURE); + } else { + payload_buffer_size = value; + } + } + if (packet != NULL) { + if (ConfValIsTrue(packet)) { + json_output_ctx->flags |= LOG_JSON_PACKET; + } + } + if (tagged_packets != NULL) { + if (ConfValIsTrue(tagged_packets)) { + json_output_ctx->flags |= LOG_JSON_TAGGED_PACKETS; + } + } + if (dnp3 != NULL) { + if (ConfValIsTrue(dnp3)) { + json_output_ctx->flags |= LOG_JSON_DNP3; + } + } + + json_output_ctx->payload_buffer_size = payload_buffer_size; + HttpXFFGetCfg(conf, xff_cfg); + } +} + /** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. @@ -427,21 +747,37 @@ static void JsonAlertLogDeInitCtxSub(OutputCtx *output_ctx) */ static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) { + AlertJsonOutputCtx *json_output_ctx = NULL; LogFileCtx *logfile_ctx = LogFileNewCtx(); if (logfile_ctx == NULL) { SCLogDebug("AlertFastLogInitCtx2: Could not create new LogFileCtx"); return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(logfile_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); - if (unlikely(output_ctx == NULL)) + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + SCFree(output_ctx); return NULL; - output_ctx->data = logfile_ctx; + } + memset(json_output_ctx, 0, sizeof(AlertJsonOutputCtx)); + + json_output_ctx->file_ctx = logfile_ctx; + + XffSetup(json_output_ctx, conf); + + output_ctx->data = json_output_ctx; output_ctx->DeInit = JsonAlertLogDeInitCtx; return output_ctx; @@ -454,81 +790,54 @@ static OutputCtx *JsonAlertLogInitCtx(ConfNode *conf) */ static OutputCtx *JsonAlertLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ajt = parent_ctx->data; + AlertJsonOutputCtx *json_output_ctx = NULL; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) return NULL; - AlertJsonOutputCtx *json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); + json_output_ctx = SCMalloc(sizeof(AlertJsonOutputCtx)); if (unlikely(json_output_ctx == NULL)) { - SCFree(output_ctx); - return NULL; + goto error; } - memset(json_output_ctx, 0, sizeof(AlertJsonOutputCtx)); + json_output_ctx->file_ctx = ajt->file_ctx; - if (conf != NULL) { - const char *payload = ConfNodeLookupChildValue(conf, "payload"); - const char *packet = ConfNodeLookupChildValue(conf, "packet"); - const char *payload_printable = ConfNodeLookupChildValue(conf, "payload-printable"); - const char *http = ConfNodeLookupChildValue(conf, "http"); - - if (http != NULL) { - if (ConfValIsTrue(http)) { - json_output_ctx->flags |= LOG_JSON_HTTP; - } - } - if (payload_printable != NULL) { - if (ConfValIsTrue(payload_printable)) { - json_output_ctx->flags |= LOG_JSON_PAYLOAD; - } - } - if (payload != NULL) { - if (ConfValIsTrue(payload)) { - json_output_ctx->flags |= LOG_JSON_PAYLOAD_BASE64; - } - } - if (packet != NULL) { - if (ConfValIsTrue(packet)) { - json_output_ctx->flags |= LOG_JSON_PACKET; - } - } - } + XffSetup(json_output_ctx, conf); output_ctx->data = json_output_ctx; output_ctx->DeInit = JsonAlertLogDeInitCtxSub; return output_ctx; + +error: + if (json_output_ctx != NULL) { + SCFree(json_output_ctx); + } + if (output_ctx != NULL) { + SCFree(output_ctx); + } + + return NULL; } -void TmModuleJsonAlertLogRegister (void) +void JsonAlertLogRegister (void) { - tmm_modules[TMM_JSONALERTLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONALERTLOG].ThreadInit = JsonAlertLogThreadInit; - tmm_modules[TMM_JSONALERTLOG].ThreadDeinit = JsonAlertLogThreadDeinit; - tmm_modules[TMM_JSONALERTLOG].cap_flags = 0; - tmm_modules[TMM_JSONALERTLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "alert-json-log", - JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition); - OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.alert", - JsonAlertLogInitCtxSub, JsonAlertLogger, JsonAlertLogCondition); + OutputRegisterPacketModule(LOGGER_JSON_ALERT, MODULE_NAME, "alert-json-log", + JsonAlertLogInitCtx, JsonAlertLogger, JsonAlertLogCondition, + JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_ALERT, "eve-log", MODULE_NAME, + "eve-log.alert", JsonAlertLogInitCtxSub, JsonAlertLogger, + JsonAlertLogCondition, JsonAlertLogThreadInit, JsonAlertLogThreadDeinit, + NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonAlertLogRegister (void) +void JsonAlertLogRegister (void) { - tmm_modules[TMM_JSONALERTLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONALERTLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-alert.h b/src/output-json-alert.h index ec8abb7e4ebf..645b6f5c0270 100644 --- a/src/output-json-alert.h +++ b/src/output-json-alert.h @@ -27,7 +27,10 @@ #ifndef __OUTPUT_JSON_ALERT_H__ #define __OUTPUT_JSON_ALERT_H__ -void TmModuleJsonAlertLogRegister (void); +void JsonAlertLogRegister(void); +#ifdef HAVE_LIBJANSSON +void AlertJsonHeader(const Packet *p, const PacketAlert *pa, json_t *js); +#endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_ALERT_H__ */ diff --git a/src/output-json-dnp3-objects.c b/src/output-json-dnp3-objects.c new file mode 100644 index 000000000000..8fc7e760c0d5 --- /dev/null +++ b/src/output-json-dnp3-objects.c @@ -0,0 +1,2720 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +#include "suricata-common.h" + +#include "util-crypt.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LIBJANSSON + +void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object, + DNP3Point *point) +{ + + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { + case DNP3_OBJECT_CODE(1, 1): { + DNP3ObjectG1V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(1, 2): { + DNP3ObjectG1V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(2, 1): { + DNP3ObjectG2V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(2, 2): { + DNP3ObjectG2V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(2, 3): { + DNP3ObjectG2V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(3, 1): { + DNP3ObjectG3V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(3, 2): { + DNP3ObjectG3V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(4, 1): { + DNP3ObjectG4V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(4, 2): { + DNP3ObjectG4V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(4, 3): { + DNP3ObjectG4V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "chatter_filter", + json_integer(data->chatter_filter)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "relative_time_ms", + json_integer(data->relative_time_ms)); + break; + } + case DNP3_OBJECT_CODE(10, 1): { + DNP3ObjectG10V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(10, 2): { + DNP3ObjectG10V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(11, 1): { + DNP3ObjectG11V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(11, 2): { + DNP3ObjectG11V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "state", + json_integer(data->state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(12, 1): { + DNP3ObjectG12V1 *data = point->data; + json_object_set_new(js, "op_type", + json_integer(data->op_type)); + json_object_set_new(js, "qu", + json_integer(data->qu)); + json_object_set_new(js, "cr", + json_integer(data->cr)); + json_object_set_new(js, "tcc", + json_integer(data->tcc)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "ontime", + json_integer(data->ontime)); + json_object_set_new(js, "offtime", + json_integer(data->offtime)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + break; + } + case DNP3_OBJECT_CODE(12, 2): { + DNP3ObjectG12V2 *data = point->data; + json_object_set_new(js, "op_type", + json_integer(data->op_type)); + json_object_set_new(js, "qu", + json_integer(data->qu)); + json_object_set_new(js, "cr", + json_integer(data->cr)); + json_object_set_new(js, "tcc", + json_integer(data->tcc)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "ontime", + json_integer(data->ontime)); + json_object_set_new(js, "offtime", + json_integer(data->offtime)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved", + json_integer(data->reserved)); + break; + } + case DNP3_OBJECT_CODE(12, 3): { + DNP3ObjectG12V3 *data = point->data; + json_object_set_new(js, "point", + json_integer(data->point)); + break; + } + case DNP3_OBJECT_CODE(13, 1): { + DNP3ObjectG13V1 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "commanded_state", + json_integer(data->commanded_state)); + break; + } + case DNP3_OBJECT_CODE(13, 2): { + DNP3ObjectG13V2 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "commanded_state", + json_integer(data->commanded_state)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(20, 1): { + DNP3ObjectG20V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 2): { + DNP3ObjectG20V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 3): { + DNP3ObjectG20V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 4): { + DNP3ObjectG20V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 5): { + DNP3ObjectG20V5 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 6): { + DNP3ObjectG20V6 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 7): { + DNP3ObjectG20V7 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(20, 8): { + DNP3ObjectG20V8 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 1): { + DNP3ObjectG21V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 2): { + DNP3ObjectG21V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 3): { + DNP3ObjectG21V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 4): { + DNP3ObjectG21V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 5): { + DNP3ObjectG21V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 6): { + DNP3ObjectG21V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 7): { + DNP3ObjectG21V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 8): { + DNP3ObjectG21V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(21, 9): { + DNP3ObjectG21V9 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 10): { + DNP3ObjectG21V10 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 11): { + DNP3ObjectG21V11 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(21, 12): { + DNP3ObjectG21V12 *data = point->data; + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 1): { + DNP3ObjectG22V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 2): { + DNP3ObjectG22V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 3): { + DNP3ObjectG22V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 4): { + DNP3ObjectG22V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(22, 5): { + DNP3ObjectG22V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(22, 6): { + DNP3ObjectG22V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(22, 7): { + DNP3ObjectG22V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(22, 8): { + DNP3ObjectG22V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 1): { + DNP3ObjectG23V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 2): { + DNP3ObjectG23V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 3): { + DNP3ObjectG23V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 4): { + DNP3ObjectG23V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + break; + } + case DNP3_OBJECT_CODE(23, 5): { + DNP3ObjectG23V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 6): { + DNP3ObjectG23V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 7): { + DNP3ObjectG23V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(23, 8): { + DNP3ObjectG23V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "rollover", + json_integer(data->rollover)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "count", + json_integer(data->count)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(30, 1): { + DNP3ObjectG30V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 2): { + DNP3ObjectG30V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 3): { + DNP3ObjectG30V3 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 4): { + DNP3ObjectG30V4 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 5): { + DNP3ObjectG30V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(30, 6): { + DNP3ObjectG30V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 1): { + DNP3ObjectG31V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 2): { + DNP3ObjectG31V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 3): { + DNP3ObjectG31V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(31, 4): { + DNP3ObjectG31V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(31, 5): { + DNP3ObjectG31V5 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 6): { + DNP3ObjectG31V6 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 7): { + DNP3ObjectG31V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(31, 8): { + DNP3ObjectG31V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 1): { + DNP3ObjectG32V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 2): { + DNP3ObjectG32V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 3): { + DNP3ObjectG32V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(32, 4): { + DNP3ObjectG32V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(32, 5): { + DNP3ObjectG32V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 6): { + DNP3ObjectG32V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(32, 7): { + DNP3ObjectG32V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(32, 8): { + DNP3ObjectG32V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 1): { + DNP3ObjectG33V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 2): { + DNP3ObjectG33V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 3): { + DNP3ObjectG33V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 4): { + DNP3ObjectG33V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 5): { + DNP3ObjectG33V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 6): { + DNP3ObjectG33V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(33, 7): { + DNP3ObjectG33V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(33, 8): { + DNP3ObjectG33V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(34, 1): { + DNP3ObjectG34V1 *data = point->data; + json_object_set_new(js, "deadband_value", + json_integer(data->deadband_value)); + break; + } + case DNP3_OBJECT_CODE(34, 2): { + DNP3ObjectG34V2 *data = point->data; + json_object_set_new(js, "deadband_value", + json_integer(data->deadband_value)); + break; + } + case DNP3_OBJECT_CODE(34, 3): { + DNP3ObjectG34V3 *data = point->data; + json_object_set_new(js, "deadband_value", + json_real(data->deadband_value)); + break; + } + case DNP3_OBJECT_CODE(40, 1): { + DNP3ObjectG40V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(40, 2): { + DNP3ObjectG40V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(40, 3): { + DNP3ObjectG40V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(40, 4): { + DNP3ObjectG40V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(41, 1): { + DNP3ObjectG41V1 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(41, 2): { + DNP3ObjectG41V2 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(41, 3): { + DNP3ObjectG41V3 *data = point->data; + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(41, 4): { + DNP3ObjectG41V4 *data = point->data; + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "control_status", + json_integer(data->control_status)); + break; + } + case DNP3_OBJECT_CODE(42, 1): { + DNP3ObjectG42V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 2): { + DNP3ObjectG42V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 3): { + DNP3ObjectG42V3 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(42, 4): { + DNP3ObjectG42V4 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_integer(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(42, 5): { + DNP3ObjectG42V5 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 6): { + DNP3ObjectG42V6 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + break; + } + case DNP3_OBJECT_CODE(42, 7): { + DNP3ObjectG42V7 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(42, 8): { + DNP3ObjectG42V8 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "over_range", + json_integer(data->over_range)); + json_object_set_new(js, "reference_err", + json_integer(data->reference_err)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "value", + json_real(data->value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 1): { + DNP3ObjectG43V1 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 2): { + DNP3ObjectG43V2 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 3): { + DNP3ObjectG43V3 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 4): { + DNP3ObjectG43V4 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_integer(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 5): { + DNP3ObjectG43V5 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 6): { + DNP3ObjectG43V6 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + break; + } + case DNP3_OBJECT_CODE(43, 7): { + DNP3ObjectG43V7 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(43, 8): { + DNP3ObjectG43V8 *data = point->data; + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "commanded_value", + json_real(data->commanded_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(50, 1): { + DNP3ObjectG50V1 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(50, 2): { + DNP3ObjectG50V2 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + json_object_set_new(js, "interval", + json_integer(data->interval)); + break; + } + case DNP3_OBJECT_CODE(50, 3): { + DNP3ObjectG50V3 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(50, 4): { + DNP3ObjectG50V4 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + json_object_set_new(js, "interval_count", + json_integer(data->interval_count)); + json_object_set_new(js, "interval_units", + json_integer(data->interval_units)); + break; + } + case DNP3_OBJECT_CODE(51, 1): { + DNP3ObjectG51V1 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(51, 2): { + DNP3ObjectG51V2 *data = point->data; + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + case DNP3_OBJECT_CODE(52, 1): { + DNP3ObjectG52V1 *data = point->data; + json_object_set_new(js, "delay_secs", + json_integer(data->delay_secs)); + break; + } + case DNP3_OBJECT_CODE(52, 2): { + DNP3ObjectG52V2 *data = point->data; + json_object_set_new(js, "delay_ms", + json_integer(data->delay_ms)); + break; + } + case DNP3_OBJECT_CODE(70, 1): { + DNP3ObjectG70V1 *data = point->data; + json_object_set_new(js, "filename_size", + json_integer(data->filename_size)); + json_object_set_new(js, "filetype_code", + json_integer(data->filetype_code)); + json_object_set_new(js, "attribute_code", + json_integer(data->attribute_code)); + json_object_set_new(js, "start_record", + json_integer(data->start_record)); + json_object_set_new(js, "end_record", + json_integer(data->end_record)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "created_timestamp", + json_integer(data->created_timestamp)); + json_object_set_new(js, "permission", + json_integer(data->permission)); + json_object_set_new(js, "file_id", + json_integer(data->file_id)); + json_object_set_new(js, "owner_id", + json_integer(data->owner_id)); + json_object_set_new(js, "group_id", + json_integer(data->group_id)); + json_object_set_new(js, "file_function_code", + json_integer(data->file_function_code)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + if (data->filename_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->filename_size + 1]; + memcpy(tmpbuf, data->filename, data->filename_size); + tmpbuf[data->filename_size] = '\0'; + json_object_set_new(js, "filename", json_string(tmpbuf)); + } else { + json_object_set_new(js, "filename", json_string("")); + } + json_object_set_new(js, "data_size", + json_integer(data->data_size)); + if (data->data_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->data_size + 1]; + memcpy(tmpbuf, data->data, data->data_size); + tmpbuf[data->data_size] = '\0'; + json_object_set_new(js, "data", json_string(tmpbuf)); + } else { + json_object_set_new(js, "data", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 2): { + DNP3ObjectG70V2 *data = point->data; + json_object_set_new(js, "username_offset", + json_integer(data->username_offset)); + json_object_set_new(js, "username_size", + json_integer(data->username_size)); + json_object_set_new(js, "password_offset", + json_integer(data->password_offset)); + json_object_set_new(js, "password_size", + json_integer(data->password_size)); + json_object_set_new(js, "authentication_key", + json_integer(data->authentication_key)); + if (data->username_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->username_size + 1]; + memcpy(tmpbuf, data->username, data->username_size); + tmpbuf[data->username_size] = '\0'; + json_object_set_new(js, "username", json_string(tmpbuf)); + } else { + json_object_set_new(js, "username", json_string("")); + } + if (data->password_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->password_size + 1]; + memcpy(tmpbuf, data->password, data->password_size); + tmpbuf[data->password_size] = '\0'; + json_object_set_new(js, "password", json_string(tmpbuf)); + } else { + json_object_set_new(js, "password", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 3): { + DNP3ObjectG70V3 *data = point->data; + json_object_set_new(js, "filename_offset", + json_integer(data->filename_offset)); + json_object_set_new(js, "filename_size", + json_integer(data->filename_size)); + json_object_set_new(js, "created", + json_integer(data->created)); + json_object_set_new(js, "permissions", + json_integer(data->permissions)); + json_object_set_new(js, "authentication_key", + json_integer(data->authentication_key)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "operational_mode", + json_integer(data->operational_mode)); + json_object_set_new(js, "maximum_block_size", + json_integer(data->maximum_block_size)); + json_object_set_new(js, "request_id", + json_integer(data->request_id)); + if (data->filename_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->filename_size + 1]; + memcpy(tmpbuf, data->filename, data->filename_size); + tmpbuf[data->filename_size] = '\0'; + json_object_set_new(js, "filename", json_string(tmpbuf)); + } else { + json_object_set_new(js, "filename", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 4): { + DNP3ObjectG70V4 *data = point->data; + json_object_set_new(js, "file_handle", + json_integer(data->file_handle)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "maximum_block_size", + json_integer(data->maximum_block_size)); + json_object_set_new(js, "request_id", + json_integer(data->request_id)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + if (data->optional_text_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->optional_text_len + 1]; + memcpy(tmpbuf, data->optional_text, data->optional_text_len); + tmpbuf[data->optional_text_len] = '\0'; + json_object_set_new(js, "optional_text", json_string(tmpbuf)); + } else { + json_object_set_new(js, "optional_text", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 5): { + DNP3ObjectG70V5 *data = point->data; + json_object_set_new(js, "file_handle", + json_integer(data->file_handle)); + json_object_set_new(js, "block_number", + json_integer(data->block_number)); + if (data->file_data_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->file_data_len + 1]; + memcpy(tmpbuf, data->file_data, data->file_data_len); + tmpbuf[data->file_data_len] = '\0'; + json_object_set_new(js, "file_data", json_string(tmpbuf)); + } else { + json_object_set_new(js, "file_data", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 6): { + DNP3ObjectG70V6 *data = point->data; + json_object_set_new(js, "file_handle", + json_integer(data->file_handle)); + json_object_set_new(js, "block_number", + json_integer(data->block_number)); + json_object_set_new(js, "status_code", + json_integer(data->status_code)); + if (data->optional_text_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->optional_text_len + 1]; + memcpy(tmpbuf, data->optional_text, data->optional_text_len); + tmpbuf[data->optional_text_len] = '\0'; + json_object_set_new(js, "optional_text", json_string(tmpbuf)); + } else { + json_object_set_new(js, "optional_text", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 7): { + DNP3ObjectG70V7 *data = point->data; + json_object_set_new(js, "filename_offset", + json_integer(data->filename_offset)); + json_object_set_new(js, "filename_size", + json_integer(data->filename_size)); + json_object_set_new(js, "file_type", + json_integer(data->file_type)); + json_object_set_new(js, "file_size", + json_integer(data->file_size)); + json_object_set_new(js, "created_timestamp", + json_integer(data->created_timestamp)); + json_object_set_new(js, "permissions", + json_integer(data->permissions)); + json_object_set_new(js, "request_id", + json_integer(data->request_id)); + if (data->filename_size > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->filename_size + 1]; + memcpy(tmpbuf, data->filename, data->filename_size); + tmpbuf[data->filename_size] = '\0'; + json_object_set_new(js, "filename", json_string(tmpbuf)); + } else { + json_object_set_new(js, "filename", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(70, 8): { + DNP3ObjectG70V8 *data = point->data; + if (data->file_specification_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->file_specification_len + 1]; + memcpy(tmpbuf, data->file_specification, data->file_specification_len); + tmpbuf[data->file_specification_len] = '\0'; + json_object_set_new(js, "file_specification", json_string(tmpbuf)); + } else { + json_object_set_new(js, "file_specification", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(80, 1): { + DNP3ObjectG80V1 *data = point->data; + json_object_set_new(js, "state", + json_integer(data->state)); + break; + } + case DNP3_OBJECT_CODE(81, 1): { + DNP3ObjectG81V1 *data = point->data; + json_object_set_new(js, "fill_percentage", + json_integer(data->fill_percentage)); + json_object_set_new(js, "overflow_state", + json_integer(data->overflow_state)); + json_object_set_new(js, "group", + json_integer(data->group)); + json_object_set_new(js, "variation", + json_integer(data->variation)); + break; + } + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *data = point->data; + json_object_set_new(js, "data->vendor_code", json_string(data->vendor_code)); + json_object_set_new(js, "object_id", + json_integer(data->object_id)); + json_object_set_new(js, "length", + json_integer(data->length)); + unsigned long data_objects_b64_len = data->length * 2; + uint8_t data_objects_b64[data_objects_b64_len]; + Base64Encode(data->data_objects, data->length, + data_objects_b64, &data_objects_b64_len); + json_object_set_new(js, "data->data_objects", + json_string((char *)data_objects_b64)); + break; + } + case DNP3_OBJECT_CODE(86, 2): { + DNP3ObjectG86V2 *data = point->data; + json_object_set_new(js, "rd", + json_integer(data->rd)); + json_object_set_new(js, "wr", + json_integer(data->wr)); + json_object_set_new(js, "st", + json_integer(data->st)); + json_object_set_new(js, "ev", + json_integer(data->ev)); + json_object_set_new(js, "df", + json_integer(data->df)); + json_object_set_new(js, "padding0", + json_integer(data->padding0)); + json_object_set_new(js, "padding1", + json_integer(data->padding1)); + json_object_set_new(js, "padding2", + json_integer(data->padding2)); + break; + } + case DNP3_OBJECT_CODE(102, 1): { + DNP3ObjectG102V1 *data = point->data; + json_object_set_new(js, "value", + json_integer(data->value)); + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *data = point->data; + json_object_set_new(js, "csq", + json_integer(data->csq)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + json_object_set_new(js, "mal", + json_integer(data->mal)); + json_object_set_new(js, "reason", + json_integer(data->reason)); + unsigned long challenge_data_b64_len = data->challenge_data_len * 2; + uint8_t challenge_data_b64[challenge_data_b64_len]; + Base64Encode(data->challenge_data, data->challenge_data_len, + challenge_data_b64, &challenge_data_b64_len); + json_object_set_new(js, "data->challenge_data", + json_string((char *)challenge_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *data = point->data; + json_object_set_new(js, "csq", + json_integer(data->csq)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + unsigned long mac_value_b64_len = data->mac_value_len * 2; + uint8_t mac_value_b64[mac_value_b64_len]; + Base64Encode(data->mac_value, data->mac_value_len, + mac_value_b64, &mac_value_b64_len); + json_object_set_new(js, "data->mac_value", + json_string((char *)mac_value_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 3): { + DNP3ObjectG120V3 *data = point->data; + json_object_set_new(js, "csq", + json_integer(data->csq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + break; + } + case DNP3_OBJECT_CODE(120, 4): { + DNP3ObjectG120V4 *data = point->data; + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + json_object_set_new(js, "key_wrap_alg", + json_integer(data->key_wrap_alg)); + json_object_set_new(js, "key_status", + json_integer(data->key_status)); + json_object_set_new(js, "mal", + json_integer(data->mal)); + json_object_set_new(js, "challenge_data_len", + json_integer(data->challenge_data_len)); + unsigned long challenge_data_b64_len = data->challenge_data_len * 2; + uint8_t challenge_data_b64[challenge_data_b64_len]; + Base64Encode(data->challenge_data, data->challenge_data_len, + challenge_data_b64, &challenge_data_b64_len); + json_object_set_new(js, "data->challenge_data", + json_string((char *)challenge_data_b64)); + unsigned long mac_value_b64_len = data->mac_value_len * 2; + uint8_t mac_value_b64[mac_value_b64_len]; + Base64Encode(data->mac_value, data->mac_value_len, + mac_value_b64, &mac_value_b64_len); + json_object_set_new(js, "data->mac_value", + json_string((char *)mac_value_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + unsigned long wrapped_key_data_b64_len = data->wrapped_key_data_len * 2; + uint8_t wrapped_key_data_b64[wrapped_key_data_b64_len]; + Base64Encode(data->wrapped_key_data, data->wrapped_key_data_len, + wrapped_key_data_b64, &wrapped_key_data_b64_len); + json_object_set_new(js, "data->wrapped_key_data", + json_string((char *)wrapped_key_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 7): { + DNP3ObjectG120V7 *data = point->data; + json_object_set_new(js, "sequence_number", + json_integer(data->sequence_number)); + json_object_set_new(js, "usr", + json_integer(data->usr)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "error_code", + json_integer(data->error_code)); + json_object_set_new(js, "time_of_error", + json_integer(data->time_of_error)); + if (data->error_text_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->error_text_len + 1]; + memcpy(tmpbuf, data->error_text, data->error_text_len); + tmpbuf[data->error_text_len] = '\0'; + json_object_set_new(js, "error_text", json_string(tmpbuf)); + } else { + json_object_set_new(js, "error_text", json_string("")); + } + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *data = point->data; + json_object_set_new(js, "key_change_method", + json_integer(data->key_change_method)); + json_object_set_new(js, "certificate_type", + json_integer(data->certificate_type)); + unsigned long certificate_b64_len = data->certificate_len * 2; + uint8_t certificate_b64[certificate_b64_len]; + Base64Encode(data->certificate, data->certificate_len, + certificate_b64, &certificate_b64_len); + json_object_set_new(js, "data->certificate", + json_string((char *)certificate_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *data = point->data; + unsigned long mac_value_b64_len = data->mac_value_len * 2; + uint8_t mac_value_b64[mac_value_b64_len]; + Base64Encode(data->mac_value, data->mac_value_len, + mac_value_b64, &mac_value_b64_len); + json_object_set_new(js, "data->mac_value", + json_string((char *)mac_value_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *data = point->data; + json_object_set_new(js, "key_change_method", + json_integer(data->key_change_method)); + json_object_set_new(js, "operation", + json_integer(data->operation)); + json_object_set_new(js, "scs", + json_integer(data->scs)); + json_object_set_new(js, "user_role", + json_integer(data->user_role)); + json_object_set_new(js, "user_role_expiry_interval", + json_integer(data->user_role_expiry_interval)); + json_object_set_new(js, "username_len", + json_integer(data->username_len)); + json_object_set_new(js, "user_public_key_len", + json_integer(data->user_public_key_len)); + json_object_set_new(js, "certification_data_len", + json_integer(data->certification_data_len)); + if (data->username_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->username_len + 1]; + memcpy(tmpbuf, data->username, data->username_len); + tmpbuf[data->username_len] = '\0'; + json_object_set_new(js, "username", json_string(tmpbuf)); + } else { + json_object_set_new(js, "username", json_string("")); + } + unsigned long user_public_key_b64_len = data->user_public_key_len * 2; + uint8_t user_public_key_b64[user_public_key_b64_len]; + Base64Encode(data->user_public_key, data->user_public_key_len, + user_public_key_b64, &user_public_key_b64_len); + json_object_set_new(js, "data->user_public_key", + json_string((char *)user_public_key_b64)); + unsigned long certification_data_b64_len = data->certification_data_len * 2; + uint8_t certification_data_b64[certification_data_b64_len]; + Base64Encode(data->certification_data, data->certification_data_len, + certification_data_b64, &certification_data_b64_len); + json_object_set_new(js, "data->certification_data", + json_string((char *)certification_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *data = point->data; + json_object_set_new(js, "key_change_method", + json_integer(data->key_change_method)); + json_object_set_new(js, "username_len", + json_integer(data->username_len)); + json_object_set_new(js, "master_challenge_data_len", + json_integer(data->master_challenge_data_len)); + if (data->username_len > 0) { + /* First create a null terminated string as not all versions + * of jansson have json_stringn. */ + char tmpbuf[data->username_len + 1]; + memcpy(tmpbuf, data->username, data->username_len); + tmpbuf[data->username_len] = '\0'; + json_object_set_new(js, "username", json_string(tmpbuf)); + } else { + json_object_set_new(js, "username", json_string("")); + } + unsigned long master_challenge_data_b64_len = data->master_challenge_data_len * 2; + uint8_t master_challenge_data_b64[master_challenge_data_b64_len]; + Base64Encode(data->master_challenge_data, data->master_challenge_data_len, + master_challenge_data_b64, &master_challenge_data_b64_len); + json_object_set_new(js, "data->master_challenge_data", + json_string((char *)master_challenge_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + json_object_set_new(js, "challenge_data_len", + json_integer(data->challenge_data_len)); + unsigned long challenge_data_b64_len = data->challenge_data_len * 2; + uint8_t challenge_data_b64[challenge_data_b64_len]; + Base64Encode(data->challenge_data, data->challenge_data_len, + challenge_data_b64, &challenge_data_b64_len); + json_object_set_new(js, "data->challenge_data", + json_string((char *)challenge_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *data = point->data; + json_object_set_new(js, "ksq", + json_integer(data->ksq)); + json_object_set_new(js, "user_number", + json_integer(data->user_number)); + json_object_set_new(js, "encrypted_update_key_len", + json_integer(data->encrypted_update_key_len)); + unsigned long encrypted_update_key_data_b64_len = data->encrypted_update_key_len * 2; + uint8_t encrypted_update_key_data_b64[encrypted_update_key_data_b64_len]; + Base64Encode(data->encrypted_update_key_data, data->encrypted_update_key_len, + encrypted_update_key_data_b64, &encrypted_update_key_data_b64_len); + json_object_set_new(js, "data->encrypted_update_key_data", + json_string((char *)encrypted_update_key_data_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *data = point->data; + unsigned long digital_signature_b64_len = data->digital_signature_len * 2; + uint8_t digital_signature_b64[digital_signature_b64_len]; + Base64Encode(data->digital_signature, data->digital_signature_len, + digital_signature_b64, &digital_signature_b64_len); + json_object_set_new(js, "data->digital_signature", + json_string((char *)digital_signature_b64)); + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *data = point->data; + unsigned long mac_b64_len = data->mac_len * 2; + uint8_t mac_b64[mac_b64_len]; + Base64Encode(data->mac, data->mac_len, + mac_b64, &mac_b64_len); + json_object_set_new(js, "data->mac", + json_string((char *)mac_b64)); + break; + } + case DNP3_OBJECT_CODE(121, 1): { + DNP3ObjectG121V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "count_value", + json_integer(data->count_value)); + break; + } + case DNP3_OBJECT_CODE(122, 1): { + DNP3ObjectG122V1 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "count_value", + json_integer(data->count_value)); + break; + } + case DNP3_OBJECT_CODE(122, 2): { + DNP3ObjectG122V2 *data = point->data; + json_object_set_new(js, "online", + json_integer(data->online)); + json_object_set_new(js, "restart", + json_integer(data->restart)); + json_object_set_new(js, "comm_lost", + json_integer(data->comm_lost)); + json_object_set_new(js, "remote_forced", + json_integer(data->remote_forced)); + json_object_set_new(js, "local_forced", + json_integer(data->local_forced)); + json_object_set_new(js, "reserved0", + json_integer(data->reserved0)); + json_object_set_new(js, "discontinuity", + json_integer(data->discontinuity)); + json_object_set_new(js, "reserved1", + json_integer(data->reserved1)); + json_object_set_new(js, "association_id", + json_integer(data->association_id)); + json_object_set_new(js, "count_value", + json_integer(data->count_value)); + json_object_set_new(js, "timestamp", + json_integer(data->timestamp)); + break; + } + default: + SCLogDebug("Unknown object: %d:%d", object->group, + object->variation); + break; + } + +} + +#endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-dnp3-objects.h b/src/output-json-dnp3-objects.h new file mode 100644 index 000000000000..6517d0631da1 --- /dev/null +++ b/src/output-json-dnp3-objects.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __OUTPUT_JSON_DNP3_OBJECTS_H__ +#define __OUTPUT_JSON_DNP3_OBJECTS_H__ + +#ifdef HAVE_LIBJANSSON +void OutputJsonDNP3SetItem(json_t *js, DNP3Object *object, + DNP3Point *item); +#endif /* HAVE_LIBJANSSON */ + +#endif /* __OUTPUT_JSON_DNP3_OBJECTS_H__ */ diff --git a/src/output-json-dnp3.c b/src/output-json-dnp3.c new file mode 100644 index 000000000000..e726959d48e9 --- /dev/null +++ b/src/output-json-dnp3.c @@ -0,0 +1,449 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" +#include "util-buffer.h" +#include "util-crypt.h" +#include "util-debug.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#include "detect-dnp3.h" + +#include "output.h" +#include "output-json.h" +#include "output-json-dnp3-objects.h" + +#ifdef HAVE_LIBJANSSON +#include + +typedef struct LogDNP3FileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; + uint8_t include_object_data; +} LogDNP3FileCtx; + +typedef struct LogDNP3LogThread_ { + LogDNP3FileCtx *dnp3log_ctx; + uint32_t count; + MemBuffer *buffer; +} LogDNP3LogThread; + +static json_t *JsonDNP3LogLinkControl(uint8_t lc) +{ + json_t *lcjs = json_object(); + if (unlikely(lcjs == NULL)) { + return NULL; + } + + json_object_set_new(lcjs, "dir", json_boolean(DNP3_LINK_DIR(lc))); + json_object_set_new(lcjs, "pri", json_boolean(DNP3_LINK_PRI(lc))); + json_object_set_new(lcjs, "fcb", json_boolean(DNP3_LINK_FCB(lc))); + json_object_set_new(lcjs, "fcv", json_boolean(DNP3_LINK_FCV(lc))); + json_object_set_new(lcjs, "function_code", json_integer(DNP3_LINK_FC(lc))); + + return lcjs; +} + +static json_t *JsonDNP3LogIin(uint16_t iin) +{ + json_t *iinjs = json_object(); + if (unlikely(iinjs == NULL)) { + return NULL; + } + + json_t *indicators = json_array(); + if (unlikely(indicators == NULL)) { + json_decref(iinjs); + return NULL; + } + + if (iin) { + int mapping = 0; + do { + if (iin & DNP3IndicatorsMap[mapping].value) { + json_array_append_new(indicators, + json_string(DNP3IndicatorsMap[mapping].name)); + } + mapping++; + } while (DNP3IndicatorsMap[mapping].name != NULL); + } + json_object_set_new(iinjs, "indicators", indicators); + + return iinjs; +} + +static json_t *JsonDNP3LogApplicationControl(uint8_t ac) +{ + json_t *acjs = json_object(); + if (unlikely(acjs == NULL)) { + return NULL; + } + + json_object_set_new(acjs, "fir", json_boolean(DNP3_APP_FIR(ac))); + json_object_set_new(acjs, "fin", json_boolean(DNP3_APP_FIN(ac))); + json_object_set_new(acjs, "con", json_boolean(DNP3_APP_CON(ac))); + json_object_set_new(acjs, "uns", json_boolean(DNP3_APP_UNS(ac))); + json_object_set_new(acjs, "sequence", json_integer(DNP3_APP_SEQ(ac))); + + return acjs; +} + +/** + * \brief Log the items (points) for an object. + * + * TODO: Autogenerate this function based on object definitions. + */ +static json_t *JsonDNP3LogObjectItems(DNP3Object *object) +{ + DNP3Point *item; + json_t *jsitems; + + if (unlikely((jsitems = json_array()) == NULL)) { + return NULL; + } + + TAILQ_FOREACH(item, object->points, next) { + json_t *js = json_object(); + if (unlikely(js == NULL)) { + break; + } + + json_object_set_new(js, "prefix", json_integer(item->prefix)); + json_object_set_new(js, "index", json_integer(item->index)); + if (DNP3PrefixIsSize(object->prefix_code)) { + json_object_set_new(js, "size", json_integer(item->size)); + } + + OutputJsonDNP3SetItem(js, object, item); + json_array_append_new(jsitems, js); + } + + return jsitems; +} + +/** + * \brief Log the application layer objects. + * + * \param objects A list of DNP3 objects. + * + * \retval a json_t pointer containing the logged DNP3 objects. + */ +static json_t *JsonDNP3LogObjects(DNP3ObjectList *objects) +{ + DNP3Object *object; + json_t *js = json_array(); + if (unlikely(js == NULL)) { + return NULL; + } + + TAILQ_FOREACH(object, objects, next) { + json_t *objs = json_object(); + if (unlikely(objs == NULL)) { + goto error; + } + json_object_set_new(objs, "group", json_integer(object->group)); + json_object_set_new(objs, "variation", + json_integer(object->variation)); + json_object_set_new(objs, "qualifier", json_integer(object->qualifier)); + json_object_set_new(objs, "prefix_code", + json_integer(object->prefix_code)); + json_object_set_new(objs, "range_code", + json_integer(object->range_code)); + json_object_set_new(objs, "start", json_integer(object->start)); + json_object_set_new(objs, "stop", json_integer(object->stop)); + json_object_set_new(objs, "count", json_integer(object->count)); + + if (object->points != NULL && !TAILQ_EMPTY(object->points)) { + json_t *points = JsonDNP3LogObjectItems(object); + if (points != NULL) { + json_object_set_new(objs, "points", points); + } + } + + json_array_append_new(js, objs); + } + + return js; +error: + json_decref(js); + return NULL; +} + +json_t *JsonDNP3LogRequest(DNP3Transaction *dnp3tx) +{ + json_t *dnp3js = json_object(); + if (dnp3js == NULL) { + return NULL;; + } + json_object_set_new(dnp3js, "type", json_string("request")); + + json_t *lcjs = JsonDNP3LogLinkControl(dnp3tx->request_lh.control); + if (lcjs != NULL) { + json_object_set_new(dnp3js, "control", lcjs); + } + + json_object_set_new(dnp3js, "src", json_integer(dnp3tx->request_lh.src)); + json_object_set_new(dnp3js, "dst", json_integer(dnp3tx->request_lh.dst)); + + /* DNP3 application layer. */ + json_t *al = json_object(); + if (al == NULL) { + goto error; + } + json_object_set_new(dnp3js, "application", al); + + json_t *acjs = JsonDNP3LogApplicationControl(dnp3tx->request_ah.control); + if (acjs != NULL) { + json_object_set_new(al, "control", acjs); + } + + json_object_set_new(al, "function_code", + json_integer(dnp3tx->request_ah.function_code)); + + json_t *objects = JsonDNP3LogObjects(&dnp3tx->request_objects); + if (objects != NULL) { + json_object_set_new(al, "objects", objects); + } + json_object_set_new(al, "complete", + json_boolean(dnp3tx->request_complete)); + + return dnp3js; + +error: + json_decref(dnp3js); + return NULL; +} + +json_t *JsonDNP3LogResponse(DNP3Transaction *dnp3tx) +{ + json_t *dnp3js = json_object(); + if (dnp3js == NULL) { + return NULL; + } + if (dnp3tx->response_ah.function_code == DNP3_APP_FC_UNSOLICITED_RESP) { + json_object_set_new(dnp3js, "type", + json_string("unsolicited_response")); + } + else { + json_object_set_new(dnp3js, "type", json_string("response")); + } + + json_t *lcjs = JsonDNP3LogLinkControl(dnp3tx->response_lh.control); + if (lcjs != NULL) { + json_object_set_new(dnp3js, "control", lcjs); + } + + json_object_set_new(dnp3js, "src", json_integer(dnp3tx->response_lh.src)); + json_object_set_new(dnp3js, "dst", json_integer(dnp3tx->response_lh.dst)); + + /* DNP3 application layer. */ + json_t *al = json_object(); + if (al == NULL) { + goto error; + } + json_object_set_new(dnp3js, "application", al); + + json_t *acjs = JsonDNP3LogApplicationControl(dnp3tx->response_ah.control); + if (acjs != NULL) { + json_object_set_new(al, "control", acjs); + } + + json_object_set_new(al, "function_code", + json_integer(dnp3tx->response_ah.function_code)); + + json_t *iinjs = JsonDNP3LogIin(dnp3tx->response_iin.iin1 << 8 | + dnp3tx->response_iin.iin2); + if (iinjs != NULL) { + json_object_set_new(dnp3js, "iin", iinjs); + } + + json_t *objects = JsonDNP3LogObjects(&dnp3tx->response_objects); + if (objects != NULL) { + json_object_set_new(al, "objects", objects); + } + json_object_set_new(al, "complete", + json_boolean(dnp3tx->response_complete)); + + return dnp3js; + +error: + json_decref(dnp3js); + return NULL; +} + +static int JsonDNP3LoggerToServer(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + SCEnter(); + LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; + DNP3Transaction *tx = vtx; + + MemBuffer *buffer = (MemBuffer *)thread->buffer; + + MemBufferReset(buffer); + if (tx->has_request && tx->request_done) { + json_t *js = CreateJSONHeader((Packet *)p, 1, "dnp3"); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + json_t *dnp3js = JsonDNP3LogRequest(tx); + if (dnp3js != NULL) { + json_object_set_new(js, "dnp3", dnp3js); + OutputJSONBuffer(js, thread->dnp3log_ctx->file_ctx, &buffer); + } + json_decref(js); + } + + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDNP3LoggerToClient(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + SCEnter(); + LogDNP3LogThread *thread = (LogDNP3LogThread *)thread_data; + DNP3Transaction *tx = vtx; + + MemBuffer *buffer = (MemBuffer *)thread->buffer; + + MemBufferReset(buffer); + if (tx->has_response && tx->response_done) { + json_t *js = CreateJSONHeader((Packet *)p, 1, "dnp3"); + if (unlikely(js == NULL)) { + return TM_ECODE_OK; + } + json_t *dnp3js = JsonDNP3LogResponse(tx); + if (dnp3js != NULL) { + json_object_set_new(js, "dnp3", dnp3js); + OutputJSONBuffer(js, thread->dnp3log_ctx->file_ctx, &buffer); + } + json_decref(js); + } + + SCReturnInt(TM_ECODE_OK); +} + +static void OutputDNP3LogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + LogDNP3FileCtx *dnp3log_ctx = (LogDNP3FileCtx *)output_ctx->data; + SCFree(dnp3log_ctx); + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "dnp3.json" + +static OutputCtx *OutputDNP3LogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + LogDNP3FileCtx *dnp3log_ctx = SCCalloc(1, sizeof(*dnp3log_ctx)); + if (unlikely(dnp3log_ctx == NULL)) { + return NULL; + } + dnp3log_ctx->file_ctx = ajt->file_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(dnp3log_ctx); + return NULL; + } + output_ctx->data = dnp3log_ctx; + output_ctx->DeInit = OutputDNP3LogDeInitCtxSub; + + SCLogInfo("DNP3 log sub-module initialized."); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNP3); + + return output_ctx; +} + +#define OUTPUT_BUFFER_SIZE 65535 + +static TmEcode JsonDNP3LogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogDNP3LogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for DNP3. \"initdata\" is NULL."); + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (unlikely(thread->buffer == NULL)) { + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->dnp3log_ctx = ((OutputCtx *)initdata)->data; + *data = (void *)thread; + + return TM_ECODE_OK; +} + +static TmEcode JsonDNP3LogThreadDeinit(ThreadVars *t, void *data) +{ + LogDNP3LogThread *thread = (LogDNP3LogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + if (thread->buffer != NULL) { + MemBufferFree(thread->buffer); + } + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonDNP3LogRegister(void) +{ + /* Register direction aware eve sub-modules. */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNP3, "eve-log", + "JsonDNP3Log", "eve-log.dnp3", OutputDNP3LogInitSub, ALPROTO_DNP3, + JsonDNP3LoggerToServer, 0, 1, JsonDNP3LogThreadInit, + JsonDNP3LogThreadDeinit, NULL); + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNP3, "eve-log", + "JsonDNP3Log", "eve-log.dnp3", OutputDNP3LogInitSub, ALPROTO_DNP3, + JsonDNP3LoggerToClient, 1, 1, JsonDNP3LogThreadInit, + JsonDNP3LogThreadDeinit, NULL); +} + +#else + +void JsonDNP3LogRegister (void) +{ +} + +#endif diff --git a/src/output-json-dnp3.h b/src/output-json-dnp3.h new file mode 100644 index 000000000000..da1e0193007e --- /dev/null +++ b/src/output-json-dnp3.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __OUTPUT_JSON_DNP3_H__ +#define __OUTPUT_JSON_DNP3_H__ + +#include "app-layer-dnp3.h" + +#ifdef HAVE_LIBJANSSON +json_t *JsonDNP3LogRequest(DNP3Transaction *); +json_t *JsonDNP3LogResponse(DNP3Transaction *); +#endif /* HAVE_LIBJANSSON */ + +void JsonDNP3LogRegister(void); + +#endif /* __OUTPUT_JSON_DNP3_H__ */ diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 44494dbc0925..96689777ec24 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -51,15 +51,203 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include /* we can do query logging as well, but it's disabled for now as the * TX id handling doesn't expect it */ #define QUERY 0 +#define LOG_QUERIES BIT_U64(0) +#define LOG_ANSWERS BIT_U64(1) + +#define LOG_A BIT_U64(2) +#define LOG_NS BIT_U64(3) +#define LOG_MD BIT_U64(4) +#define LOG_MF BIT_U64(5) +#define LOG_CNAME BIT_U64(6) +#define LOG_SOA BIT_U64(7) +#define LOG_MB BIT_U64(8) +#define LOG_MG BIT_U64(9) +#define LOG_MR BIT_U64(10) +#define LOG_NULL BIT_U64(11) +#define LOG_WKS BIT_U64(12) +#define LOG_PTR BIT_U64(13) +#define LOG_HINFO BIT_U64(14) +#define LOG_MINFO BIT_U64(15) +#define LOG_MX BIT_U64(16) +#define LOG_TXT BIT_U64(17) +#define LOG_RP BIT_U64(18) +#define LOG_AFSDB BIT_U64(19) +#define LOG_X25 BIT_U64(20) +#define LOG_ISDN BIT_U64(21) +#define LOG_RT BIT_U64(22) +#define LOG_NSAP BIT_U64(23) +#define LOG_NSAPPTR BIT_U64(24) +#define LOG_SIG BIT_U64(25) +#define LOG_KEY BIT_U64(26) +#define LOG_PX BIT_U64(27) +#define LOG_GPOS BIT_U64(28) +#define LOG_AAAA BIT_U64(29) +#define LOG_LOC BIT_U64(30) +#define LOG_NXT BIT_U64(31) +#define LOG_SRV BIT_U64(32) +#define LOG_ATMA BIT_U64(33) +#define LOG_NAPTR BIT_U64(34) +#define LOG_KX BIT_U64(35) +#define LOG_CERT BIT_U64(36) +#define LOG_A6 BIT_U64(37) +#define LOG_DNAME BIT_U64(38) +#define LOG_OPT BIT_U64(39) +#define LOG_APL BIT_U64(40) +#define LOG_DS BIT_U64(41) +#define LOG_SSHFP BIT_U64(42) +#define LOG_IPSECKEY BIT_U64(43) +#define LOG_RRSIG BIT_U64(44) +#define LOG_NSEC BIT_U64(45) +#define LOG_DNSKEY BIT_U64(46) +#define LOG_DHCID BIT_U64(47) +#define LOG_NSEC3 BIT_U64(48) +#define LOG_NSEC3PARAM BIT_U64(49) +#define LOG_TLSA BIT_U64(50) +#define LOG_HIP BIT_U64(51) +#define LOG_CDS BIT_U64(52) +#define LOG_CDNSKEY BIT_U64(53) +#define LOG_SPF BIT_U64(54) +#define LOG_TKEY BIT_U64(55) +#define LOG_TSIG BIT_U64(56) +#define LOG_MAILA BIT_U64(57) +#define LOG_ANY BIT_U64(58) +#define LOG_URI BIT_U64(59) + +#define LOG_ALL_RRTYPES (~(uint64_t)(LOG_QUERIES|LOG_ANSWERS)) + +typedef enum { + DNS_RRTYPE_A = 0, + DNS_RRTYPE_NS, + DNS_RRTYPE_MD, + DNS_RRTYPE_MF, + DNS_RRTYPE_CNAME, + DNS_RRTYPE_SOA, + DNS_RRTYPE_MB, + DNS_RRTYPE_MG, + DNS_RRTYPE_MR, + DNS_RRTYPE_NULL, + DNS_RRTYPE_WKS, + DNS_RRTYPE_PTR, + DNS_RRTYPE_HINFO, + DNS_RRTYPE_MINFO, + DNS_RRTYPE_MX, + DNS_RRTYPE_TXT, + DNS_RRTYPE_RP, + DNS_RRTYPE_AFSDB, + DNS_RRTYPE_X25, + DNS_RRTYPE_ISDN, + DNS_RRTYPE_RT, + DNS_RRTYPE_NSAP, + DNS_RRTYPE_NSAPPTR, + DNS_RRTYPE_SIG, + DNS_RRTYPE_KEY, + DNS_RRTYPE_PX, + DNS_RRTYPE_GPOS, + DNS_RRTYPE_AAAA, + DNS_RRTYPE_LOC, + DNS_RRTYPE_NXT, + DNS_RRTYPE_SRV, + DNS_RRTYPE_ATMA, + DNS_RRTYPE_NAPTR, + DNS_RRTYPE_KX, + DNS_RRTYPE_CERT, + DNS_RRTYPE_A6, + DNS_RRTYPE_DNAME, + DNS_RRTYPE_OPT, + DNS_RRTYPE_APL, + DNS_RRTYPE_DS, + DNS_RRTYPE_SSHFP, + DNS_RRTYPE_IPSECKEY, + DNS_RRTYPE_RRSIG, + DNS_RRTYPE_NSEC, + DNS_RRTYPE_DNSKEY, + DNS_RRTYPE_DHCID, + DNS_RRTYPE_NSEC3, + DNS_RRTYPE_NSEC3PARAM, + DNS_RRTYPE_TLSA, + DNS_RRTYPE_HIP, + DNS_RRTYPE_CDS, + DNS_RRTYPE_CDNSKEY, + DNS_RRTYPE_SPF, + DNS_RRTYPE_TKEY, + DNS_RRTYPE_TSIG, + DNS_RRTYPE_MAILA, + DNS_RRTYPE_ANY, + DNS_RRTYPE_URI +} DnsRRTypes; + +static struct { + char *config_rrtype; + uint64_t flags; +} dns_rrtype_fields[] = { + { "a", LOG_A }, + { "ns", LOG_NS }, + { "md", LOG_MD }, + { "mf", LOG_MF }, + { "cname", LOG_CNAME }, + { "soa", LOG_SOA }, + { "mb", LOG_MB }, + { "mg", LOG_MG }, + { "mr", LOG_MR }, + { "null", LOG_NULL }, + { "wks", LOG_WKS }, + { "ptr", LOG_PTR }, + { "hinfo", LOG_HINFO }, + { "minfo", LOG_MINFO }, + { "mx", LOG_MX }, + { "txt", LOG_TXT }, + { "rp", LOG_RP }, + { "afsdb", LOG_AFSDB }, + { "x25", LOG_X25 }, + { "isdn", LOG_ISDN }, + { "rt", LOG_RT }, + { "nsap", LOG_NSAP }, + { "nsapptr", LOG_NSAPPTR }, + { "sig", LOG_SIG }, + { "key", LOG_KEY }, + { "px", LOG_PX }, + { "gpos", LOG_GPOS }, + { "aaaa", LOG_AAAA }, + { "loc", LOG_LOC }, + { "nxt", LOG_NXT }, + { "srv", LOG_SRV }, + { "atma", LOG_ATMA }, + { "naptr", LOG_NAPTR }, + { "kx", LOG_KX }, + { "cert", LOG_CERT }, + { "a6", LOG_A6 }, + { "dname", LOG_DNAME }, + { "opt", LOG_OPT }, + { "apl", LOG_APL }, + { "ds", LOG_DS }, + { "sshfp", LOG_SSHFP }, + { "ipseckey", LOG_IPSECKEY }, + { "rrsig", LOG_RRSIG }, + { "nsec", LOG_NSEC }, + { "dnskey", LOG_DNSKEY }, + { "dhcid", LOG_DHCID }, + { "nsec3", LOG_NSEC3 }, + { "nsec3param", LOG_NSEC3PARAM }, + { "tlsa", LOG_TLSA }, + { "hip", LOG_HIP }, + { "cds", LOG_CDS }, + { "cdnskey", LOG_CDNSKEY }, + { "spf", LOG_SPF }, + { "tkey", LOG_TKEY }, + { "tsig", LOG_TSIG }, + { "maila", LOG_MAILA }, + { "any", LOG_ANY }, + { "uri", LOG_URI } +}; + typedef struct LogDnsFileCtx_ { LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ + uint64_t flags; /** Store mode */ } LogDnsFileCtx; typedef struct LogDnsLogThread_ { @@ -70,20 +258,153 @@ typedef struct LogDnsLogThread_ { MemBuffer *buffer; } LogDnsLogThread; +static int DNSRRTypeEnabled(uint16_t type, uint64_t flags) +{ + if (likely(flags == ~0UL)) { + return 1; + } + + switch (type) { + case DNS_RECORD_TYPE_A: + return ((flags & LOG_A) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NS: + return ((flags & LOG_NS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MD: + return ((flags & LOG_MD) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MF: + return ((flags & LOG_MF) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CNAME: + return ((flags & LOG_CNAME) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SOA: + return ((flags & LOG_SOA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MB: + return ((flags & LOG_MB) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MG: + return ((flags & LOG_MG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MR: + return ((flags & LOG_MR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NULL: + return ((flags & LOG_NULL) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_WKS: + return ((flags & LOG_WKS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_PTR: + return ((flags & LOG_PTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_HINFO: + return ((flags & LOG_HINFO) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MINFO: + return ((flags & LOG_MINFO) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MX: + return ((flags & LOG_MX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TXT: + return ((flags & LOG_TXT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RP: + return ((flags & LOG_RP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_AFSDB: + return ((flags & LOG_AFSDB) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_X25: + return ((flags & LOG_X25) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ISDN: + return ((flags & LOG_ISDN) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RT: + return ((flags & LOG_RT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSAP: + return ((flags & LOG_NSAP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSAPPTR: + return ((flags & LOG_NSAPPTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SIG: + return ((flags & LOG_SIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_KEY: + return ((flags & LOG_KEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_PX: + return ((flags & LOG_PX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_GPOS: + return ((flags & LOG_GPOS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_AAAA: + return ((flags & LOG_AAAA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_LOC: + return ((flags & LOG_LOC) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NXT: + return ((flags & LOG_NXT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SRV: + return ((flags & LOG_SRV) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ATMA: + return ((flags & LOG_ATMA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NAPTR: + return ((flags & LOG_NAPTR) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_KX: + return ((flags & LOG_KX) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CERT: + return ((flags & LOG_CERT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_A6: + return ((flags & LOG_A6) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DNAME: + return ((flags & LOG_DNAME) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_OPT: + return ((flags & LOG_OPT) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_APL: + return ((flags & LOG_APL) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DS: + return ((flags & LOG_DS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SSHFP: + return ((flags & LOG_SSHFP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_IPSECKEY: + return ((flags & LOG_IPSECKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_RRSIG: + return ((flags & LOG_RRSIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC: + return ((flags & LOG_NSEC) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DNSKEY: + return ((flags & LOG_DNSKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_DHCID: + return ((flags & LOG_DHCID) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC3: + return ((flags & LOG_NSEC3) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_NSEC3PARAM: + return ((flags & LOG_NSEC3PARAM) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TLSA: + return ((flags & LOG_TLSA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_HIP: + return ((flags & LOG_HIP) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CDS: + return ((flags & LOG_CDS) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_CDNSKEY: + return ((flags & LOG_CDNSKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_SPF: + return ((flags & LOG_SPF) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TKEY: + return ((flags & LOG_TKEY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_TSIG: + return ((flags & LOG_TSIG) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_MAILA: + return ((flags & LOG_MAILA) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_ANY: + return ((flags & LOG_ANY) != 0) ? 1 : 0; + case DNS_RECORD_TYPE_URI: + return ((flags & LOG_URI) != 0) ? 1 : 0; + default: + return 0; + } +} + +static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, + uint64_t tx_id, DNSQueryEntry *entry) __attribute__((nonnull)); + static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; - SCLogDebug("got a DNS request and now logging !!"); + if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + return; + } + json_t *djs = json_object(); if (djs == NULL) { return; } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); /* type */ json_object_set_new(djs, "type", json_string("query")); @@ -109,13 +430,20 @@ static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, /* dns */ json_object_set_new(js, "dns", djs); - OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(js, "dns"); } -static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, DNSAnswerEntry *entry) +static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSAnswerEntry *entry) __attribute__((nonnull)); + +static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSAnswerEntry *entry) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; + if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + return; + } + json_t *js = json_object(); if (js == NULL) return; @@ -126,55 +454,134 @@ static void OutputAnswer(LogDnsLogThread *aft, json_t *djs, DNSTransaction *tx, /* id */ json_object_set_new(js, "id", json_integer(tx->tx_id)); - if (entry != NULL) { - /* query */ - if (entry->fqdn_len > 0) { - char *c; - c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)), - entry->fqdn_len); - if (c != NULL) { - json_object_set_new(js, "rrname", json_string(c)); - SCFree(c); - } + /* rcode */ + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + json_object_set_new(js, "rcode", json_string(rcode)); + + /* query */ + if (entry->fqdn_len > 0) { + char *c; + c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)), + entry->fqdn_len); + if (c != NULL) { + json_object_set_new(js, "rrname", json_string(c)); + SCFree(c); } + } - /* name */ - char record[16] = ""; - DNSCreateTypeString(entry->type, record, sizeof(record)); - json_object_set_new(js, "rrtype", json_string(record)); - - /* ttl */ - json_object_set_new(js, "ttl", json_integer(entry->ttl)); - - uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len); - if (entry->type == DNS_RECORD_TYPE_A) { - char a[16] = ""; - PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); - json_object_set_new(js, "rdata", json_string(a)); - } else if (entry->type == DNS_RECORD_TYPE_AAAA) { - char a[46] = ""; - PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); - json_object_set_new(js, "rdata", json_string(a)); - } else if (entry->data_len == 0) { + /* name */ + char record[16] = ""; + DNSCreateTypeString(entry->type, record, sizeof(record)); + json_object_set_new(js, "rrtype", json_string(record)); + + /* ttl */ + json_object_set_new(js, "ttl", json_integer(entry->ttl)); + + uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len); + if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) { + char a[16] = ""; + PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); + json_object_set_new(js, "rdata", json_string(a)); + } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) { + char a[46] = ""; + PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); + json_object_set_new(js, "rdata", json_string(a)); + } else if (entry->data_len == 0) { + json_object_set_new(js, "rdata", json_string("")); + } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME || + entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR || + entry->type == DNS_RECORD_TYPE_NS) { + if (entry->data_len != 0) { + char buffer[256] = ""; + uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ? + entry->data_len : sizeof(buffer) - 1; + memcpy(buffer, ptr, copy_len); + buffer[copy_len] = '\0'; + json_object_set_new(js, "rdata", json_string(buffer)); + } else { json_object_set_new(js, "rdata", json_string("")); - } else if (entry->type == DNS_RECORD_TYPE_TXT) { - if (entry->data_len != 0) { - char buffer[256] = ""; - uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ? - entry->data_len : sizeof(buffer) - 1; - memcpy(buffer, ptr, copy_len); - buffer[copy_len] = '\0'; - json_object_set_new(js, "rdata", json_string(buffer)); - } else { - json_object_set_new(js, "rdata", json_string("")); + } + } else if (entry->type == DNS_RECORD_TYPE_SSHFP) { + if (entry->data_len > 2) { + /* get algo and type */ + uint8_t algo = *ptr; + uint8_t fptype = *(ptr+1); + + /* turn fp raw buffer into a nice :-separate hex string */ + uint16_t fp_len = (entry->data_len - 2); + uint8_t *dptr = ptr+2; + + /* c-string for ':' separated hex and trailing \0. */ + uint32_t output_len = fp_len * 3 + 1; + char hexstring[output_len]; + memset(hexstring, 0x00, output_len); + + uint16_t x; + for (x = 0; x < fp_len; x++) { + char one[4]; + snprintf(one, sizeof(one), x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]); + strlcat(hexstring, one, output_len); + } + + /* wrap the whole thing in it's own structure */ + json_t *hjs = json_object(); + if (hjs != NULL) { + json_object_set_new(hjs, "fingerprint", json_string(hexstring)); + json_object_set_new(hjs, "algo", json_integer(algo)); + json_object_set_new(hjs, "type", json_integer(fptype)); + + json_object_set_new(js, "sshfp", hjs); } } } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); + json_object_set_new(djs, "dns", js); + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); + json_object_del(djs, "dns"); + + return; +} + +static void OutputFailure(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSQueryEntry *entry) __attribute__((nonnull)); + +static void OutputFailure(LogDnsLogThread *aft, json_t *djs, + DNSTransaction *tx, DNSQueryEntry *entry) +{ + if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) { + return; + } + + json_t *js = json_object(); + if (js == NULL) + return; + + /* type */ + json_object_set_new(js, "type", json_string("answer")); + + /* id */ + json_object_set_new(js, "id", json_integer(tx->tx_id)); + + /* rcode */ + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + json_object_set_new(js, "rcode", json_string(rcode)); + + /* no answer RRs, use query for rname */ + char *c; + c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSQueryEntry)), entry->len); + if (c != NULL) { + json_object_set_new(js, "rrname", json_string(c)); + SCFree(c); + } + + /* reset */ + MemBufferReset(aft->buffer); json_object_set_new(djs, "dns", js); - OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, buffer); + OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer); json_object_del(djs, "dns"); return; @@ -185,8 +592,15 @@ static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uin SCLogDebug("got a DNS response and now logging !!"); - if (tx->no_such_name) { - OutputAnswer(aft, js, tx, NULL); + /* rcode != noerror */ + if (tx->rcode) { + /* Most DNS servers do not support multiple queries because + * the rcode in response is not per-query. Multiple queries + * are likely to lead to FORMERR, so log this. */ + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + OutputFailure(aft, js, tx, query); + } } DNSAnswerEntry *entry = NULL; @@ -201,32 +615,51 @@ static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uin } -static int JsonDnsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) +static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) { SCEnter(); LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; DNSTransaction *tx = txptr; json_t *js; - DNSQueryEntry *query = NULL; - TAILQ_FOREACH(query, &tx->query_list, next) { - js = CreateJSONHeader((Packet *)p, 1, "dns"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; + if (likely(dnslog_ctx->flags & LOG_QUERIES) != 0) { + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + js = CreateJSONHeader((Packet *)p, 1, "dns"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; - LogQuery(td, js, tx, tx_id, query); + LogQuery(td, js, tx, tx_id, query); - json_decref(js); + json_decref(js); + } } - js = CreateJSONHeader((Packet *)p, 0, "dns"); - if (unlikely(js == NULL)) - return TM_ECODE_OK; + SCReturnInt(TM_ECODE_OK); +} + +static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id) +{ + SCEnter(); + + LogDnsLogThread *td = (LogDnsLogThread *)thread_data; + LogDnsFileCtx *dnslog_ctx = td->dnslog_ctx; + DNSTransaction *tx = txptr; + json_t *js; + + if (likely(dnslog_ctx->flags & LOG_ANSWERS) != 0) { + js = CreateJSONHeader((Packet *)p, 0, "dns"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; - LogAnswers(td, js, tx, tx_id); + LogAnswers(td, js, tx, tx_id); - json_decref(js); + json_decref(js); + } SCReturnInt(TM_ECODE_OK); } @@ -241,7 +674,7 @@ static TmEcode LogDnsLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for DNSLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogDNS. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -290,9 +723,54 @@ static void LogDnsLogDeInitCtxSub(OutputCtx *output_ctx) SCFree(output_ctx); } +static void JsonDnsLogInitFilters(LogDnsFileCtx *dnslog_ctx, ConfNode *conf) +{ + dnslog_ctx->flags = ~0UL; + + if (conf) { + const char *query = ConfNodeLookupChildValue(conf, "query"); + if (query != NULL) { + if (ConfValIsTrue(query)) { + dnslog_ctx->flags |= LOG_QUERIES; + } else { + dnslog_ctx->flags &= ~LOG_QUERIES; + } + } + const char *response = ConfNodeLookupChildValue(conf, "answer"); + if (response != NULL) { + if (ConfValIsTrue(response)) { + dnslog_ctx->flags |= LOG_ANSWERS; + } else { + dnslog_ctx->flags &= ~LOG_ANSWERS; + } + } + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { + dnslog_ctx->flags &= ~LOG_ALL_RRTYPES; + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) + { + if (field != NULL) + { + DnsRRTypes f; + for (f = DNS_RRTYPE_A; f < DNS_RRTYPE_TXT; f++) + { + if (strcasecmp(dns_rrtype_fields[f].config_rrtype, + field->val) == 0) + { + dnslog_ctx->flags |= dns_rrtype_fields[f].flags; + break; + } + } + } + } + } + } +} + static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogDnsFileCtx *dnslog_ctx = SCMalloc(sizeof(LogDnsFileCtx)); if (unlikely(dnslog_ctx == NULL)) { @@ -300,7 +778,7 @@ static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) } memset(dnslog_ctx, 0x00, sizeof(LogDnsFileCtx)); - dnslog_ctx->file_ctx = ajt->file_ctx; + dnslog_ctx->file_ctx = ojc->file_ctx; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { @@ -311,6 +789,8 @@ static OutputCtx *JsonDnsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) output_ctx->data = dnslog_ctx; output_ctx->DeInit = LogDnsLogDeInitCtxSub; + JsonDnsLogInitFilters(dnslog_ctx, conf); + SCLogDebug("DNS log sub-module initialized"); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); @@ -333,7 +813,7 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } @@ -357,6 +837,8 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) output_ctx->data = dnslog_ctx; output_ctx->DeInit = LogDnsLogDeInitCtx; + JsonDnsLogInitFilters(dnslog_ctx, conf); + SCLogDebug("DNS log output initialized"); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); @@ -367,33 +849,35 @@ static OutputCtx *JsonDnsLogInitCtx(ConfNode *conf) #define MODULE_NAME "JsonDnsLog" -void TmModuleJsonDnsLogRegister (void) +void JsonDnsLogRegister (void) { - tmm_modules[TMM_JSONDNSLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONDNSLOG].ThreadInit = LogDnsLogThreadInit; - tmm_modules[TMM_JSONDNSLOG].ThreadDeinit = LogDnsLogThreadDeinit; - tmm_modules[TMM_JSONDNSLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONDNSLOG].cap_flags = 0; - tmm_modules[TMM_JSONDNSLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterTxModule(MODULE_NAME, "dns-json-log", JsonDnsLogInitCtx, - ALPROTO_DNS, JsonDnsLogger); - OutputRegisterTxSubModule("eve-log", MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, - ALPROTO_DNS, JsonDnsLogger); + /* Logger for requests. */ + OutputRegisterTxModuleWithProgress(LOGGER_JSON_DNS, MODULE_NAME, + "dns-json-log", JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToServer, + 0, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); + + /* Logger for replies. */ + OutputRegisterTxModuleWithProgress(LOGGER_JSON_DNS, MODULE_NAME, + "dns-json-log", JsonDnsLogInitCtx, ALPROTO_DNS, JsonDnsLoggerToClient, + 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); + + /* Sub-logger for requests. */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNS, "eve-log", + MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, ALPROTO_DNS, + JsonDnsLoggerToServer, 0, 1, LogDnsLogThreadInit, + LogDnsLogThreadDeinit, NULL); + + /* Sub-logger for replies. */ + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_DNS, "eve-log", + MODULE_NAME, "eve-log.dns", JsonDnsLogInitCtxSub, ALPROTO_DNS, + JsonDnsLoggerToClient, 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, + NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonDnsLogRegister (void) +void JsonDnsLogRegister (void) { - tmm_modules[TMM_JSONDNSLOG].name = "JsonDnsLog"; - tmm_modules[TMM_JSONDNSLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-dns.h b/src/output-json-dns.h index f26227e37480..9c3e88011578 100644 --- a/src/output-json-dns.h +++ b/src/output-json-dns.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_DNS_H__ #define __OUTPUT_JSON_DNS_H__ -void TmModuleJsonDnsLogRegister (void); +void JsonDnsLogRegister(void); #endif /* __OUTPUT_JSON_DNS_H__ */ diff --git a/src/output-json-drop.c b/src/output-json-drop.c index 19a4f071199c..e26fd6dcb6ed 100644 --- a/src/output-json-drop.c +++ b/src/output-json-drop.c @@ -36,7 +36,6 @@ #include "util-debug.h" #include "decode-ipv4.h" -#include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -44,6 +43,7 @@ #include "output.h" #include "output-json.h" +#include "output-json-alert.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -58,14 +58,22 @@ #define MODULE_NAME "JsonDropLog" #ifdef HAVE_LIBJANSSON -#include + +#define LOG_DROP_ALERTS 1 + +typedef struct JsonDropOutputCtx_ { + LogFileCtx *file_ctx; + uint8_t flags; +} JsonDropOutputCtx; typedef struct JsonDropLogThread_ { - /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ - LogFileCtx* file_ctx; + JsonDropOutputCtx *drop_ctx; MemBuffer *buffer; } JsonDropLogThread; +/* default to true as this has been the default behavior for a long time */ +static int g_droplog_flows_start = 1; + /** * \brief Log the dropped packets in netfilter format when engine is running * in inline mode @@ -78,7 +86,6 @@ typedef struct JsonDropLogThread_ { static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) { uint16_t proto = 0; - MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = CreateJSONHeader((Packet *)p, 0, "drop");//TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; @@ -90,7 +97,7 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); if (PKT_IS_IPV4(p)) { json_object_set_new(djs, "len", json_integer(IPV4_GET_IPLEN(p))); @@ -107,20 +114,24 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) } switch (proto) { case IPPROTO_TCP: - json_object_set_new(djs, "tcpseq", json_integer(TCP_GET_SEQ(p))); - json_object_set_new(djs, "tcpack", json_integer(TCP_GET_ACK(p))); - json_object_set_new(djs, "tcpwin", json_integer(TCP_GET_WINDOW(p))); - json_object_set_new(djs, "syn", TCP_ISSET_FLAG_SYN(p) ? json_true() : json_false()); - json_object_set_new(djs, "ack", TCP_ISSET_FLAG_ACK(p) ? json_true() : json_false()); - json_object_set_new(djs, "psh", TCP_ISSET_FLAG_PUSH(p) ? json_true() : json_false()); - json_object_set_new(djs, "rst", TCP_ISSET_FLAG_RST(p) ? json_true() : json_false()); - json_object_set_new(djs, "urg", TCP_ISSET_FLAG_URG(p) ? json_true() : json_false()); - json_object_set_new(djs, "fin", TCP_ISSET_FLAG_FIN(p) ? json_true() : json_false()); - json_object_set_new(djs, "tcpres", json_integer(TCP_GET_RAW_X2(p->tcph))); - json_object_set_new(djs, "tcpurgp", json_integer(TCP_GET_URG_POINTER(p))); + if (PKT_IS_TCP(p)) { + json_object_set_new(djs, "tcpseq", json_integer(TCP_GET_SEQ(p))); + json_object_set_new(djs, "tcpack", json_integer(TCP_GET_ACK(p))); + json_object_set_new(djs, "tcpwin", json_integer(TCP_GET_WINDOW(p))); + json_object_set_new(djs, "syn", TCP_ISSET_FLAG_SYN(p) ? json_true() : json_false()); + json_object_set_new(djs, "ack", TCP_ISSET_FLAG_ACK(p) ? json_true() : json_false()); + json_object_set_new(djs, "psh", TCP_ISSET_FLAG_PUSH(p) ? json_true() : json_false()); + json_object_set_new(djs, "rst", TCP_ISSET_FLAG_RST(p) ? json_true() : json_false()); + json_object_set_new(djs, "urg", TCP_ISSET_FLAG_URG(p) ? json_true() : json_false()); + json_object_set_new(djs, "fin", TCP_ISSET_FLAG_FIN(p) ? json_true() : json_false()); + json_object_set_new(djs, "tcpres", json_integer(TCP_GET_RAW_X2(p->tcph))); + json_object_set_new(djs, "tcpurgp", json_integer(TCP_GET_URG_POINTER(p))); + } break; case IPPROTO_UDP: - json_object_set_new(djs, "udplen", json_integer(UDP_GET_LEN(p))); + if (PKT_IS_UDP(p)) { + json_object_set_new(djs, "udplen", json_integer(UDP_GET_LEN(p))); + } break; case IPPROTO_ICMP: if (PKT_IS_ICMPV4(p)) { @@ -133,7 +144,31 @@ static int DropLogJSON (JsonDropLogThread *aft, const Packet *p) break; } json_object_set_new(js, "drop", djs); - OutputJSONBuffer(js, aft->file_ctx, buffer); + + if (aft->drop_ctx->flags & LOG_DROP_ALERTS) { + int logged = 0; + int i; + for (i = 0; i < p->alerts.cnt; i++) { + const PacketAlert *pa = &p->alerts.alerts[i]; + if (unlikely(pa->s == NULL)) { + continue; + } + if ((pa->action & (ACTION_REJECT|ACTION_REJECT_DST|ACTION_REJECT_BOTH)) || + ((pa->action & ACTION_DROP) && EngineModeIsIPS())) + { + AlertJsonHeader(p, pa, js); + logged = 1; + } + } + if (logged == 0) { + if (p->alerts.drop.action != 0) { + const PacketAlert *pa = &p->alerts.drop; + AlertJsonHeader(p, pa, js); + } + } + } + + OutputJSONBuffer(js, aft->drop_ctx->file_ctx, &aft->buffer); json_object_del(js, "drop"); json_object_clear(js); json_decref(js); @@ -148,9 +183,10 @@ static TmEcode JsonDropLogThreadInit(ThreadVars *t, void *initdata, void **data) if (unlikely(aft == NULL)) return TM_ECODE_FAILED; memset(aft, 0, sizeof(*aft)); + if(initdata == NULL) { - SCLogDebug("Error getting context for AlertFastLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogDrop. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -162,7 +198,7 @@ static TmEcode JsonDropLogThreadInit(ThreadVars *t, void *initdata, void **data) } /** Use the Ouptut Context (file pointer and mutex) */ - aft->file_ctx = ((OutputCtx *)initdata)->data; + aft->drop_ctx = ((OutputCtx *)initdata)->data; *data = (void *)aft; return TM_ECODE_OK; @@ -184,12 +220,21 @@ static TmEcode JsonDropLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } +static void JsonDropOutputCtxFree(JsonDropOutputCtx *drop_ctx) +{ + if (drop_ctx != NULL) { + if (drop_ctx->file_ctx != NULL) + LogFileFreeCtx(drop_ctx->file_ctx); + SCFree(drop_ctx); + } +} + static void JsonDropLogDeInitCtx(OutputCtx *output_ctx) { OutputDropLoggerDisable(); - LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; - LogFileFreeCtx(logfile_ctx); + JsonDropOutputCtx *drop_ctx = output_ctx->data; + JsonDropOutputCtxFree(drop_ctx); SCFree(output_ctx); } @@ -197,6 +242,8 @@ static void JsonDropLogDeInitCtxSub(OutputCtx *output_ctx) { OutputDropLoggerDisable(); + JsonDropOutputCtx *drop_ctx = output_ctx->data; + SCFree(drop_ctx); SCLogDebug("cleaning up sub output_ctx %p", output_ctx); SCFree(output_ctx); } @@ -210,22 +257,48 @@ static OutputCtx *JsonDropLogInitCtx(ConfNode *conf) return NULL; } - LogFileCtx *logfile_ctx = LogFileNewCtx(); - if (logfile_ctx == NULL) { + JsonDropOutputCtx *drop_ctx = SCCalloc(1, sizeof(*drop_ctx)); + if (drop_ctx == NULL) + return NULL; + + drop_ctx->file_ctx = LogFileNewCtx(); + if (drop_ctx->file_ctx == NULL) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } - if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) { - LogFileFreeCtx(logfile_ctx); + if (SCConfLogOpenGeneric(conf, drop_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } - output_ctx->data = logfile_ctx; + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "alerts"); + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + drop_ctx->flags = LOG_DROP_ALERTS; + } + } + extended = ConfNodeLookupChildValue(conf, "flows"); + if (extended != NULL) { + if (strcasecmp(extended, "start") == 0) { + g_droplog_flows_start = 1; + } else if (strcasecmp(extended, "all") == 0) { + g_droplog_flows_start = 0; + } else { + SCLogWarning(SC_ERR_CONF_YAML_ERROR, "valid options for " + "'flow' are 'start' and 'all'"); + } + } + } + + output_ctx->data = drop_ctx; output_ctx->DeInit = JsonDropLogDeInitCtx; return output_ctx; } @@ -240,12 +313,39 @@ static OutputCtx *JsonDropLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) AlertJsonThread *ajt = parent_ctx->data; + JsonDropOutputCtx *drop_ctx = SCCalloc(1, sizeof(*drop_ctx)); + if (drop_ctx == NULL) + return NULL; + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { + JsonDropOutputCtxFree(drop_ctx); return NULL; } - output_ctx->data = ajt->file_ctx; + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "alerts"); + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + drop_ctx->flags = LOG_DROP_ALERTS; + } + } + extended = ConfNodeLookupChildValue(conf, "flows"); + if (extended != NULL) { + if (strcasecmp(extended, "start") == 0) { + g_droplog_flows_start = 1; + } else if (strcasecmp(extended, "all") == 0) { + g_droplog_flows_start = 0; + } else { + SCLogWarning(SC_ERR_CONF_YAML_ERROR, "valid options for " + "'flow' are 'start' and 'all'"); + } + } + } + + drop_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = drop_ctx; output_ctx->DeInit = JsonDropLogDeInitCtxSub; return output_ctx; } @@ -266,15 +366,16 @@ static int JsonDropLogger(ThreadVars *tv, void *thread_data, const Packet *p) if (r < 0) return -1; + if (!g_droplog_flows_start) + return 0; + if (p->flow) { - FLOWLOCK_RDLOCK(p->flow); if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) p->flow->flags |= FLOW_TOSERVER_DROP_LOGGED; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) p->flow->flags |= FLOW_TOCLIENT_DROP_LOGGED; } - FLOWLOCK_UNLOCK(p->flow); } return 0; } @@ -299,16 +400,21 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) return FALSE; } - if (p->flow != NULL) { + if (g_droplog_flows_start && p->flow != NULL) { int ret = FALSE; - FLOWLOCK_RDLOCK(p->flow); + + /* for a flow that will be dropped fully, log just once per direction */ if (p->flow->flags & FLOW_ACTION_DROP) { if (PKT_IS_TOSERVER(p) && !(p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) ret = TRUE; else if (PKT_IS_TOCLIENT(p) && !(p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) ret = TRUE; } - FLOWLOCK_UNLOCK(p->flow); + + /* if drop is caused by signature, log anyway */ + if (p->alerts.drop.action != 0) + ret = TRUE; + return ret; } else if (PACKET_TEST_ACTION(p, ACTION_DROP)) { return TRUE; @@ -317,32 +423,21 @@ static int JsonDropLogCondition(ThreadVars *tv, const Packet *p) return FALSE; } -void TmModuleJsonDropLogRegister (void) +void JsonDropLogRegister (void) { - tmm_modules[TMM_JSONDROPLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONDROPLOG].ThreadInit = JsonDropLogThreadInit; - tmm_modules[TMM_JSONDROPLOG].ThreadDeinit = JsonDropLogThreadDeinit; - tmm_modules[TMM_JSONDROPLOG].cap_flags = 0; - tmm_modules[TMM_JSONDROPLOG].flags = TM_FLAG_LOGAPI_TM; - - OutputRegisterPacketModule(MODULE_NAME, "drop-json-log", - JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition); - OutputRegisterPacketSubModule("eve-log", MODULE_NAME, "eve-log.drop", - JsonDropLogInitCtxSub, JsonDropLogger, JsonDropLogCondition); + OutputRegisterPacketModule(LOGGER_JSON_DROP, MODULE_NAME, "drop-json-log", + JsonDropLogInitCtx, JsonDropLogger, JsonDropLogCondition, + JsonDropLogThreadInit, JsonDropLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_DROP, "eve-log", MODULE_NAME, + "eve-log.drop", JsonDropLogInitCtxSub, JsonDropLogger, + JsonDropLogCondition, JsonDropLogThreadInit, JsonDropLogThreadDeinit, + NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonDropLogRegister (void) +void JsonDropLogRegister (void) { - tmm_modules[TMM_JSONDROPLOG].name = MODULE_NAME; - tmm_modules[TMM_JSONDROPLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-drop.h b/src/output-json-drop.h index c02057c14cbb..d4fc9a16283c 100644 --- a/src/output-json-drop.h +++ b/src/output-json-drop.h @@ -25,6 +25,6 @@ #ifndef __OUTPUT_JSON_DROP_H__ #define __OUTPUT_JSON_DROP_H__ -void TmModuleJsonDropLogRegister (void); +void JsonDropLogRegister(void); #endif /* __OUTPUT_DROPLOG_H__ */ diff --git a/src/output-json-email-common.c b/src/output-json-email-common.c new file mode 100644 index 000000000000..a802b4a1218b --- /dev/null +++ b/src/output-json-email-common.c @@ -0,0 +1,470 @@ +/* Copyright (C) 2007-2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * \author Eric Leblond + * + * Implements json common email logging portion of the engine. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "tm-threads-common.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" +#include "app-layer-parser.h" +#include "output.h" +#include "app-layer-smtp.h" +#include "app-layer.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-byte.h" + +#include "util-logopenfile.h" +#include "util-crypt.h" + +#include "output-json.h" +#include "output-json-email-common.h" + +#ifdef HAVE_LIBJANSSON + +#define LOG_EMAIL_DEFAULT 0 +#define LOG_EMAIL_EXTENDED (1<<0) +#define LOG_EMAIL_ARRAY (1<<1) /* require array handling */ +#define LOG_EMAIL_COMMA (1<<2) /* require array handling */ +#define LOG_EMAIL_BODY_MD5 (1<<3) +#define LOG_EMAIL_SUBJECT_MD5 (1<<4) + +struct { + char *config_field; + char *email_field; + uint32_t flags; +} email_fields[] = { + { "reply_to", "reply-to", LOG_EMAIL_DEFAULT }, + { "bcc", "bcc", LOG_EMAIL_COMMA|LOG_EMAIL_EXTENDED }, + { "message_id", "message-id", LOG_EMAIL_EXTENDED }, + { "subject", "subject", LOG_EMAIL_EXTENDED }, + { "x_mailer", "x-mailer", LOG_EMAIL_EXTENDED }, + { "user_agent", "user-agent", LOG_EMAIL_EXTENDED }, + { "received", "received", LOG_EMAIL_ARRAY }, + { "x_originating_ip", "x-originating-ip", LOG_EMAIL_DEFAULT }, + { "in_reply_to", "in-reply-to", LOG_EMAIL_DEFAULT }, + { "references", "references", LOG_EMAIL_DEFAULT }, + { "importance", "importance", LOG_EMAIL_DEFAULT }, + { "priority", "priority", LOG_EMAIL_DEFAULT }, + { "sensitivity", "sensitivity", LOG_EMAIL_DEFAULT }, + { "organization", "organization", LOG_EMAIL_DEFAULT }, + { "content_md5", "content-md5", LOG_EMAIL_DEFAULT }, + { "date", "date", LOG_EMAIL_DEFAULT }, + { NULL, NULL, LOG_EMAIL_DEFAULT}, +}; + +static inline char *SkipWhiteSpaceTill(char *p, char *savep) +{ + char *sp = p; + if (unlikely(p == NULL)) { + return NULL; + } + while (((*sp == '\t') || (*sp == ' ')) && (sp < savep)) { + sp++; + } + return sp; +} + +static json_t* JsonEmailJsonArrayFromCommaList(const uint8_t *val, size_t len) +{ + json_t *ajs = json_array(); + if (likely(ajs != NULL)) { + char *savep = NULL; + char *p; + char *sp; + char *to_line = BytesToString((uint8_t *)val, len); + if (likely(to_line != NULL)) { + p = strtok_r(to_line, ",", &savep); + if (p == NULL) { + json_decref(ajs); + SCFree(to_line); + return NULL; + } + sp = SkipWhiteSpaceTill(p, savep); + json_array_append_new(ajs, json_string(sp)); + while ((p = strtok_r(NULL, ",", &savep)) != NULL) { + sp = SkipWhiteSpaceTill(p, savep); + json_array_append_new(ajs, json_string(sp)); + } + } else { + json_decref(ajs); + return NULL; + } + SCFree(to_line); + } + + return ajs; +} + + +#ifdef HAVE_NSS +static void JsonEmailLogJSONMd5(OutputJsonEmailCtx *email_ctx, json_t *js, SMTPTransaction *tx) +{ + if (email_ctx->flags & LOG_EMAIL_SUBJECT_MD5) { + MimeDecField *field; + MimeDecEntity *entity = tx->msg_tail; + if (entity == NULL) { + return; + } + field = MimeDecFindField(entity, "subject"); + if (field != NULL) { + unsigned char md5[MD5_LENGTH]; + char smd5[256]; + char *value = BytesToString((uint8_t *)field->value , field->value_len); + if (value) { + size_t i,x; + HASH_HashBuf(HASH_AlgMD5, md5, (unsigned char *)value, strlen(value)); + for (i = 0, x = 0; x < sizeof(md5); x++) { + i += snprintf(smd5 + i, 255 - i, "%02x", md5[x]); + } + json_object_set_new(js, "subject_md5", json_string(smd5)); + SCFree(value); + } + } + } + + if (email_ctx->flags & LOG_EMAIL_BODY_MD5) { + MimeDecParseState *mime_state = tx->mime_state; + if (mime_state && mime_state->md5_ctx && (mime_state->state_flag == PARSE_DONE)) { + size_t x; + int i; + char s[256]; + if (likely(s != NULL)) { + for (i = 0, x = 0; x < sizeof(mime_state->md5); x++) { + i += snprintf(s + i, 255-i, "%02x", mime_state->md5[x]); + } + json_object_set_new(js, "body_md5", json_string(s)); + } + } + } +} +#endif + +static int JsonEmailAddToJsonArray(const uint8_t *val, size_t len, void *data) +{ + json_t *ajs = data; + + if (ajs == NULL) + return 0; + char *value = BytesToString((uint8_t *)val, len); + json_array_append_new(ajs, json_string(value)); + SCFree(value); + return 1; +} + +static void JsonEmailLogJSONCustom(OutputJsonEmailCtx *email_ctx, json_t *js, SMTPTransaction *tx) +{ + int f = 0; + MimeDecField *field; + MimeDecEntity *entity = tx->msg_tail; + if (entity == NULL) { + return; + } + + while(email_fields[f].config_field) { + if (((email_ctx->fields & (1ULL<flags & LOG_EMAIL_EXTENDED) && (email_fields[f].flags & LOG_EMAIL_EXTENDED)) + ) { + if (email_fields[f].flags & LOG_EMAIL_ARRAY) { + json_t *ajs = json_array(); + if (ajs) { + int found = MimeDecFindFieldsForEach(entity, email_fields[f].email_field, JsonEmailAddToJsonArray, ajs); + if (found > 0) { + json_object_set_new(js, email_fields[f].config_field, ajs); + } else { + json_decref(ajs); + } + } + } else if (email_fields[f].flags & LOG_EMAIL_COMMA) { + field = MimeDecFindField(entity, email_fields[f].email_field); + if (field) { + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(js, email_fields[f].config_field, ajs); + } + } + } else { + field = MimeDecFindField(entity, email_fields[f].email_field); + if (field != NULL) { + char *s = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + if (likely(s != NULL)) { + json_object_set_new(js, email_fields[f].config_field, json_string(s)); + SCFree(s); + } + } + } + + } + f++; + } +} + +/* JSON format logging */ +json_t *JsonEmailLogJsonData(const Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + SMTPState *smtp_state; + MimeDecParseState *mime_state; + MimeDecEntity *entity; + + json_t *sjs = json_object(); + if (sjs == NULL) { + SCReturnPtr(NULL, "json_t"); + } + + /* check if we have SMTP state or not */ + AppProto proto = FlowGetAppProtocol(f); + switch (proto) { + case ALPROTO_SMTP: + smtp_state = (SMTPState *)state; + if (smtp_state == NULL) { + SCLogDebug("no smtp state, so no request logging"); + json_decref(sjs); + SCReturnPtr(NULL, "json_t"); + } + SMTPTransaction *tx = vtx; + mime_state = tx->mime_state; + entity = tx->msg_tail; + SCLogDebug("lets go mime_state %p, entity %p, state_flag %u", mime_state, entity, mime_state ? mime_state->state_flag : 0); + break; + default: + /* don't know how we got here */ + json_decref(sjs); + SCReturnPtr(NULL, "json_t"); + } + if ((mime_state != NULL)) { + if (entity == NULL) { + json_decref(sjs); + SCReturnPtr(NULL, "json_t"); + } + + json_object_set_new(sjs, "status", + json_string(MimeDecParseStateGetStatus(mime_state))); + + MimeDecField *field; + + /* From: */ + field = MimeDecFindField(entity, "from"); + if (field != NULL) { + char *s = BytesToString((uint8_t *)field->value, + (size_t)field->value_len); + if (likely(s != NULL)) { + //printf("From: \"%s\"\n", s); + char * sp = SkipWhiteSpaceTill(s, s + strlen(s)); + json_object_set_new(sjs, "from", json_string(sp)); + SCFree(s); + } + } + + /* To: */ + field = MimeDecFindField(entity, "to"); + if (field != NULL) { + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(sjs, "to", ajs); + } + } + + /* Cc: */ + field = MimeDecFindField(entity, "cc"); + if (field != NULL) { + json_t *ajs = JsonEmailJsonArrayFromCommaList(field->value, field->value_len); + if (ajs) { + json_object_set_new(sjs, "cc", ajs); + } + } + + if (mime_state->stack == NULL || mime_state->stack->top == NULL || mime_state->stack->top->data == NULL) { + json_decref(sjs); + SCReturnPtr(NULL, "json_t"); + } + + entity = (MimeDecEntity *)mime_state->stack->top->data; + int attch_cnt = 0; + int url_cnt = 0; + json_t *js_attch = json_array(); + json_t *js_url = json_array(); + if (entity->url_list != NULL) { + MimeDecUrl *url; + for (url = entity->url_list; url != NULL; url = url->next) { + char *s = BytesToString((uint8_t *)url->url, + (size_t)url->url_len); + if (s != NULL) { + json_array_append_new(js_url, + json_string(s)); + SCFree(s); + url_cnt += 1; + } + } + } + for (entity = entity->child; entity != NULL; entity = entity->next) { + if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) { + + char *s = BytesToString((uint8_t *)entity->filename, + (size_t)entity->filename_len); + json_array_append_new(js_attch, + json_string(s)); + SCFree(s); + attch_cnt += 1; + } + if (entity->url_list != NULL) { + MimeDecUrl *url; + for (url = entity->url_list; url != NULL; url = url->next) { + char *s = BytesToString((uint8_t *)url->url, + (size_t)url->url_len); + if (s != NULL) { + json_array_append_new(js_url, + json_string(s)); + SCFree(s); + url_cnt += 1; + } + } + } + } + if (attch_cnt > 0) { + json_object_set_new(sjs, "attachment", js_attch); + } else { + json_decref(js_attch); + } + if (url_cnt > 0) { + json_object_set_new(sjs, "url", js_url); + } else { + json_decref(js_url); + } + SCReturnPtr(sjs, "json_t"); + } + + json_decref(sjs); + SCReturnPtr(NULL, "json_t"); +} + +/* JSON format logging */ +TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + json_t *sjs = JsonEmailLogJsonData(f, state, vtx, tx_id); + OutputJsonEmailCtx *email_ctx = aft->emaillog_ctx; + SMTPTransaction *tx = (SMTPTransaction *) vtx; + + if (sjs == NULL) { + SCReturnInt(TM_ECODE_FAILED); + } + + if ((email_ctx->flags & LOG_EMAIL_EXTENDED) || (email_ctx->fields != 0)) + JsonEmailLogJSONCustom(email_ctx, sjs, tx); + +#ifdef HAVE_NSS + JsonEmailLogJSONMd5(email_ctx, sjs, tx); +#endif + + if (sjs) { + json_object_set_new(js, "email", sjs); + SCReturnInt(TM_ECODE_OK); + } else + SCReturnInt(TM_ECODE_FAILED); +} + +json_t *JsonEmailAddMetadata(const Flow *f, uint32_t tx_id) +{ + SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); + if (smtp_state) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); + + if (tx) { + return JsonEmailLogJsonData(f, smtp_state, tx, tx_id); + } + } + + return NULL; +} + + +void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx) +{ + if (conf) { + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + + if (extended != NULL) { + if (ConfValIsTrue(extended)) { + email_ctx->flags = LOG_EMAIL_EXTENDED; + } + } + + email_ctx->fields = 0; + ConfNode *custom; + if ((custom = ConfNodeLookupChild(conf, "custom")) != NULL) { + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) { + if (field != NULL) { + int f = 0; + while(email_fields[f].config_field) { + if ((strcmp(email_fields[f].config_field, + field->val) == 0) || + (strcasecmp(email_fields[f].email_field, + field->val) == 0)) + { + email_ctx->fields |= (1ULL<flags = 0; + ConfNode *md5_conf; + if ((md5_conf = ConfNodeLookupChild(conf, "md5")) != NULL) { + ConfNode *field; + TAILQ_FOREACH(field, &md5_conf->head, next) { + if (field != NULL) { + if (strcmp("body", field->val) == 0) { + SCLogInfo("Going to log the md5 sum of email body"); + email_ctx->flags |= LOG_EMAIL_BODY_MD5; + } + if (strcmp("subject", field->val) == 0) { + SCLogInfo("Going to log the md5 sum of email subject"); + email_ctx->flags |= LOG_EMAIL_SUBJECT_MD5; + } + } + } + } + } + return; +} + + +#endif diff --git a/src/output-json-email-common.h b/src/output-json-email-common.h new file mode 100644 index 000000000000..88cfa5576b03 --- /dev/null +++ b/src/output-json-email-common.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_EMAIL_COMMON_H__ +#define __OUTPUT_JSON_EMAIL_COMMON_H__ + +typedef struct OutputJsonEmailCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ + uint64_t fields;/** Store fields */ +} OutputJsonEmailCtx; + + +#ifdef HAVE_LIBJANSSON +typedef struct JsonEmailLogThread_ { + OutputJsonEmailCtx *emaillog_ctx; + MemBuffer *buffer; +} JsonEmailLogThread; + +TmEcode JsonEmailLogJson(JsonEmailLogThread *aft, json_t *js, const Packet *p, Flow *f, void *state, void *vtx, uint64_t tx_id); +json_t *JsonEmailAddMetadata(const Flow *f, uint32_t tx_id); +#endif + +void OutputEmailInitConf(ConfNode *conf, OutputJsonEmailCtx *email_ctx); + +#endif /* __OUTPUT_JSON_EMAIL_COMMON_H__ */ diff --git a/src/output-json-file.c b/src/output-json-file.c index aacb60c6c16d..e840b669c842 100644 --- a/src/output-json-file.c +++ b/src/output-json-file.c @@ -51,18 +51,20 @@ #include "util-buffer.h" #include "util-byte.h" -#include "output.h" -#include "output-json.h" - #include "log-file.h" #include "util-logopenfile.h" +#include "output.h" +#include "output-json.h" +#include "output-json-http.h" +#include "output-json-smtp.h" +#include "output-json-email-common.h" + #include "app-layer-htp.h" #include "util-memcmp.h" #include "stream-tcp-reassemble.h" #ifdef HAVE_LIBJANSSON -#include typedef struct OutputFileCtx_ { LogFileCtx *file_ctx; @@ -74,128 +76,41 @@ typedef struct JsonFileLogThread_ { MemBuffer *buffer; } JsonFileLogThread; -static json_t *LogFileMetaGetUri(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL) { - HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); - if (tx_ud != NULL && tx_ud->request_uri_normalized != NULL) { - char *s = bstr_util_strdup_to_c(tx_ud->request_uri_normalized); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - } - - return NULL; -} - -static json_t *LogFileMetaGetHost(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL && tx->request_hostname != NULL) { - char *s = bstr_util_strdup_to_c(tx->request_hostname); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - - return NULL; -} - -static json_t *LogFileMetaGetReferer(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL) { - htp_header_t *h = NULL; - h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "Referer"); - if (h != NULL) { - char *s = bstr_util_strdup_to_c(h->value); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - } - - return NULL; -} - -static json_t *LogFileMetaGetUserAgent(const Packet *p, const File *ff) -{ - HtpState *htp_state = (HtpState *)p->flow->alstate; - json_t *js = NULL; - if (htp_state != NULL) { - htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, ff->txid); - if (tx != NULL) { - htp_header_t *h = NULL; - h = (htp_header_t *)htp_table_get_c(tx->request_headers, - "User-Agent"); - if (h != NULL) { - char *s = bstr_util_strdup_to_c(h->value); - if (s != NULL) { - js = json_string(s); - SCFree(s); - if (js != NULL) - return js; - } - } - } - } - - return NULL; -} - /** * \internal * \brief Write meta data on a single line json record */ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const File *ff) { - MemBuffer *buffer = (MemBuffer *)aft->buffer; json_t *js = CreateJSONHeader((Packet *)p, 0, "fileinfo"); //TODO const + json_t *hjs = NULL; if (unlikely(js == NULL)) return; /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); - json_t *hjs = json_object(); - if (unlikely(hjs == NULL)) { - json_decref(js); - return; + switch (p->flow->alproto) { + case ALPROTO_HTTP: + hjs = JsonHttpAddMetadata(p->flow, ff->txid); + if (hjs) + json_object_set_new(js, "http", hjs); + break; + case ALPROTO_SMTP: + hjs = JsonSMTPAddMetadata(p->flow, ff->txid); + if (hjs) + json_object_set_new(js, "smtp", hjs); + hjs = JsonEmailAddMetadata(p->flow, ff->txid); + if (hjs) + json_object_set_new(js, "email", hjs); + break; } - json_object_set_new(hjs, "url", LogFileMetaGetUri(p, ff)); - json_object_set_new(hjs, "hostname", LogFileMetaGetHost(p, ff)); - json_object_set_new(hjs, "http_refer", LogFileMetaGetReferer(p, ff)); - json_object_set_new(hjs, "http_user_agent", LogFileMetaGetUserAgent(p, ff)); - json_object_set_new(js, "http", hjs); + json_object_set_new(js, "app_proto", + json_string(AppProtoToString(p->flow->alproto))); json_t *fjs = json_object(); if (unlikely(fjs == NULL)) { - json_decref(hjs); json_decref(js); return; } @@ -204,8 +119,10 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F json_object_set_new(fjs, "filename", json_string(s)); if (s != NULL) SCFree(s); +#ifdef HAVE_MAGIC if (ff->magic) json_object_set_new(fjs, "magic", json_string((char *)ff->magic)); +#endif switch (ff->state) { case FILE_STATE_CLOSED: json_object_set_new(fjs, "state", json_string("CLOSED")); @@ -213,14 +130,29 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F if (ff->flags & FILE_MD5) { size_t x; int i; - char *s = SCMalloc(256); - if (likely(s != NULL)) { - for (i = 0, x = 0; x < sizeof(ff->md5); x++) { - i += snprintf(&s[i], 255-i, "%02x", ff->md5[x]); - } - json_object_set_new(fjs, "md5", json_string(s)); - SCFree(s); + char str[256]; + for (i = 0, x = 0; x < sizeof(ff->md5); x++) { + i += snprintf(&str[i], 255-i, "%02x", ff->md5[x]); + } + json_object_set_new(fjs, "md5", json_string(str)); + } + if (ff->flags & FILE_SHA1) { + size_t x; + int i; + char str[256]; + for (i = 0, x = 0; x < sizeof(ff->sha1); x++) { + i += snprintf(&str[i], 255-i, "%02x", ff->sha1[x]); + } + json_object_set_new(fjs, "sha1", json_string(str)); + } + if (ff->flags & FILE_SHA256) { + size_t x; + int i; + char str[256]; + for (i = 0, x = 0; x < sizeof(ff->sha256); x++) { + i += snprintf(&str[i], 255-i, "%02x", ff->sha256[x]); } + json_object_set_new(fjs, "sha256", json_string(str)); } #endif break; @@ -236,14 +168,26 @@ static void FileWriteJsonRecord(JsonFileLogThread *aft, const Packet *p, const F } json_object_set_new(fjs, "stored", (ff->flags & FILE_STORED) ? json_true() : json_false()); - json_object_set_new(fjs, "size", json_integer(ff->size)); + if (ff->flags & FILE_STORED) { + json_object_set_new(fjs, "file_id", json_integer(ff->file_id)); + } + json_object_set_new(fjs, "size", json_integer(FileTrackedSize(ff))); json_object_set_new(fjs, "tx_id", json_integer(ff->txid)); /* originally just 'file', but due to bug 1127 naming it fileinfo */ json_object_set_new(js, "fileinfo", fjs); - OutputJSONBuffer(js, aft->filelog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, aft->filelog_ctx->file_ctx, &aft->buffer); json_object_del(js, "fileinfo"); - json_object_del(js, "http"); + + switch (p->flow->alproto) { + case ALPROTO_HTTP: + json_object_del(js, "http"); + break; + case ALPROTO_SMTP: + json_object_del(js, "smtp"); + json_object_del(js, "email"); + break; + } json_object_clear(js); json_decref(js); @@ -273,7 +217,7 @@ static TmEcode JsonFileLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogFile. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -319,7 +263,7 @@ static void OutputFileLogDeinitSub(OutputCtx *output_ctx) * */ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; OutputFileCtx *output_file_ctx = SCMalloc(sizeof(OutputFileCtx)); if (unlikely(output_file_ctx == NULL)) @@ -331,24 +275,22 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - output_file_ctx->file_ctx = ajt->file_ctx; + output_file_ctx->file_ctx = ojc->file_ctx; if (conf) { + const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore"); + if (force_filestore != NULL && ConfValIsTrue(force_filestore)) { + FileForceFilestoreEnable(); + SCLogConfig("forcing filestore of all files"); + } + const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); if (force_magic != NULL && ConfValIsTrue(force_magic)) { FileForceMagicEnable(); - SCLogInfo("forcing magic lookup for logged files"); + SCLogConfig("forcing magic lookup for logged files"); } - const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); - if (force_md5 != NULL && ConfValIsTrue(force_md5)) { -#ifdef HAVE_NSS - FileForceMd5Enable(); - SCLogInfo("forcing md5 calculation for logged files"); -#else - SCLogInfo("md5 calculation requires linking against libnss"); -#endif - } + FileForceHashParseCfg(conf); } output_ctx->data = output_file_ctx; @@ -358,30 +300,18 @@ OutputCtx *OutputFileLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return output_ctx; } -void TmModuleJsonFileLogRegister (void) +void JsonFileLogRegister (void) { - tmm_modules[TMM_JSONFILELOG].name = "JsonFileLog"; - tmm_modules[TMM_JSONFILELOG].ThreadInit = JsonFileLogThreadInit; - tmm_modules[TMM_JSONFILELOG].ThreadDeinit = JsonFileLogThreadDeinit; - tmm_modules[TMM_JSONFILELOG].flags = TM_FLAG_LOGAPI_TM; - /* register as child of eve-log */ - OutputRegisterFileSubModule("eve-log", "JsonFileLog", "eve-log.files", - OutputFileLogInitSub, JsonFileLogger); + OutputRegisterFileSubModule(LOGGER_JSON_FILE, "eve-log", "JsonFileLog", + "eve-log.files", OutputFileLogInitSub, JsonFileLogger, + JsonFileLogThreadInit, JsonFileLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonFileLogRegister (void) +void JsonFileLogRegister (void) { - tmm_modules[TMM_JSONFILELOG].name = "JsonFileLog"; - tmm_modules[TMM_JSONFILELOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-file.h b/src/output-json-file.h index e101897f7bf2..680724f6cbb5 100644 --- a/src/output-json-file.h +++ b/src/output-json-file.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_FILE_H__ #define __OUTPUT_JSON_FILE_H__ -void TmModuleJsonFileLogRegister (void); +void JsonFileLogRegister(void); #endif /* __OUTPUT_JSON_FILE_H__ */ diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 760234d4b162..e2d7c1b5c255 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -49,7 +49,6 @@ #include "stream-tcp-private.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogJsonFileCtx_ { LogFileCtx *file_ctx; @@ -188,7 +187,16 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) return; } - json_object_set_new(hjs, "app_proto", json_string(AppProtoToString(f->alproto))); + json_object_set_new(js, "app_proto", + json_string(AppProtoToString(f->alproto))); + if (f->alproto_ts != f->alproto) { + json_object_set_new(js, "app_proto_ts", + json_string(AppProtoToString(f->alproto_ts))); + } + if (f->alproto_tc != f->alproto) { + json_object_set_new(js, "app_proto_tc", + json_string(AppProtoToString(f->alproto_tc))); + } json_object_set_new(hjs, "pkts_toserver", json_integer(f->todstpktcnt)); @@ -220,6 +228,24 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) state = "established"; else if (f->flow_end_flags & FLOW_END_FLAG_STATE_CLOSED) state = "closed"; + else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) { + state = "bypassed"; + int flow_state = SC_ATOMIC_GET(f->flow_state); + switch (flow_state) { + case FLOW_STATE_LOCAL_BYPASSED: + json_object_set_new(hjs, "bypass", + json_string("local")); + break; + case FLOW_STATE_CAPTURE_BYPASSED: + json_object_set_new(hjs, "bypass", + json_string("capture")); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Invalid flow state: %d, contact developers", + flow_state); + } + } json_object_set_new(hjs, "state", json_string(state)); @@ -235,6 +261,8 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) json_object_set_new(hjs, "reason", json_string(reason)); + json_object_set_new(hjs, "alerted", json_boolean(FlowHasAlerts(f))); + json_object_set_new(js, "flow", hjs); @@ -247,7 +275,7 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) TcpSession *ssn = f->protoctx; - char hexflags[3] = ""; + char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->tcp_packet_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); @@ -263,46 +291,46 @@ static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f) JsonTcpFlags(ssn ? ssn->tcp_packet_flags : 0, tjs); if (ssn) { - char *state = NULL; + char *tcp_state = NULL; switch (ssn->state) { case TCP_NONE: - state = "none"; + tcp_state = "none"; break; case TCP_LISTEN: - state = "listen"; + tcp_state = "listen"; break; case TCP_SYN_SENT: - state = "syn_sent"; + tcp_state = "syn_sent"; break; case TCP_SYN_RECV: - state = "syn_recv"; + tcp_state = "syn_recv"; break; case TCP_ESTABLISHED: - state = "established"; + tcp_state = "established"; break; case TCP_FIN_WAIT1: - state = "fin_wait1"; + tcp_state = "fin_wait1"; break; case TCP_FIN_WAIT2: - state = "fin_wait2"; + tcp_state = "fin_wait2"; break; case TCP_TIME_WAIT: - state = "time_wait"; + tcp_state = "time_wait"; break; case TCP_LAST_ACK: - state = "last_ack"; + tcp_state = "last_ack"; break; case TCP_CLOSE_WAIT: - state = "close_wait"; + tcp_state = "close_wait"; break; case TCP_CLOSING: - state = "closing"; + tcp_state = "closing"; break; case TCP_CLOSED: - state = "closed"; + tcp_state = "closed"; break; } - json_object_set_new(tjs, "state", json_string(state)); + json_object_set_new(tjs, "state", json_string(tcp_state)); } json_object_set_new(js, "tcp", tjs); @@ -313,10 +341,9 @@ static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) { SCEnter(); JsonFlowLogThread *jhl = (JsonFlowLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); json_t *js = CreateJSONHeaderFromFlow(f, "flow"); //TODO const if (unlikely(js == NULL)) @@ -324,7 +351,7 @@ static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) JsonFlowLogJSON(jhl, js, f); - OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "http"); json_object_clear(js); @@ -348,11 +375,11 @@ OutputCtx *OutputFlowLogInit(ConfNode *conf) SCLogInfo("hi"); LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_FLOW_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } @@ -386,7 +413,7 @@ static void OutputFlowLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogJsonFileCtx *flow_ctx = SCMalloc(sizeof(LogJsonFileCtx)); if (unlikely(flow_ctx == NULL)) @@ -398,7 +425,7 @@ OutputCtx *OutputFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - flow_ctx->file_ctx = ajt->file_ctx; + flow_ctx->file_ctx = ojc->file_ctx; flow_ctx->flags = LOG_HTTP_DEFAULT; output_ctx->data = flow_ctx; @@ -417,7 +444,7 @@ static TmEcode JsonFlowLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogFlow. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -450,36 +477,23 @@ static TmEcode JsonFlowLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonFlowLogRegister (void) +void JsonFlowLogRegister (void) { - tmm_modules[TMM_JSONFLOWLOG].name = "JsonFlowLog"; - tmm_modules[TMM_JSONFLOWLOG].ThreadInit = JsonFlowLogThreadInit; - tmm_modules[TMM_JSONFLOWLOG].ThreadDeinit = JsonFlowLogThreadDeinit; - tmm_modules[TMM_JSONFLOWLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONFLOWLOG].cap_flags = 0; - tmm_modules[TMM_JSONFLOWLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ - OutputRegisterFlowModule("JsonFlowLog", "flow-json-log", - OutputFlowLogInit, JsonFlowLogger); + OutputRegisterFlowModule(LOGGER_JSON_FLOW, "JsonFlowLog", "flow-json-log", + OutputFlowLogInit, JsonFlowLogger, JsonFlowLogThreadInit, + JsonFlowLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterFlowSubModule("eve-log", "JsonFlowLog", "eve-log.flow", - OutputFlowLogInitSub, JsonFlowLogger); + OutputRegisterFlowSubModule(LOGGER_JSON_FLOW, "eve-log", "JsonFlowLog", + "eve-log.flow", OutputFlowLogInitSub, JsonFlowLogger, + JsonFlowLogThreadInit, JsonFlowLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonFlowLogRegister (void) +void JsonFlowLogRegister (void) { - tmm_modules[TMM_JSONFLOWLOG].name = "JsonFlowLog"; - tmm_modules[TMM_JSONFLOWLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-flow.h b/src/output-json-flow.h index 1d32c9eb6812..439af9385704 100644 --- a/src/output-json-flow.h +++ b/src/output-json-flow.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_FLOW_H__ #define __OUTPUT_JSON_FLOW_H__ -void TmModuleJsonFlowLogRegister (void); +void JsonFlowLogRegister(void); #endif /* __OUTPUT_JSON_FLOW_H__ */ diff --git a/src/output-json-http.c b/src/output-json-http.c index b5a63bf294d0..a22025278063 100644 --- a/src/output-json-http.c +++ b/src/output-json-http.c @@ -50,7 +50,6 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogHttpFileCtx_ { LogFileCtx *file_ctx; @@ -92,6 +91,8 @@ typedef enum { HTTP_FIELD_X_REQUESTED_WITH, HTTP_FIELD_DNT, HTTP_FIELD_X_FORWARDED_PROTO, + HTTP_FIELD_X_AUTHENTICATED_USER, + HTTP_FIELD_X_FLASH_VERSION, HTTP_FIELD_ACCEPT_RANGES, HTTP_FIELD_AGE, HTTP_FIELD_ALLOW, @@ -147,6 +148,8 @@ struct { { "x_requested_with", "x-requested-with", LOG_HTTP_REQUEST }, { "dnt", "dnt", LOG_HTTP_REQUEST }, { "x_forwarded_proto", "x-forwarded-proto", LOG_HTTP_REQUEST }, + { "x_authenticated_user", "x-authenticated-user", LOG_HTTP_REQUEST }, + { "x_flash_version", "x-flash-version", LOG_HTTP_REQUEST }, { "accept_range", "accept-range", 0 }, { "age", "age", 0 }, { "allow", "allow", 0 }, @@ -327,7 +330,8 @@ void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx) if (tx->response_status != NULL) { c = bstr_util_strdup_to_c(tx->response_status); if (c != NULL) { - json_object_set_new(js, "status", json_string(c)); + unsigned int val = strtoul(c, NULL, 10); + json_object_set_new(js, "status", json_integer(val)); SCFree(c); } @@ -361,9 +365,6 @@ static void JsonHttpLogJSON(JsonHttpLogThread *aft, json_t *js, htp_tx_t *tx, ui if (http_ctx->flags & LOG_HTTP_EXTENDED) JsonHttpLogJSONExtended(hjs, tx); - /* tx id for correlation with alerts */ - json_object_set_new(hjs, "tx_id", json_integer(tx_id)); - json_object_set_new(js, "http", hjs); } @@ -373,20 +374,19 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl htp_tx_t *tx = txptr; JsonHttpLogThread *jhl = (JsonHttpLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; - json_t *js = CreateJSONHeader((Packet *)p, 1, "http"); //TODO const + json_t *js = CreateJSONHeaderWithTxId((Packet *)p, 1, "http", tx_id); //TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; SCLogDebug("got a HTTP request and now logging !!"); /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); JsonHttpLogJSON(jhl, js, tx, tx_id); - OutputJSONBuffer(js, jhl->httplog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->httplog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "http"); json_object_clear(js); @@ -395,6 +395,27 @@ static int JsonHttpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl SCReturnInt(TM_ECODE_OK); } +json_t *JsonHttpAddMetadata(const Flow *f, uint64_t tx_id) +{ + HtpState *htp_state = (HtpState *)FlowGetAppState(f); + if (htp_state) { + htp_tx_t *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_HTTP, htp_state, tx_id); + + if (tx) { + json_t *hjs = json_object(); + if (unlikely(hjs == NULL)) + return NULL; + + JsonHttpLogJSONBasic(hjs, tx); + JsonHttpLogJSONExtended(hjs, tx); + + return hjs; + } + } + + return NULL; +} + static void OutputHttpLogDeinit(OutputCtx *output_ctx) { LogHttpFileCtx *http_ctx = output_ctx->data; @@ -413,7 +434,7 @@ OutputCtx *OutputHttpLogInit(ConfNode *conf) return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } @@ -461,7 +482,7 @@ static void OutputHttpLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputHttpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogHttpFileCtx *http_ctx = SCMalloc(sizeof(LogHttpFileCtx)); if (unlikely(http_ctx == NULL)) @@ -474,7 +495,7 @@ OutputCtx *OutputHttpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - http_ctx->file_ctx = ajt->file_ctx; + http_ctx->file_ctx = ojc->file_ctx; http_ctx->flags = LOG_HTTP_DEFAULT; if (conf) { @@ -528,7 +549,7 @@ static TmEcode JsonHttpLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogHTTP. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -561,36 +582,23 @@ static TmEcode JsonHttpLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonHttpLogRegister (void) +void JsonHttpLogRegister (void) { - tmm_modules[TMM_JSONHTTPLOG].name = "JsonHttpLog"; - tmm_modules[TMM_JSONHTTPLOG].ThreadInit = JsonHttpLogThreadInit; - tmm_modules[TMM_JSONHTTPLOG].ThreadDeinit = JsonHttpLogThreadDeinit; - tmm_modules[TMM_JSONHTTPLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONHTTPLOG].cap_flags = 0; - tmm_modules[TMM_JSONHTTPLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ - OutputRegisterTxModule("JsonHttpLog", "http-json-log", OutputHttpLogInit, - ALPROTO_HTTP, JsonHttpLogger); + OutputRegisterTxModule(LOGGER_JSON_HTTP, "JsonHttpLog", "http-json-log", + OutputHttpLogInit, ALPROTO_HTTP, JsonHttpLogger, JsonHttpLogThreadInit, + JsonHttpLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterTxSubModule("eve-log", "JsonHttpLog", "eve-log.http", OutputHttpLogInitSub, - ALPROTO_HTTP, JsonHttpLogger); + OutputRegisterTxSubModule(LOGGER_JSON_HTTP, "eve-log", "JsonHttpLog", + "eve-log.http", OutputHttpLogInitSub, ALPROTO_HTTP, JsonHttpLogger, + JsonHttpLogThreadInit, JsonHttpLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonHttpLogRegister (void) +void JsonHttpLogRegister (void) { - tmm_modules[TMM_JSONHTTPLOG].name = "JsonHttpLog"; - tmm_modules[TMM_JSONHTTPLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-http.h b/src/output-json-http.h index ab412d227c94..eda68c2acc75 100644 --- a/src/output-json-http.h +++ b/src/output-json-http.h @@ -24,11 +24,12 @@ #ifndef __OUTPUT_JSON_HTTP_H__ #define __OUTPUT_JSON_HTTP_H__ -void TmModuleJsonHttpLogRegister (void); +void JsonHttpLogRegister(void); #ifdef HAVE_LIBJANSSON void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx); void JsonHttpLogJSONExtended(json_t *js, htp_tx_t *tx); +json_t *JsonHttpAddMetadata(const Flow *f, uint64_t tx_id); #endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_HTTP_H__ */ diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 3a1b57d0f7b0..4733a7dcb781 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -49,7 +49,6 @@ #include "stream-tcp-private.h" #ifdef HAVE_LIBJANSSON -#include typedef struct LogJsonFileCtx_ { LogFileCtx *file_ctx; @@ -194,7 +193,7 @@ static void JsonNetFlowLogJSONToServer(JsonNetFlowLogThread *aft, json_t *js, Fl return; } - json_object_set_new(hjs, "app_proto", + json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto_ts ? f->alproto_ts : f->alproto))); json_object_set_new(hjs, "pkts", @@ -225,7 +224,7 @@ static void JsonNetFlowLogJSONToServer(JsonNetFlowLogThread *aft, json_t *js, Fl TcpSession *ssn = f->protoctx; - char hexflags[3] = ""; + char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->client.tcp_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); @@ -243,7 +242,7 @@ static void JsonNetFlowLogJSONToClient(JsonNetFlowLogThread *aft, json_t *js, Fl return; } - json_object_set_new(hjs, "app_proto", + json_object_set_new(js, "app_proto", json_string(AppProtoToString(f->alproto_tc ? f->alproto_tc : f->alproto))); json_object_set_new(hjs, "pkts", @@ -274,7 +273,7 @@ static void JsonNetFlowLogJSONToClient(JsonNetFlowLogThread *aft, json_t *js, Fl TcpSession *ssn = f->protoctx; - char hexflags[3] = ""; + char hexflags[3]; snprintf(hexflags, sizeof(hexflags), "%02x", ssn ? ssn->server.tcp_flags : 0); json_object_set_new(tjs, "tcp_flags", json_string(hexflags)); @@ -289,26 +288,25 @@ static int JsonNetFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) { SCEnter(); JsonNetFlowLogThread *jhl = (JsonNetFlowLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)jhl->buffer; /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); json_t *js = CreateJSONHeaderFromFlow(f, "netflow", 0); //TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; JsonNetFlowLogJSONToServer(jhl, js, f); - OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "netflow"); json_object_clear(js); json_decref(js); /* reset */ - MemBufferReset(buffer); + MemBufferReset(jhl->buffer); js = CreateJSONHeaderFromFlow(f, "netflow", 1); //TODO const if (unlikely(js == NULL)) return TM_ECODE_OK; JsonNetFlowLogJSONToClient(jhl, js, f); - OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, buffer); + OutputJSONBuffer(js, jhl->flowlog_ctx->file_ctx, &jhl->buffer); json_object_del(js, "netflow"); json_object_clear(js); json_decref(js); @@ -331,11 +329,11 @@ OutputCtx *OutputNetFlowLogInit(ConfNode *conf) SCLogInfo("hi"); LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_NETFLOW_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } @@ -369,7 +367,7 @@ static void OutputNetFlowLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputNetFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; LogJsonFileCtx *flow_ctx = SCMalloc(sizeof(LogJsonFileCtx)); if (unlikely(flow_ctx == NULL)) @@ -381,7 +379,7 @@ OutputCtx *OutputNetFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - flow_ctx->file_ctx = ajt->file_ctx; + flow_ctx->file_ctx = ojc->file_ctx; output_ctx->data = flow_ctx; output_ctx->DeInit = OutputNetFlowLogDeinitSub; @@ -399,7 +397,7 @@ static TmEcode JsonNetFlowLogThreadInit(ThreadVars *t, void *initdata, void **da if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogNetflow. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -432,36 +430,23 @@ static TmEcode JsonNetFlowLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleJsonNetFlowLogRegister (void) +void JsonNetFlowLogRegister(void) { - tmm_modules[TMM_JSONNETFLOWLOG].name = "JsonNetFlowLog"; - tmm_modules[TMM_JSONNETFLOWLOG].ThreadInit = JsonNetFlowLogThreadInit; - tmm_modules[TMM_JSONNETFLOWLOG].ThreadDeinit = JsonNetFlowLogThreadDeinit; - tmm_modules[TMM_JSONNETFLOWLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONNETFLOWLOG].cap_flags = 0; - tmm_modules[TMM_JSONNETFLOWLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ - OutputRegisterFlowModule("JsonNetFlowLog", "netflow-json-log", - OutputNetFlowLogInit, JsonNetFlowLogger); + OutputRegisterFlowModule(LOGGER_JSON_NETFLOW, "JsonNetFlowLog", + "netflow-json-log", OutputNetFlowLogInit, JsonNetFlowLogger, + JsonNetFlowLogThreadInit, JsonNetFlowLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterFlowSubModule("eve-log", "JsonNetFlowLog", "eve-log.netflow", - OutputNetFlowLogInitSub, JsonNetFlowLogger); + OutputRegisterFlowSubModule(LOGGER_JSON_NETFLOW, "eve-log", "JsonNetFlowLog", + "eve-log.netflow", OutputNetFlowLogInitSub, JsonNetFlowLogger, + JsonNetFlowLogThreadInit, JsonNetFlowLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonNetFlowLogRegister (void) +void JsonNetFlowLogRegister (void) { - tmm_modules[TMM_JSONNETFLOWLOG].name = "JsonNetFlowLog"; - tmm_modules[TMM_JSONNETFLOWLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-netflow.h b/src/output-json-netflow.h index 361cc3a0f347..738c497fd830 100644 --- a/src/output-json-netflow.h +++ b/src/output-json-netflow.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_JSON_NETFLOW_H__ #define __OUTPUT_JSON_NETFLOW_H__ -void TmModuleJsonNetFlowLogRegister (void); +void JsonNetFlowLogRegister(void); #endif /* __OUTPUT_JSON_FLOW_H__ */ diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c new file mode 100644 index 000000000000..6bec700e161f --- /dev/null +++ b/src/output-json-smtp.c @@ -0,0 +1,278 @@ +/* Copyright (C) 2007-2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * + * Implements SMTP JSON logging portion of the engine. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer-smtp.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#include "output-json.h" +#include "output-json-email-common.h" + +#ifdef HAVE_LIBJANSSON + +static json_t *JsonSmtpDataLogger(const Flow *f, void *state, void *vtx, uint64_t tx_id) +{ + json_t *sjs = json_object(); + SMTPTransaction *tx = vtx; + SMTPString *rcptto_str; + if (sjs == NULL) { + return NULL; + } + if (((SMTPState *)state)->helo) { + json_object_set_new(sjs, "helo", + json_string((const char *)((SMTPState *)state)->helo)); + } + if (tx->mail_from) { + json_object_set_new(sjs, "mail_from", + json_string((const char *)tx->mail_from)); + } + if (!TAILQ_EMPTY(&tx->rcpt_to_list)) { + json_t *js_rcptto = json_array(); + if (likely(js_rcptto != NULL)) { + TAILQ_FOREACH(rcptto_str, &tx->rcpt_to_list, next) { + json_array_append_new(js_rcptto, json_string((char *)rcptto_str->str)); + } + json_object_set_new(sjs, "rcpt_to", js_rcptto); + } + } + + return sjs; +} + +static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) +{ + SCEnter(); + JsonEmailLogThread *jhl = (JsonEmailLogThread *)thread_data; + + json_t *sjs; + json_t *js = CreateJSONHeaderWithTxId((Packet *)p, 1, "smtp", tx_id); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + /* reset */ + MemBufferReset(jhl->buffer); + + sjs = JsonSmtpDataLogger(f, state, tx, tx_id); + if (sjs) { + json_object_set_new(js, "smtp", sjs); + } + + if (JsonEmailLogJson(jhl, js, p, f, state, tx, tx_id) == TM_ECODE_OK) { + OutputJSONBuffer(js, jhl->emaillog_ctx->file_ctx, &jhl->buffer); + } + json_object_del(js, "email"); + if (sjs) { + json_object_del(js, "smtp"); + } + + json_object_clear(js); + json_decref(js); + + SCReturnInt(TM_ECODE_OK); + +} + +json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id) +{ + SMTPState *smtp_state = (SMTPState *)FlowGetAppState(f); + if (smtp_state) { + SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); + + if (tx) { + return JsonSmtpDataLogger(f, smtp_state, tx, tx_id); + } + } + + return NULL; +} + +static void OutputSmtpLogDeInitCtx(OutputCtx *output_ctx) +{ + OutputJsonEmailCtx *email_ctx = output_ctx->data; + if (email_ctx != NULL) { + LogFileFreeCtx(email_ctx->file_ctx); + SCFree(email_ctx); + } + SCFree(output_ctx); +} + +static void OutputSmtpLogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + OutputJsonEmailCtx *email_ctx = output_ctx->data; + if (email_ctx != NULL) { + SCFree(email_ctx); + } + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "smtp.json" +OutputCtx *OutputSmtpLogInit(ConfNode *conf) +{ + LogFileCtx *file_ctx = LogFileNewCtx(); + if(file_ctx == NULL) { + SCLogError(SC_ERR_SMTP_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputJsonEmailCtx *email_ctx = SCMalloc(sizeof(OutputJsonEmailCtx)); + if (unlikely(email_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + SCFree(email_ctx); + return NULL; + } + + email_ctx->file_ctx = file_ctx; + + output_ctx->data = email_ctx; + output_ctx->DeInit = OutputSmtpLogDeInitCtx; + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); + + return output_ctx; +} + +static OutputCtx *OutputSmtpLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputJsonCtx *ojc = parent_ctx->data; + + OutputJsonEmailCtx *email_ctx = SCMalloc(sizeof(OutputJsonEmailCtx)); + if (unlikely(email_ctx == NULL)) + return NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(email_ctx); + return NULL; + } + + email_ctx->file_ctx = ojc->file_ctx; + + OutputEmailInitConf(conf, email_ctx); + + output_ctx->data = email_ctx; + output_ctx->DeInit = OutputSmtpLogDeInitCtxSub; + + /* enable the logger for the app layer */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); + + return output_ctx; +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonSmtpLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonEmailLogThread *aft = SCMalloc(sizeof(JsonEmailLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonEmailLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for EveLogSMTP. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Ouptut Context (file pointer and mutex) */ + aft->emaillog_ctx = ((OutputCtx *)initdata)->data; + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonSmtpLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonEmailLogThread *aft = (JsonEmailLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + /* clear memory */ + memset(aft, 0, sizeof(JsonEmailLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +void JsonSmtpLogRegister (void) { + /* register as separate module */ + OutputRegisterTxModule(LOGGER_JSON_SMTP, "JsonSmtpLog", "smtp-json-log", + OutputSmtpLogInit, ALPROTO_SMTP, JsonSmtpLogger, JsonSmtpLogThreadInit, + JsonSmtpLogThreadDeinit, NULL); + + /* also register as child of eve-log */ + OutputRegisterTxSubModule(LOGGER_JSON_SMTP, "eve-log", "JsonSmtpLog", + "eve-log.smtp", OutputSmtpLogInitSub, ALPROTO_SMTP, JsonSmtpLogger, + JsonSmtpLogThreadInit, JsonSmtpLogThreadDeinit, NULL); +} + +#else + +void JsonSmtpLogRegister (void) +{ +} + +#endif diff --git a/src/output-json-smtp.h b/src/output-json-smtp.h new file mode 100644 index 000000000000..24d3f8c22de8 --- /dev/null +++ b/src/output-json-smtp.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_SMTP_H__ +#define __OUTPUT_JSON_SMTP_H__ + +void JsonSmtpLogRegister(void); +#ifdef HAVE_LIBJANSSON +json_t *JsonSMTPAddMetadata(const Flow *f, uint64_t tx_id); +#endif + +#endif /* __OUTPUT_JSON_SMTP_H__ */ diff --git a/src/output-json-ssh.c b/src/output-json-ssh.c index 0a6ea46230fd..db3c8ed0283e 100644 --- a/src/output-json-ssh.c +++ b/src/output-json-ssh.c @@ -50,7 +50,6 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include #define MODULE_NAME "LogSshLog" @@ -65,43 +64,9 @@ typedef struct JsonSshLogThread_ { MemBuffer *buffer; } JsonSshLogThread; -static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) -{ - JsonSshLogThread *aft = (JsonSshLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; - OutputSshCtx *ssh_ctx = aft->sshlog_ctx; - - if (unlikely(p->flow == NULL)) { - return 0; - } - - /* check if we have SSH state or not */ - FLOWLOCK_WRLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto end; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); - if (unlikely(ssh_state == NULL)) { - goto end; - } - - if (ssh_state->cli_hdr.software_version == NULL || ssh_state->srv_hdr.software_version == NULL) - goto end; - - json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO - if (unlikely(js == NULL)) - goto end; - - json_t *tjs = json_object(); - if (tjs == NULL) { - free(js); - goto end; - } - - /* reset */ - MemBufferReset(buffer); +void JsonSshLogJSON(json_t *tjs, SshState *ssh_state) +{ json_t *cjs = json_object(); if (cjs != NULL) { json_object_set_new(cjs, "proto_version", @@ -122,16 +87,44 @@ static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p) } json_object_set_new(tjs, "server", sjs); +} + +static int JsonSshLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *txptr, uint64_t tx_id) +{ + JsonSshLogThread *aft = (JsonSshLogThread *)thread_data; + OutputSshCtx *ssh_ctx = aft->sshlog_ctx; + + SshState *ssh_state = (SshState *)state; + if (unlikely(ssh_state == NULL)) { + return 0; + } + + if (ssh_state->cli_hdr.software_version == NULL || + ssh_state->srv_hdr.software_version == NULL) + return 0; + + json_t *js = CreateJSONHeader((Packet *)p, 1, "ssh");//TODO + if (unlikely(js == NULL)) + return 0; + + json_t *tjs = json_object(); + if (tjs == NULL) { + free(js); + return 0; + } + + /* reset */ + MemBufferReset(aft->buffer); + + JsonSshLogJSON(tjs, ssh_state); + json_object_set_new(js, "ssh", tjs); - OutputJSONBuffer(js, ssh_ctx->file_ctx, buffer); + OutputJSONBuffer(js, ssh_ctx->file_ctx, &aft->buffer); json_object_clear(js); json_decref(js); - /* we only log the state once */ - ssh_state->cli_hdr.flags |= SSH_FLAG_STATE_LOGGED; -end: - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -145,7 +138,7 @@ static TmEcode JsonSshLogThreadInit(ThreadVars *t, void *initdata, void **data) if(initdata == NULL) { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + SCLogDebug("Error getting context for EveLogSSH. \"initdata\" argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } @@ -180,8 +173,6 @@ static TmEcode JsonSshLogThreadDeinit(ThreadVars *t, void *data) static void OutputSshLogDeinit(OutputCtx *output_ctx) { - OutputSshLoggerDisable(); - OutputSshCtx *ssh_ctx = output_ctx->data; LogFileCtx *logfile_ctx = ssh_ctx->file_ctx; LogFileFreeCtx(logfile_ctx); @@ -192,19 +183,13 @@ static void OutputSshLogDeinit(OutputCtx *output_ctx) #define DEFAULT_LOG_FILENAME "ssh.json" OutputCtx *OutputSshLogInit(ConfNode *conf) { - if (OutputSshLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'ssh' logger " - "can be enabled"); - return NULL; - } - LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + SCLogError(SC_ERR_SSH_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } @@ -227,13 +212,12 @@ OutputCtx *OutputSshLogInit(ConfNode *conf) output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinit; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); return output_ctx; } static void OutputSshLogDeinitSub(OutputCtx *output_ctx) { - OutputSshLoggerDisable(); - OutputSshCtx *ssh_ctx = output_ctx->data; SCFree(ssh_ctx); SCFree(output_ctx); @@ -241,13 +225,7 @@ static void OutputSshLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; - - if (OutputSshLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'ssh' logger " - "can be enabled"); - return NULL; - } + OutputJsonCtx *ojc = parent_ctx->data; OutputSshCtx *ssh_ctx = SCMalloc(sizeof(OutputSshCtx)); if (unlikely(ssh_ctx == NULL)) @@ -259,86 +237,36 @@ OutputCtx *OutputSshLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - ssh_ctx->file_ctx = ajt->file_ctx; + ssh_ctx->file_ctx = ojc->file_ctx; output_ctx->data = ssh_ctx; output_ctx->DeInit = OutputSshLogDeinitSub; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SSH); return output_ctx; } -/** \internal - * \brief Condition function for SSH logger - * \retval bool true or false -- log now? - */ -static int JsonSshCondition(ThreadVars *tv, const Packet *p) +void JsonSshLogRegister (void) { - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_SSH) - goto dontlog; - - SshState *ssh_state = (SshState *)FlowGetAppState(p->flow); - if (ssh_state == NULL) { - SCLogDebug("no ssh state, so no logging"); - goto dontlog; - } - - /* we only log the state once */ - if (ssh_state->cli_hdr.flags & SSH_FLAG_STATE_LOGGED) - goto dontlog; - - if (ssh_state->cli_hdr.software_version == NULL || - ssh_state->srv_hdr.software_version == NULL) - goto dontlog; - - /* todo: logic to log once */ - - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; -} - -void TmModuleJsonSshLogRegister (void) -{ - tmm_modules[TMM_JSONSSHLOG].name = "JsonSshLog"; - tmm_modules[TMM_JSONSSHLOG].ThreadInit = JsonSshLogThreadInit; - tmm_modules[TMM_JSONSSHLOG].ThreadDeinit = JsonSshLogThreadDeinit; - tmm_modules[TMM_JSONSSHLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONSSHLOG].cap_flags = 0; - tmm_modules[TMM_JSONSSHLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ - OutputRegisterPacketModule("JsonSshLog", "ssh-json-log", OutputSshLogInit, - JsonSshLogger, JsonSshCondition); + OutputRegisterTxModuleWithProgress(LOGGER_JSON_SSH, + "JsonSshLog", "ssh-json-log", + OutputSshLogInit, ALPROTO_SSH, JsonSshLogger, + SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE, + JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterPacketSubModule("eve-log", "JsonSshLog", "eve-log.ssh", OutputSshLogInitSub, - JsonSshLogger, JsonSshCondition); + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_SSH, + "eve-log", "JsonSshLog", "eve-log.ssh", + OutputSshLogInitSub, ALPROTO_SSH, JsonSshLogger, + SSH_STATE_BANNER_DONE, SSH_STATE_BANNER_DONE, + JsonSshLogThreadInit, JsonSshLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -void TmModuleJsonSshLogRegister (void) +void JsonSshLogRegister (void) { - tmm_modules[TMM_JSONSSHLOG].name = "JsonSshLog"; - tmm_modules[TMM_JSONSSHLOG].ThreadInit = OutputJsonThreadInit; } #endif diff --git a/src/output-json-ssh.h b/src/output-json-ssh.h index af0711c711f0..68a7f974c679 100644 --- a/src/output-json-ssh.h +++ b/src/output-json-ssh.h @@ -24,6 +24,12 @@ #ifndef __OUTPUT_JSON_SSH_H__ #define __OUTPUT_JSON_SSH_H__ -void TmModuleJsonSshLogRegister (void); +void JsonSshLogRegister(void); + +#ifdef HAVE_LIBJANSSON +#include "app-layer-ssh.h" + +void JsonSshLogJSON(json_t *js, SshState *tx); +#endif #endif /* __OUTPUT_JSON_SSH_H__ */ diff --git a/src/output-json-stats.c b/src/output-json-stats.c new file mode 100644 index 000000000000..16bf629c910c --- /dev/null +++ b/src/output-json-stats.c @@ -0,0 +1,392 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + * + * Implements JSON stats counters logging portion of the engine. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" +#include "output.h" +#include "util-privs.h" +#include "util-buffer.h" + +#include "util-logopenfile.h" +#include "util-crypt.h" + +#include "output-json.h" +#include "output-json-stats.h" + +#define MODULE_NAME "JsonStatsLog" + +#ifdef HAVE_LIBJANSSON + +typedef struct OutputStatsCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; /** Store mode */ +} OutputStatsCtx; + +typedef struct JsonStatsLogThread_ { + OutputStatsCtx *statslog_ctx; + MemBuffer *buffer; +} JsonStatsLogThread; + +static json_t *OutputStats2Json(json_t *js, const char *key) +{ + void *iter; + + const char *dot = index(key, '.'); + if (dot == NULL) + return NULL; + + size_t predot_len = (dot - key) + 1; + char s[predot_len]; + strlcpy(s, key, predot_len); + + iter = json_object_iter_at(js, s); + const char *s2 = index(dot+1, '.'); + + json_t *value = json_object_iter_value(iter); + if (value == NULL) { + value = json_object(); + json_object_set_new(js, s, value); + } + if (s2 != NULL) { + return OutputStats2Json(value, &key[dot-key+1]); + } + return value; +} + +/** \brief turn StatsTable into a json object + * \param flags JSON_STATS_* flags for controlling output + */ +json_t *StatsToJSON(const StatsTable *st, uint8_t flags) +{ + const char delta_suffix[] = "_delta"; + struct timeval tval; + gettimeofday(&tval, NULL); + + json_t *js_stats = json_object(); + if (unlikely(js_stats == NULL)) { + return NULL; + } + + /* Uptime, in seconds. */ + json_object_set_new(js_stats, "uptime", + json_integer((int)difftime(tval.tv_sec, st->start_time))); + + uint32_t u = 0; + if (flags & JSON_STATS_TOTALS) { + for (u = 0; u < st->nstats; u++) { + if (st->stats[u].name == NULL) + continue; + const char *name = st->stats[u].name; + const char *shortname = name; + if (rindex(name, '.') != NULL) { + shortname = &name[rindex(name, '.') - name + 1]; + } + json_t *js_type = OutputStats2Json(js_stats, name); + if (js_type != NULL) { + json_object_set_new(js_type, shortname, + json_integer(st->stats[u].value)); + + if (flags & JSON_STATS_DELTAS) { + char deltaname[strlen(shortname) + strlen(delta_suffix) + 1]; + snprintf(deltaname, sizeof(deltaname), "%s%s", shortname, + delta_suffix); + json_object_set_new(js_type, deltaname, + json_integer(st->stats[u].value - st->stats[u].pvalue)); + } + } + } + } + + /* per thread stats - stored in a "threads" object. */ + if (st->tstats != NULL && (flags & JSON_STATS_THREADS)) { + /* for each thread (store) */ + json_t *threads = json_object(); + if (unlikely(threads == NULL)) { + json_decref(js_stats); + return NULL; + } + uint32_t x; + for (x = 0; x < st->ntstats; x++) { + uint32_t offset = x * st->nstats; + + /* for each counter */ + for (u = offset; u < (offset + st->nstats); u++) { + if (st->tstats[u].name == NULL) + continue; + + char str[256]; + snprintf(str, sizeof(str), "%s.%s", st->tstats[u].tm_name, st->tstats[u].name); + char *shortname = &str[rindex(str, '.') - str + 1]; + json_t *js_type = OutputStats2Json(threads, str); + + if (js_type != NULL) { + json_object_set_new(js_type, shortname, json_integer(st->tstats[u].value)); + + if (flags & JSON_STATS_DELTAS) { + char deltaname[strlen(shortname) + strlen(delta_suffix) + 1]; + snprintf(deltaname, sizeof(deltaname), "%s%s", + shortname, delta_suffix); + json_object_set_new(js_type, deltaname, + json_integer(st->tstats[u].value - st->tstats[u].pvalue)); + } + } + } + } + json_object_set_new(js_stats, "threads", threads); + } + return js_stats; +} + +static int JsonStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +{ + SCEnter(); + JsonStatsLogThread *aft = (JsonStatsLogThread *)thread_data; + + struct timeval tval; + gettimeofday(&tval, NULL); + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return 0; + char timebuf[64]; + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + json_object_set_new(js, "event_type", json_string("stats")); + + json_t *js_stats = StatsToJSON(st, aft->statslog_ctx->flags); + if (js_stats == NULL) { + json_decref(js); + return 0; + } + + json_object_set_new(js, "stats", js_stats); + + OutputJSONBuffer(js, aft->statslog_ctx->file_ctx, &aft->buffer); + MemBufferReset(aft->buffer); + + json_object_clear(js_stats); + json_object_del(js, "stats"); + json_object_clear(js); + json_decref(js); + + SCReturnInt(0); +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonStatsLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonStatsLogThread *aft = SCMalloc(sizeof(JsonStatsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonStatsLogThread)); + + if(initdata == NULL) + { + SCLogDebug("Error getting context for EveLogStats. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + /* Use the Ouptut Context (file pointer and mutex) */ + aft->statslog_ctx = ((OutputCtx *)initdata)->data; + + aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonStatsLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonStatsLogThread *aft = (JsonStatsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->buffer); + + /* clear memory */ + memset(aft, 0, sizeof(JsonStatsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void OutputStatsLogDeinit(OutputCtx *output_ctx) +{ + + OutputStatsCtx *stats_ctx = output_ctx->data; + LogFileCtx *logfile_ctx = stats_ctx->file_ctx; + LogFileFreeCtx(logfile_ctx); + SCFree(stats_ctx); + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "stats.json" +OutputCtx *OutputStatsLogInit(ConfNode *conf) +{ + LogFileCtx *file_ctx = LogFileNewCtx(); + if(file_ctx == NULL) { + SCLogError(SC_ERR_STATS_LOG_GENERIC, "couldn't create new file_ctx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(file_ctx); + return NULL; + } + + OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); + if (unlikely(stats_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + return NULL; + } + stats_ctx->flags = JSON_STATS_TOTALS; + + if (conf != NULL) { + const char *totals = ConfNodeLookupChildValue(conf, "totals"); + const char *threads = ConfNodeLookupChildValue(conf, "threads"); + const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); + SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); + + if (totals != NULL && ConfValIsFalse(totals)) { + stats_ctx->flags &= ~JSON_STATS_TOTALS; + } + if (threads != NULL && ConfValIsTrue(threads)) { + stats_ctx->flags |= JSON_STATS_THREADS; + } + if (deltas != NULL && ConfValIsTrue(deltas)) { + stats_ctx->flags |= JSON_STATS_DELTAS; + } + SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(file_ctx); + SCFree(stats_ctx); + return NULL; + } + + stats_ctx->file_ctx = file_ctx; + + output_ctx->data = stats_ctx; + output_ctx->DeInit = OutputStatsLogDeinit; + + return output_ctx; +} + +static void OutputStatsLogDeinitSub(OutputCtx *output_ctx) +{ + OutputStatsCtx *stats_ctx = output_ctx->data; + SCFree(stats_ctx); + SCFree(output_ctx); +} + +OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); + if (unlikely(stats_ctx == NULL)) + return NULL; + + stats_ctx->flags = JSON_STATS_TOTALS; + + if (conf != NULL) { + const char *totals = ConfNodeLookupChildValue(conf, "totals"); + const char *threads = ConfNodeLookupChildValue(conf, "threads"); + const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); + SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); + + if ((totals != NULL && ConfValIsFalse(totals)) && + (threads != NULL && ConfValIsFalse(threads))) { + SCFree(stats_ctx); + SCLogError(SC_ERR_JSON_STATS_LOG_NEGATED, + "Cannot disable both totals and threads in stats logging"); + return NULL; + } + + if (totals != NULL && ConfValIsFalse(totals)) { + stats_ctx->flags &= ~JSON_STATS_TOTALS; + } + if (threads != NULL && ConfValIsTrue(threads)) { + stats_ctx->flags |= JSON_STATS_THREADS; + } + if (deltas != NULL && ConfValIsTrue(deltas)) { + stats_ctx->flags |= JSON_STATS_DELTAS; + } + SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(stats_ctx); + return NULL; + } + + stats_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = stats_ctx; + output_ctx->DeInit = OutputStatsLogDeinitSub; + + return output_ctx; +} + +void JsonStatsLogRegister(void) { + /* register as separate module */ + OutputRegisterStatsModule(LOGGER_JSON_STATS, MODULE_NAME, "stats-json", + OutputStatsLogInit, JsonStatsLogger, JsonStatsLogThreadInit, + JsonStatsLogThreadDeinit, NULL); + + /* also register as child of eve-log */ + OutputRegisterStatsSubModule(LOGGER_JSON_STATS, "eve-log", MODULE_NAME, + "eve-log.stats", OutputStatsLogInitSub, JsonStatsLogger, + JsonStatsLogThreadInit, JsonStatsLogThreadDeinit, NULL); +} + +#else + +void JsonStatsLogRegister (void) +{ +} + +#endif diff --git a/src/output-json-stats.h b/src/output-json-stats.h new file mode 100644 index 000000000000..94962a3c99bb --- /dev/null +++ b/src/output-json-stats.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Tom DeCanio + */ + +#ifndef __OUTPUT_JSON_COUNTERS_H__ +#define __OUTPUT_JSON_COUNTERS_H__ + +#include "output-stats.h" + +#define JSON_STATS_TOTALS (1<<0) +#define JSON_STATS_THREADS (1<<1) +#define JSON_STATS_DELTAS (1<<2) + +#ifdef HAVE_LIBJANSSON +json_t *StatsToJSON(const StatsTable *st, uint8_t flags); +#endif +void JsonStatsLogRegister(void); + +#endif /* __OUTPUT_JSON_COUNTERS_H__ */ diff --git a/src/output-json-template.c b/src/output-json-template.c new file mode 100644 index 000000000000..3747121f584f --- /dev/null +++ b/src/output-json-template.c @@ -0,0 +1,212 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * TODO: Update \author in this file and in output-json-template.h. + * TODO: Remove SCLogNotice statements, or convert to debug. + * TODO: Implement your app-layers logging. + */ + +/** + * \file + * + * \author FirstName LastName + * + * Implement JSON/eve logging app-layer Template. + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-unittest.h" +#include "util-buffer.h" +#include "util-debug.h" +#include "util-byte.h" + +#include "output.h" +#include "output-json.h" + +#include "app-layer.h" +#include "app-layer-parser.h" + +#include "app-layer-template.h" + +#ifdef HAVE_LIBJANSSON + +typedef struct LogTemplateFileCtx_ { + LogFileCtx *file_ctx; + uint32_t flags; +} LogTemplateFileCtx; + +typedef struct LogTemplateLogThread_ { + LogTemplateFileCtx *templatelog_ctx; + uint32_t count; + MemBuffer *buffer; +} LogTemplateLogThread; + +static int JsonTemplateLogger(ThreadVars *tv, void *thread_data, + const Packet *p, Flow *f, void *state, void *tx, uint64_t tx_id) +{ + TemplateTransaction *templatetx = tx; + LogTemplateLogThread *thread = thread_data; + json_t *js, *templatejs; + + SCLogNotice("Logging template transaction %"PRIu64".", templatetx->tx_id); + + js = CreateJSONHeader((Packet *)p, 0, "template"); + if (unlikely(js == NULL)) { + return TM_ECODE_FAILED; + } + + templatejs = json_object(); + if (unlikely(templatejs == NULL)) { + goto error; + } + + /* Convert the request buffer to a string then log. */ + char *request_buffer = BytesToString(templatetx->request_buffer, + templatetx->request_buffer_len); + if (request_buffer != NULL) { + json_object_set_new(templatejs, "request", json_string(request_buffer)); + SCFree(request_buffer); + } + + /* Convert the response buffer to a string then log. */ + char *response_buffer = BytesToString(templatetx->response_buffer, + templatetx->response_buffer_len); + if (response_buffer != NULL) { + json_object_set_new(templatejs, "response", + json_string(response_buffer)); + SCFree(response_buffer); + } + + json_object_set_new(js, "template", templatejs); + + MemBufferReset(thread->buffer); + OutputJSONBuffer(js, thread->templatelog_ctx->file_ctx, &thread->buffer); + + json_decref(js); + return TM_ECODE_OK; + +error: + json_decref(js); + return TM_ECODE_FAILED; +} + +static void OutputTemplateLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogTemplateFileCtx *templatelog_ctx = (LogTemplateFileCtx *)output_ctx->data; + SCFree(templatelog_ctx); + SCFree(output_ctx); +} + +static OutputCtx *OutputTemplateLogInitSub(ConfNode *conf, + OutputCtx *parent_ctx) +{ + AlertJsonThread *ajt = parent_ctx->data; + + LogTemplateFileCtx *templatelog_ctx = SCCalloc(1, sizeof(*templatelog_ctx)); + if (unlikely(templatelog_ctx == NULL)) { + return NULL; + } + templatelog_ctx->file_ctx = ajt->file_ctx; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(*output_ctx)); + if (unlikely(output_ctx == NULL)) { + SCFree(templatelog_ctx); + return NULL; + } + output_ctx->data = templatelog_ctx; + output_ctx->DeInit = OutputTemplateLogDeInitCtxSub; + + SCLogNotice("Template log sub-module initialized."); + + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TEMPLATE); + + return output_ctx; +} + +#define OUTPUT_BUFFER_SIZE 65535 + +static TmEcode JsonTemplateLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogTemplateLogThread *thread = SCCalloc(1, sizeof(*thread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogTemplate. \"initdata\" is NULL."); + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (unlikely(thread->buffer == NULL)) { + SCFree(thread); + return TM_ECODE_FAILED; + } + + thread->templatelog_ctx = ((OutputCtx *)initdata)->data; + *data = (void *)thread; + + return TM_ECODE_OK; +} + +static TmEcode JsonTemplateLogThreadDeinit(ThreadVars *t, void *data) +{ + LogTemplateLogThread *thread = (LogTemplateLogThread *)data; + if (thread == NULL) { + return TM_ECODE_OK; + } + if (thread->buffer != NULL) { + MemBufferFree(thread->buffer); + } + SCFree(thread); + return TM_ECODE_OK; +} + +void JsonTemplateLogRegister(void) +{ + /* TEMPLATE_START_REMOVE */ + if (ConfGetNode("app-layer.protocols.template") == NULL) { + return; + } + /* TEMPLATE_END_REMOVE */ + /* Register as an eve sub-module. */ + OutputRegisterTxSubModule(LOGGER_JSON_TEMPLATE, "eve-log", "JsonTemplateLog", + "eve-log.template", OutputTemplateLogInitSub, ALPROTO_TEMPLATE, + JsonTemplateLogger, JsonTemplateLogThreadInit, + JsonTemplateLogThreadDeinit, NULL); + + SCLogNotice("Template JSON logger registered."); +} + +#else /* No JSON support. */ + +void JsonTemplateLogRegister(void) +{ +} + +#endif /* HAVE_LIBJANSSON */ diff --git a/src/output-json-template.h b/src/output-json-template.h new file mode 100644 index 000000000000..874df6b3b4a7 --- /dev/null +++ b/src/output-json-template.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author FirstName LastName + */ + +#ifndef __OUTPUT_JSON_TEMPLATE_H__ +#define __OUTPUT_JSON_TEMPLATE_H__ + +void JsonTemplateLogRegister(void); + +#endif /* __OUTPUT_JSON_TEMPLATE_H__ */ diff --git a/src/output-json-tls.c b/src/output-json-tls.c index 129b8177bf31..555c666cc4b7 100644 --- a/src/output-json-tls.c +++ b/src/output-json-tls.c @@ -50,18 +50,54 @@ #include "output-json.h" #ifdef HAVE_LIBJANSSON -#include SC_ATOMIC_DECLARE(unsigned int, cert_id); #define MODULE_NAME "LogTlsLog" +#define DEFAULT_LOG_FILENAME "tls.json" + +#define OUTPUT_BUFFER_SIZE 65535 + +#define SSL_VERSION_LENGTH 13 #define LOG_TLS_DEFAULT 0 #define LOG_TLS_EXTENDED (1 << 0) +#define LOG_TLS_CUSTOM (1 << 1) + +#define LOG_TLS_FIELD_VERSION (1 << 0) +#define LOG_TLS_FIELD_SUBJECT (1 << 1) +#define LOG_TLS_FIELD_ISSUER (1 << 2) +#define LOG_TLS_FIELD_SERIAL (1 << 3) +#define LOG_TLS_FIELD_FINGERPRINT (1 << 4) +#define LOG_TLS_FIELD_NOTBEFORE (1 << 5) +#define LOG_TLS_FIELD_NOTAFTER (1 << 6) +#define LOG_TLS_FIELD_SNI (1 << 7) +#define LOG_TLS_FIELD_CERTIFICATE (1 << 8) +#define LOG_TLS_FIELD_CHAIN (1 << 9) + +typedef struct { + char *name; + uint64_t flag; +} TlsFields; + +TlsFields tls_fields[] = { + { "version", LOG_TLS_FIELD_VERSION }, + { "subject", LOG_TLS_FIELD_SUBJECT }, + { "issuer", LOG_TLS_FIELD_ISSUER }, + { "serial", LOG_TLS_FIELD_SERIAL }, + { "fingerprint", LOG_TLS_FIELD_FINGERPRINT }, + { "not_before", LOG_TLS_FIELD_NOTBEFORE }, + { "not_after", LOG_TLS_FIELD_NOTAFTER }, + { "sni", LOG_TLS_FIELD_SNI }, + { "certificate", LOG_TLS_FIELD_CERTIFICATE }, + { "chain", LOG_TLS_FIELD_CHAIN }, + { NULL, -1 } +}; typedef struct OutputTlsCtx_ { LogFileCtx *file_ctx; - uint32_t flags; /** Store mode */ + uint32_t flags; /** Store mode */ + uint64_t fields; /** Store fields */ } OutputTlsCtx; @@ -70,18 +106,45 @@ typedef struct JsonTlsLogThread_ { MemBuffer *buffer; } JsonTlsLogThread; -#define SSL_VERSION_LENGTH 13 +static void JsonTlsLogSubject(json_t *js, SSLState *ssl_state) +{ + json_object_set_new(js, "subject", + json_string(ssl_state->server_connp.cert0_subject)); +} -static void LogTlsLogExtendedJSON(json_t *tjs, SSLState * state) +static void JsonTlsLogIssuer(json_t *js, SSLState *ssl_state) { - char ssl_version[SSL_VERSION_LENGTH + 1]; + json_object_set_new(js, "issuerdn", + json_string(ssl_state->server_connp.cert0_issuerdn)); +} + +static void JsonTlsLogFingerprint(json_t *js, SSLState *ssl_state) +{ + json_object_set_new(js, "fingerprint", + json_string(ssl_state->server_connp.cert0_fingerprint)); +} + +static void JsonTlsLogSni(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->client_connp.sni) { + json_object_set_new(js, "sni", + json_string(ssl_state->client_connp.sni)); + } +} - /* tls.fingerprint */ - json_object_set_new(tjs, "fingerprint", - json_string(state->server_connp.cert0_fingerprint)); +static void JsonTlsLogSerial(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_serial) { + json_object_set_new(js, "serial", + json_string(ssl_state->server_connp.cert0_serial)); + } +} + +static void JsonTlsLogVersion(json_t *js, SSLState *ssl_state) +{ + char ssl_version[SSL_VERSION_LENGTH + 1]; - /* tls.version */ - switch (state->server_connp.version) { + switch (ssl_state->server_connp.version) { case TLS_VERSION_UNKNOWN: snprintf(ssl_version, SSL_VERSION_LENGTH, "UNDETERMINED"); break; @@ -102,90 +165,225 @@ static void LogTlsLogExtendedJSON(json_t *tjs, SSLState * state) break; default: snprintf(ssl_version, SSL_VERSION_LENGTH, "0x%04x", - state->server_connp.version); + ssl_state->server_connp.version); break; } - json_object_set_new(tjs, "version", json_string(ssl_version)); + json_object_set_new(js, "version", json_string(ssl_version)); } -static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +static void JsonTlsLogNotBefore(json_t *js, SSLState *ssl_state) { - JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; - MemBuffer *buffer = (MemBuffer *)aft->buffer; - OutputTlsCtx *tls_ctx = aft->tlslog_ctx; + if (ssl_state->server_connp.cert0_not_before != 0) { + char timebuf[64]; + struct timeval tv; + tv.tv_sec = ssl_state->server_connp.cert0_not_before; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + json_object_set_new(js, "notbefore", json_string(timebuf)); + } +} - if (unlikely(p->flow == NULL)) { - return 0; +static void JsonTlsLogNotAfter(json_t *js, SSLState *ssl_state) +{ + if (ssl_state->server_connp.cert0_not_after != 0) { + char timebuf[64]; + struct timeval tv; + tv.tv_sec = ssl_state->server_connp.cert0_not_after; + tv.tv_usec = 0; + CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf)); + json_object_set_new(js, "notafter", json_string(timebuf)); + } +} + +static void JsonTlsLogCertificate(json_t *js, SSLState *ssl_state) +{ + if ((ssl_state->server_connp.cert_input == NULL) || + (ssl_state->server_connp.cert_input_len == 0)) { + return; + } + + SSLCertsChain *cert = TAILQ_FIRST(&ssl_state->server_connp.certs); + if (cert == NULL) { + return; + } + + unsigned long len = cert->cert_len * 2; + uint8_t encoded[len]; + if (Base64Encode(cert->cert_data, cert->cert_len, encoded, &len) == + SC_BASE64_OK) { + json_object_set_new(js, "certificate", json_string((char *)encoded)); + } +} + +static void JsonTlsLogChain(json_t *js, SSLState *ssl_state) +{ + if ((ssl_state->server_connp.cert_input == NULL) || + (ssl_state->server_connp.cert_input_len == 0)) { + return; + } + + json_t *chain = json_array(); + if (chain == NULL) { + return; + } + + SSLCertsChain *cert; + TAILQ_FOREACH(cert, &ssl_state->server_connp.certs, next) { + unsigned long len = cert->cert_len * 2; + uint8_t encoded[len]; + if (Base64Encode(cert->cert_data, cert->cert_len, encoded, &len) == + SC_BASE64_OK) { + json_array_append_new(chain, json_string((char *)encoded)); + } } - /* check if we have TLS state or not */ - FLOWLOCK_WRLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto end; + json_object_set_new(js, "chain", chain); +} + +void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state) +{ + /* tls subject */ + JsonTlsLogSubject(js, ssl_state); + + /* tls issuerdn */ + JsonTlsLogIssuer(js, ssl_state); +} + +static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, json_t *js, + SSLState *ssl_state) +{ + /* tls subject */ + if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECT) + JsonTlsLogSubject(js, ssl_state); + + /* tls issuerdn */ + if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER) + JsonTlsLogIssuer(js, ssl_state); + + /* tls serial */ + if (tls_ctx->fields & LOG_TLS_FIELD_SERIAL) + JsonTlsLogSerial(js, ssl_state); - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); + /* tls fingerprint */ + if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT) + JsonTlsLogFingerprint(js, ssl_state); + + /* tls sni */ + if (tls_ctx->fields & LOG_TLS_FIELD_SNI) + JsonTlsLogSni(js, ssl_state); + + /* tls version */ + if (tls_ctx->fields & LOG_TLS_FIELD_VERSION) + JsonTlsLogVersion(js, ssl_state); + + /* tls notbefore */ + if (tls_ctx->fields & LOG_TLS_FIELD_NOTBEFORE) + JsonTlsLogNotBefore(js, ssl_state); + + /* tls notafter */ + if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER) + JsonTlsLogNotAfter(js, ssl_state); + + /* tls certificate */ + if (tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) + JsonTlsLogCertificate(js, ssl_state); + + /* tls chain */ + if (tls_ctx->fields & LOG_TLS_FIELD_CHAIN) + JsonTlsLogChain(js, ssl_state); +} + +void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state) +{ + JsonTlsLogJSONBasic(tjs, state); + + /* tls serial */ + JsonTlsLogSerial(tjs, state); + + /* tls fingerprint */ + JsonTlsLogFingerprint(tjs, state); + + /* tls sni */ + JsonTlsLogSni(tjs, state); + + /* tls version */ + JsonTlsLogVersion(tjs, state); + + /* tls notbefore */ + JsonTlsLogNotBefore(tjs, state); + + /* tls notafter */ + JsonTlsLogNotAfter(tjs, state); +} + +static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p, + Flow *f, void *state, void *txptr, uint64_t tx_id) +{ + JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data; + OutputTlsCtx *tls_ctx = aft->tlslog_ctx; + + SSLState *ssl_state = (SSLState *)state; if (unlikely(ssl_state == NULL)) { - goto end; + return 0; } - if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL) - goto end; + if (ssl_state->server_connp.cert0_issuerdn == NULL || + ssl_state->server_connp.cert0_subject == NULL) { + return 0; + } - json_t *js = CreateJSONHeader((Packet *)p, 0, "tls");//TODO - if (unlikely(js == NULL)) - goto end; + json_t *js = CreateJSONHeader((Packet *)p, 1, "tls"); + if (unlikely(js == NULL)) { + return 0; + } json_t *tjs = json_object(); if (tjs == NULL) { free(js); - goto end; + return 0; } /* reset */ - MemBufferReset(buffer); + MemBufferReset(aft->buffer); - /* tls.subject */ - json_object_set_new(tjs, "subject", - json_string(ssl_state->server_connp.cert0_subject)); - - /* tls.issuerdn */ - json_object_set_new(tjs, "issuerdn", - json_string(ssl_state->server_connp.cert0_issuerdn)); - - if (tls_ctx->flags & LOG_TLS_EXTENDED) { - LogTlsLogExtendedJSON(tjs, ssl_state); + /* log custom fields */ + if (tls_ctx->flags & LOG_TLS_CUSTOM) { + JsonTlsLogJSONCustom(tls_ctx, tjs, ssl_state); + } + /* log extended */ + else if (tls_ctx->flags & LOG_TLS_EXTENDED) { + JsonTlsLogJSONExtended(tjs, ssl_state); + } + /* log basic */ + else { + JsonTlsLogJSONBasic(tjs, ssl_state); } json_object_set_new(js, "tls", tjs); - OutputJSONBuffer(js, tls_ctx->file_ctx, buffer); + OutputJSONBuffer(js, tls_ctx->file_ctx, &aft->buffer); json_object_clear(js); json_decref(js); - /* we only log the state once */ - ssl_state->flags |= SSL_AL_FLAG_STATE_LOGGED; -end: - FLOWLOCK_UNLOCK(p->flow); return 0; } -#define OUTPUT_BUFFER_SIZE 65535 static TmEcode JsonTlsLogThreadInit(ThreadVars *t, void *initdata, void **data) { JsonTlsLogThread *aft = SCMalloc(sizeof(JsonTlsLogThread)); - if (unlikely(aft == NULL)) + if (unlikely(aft == NULL)) { return TM_ECODE_FAILED; + } + memset(aft, 0, sizeof(JsonTlsLogThread)); - if(initdata == NULL) - { - SCLogDebug("Error getting context for HTTPLog. \"initdata\" argument NULL"); + if (initdata == NULL) { + SCLogDebug("Error getting context for eve-log tls 'initdata' argument NULL"); SCFree(aft); return TM_ECODE_FAILED; } - /* Use the Ouptut Context (file pointer and mutex) */ + /* use the Output Context (file pointer and mutex) */ aft->tlslog_ctx = ((OutputCtx *)initdata)->data; aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); @@ -206,6 +404,7 @@ static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) } MemBufferFree(aft->buffer); + /* clear memory */ memset(aft, 0, sizeof(JsonTlsLogThread)); @@ -215,8 +414,6 @@ static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data) static void OutputTlsLogDeinit(OutputCtx *output_ctx) { - OutputTlsLoggerDisable(); - OutputTlsCtx *tls_ctx = output_ctx->data; LogFileCtx *logfile_ctx = tls_ctx->file_ctx; LogFileFreeCtx(logfile_ctx); @@ -224,27 +421,66 @@ static void OutputTlsLogDeinit(OutputCtx *output_ctx) SCFree(output_ctx); } -#define DEFAULT_LOG_FILENAME "tls.json" -OutputCtx *OutputTlsLogInit(ConfNode *conf) +static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf) { - if (OutputTlsLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " - "can be enabled"); + OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + if (unlikely(tls_ctx == NULL)) return NULL; + + tls_ctx->flags = LOG_TLS_DEFAULT; + tls_ctx->fields = 0; + + if (conf == NULL) + return tls_ctx; + + const char *extended = ConfNodeLookupChildValue(conf, "extended"); + if (extended) { + if (ConfValIsTrue(extended)) { + tls_ctx->flags = LOG_TLS_EXTENDED; + } } + ConfNode *custom = ConfNodeLookupChild(conf, "custom"); + if (custom) { + tls_ctx->flags = LOG_TLS_CUSTOM; + ConfNode *field; + TAILQ_FOREACH(field, &custom->head, next) + { + TlsFields *valid_fields = tls_fields; + for ( ; valid_fields->name != NULL; valid_fields++) { + if (strcasecmp(field->val, valid_fields->name) == 0) { + tls_ctx->fields |= valid_fields->flag; + break; + } + } + } + } + + if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && + (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { + SCLogWarning(SC_WARN_DUPLICATE_OUTPUT, + "Both 'certificate' and 'chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); + } + + return tls_ctx; +} + +OutputCtx *OutputTlsLogInit(ConfNode *conf) +{ LogFileCtx *file_ctx = LogFileNewCtx(); - if(file_ctx == NULL) { - SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); + if (file_ctx == NULL) { + SCLogError(SC_ERR_TLS_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } - if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } - OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf); if (unlikely(tls_ctx == NULL)) { LogFileFreeCtx(file_ctx); return NULL; @@ -258,27 +494,17 @@ OutputCtx *OutputTlsLogInit(ConfNode *conf) } tls_ctx->file_ctx = file_ctx; - tls_ctx->flags = LOG_TLS_DEFAULT; - if (conf) { - const char *extended = ConfNodeLookupChildValue(conf, "extended"); - - if (extended != NULL) { - if (ConfValIsTrue(extended)) { - tls_ctx->flags = LOG_TLS_EXTENDED; - } - } - } output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinit; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); + return output_ctx; } static void OutputTlsLogDeinitSub(OutputCtx *output_ctx) { - OutputTlsLoggerDisable(); - OutputTlsCtx *tls_ctx = output_ctx->data; SCFree(tls_ctx); SCFree(output_ctx); @@ -286,15 +512,9 @@ static void OutputTlsLogDeinitSub(OutputCtx *output_ctx) OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { - AlertJsonThread *ajt = parent_ctx->data; + OutputJsonCtx *ojc = parent_ctx->data; - if (OutputTlsLoggerEnable() != 0) { - SCLogError(SC_ERR_CONF_YAML_ERROR, "only one 'tls' logger " - "can be enabled"); - return NULL; - } - - OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx)); + OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf); if (unlikely(tls_ctx == NULL)) return NULL; @@ -304,96 +524,44 @@ OutputCtx *OutputTlsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } - tls_ctx->file_ctx = ajt->file_ctx; - tls_ctx->flags = LOG_TLS_DEFAULT; - - if (conf) { - const char *extended = ConfNodeLookupChildValue(conf, "extended"); + tls_ctx->file_ctx = ojc->file_ctx; - if (extended != NULL) { - if (ConfValIsTrue(extended)) { - tls_ctx->flags = LOG_TLS_EXTENDED; - } - } + if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) && + (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) { + SCLogWarning(SC_WARN_DUPLICATE_OUTPUT, + "Both 'certificate' and 'chain' contains the top " + "certificate, so only one of them should be enabled " + "at a time"); } + output_ctx->data = tls_ctx; output_ctx->DeInit = OutputTlsLogDeinitSub; - return output_ctx; -} - -/** \internal - * \brief Condition function for TLS logger - * \retval bool true or false -- log now? - */ -static int JsonTlsCondition(ThreadVars *tv, const Packet *p) -{ - if (p->flow == NULL) { - return FALSE; - } - - if (!(PKT_IS_TCP(p))) { - return FALSE; - } - - FLOWLOCK_RDLOCK(p->flow); - uint16_t proto = FlowGetAppProtocol(p->flow); - if (proto != ALPROTO_TLS) - goto dontlog; - - SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow); - if (ssl_state == NULL) { - SCLogDebug("no tls state, so no request logging"); - goto dontlog; - } - - /* we only log the state once */ - if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED) - goto dontlog; - - if (ssl_state->server_connp.cert0_issuerdn == NULL || - ssl_state->server_connp.cert0_subject == NULL) - goto dontlog; - - /* todo: logic to log once */ + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_TLS); - FLOWLOCK_UNLOCK(p->flow); - return TRUE; -dontlog: - FLOWLOCK_UNLOCK(p->flow); - return FALSE; + return output_ctx; } -void TmModuleJsonTlsLogRegister (void) +void JsonTlsLogRegister (void) { - tmm_modules[TMM_JSONTLSLOG].name = "JsonTlsLog"; - tmm_modules[TMM_JSONTLSLOG].ThreadInit = JsonTlsLogThreadInit; - tmm_modules[TMM_JSONTLSLOG].ThreadDeinit = JsonTlsLogThreadDeinit; - tmm_modules[TMM_JSONTLSLOG].RegisterTests = NULL; - tmm_modules[TMM_JSONTLSLOG].cap_flags = 0; - tmm_modules[TMM_JSONTLSLOG].flags = TM_FLAG_LOGAPI_TM; - /* register as separate module */ - OutputRegisterPacketModule("JsonTlsLog", "tls-json-log", OutputTlsLogInit, - JsonTlsLogger, JsonTlsCondition); + OutputRegisterTxModuleWithProgress(LOGGER_JSON_TLS, "JsonTlsLog", + "tls-json-log", OutputTlsLogInit, ALPROTO_TLS, JsonTlsLogger, + TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, JsonTlsLogThreadInit, + JsonTlsLogThreadDeinit, NULL); /* also register as child of eve-log */ - OutputRegisterPacketSubModule("eve-log", "JsonTlsLog", "eve-log.tls", OutputTlsLogInitSub, - JsonTlsLogger, JsonTlsCondition); + OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TLS, "eve-log", + "JsonTlsLog", "eve-log.tls", OutputTlsLogInitSub, ALPROTO_TLS, + JsonTlsLogger, TLS_HANDSHAKE_DONE, TLS_HANDSHAKE_DONE, + JsonTlsLogThreadInit, JsonTlsLogThreadDeinit, NULL); } #else -static TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +void JsonTlsLogRegister (void) { - SCLogInfo("Can't init JSON output - JSON support was disabled during build."); - return TM_ECODE_FAILED; } -void TmModuleJsonTlsLogRegister (void) -{ - tmm_modules[TMM_JSONTLSLOG].name = "JsonTlsLog"; - tmm_modules[TMM_JSONTLSLOG].ThreadInit = OutputJsonThreadInit; -} +#endif /* HAVE_LIBJANSSON */ -#endif diff --git a/src/output-json-tls.h b/src/output-json-tls.h index 931414f3013b..06657c8e852c 100644 --- a/src/output-json-tls.h +++ b/src/output-json-tls.h @@ -24,6 +24,13 @@ #ifndef __OUTPUT_JSON_TLS_H__ #define __OUTPUT_JSON_TLS_H__ -void TmModuleJsonTlsLogRegister (void); +void JsonTlsLogRegister(void); + +#ifdef HAVE_LIBJANSSON +#include "app-layer-ssl.h" + +void JsonTlsLogJSONBasic(json_t *js, SSLState *ssl_state); +void JsonTlsLogJSONExtended(json_t *js, SSLState *ssl_state); +#endif /* HAVE_LIBJANSSON */ #endif /* __OUTPUT_JSON_TLS_H__ */ diff --git a/src/output-json-vars.c b/src/output-json-vars.c new file mode 100644 index 000000000000..c0747ca9ff4b --- /dev/null +++ b/src/output-json-vars.c @@ -0,0 +1,277 @@ +/* Copyright (C) 2013-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Logs vars in JSON format. + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "tm-threads.h" +#include "threadvars.h" +#include "util-debug.h" + +#include "util-misc.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-reference.h" +#include "app-layer-parser.h" +#include "app-layer-dnp3.h" +#include "app-layer-htp.h" +#include "app-layer-htp-xff.h" +#include "util-classification-config.h" +#include "util-syslog.h" +#include "util-logopenfile.h" + +#include "output.h" +#include "output-json.h" + +#include "util-byte.h" +#include "util-privs.h" +#include "util-print.h" +#include "util-proto-name.h" +#include "util-optimize.h" +#include "util-buffer.h" +#include "util-crypt.h" + +#define MODULE_NAME "JsonVarsLog" + +#ifdef HAVE_LIBJANSSON + +#define JSON_STREAM_BUFFER_SIZE 4096 + +typedef struct VarsJsonOutputCtx_ { + LogFileCtx* file_ctx; +} VarsJsonOutputCtx; + +typedef struct JsonVarsLogThread_ { + /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ + LogFileCtx* file_ctx; + MemBuffer *json_buffer; + VarsJsonOutputCtx* json_output_ctx; +} JsonVarsLogThread; + +static int VarsJson(ThreadVars *tv, JsonVarsLogThread *aft, const Packet *p) +{ + json_t *js = CreateJSONHeader((Packet *)p, 0, "vars"); + if (unlikely(js == NULL)) + return TM_ECODE_OK; + + JsonAddVars(p, p->flow, js); + OutputJSONBuffer(js, aft->file_ctx, &aft->json_buffer); + json_object_del(js, "vars"); + json_object_clear(js); + json_decref(js); + + return TM_ECODE_OK; +} + +static int JsonVarsLogger(ThreadVars *tv, void *thread_data, const Packet *p) +{ + JsonVarsLogThread *aft = thread_data; + + return VarsJson(tv, aft, p); +} + +static int JsonVarsLogCondition(ThreadVars *tv, const Packet *p) +{ + if (p->pktvar) { + return TRUE; + } + return FALSE; +} + +#define OUTPUT_BUFFER_SIZE 65535 +static TmEcode JsonVarsLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + JsonVarsLogThread *aft = SCMalloc(sizeof(JsonVarsLogThread)); + if (unlikely(aft == NULL)) + return TM_ECODE_FAILED; + memset(aft, 0, sizeof(JsonVarsLogThread)); + if(initdata == NULL) + { + SCLogDebug("Error getting context for EveLogVars. \"initdata\" argument NULL"); + SCFree(aft); + return TM_ECODE_FAILED; + } + + aft->json_buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE); + if (aft->json_buffer == NULL) { + SCFree(aft); + return TM_ECODE_FAILED; + } + + /** Use the Output Context (file pointer and mutex) */ + VarsJsonOutputCtx *json_output_ctx = ((OutputCtx *)initdata)->data; + aft->file_ctx = json_output_ctx->file_ctx; + aft->json_output_ctx = json_output_ctx; + + *data = (void *)aft; + return TM_ECODE_OK; +} + +static TmEcode JsonVarsLogThreadDeinit(ThreadVars *t, void *data) +{ + JsonVarsLogThread *aft = (JsonVarsLogThread *)data; + if (aft == NULL) { + return TM_ECODE_OK; + } + + MemBufferFree(aft->json_buffer); + + /* clear memory */ + memset(aft, 0, sizeof(JsonVarsLogThread)); + + SCFree(aft); + return TM_ECODE_OK; +} + +static void JsonVarsLogDeInitCtx(OutputCtx *output_ctx) +{ + VarsJsonOutputCtx *json_output_ctx = (VarsJsonOutputCtx *) output_ctx->data; + if (json_output_ctx != NULL) { + LogFileFreeCtx(json_output_ctx->file_ctx); + SCFree(json_output_ctx); + } + SCFree(output_ctx); +} + +static void JsonVarsLogDeInitCtxSub(OutputCtx *output_ctx) +{ + SCLogDebug("cleaning up sub output_ctx %p", output_ctx); + + VarsJsonOutputCtx *json_output_ctx = (VarsJsonOutputCtx *) output_ctx->data; + + if (json_output_ctx != NULL) { + SCFree(json_output_ctx); + } + SCFree(output_ctx); +} + +#define DEFAULT_LOG_FILENAME "vars.json" + +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonVarsLogInitCtx(ConfNode *conf) +{ + VarsJsonOutputCtx *json_output_ctx = NULL; + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + SCLogDebug("VarsFastLogInitCtx2: Could not create new LogFileCtx"); + return NULL; + } + + if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + json_output_ctx = SCMalloc(sizeof(VarsJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + LogFileFreeCtx(logfile_ctx); + SCFree(output_ctx); + return NULL; + } + memset(json_output_ctx, 0, sizeof(VarsJsonOutputCtx)); + + json_output_ctx->file_ctx = logfile_ctx; + + output_ctx->data = json_output_ctx; + output_ctx->DeInit = JsonVarsLogDeInitCtx; + + return output_ctx; +} + +/** + * \brief Create a new LogFileCtx for "fast" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +static OutputCtx *JsonVarsLogInitCtxSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputJsonCtx *ajt = parent_ctx->data; + VarsJsonOutputCtx *json_output_ctx = NULL; + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) + return NULL; + + json_output_ctx = SCMalloc(sizeof(VarsJsonOutputCtx)); + if (unlikely(json_output_ctx == NULL)) { + goto error; + } + memset(json_output_ctx, 0, sizeof(VarsJsonOutputCtx)); + + json_output_ctx->file_ctx = ajt->file_ctx; + + output_ctx->data = json_output_ctx; + output_ctx->DeInit = JsonVarsLogDeInitCtxSub; + + return output_ctx; + +error: + if (json_output_ctx != NULL) { + SCFree(json_output_ctx); + } + if (output_ctx != NULL) { + SCFree(output_ctx); + } + + return NULL; +} + +void JsonVarsLogRegister (void) +{ + OutputRegisterPacketModule(LOGGER_JSON_VARS, MODULE_NAME, "vars-json-log", + JsonVarsLogInitCtx, JsonVarsLogger, JsonVarsLogCondition, + JsonVarsLogThreadInit, JsonVarsLogThreadDeinit, NULL); + OutputRegisterPacketSubModule(LOGGER_JSON_VARS, "eve-log", MODULE_NAME, + "eve-log.vars", JsonVarsLogInitCtxSub, JsonVarsLogger, + JsonVarsLogCondition, JsonVarsLogThreadInit, JsonVarsLogThreadDeinit, + NULL); +} + +#else + +void JsonVarsLogRegister (void) +{ +} + +#endif diff --git a/src/output-json-vars.h b/src/output-json-vars.h new file mode 100644 index 000000000000..395fbce09cf8 --- /dev/null +++ b/src/output-json-vars.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2013-2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Logs alerts in JSON format. + * + */ + +#ifndef __OUTPUT_JSON_VARS_H__ +#define __OUTPUT_JSON_VARS_H__ + +void JsonVarsLogRegister(void); + +#endif /* __OUTPUT_JSON_VARS_H__ */ diff --git a/src/output-json.c b/src/output-json.c index b37e9ad1733d..5a457cd5046f 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -20,7 +20,7 @@ * * \author Tom DeCanio * - * Logs alerts in JSON format. + * Logs detection and monitoring events in JSON format. * */ @@ -38,7 +38,6 @@ #include "util-unittest.h" #include "util-unittest-helper.h" -#include "detect.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" @@ -59,6 +58,8 @@ #include "util-logopenfile.h" #include "util-device.h" +#include "flow-var.h" +#include "flow-bit.h" #ifndef HAVE_LIBJANSSON @@ -66,89 +67,195 @@ * */ -TmEcode OutputJson (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode OutputJsonThreadInit(ThreadVars *, void *, void **); -TmEcode OutputJsonThreadDeinit(ThreadVars *, void *); int OutputJsonOpenFileCtx(LogFileCtx *, char *); -void OutputJsonRegisterTests(void); - -void TmModuleOutputJsonRegister (void) -{ - tmm_modules[TMM_OUTPUTJSON].name = "OutputJSON"; - tmm_modules[TMM_OUTPUTJSON].ThreadInit = OutputJsonThreadInit; - tmm_modules[TMM_OUTPUTJSON].Func = OutputJson; - tmm_modules[TMM_OUTPUTJSON].ThreadDeinit = OutputJsonThreadDeinit; - tmm_modules[TMM_OUTPUTJSON].RegisterTests = OutputJsonRegisterTests; -} - -OutputCtx *OutputJsonInitCtx(ConfNode *conf) -{ - SCLogDebug("Can't init JSON output - JSON support was disabled during build."); - return NULL; -} - -TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) -{ - SCLogDebug("Can't init JSON output thread - JSON support was disabled during build."); - return TM_ECODE_FAILED; -} - -TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - return TM_ECODE_OK; -} - -TmEcode OutputJsonThreadDeinit(ThreadVars *t, void *data) -{ - return TM_ECODE_FAILED; -} -void OutputJsonRegisterTests (void) +void OutputJsonRegister (void) { + SCLogDebug("Can't register JSON output - JSON support was disabled during build."); } #else /* implied we do have JSON support */ -#include - #define DEFAULT_LOG_FILENAME "eve.json" #define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" #define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 #define DEFAULT_ALERT_SYSLOG_LEVEL LOG_INFO #define MODULE_NAME "OutputJSON" -#define OUTPUT_BUFFER_SIZE 65535 - -#ifndef OS_WIN32 -static int alert_syslog_level = DEFAULT_ALERT_SYSLOG_LEVEL; -#endif /* OS_WIN32 */ +#define OUTPUT_BUFFER_SIZE 65536 -TmEcode OutputJson (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode OutputJsonThreadInit(ThreadVars *, void *, void **); -TmEcode OutputJsonThreadDeinit(ThreadVars *, void *); -void OutputJsonExitPrintStats(ThreadVars *, void *); -void OutputJsonRegisterTests(void); static void OutputJsonDeInitCtx(OutputCtx *); -void TmModuleOutputJsonRegister (void) +void OutputJsonRegister (void) { - tmm_modules[TMM_OUTPUTJSON].name = MODULE_NAME; - tmm_modules[TMM_OUTPUTJSON].ThreadInit = OutputJsonThreadInit; - tmm_modules[TMM_OUTPUTJSON].Func = OutputJson; - tmm_modules[TMM_OUTPUTJSON].ThreadExitPrintStats = OutputJsonExitPrintStats; - tmm_modules[TMM_OUTPUTJSON].ThreadDeinit = OutputJsonThreadDeinit; - tmm_modules[TMM_OUTPUTJSON].RegisterTests = OutputJsonRegisterTests; - tmm_modules[TMM_OUTPUTJSON].cap_flags = 0; - OutputRegisterModule(MODULE_NAME, "eve-log", OutputJsonInitCtx); } /* Default Sensor ID value */ static int64_t sensor_id = -1; /* -1 = not defined */ -static enum JsonOutput json_out = ALERT_FILE; +static void JsonAddPacketvars(const Packet *p, json_t *js_vars) +{ + if (p == NULL || p->pktvar == NULL) { + return; + } + json_t *js_pktvars = NULL; + PktVar *pv = p->pktvar; + while (pv != NULL) { + if (pv->key || pv->id > 0) { + if (js_pktvars == NULL) { + js_pktvars = json_array(); + if (js_pktvars == NULL) + break; + } + json_t *js_pair = json_object(); + if (js_pair == NULL) { + break; + } + + if (pv->key != NULL) { + uint32_t offset = 0; + uint8_t keybuf[pv->key_len + 1]; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + pv->key, pv->key_len); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + json_object_set_new(js_pair, (char *)keybuf, + json_string((char *)printable_buf)); + } else { + const char *varname = VarNameStoreLookupById(pv->id, VAR_TYPE_PKT_VAR); + uint32_t len = pv->value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + pv->value, pv->value_len); + + json_object_set_new(js_pair, varname, + json_string((char *)printable_buf)); + } + json_array_append_new(js_pktvars, js_pair); + } + pv = pv->next; + } + if (js_pktvars) { + json_object_set_new(js_vars, "pktvars", js_pktvars); + } +} + +static void JsonAddFlowvars(const Flow *f, json_t *js_vars) +{ + if (f == NULL || f->flowvar == NULL) { + return; + } + json_t *js_flowvars = NULL; + json_t *js_flowints = NULL; + json_t *js_flowbits = NULL; + GenericVar *gv = f->flowvar; + while (gv != NULL) { + if (gv->type == DETECT_FLOWVAR || gv->type == DETECT_FLOWINT) { + FlowVar *fv = (FlowVar *)gv; + if (fv->datatype == FLOWVAR_TYPE_STR && fv->key == NULL) { + const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_VAR); + if (varname) { + if (js_flowvars == NULL) { + js_flowvars = json_object(); + if (js_flowvars == NULL) + break; + } + + uint32_t len = fv->data.fv_str.value_len; + uint8_t printable_buf[len + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + fv->data.fv_str.value, fv->data.fv_str.value_len); + + json_object_set_new(js_flowvars, varname, + json_string((char *)printable_buf)); + } + } else if (fv->datatype == FLOWVAR_TYPE_STR && fv->key != NULL) { + if (js_flowvars == NULL) { + js_flowvars = json_object(); + if (js_flowvars == NULL) + break; + } + + uint8_t keybuf[fv->keylen + 1]; + uint32_t offset = 0; + PrintStringsToBuffer(keybuf, &offset, + sizeof(keybuf), + fv->key, fv->keylen); + + uint32_t len = fv->data.fv_str.value_len; + uint8_t printable_buf[len + 1]; + offset = 0; + PrintStringsToBuffer(printable_buf, &offset, + sizeof(printable_buf), + fv->data.fv_str.value, fv->data.fv_str.value_len); + + json_object_set_new(js_flowvars, (const char *)keybuf, + json_string((char *)printable_buf)); + + } else if (fv->datatype == FLOWVAR_TYPE_INT) { + const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_INT); + if (varname) { + if (js_flowints == NULL) { + js_flowints = json_object(); + if (js_flowints == NULL) + break; + } + + json_object_set_new(js_flowints, varname, json_integer(fv->data.fv_int.value)); + } + + } + } else if (gv->type == DETECT_FLOWBITS) { + FlowBit *fb = (FlowBit *)gv; + const char *varname = VarNameStoreLookupById(fb->idx, VAR_TYPE_FLOW_BIT); + if (varname) { + if (js_flowbits == NULL) { + js_flowbits = json_object(); + if (js_flowbits == NULL) + break; + } + json_object_set_new(js_flowbits, varname, json_boolean(1)); + } + } + gv = gv->next; + } + if (js_flowbits) { + json_object_set_new(js_vars, "flowbits", js_flowbits); + } + if (js_flowints) { + json_object_set_new(js_vars, "flowints", js_flowints); + } + if (js_flowvars) { + json_object_set_new(js_vars, "flowvars", js_flowvars); + } +} + +void JsonAddVars(const Packet *p, const Flow *f, json_t *js) +{ + if ((p && p->pktvar) || (f && f->flowvar)) { + json_t *js_vars = json_object(); + if (js_vars) { + if (f && f->flowvar) { + JsonAddFlowvars(f, js_vars); + } + if (p && p->pktvar) { + JsonAddPacketvars(p, js_vars); + } -static enum JsonFormat format = COMPACT; + json_object_set_new(js, "vars", js_vars); + } + } +} /** \brief jsonify tcp flags field * Only add 'true' fields in an attempt to keep things reasonably compact. @@ -173,73 +280,123 @@ void JsonTcpFlags(uint8_t flags, json_t *js) json_object_set_new(js, "cwr", json_true()); } -void CreateJSONFlowId(json_t *js, const Flow *f) -{ - if (f == NULL) - return; -#if __WORDSIZE == 64 - uint64_t addr = (uint64_t)f; -#else - uint32_t addr = (uint32_t)f; -#endif - json_object_set_new(js, "flow_id", json_integer(addr)); -} - -json_t *CreateJSONHeader(Packet *p, int direction_sensitive, char *event_type) +/** + * \brief Add five tuple from packet to JSON object + * + * \param p Packet + * \param direction_sensitive Indicate direction sensitivity + * \param js JSON object + */ +void JsonFiveTuple(const Packet *p, int direction_sensitive, json_t *js) { - char timebuf[64]; char srcip[46], dstip[46]; Port sp, dp; - - json_t *js = json_object(); - if (unlikely(js == NULL)) - return NULL; - - CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); + char proto[16]; srcip[0] = '\0'; dstip[0] = '\0'; + if (direction_sensitive) { if ((PKT_IS_TOSERVER(p))) { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), + dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), + dstip, sizeof(dstip)); } sp = p->sp; dp = p->dp; } else { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), + dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), + dstip, sizeof(dstip)); } sp = p->dp; dp = p->sp; } } else { if (PKT_IS_IPV4(p)) { - PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), + dstip, sizeof(dstip)); } else if (PKT_IS_IPV6(p)) { - PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); - PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), + srcip, sizeof(srcip)); + PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), + dstip, sizeof(dstip)); } sp = p->sp; dp = p->dp; } - char proto[16]; if (SCProtoNameValid(IP_GET_IPPROTO(p)) == TRUE) { strlcpy(proto, known_proto[IP_GET_IPPROTO(p)], sizeof(proto)); } else { snprintf(proto, sizeof(proto), "%03" PRIu32, IP_GET_IPPROTO(p)); } + json_object_set_new(js, "src_ip", json_string(srcip)); + + switch(p->proto) { + case IPPROTO_ICMP: + break; + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + json_object_set_new(js, "src_port", json_integer(sp)); + break; + } + + json_object_set_new(js, "dest_ip", json_string(dstip)); + + switch(p->proto) { + case IPPROTO_ICMP: + break; + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + json_object_set_new(js, "dest_port", json_integer(dp)); + break; + } + + json_object_set_new(js, "proto", json_string(proto)); +} + +void CreateJSONFlowId(json_t *js, const Flow *f) +{ + if (f == NULL) + return; + int64_t flow_id = FlowGetId(f); + /* reduce to 51 bits as Javascript and even JSON often seem to + * max out there. */ + flow_id &= 0x7ffffffffffffLL; + json_object_set_new(js, "flow_id", json_integer(flow_id)); +} + +json_t *CreateJSONHeader(const Packet *p, int direction_sensitive, + const char *event_type) +{ + char timebuf[64]; + + json_t *js = json_object(); + if (unlikely(js == NULL)) + return NULL; + + CreateIsoTimeString(&p->ts, timebuf, sizeof(timebuf)); + /* time & tx */ json_object_set_new(js, "timestamp", json_string(timebuf)); @@ -287,28 +444,10 @@ json_t *CreateJSONHeader(Packet *p, int direction_sensitive, char *event_type) } } - /* tuple */ - json_object_set_new(js, "src_ip", json_string(srcip)); - switch(p->proto) { - case IPPROTO_ICMP: - break; - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_SCTP: - json_object_set_new(js, "src_port", json_integer(sp)); - break; - } - json_object_set_new(js, "dest_ip", json_string(dstip)); - switch(p->proto) { - case IPPROTO_ICMP: - break; - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_SCTP: - json_object_set_new(js, "dest_port", json_integer(dp)); - break; - } - json_object_set_new(js, "proto", json_string(proto)); + /* 5-tuple */ + JsonFiveTuple(p, direction_sensitive, js); + + /* icmp */ switch (p->proto) { case IPPROTO_ICMP: if (p->icmpv4h) { @@ -331,75 +470,55 @@ json_t *CreateJSONHeader(Packet *p, int direction_sensitive, char *event_type) return js; } -int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer) +json_t *CreateJSONHeaderWithTxId(const Packet *p, int direction_sensitive, + const char *event_type, uint64_t tx_id) { - char *js_s = json_dumps(js, - JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| -#ifdef JSON_ESCAPE_SLASH - JSON_ESCAPE_SLASH -#else - 0 -#endif - ); - if (unlikely(js_s == NULL)) - return TM_ECODE_OK; + json_t *js = CreateJSONHeader(p, direction_sensitive, event_type); + if (unlikely(js == NULL)) + return NULL; - SCMutexLock(&file_ctx->fp_mutex); - if (json_out == ALERT_SYSLOG) { - syslog(alert_syslog_level, "%s", js_s); - } else if (json_out == ALERT_FILE) { - MemBufferWriteString(buffer, "%s\n", js_s); - file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), - MEMBUFFER_OFFSET(buffer), file_ctx); - } - SCMutexUnlock(&file_ctx->fp_mutex); - free(js_s); - return 0; -} + /* tx id for correlation with other events */ + json_object_set_new(js, "tx_id", json_integer(tx_id)); -TmEcode OutputJson (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - return TM_ECODE_OK; + return js; } -TmEcode OutputJsonThreadInit(ThreadVars *t, void *initdata, void **data) +int OutputJSONMemBufferCallback(const char *str, size_t size, void *data) { - AlertJsonThread *aft = SCMalloc(sizeof(AlertJsonThread)); - if (unlikely(aft == NULL)) - return TM_ECODE_FAILED; - memset(aft, 0, sizeof(AlertJsonThread)); - - if(initdata == NULL) - { - SCLogDebug("Error getting context for AlertJson. \"initdata\" argument NULL"); - SCFree(aft); - return TM_ECODE_FAILED; + OutputJSONMemBufferWrapper *wrapper = data; + MemBuffer **memb = wrapper->buffer; + + if (MEMBUFFER_OFFSET(*memb) + size >= MEMBUFFER_SIZE(*memb)) { + MemBufferExpand(memb, wrapper->expand_by); } - *data = (void *)aft; - return TM_ECODE_OK; + MemBufferWriteRaw((*memb), str, size); + return 0; } -TmEcode OutputJsonThreadDeinit(ThreadVars *t, void *data) +int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer) { - AlertJsonThread *aft = (AlertJsonThread *)data; - if (aft == NULL) { - return TM_ECODE_OK; + if (file_ctx->sensor_name) { + json_object_set_new(js, "host", + json_string(file_ctx->sensor_name)); } - SCFree(aft); - return TM_ECODE_OK; -} - -void OutputJsonExitPrintStats(ThreadVars *tv, void *data) -{ - AlertJsonThread *aft = (AlertJsonThread *)data; - if (aft == NULL) { - return; + if (file_ctx->prefix) { + MemBufferWriteRaw((*buffer), file_ctx->prefix, file_ctx->prefix_len); } - SCLogInfo("JSON output wrote %" PRIu64 " alerts", aft->file_ctx->alerts); + OutputJSONMemBufferWrapper wrapper = { + .buffer = buffer, + .expand_by = OUTPUT_BUFFER_SIZE + }; + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, + file_ctx->json_flags); + if (r != 0) + return TM_ECODE_OK; + + LogFileWrite(file_ctx, *buffer); + return 0; } /** @@ -410,6 +529,19 @@ void OutputJsonExitPrintStats(ThreadVars *tv, void *data) OutputCtx *OutputJsonInitCtx(ConfNode *conf) { OutputJsonCtx *json_ctx = SCCalloc(1, sizeof(OutputJsonCtx));; + + /* First lookup a sensor-name value in this outputs configuration + * node (deprecated). If that fails, lookup the global one. */ + const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); + if (sensor_name != NULL) { + SCLogWarning(SC_ERR_DEPRECATED_CONF, + "Found deprecated eve-log setting \"sensor-name\". " + "Please set sensor-name globally."); + } + else { + (void)ConfGet("sensor-name", (char **)&sensor_name); + } + if (unlikely(json_ctx == NULL)) { SCLogDebug("AlertJsonInitCtx: Could not create new LogFileCtx"); return NULL; @@ -422,6 +554,17 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) return NULL; } + if (sensor_name) { + json_ctx->file_ctx->sensor_name = SCStrdup(sensor_name); + if (json_ctx->file_ctx->sensor_name == NULL) { + LogFileFreeCtx(json_ctx->file_ctx); + SCFree(json_ctx); + return NULL; + } + } else { + json_ctx->file_ctx->sensor_name = NULL; + } + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { LogFileFreeCtx(json_ctx->file_ctx); @@ -443,13 +586,21 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) if (output_s != NULL) { if (strcmp(output_s, "file") == 0 || strcmp(output_s, "regular") == 0) { - json_ctx->json_out = ALERT_FILE; + json_ctx->json_out = LOGFILE_TYPE_FILE; } else if (strcmp(output_s, "syslog") == 0) { - json_ctx->json_out = ALERT_SYSLOG; + json_ctx->json_out = LOGFILE_TYPE_SYSLOG; } else if (strcmp(output_s, "unix_dgram") == 0) { - json_ctx->json_out = ALERT_UNIX_DGRAM; + json_ctx->json_out = LOGFILE_TYPE_UNIX_DGRAM; } else if (strcmp(output_s, "unix_stream") == 0) { - json_ctx->json_out = ALERT_UNIX_STREAM; + json_ctx->json_out = LOGFILE_TYPE_UNIX_STREAM; + } else if (strcmp(output_s, "redis") == 0) { +#ifdef HAVE_LIBHIREDIS + json_ctx->json_out = LOGFILE_TYPE_REDIS; +#else + SCLogError(SC_ERR_INVALID_ARGUMENT, + "redis JSON output option is not compiled"); + exit(EXIT_FAILURE); +#endif } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid JSON output option: %s", output_s); @@ -457,9 +608,25 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } } - if (json_ctx->json_out == ALERT_FILE) { + const char *prefix = ConfNodeLookupChildValue(conf, "prefix"); + if (prefix != NULL) + { + SCLogInfo("Using prefix '%s' for JSON messages", prefix); + json_ctx->file_ctx->prefix = SCStrdup(prefix); + if (json_ctx->file_ctx->prefix == NULL) + { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory for eve-log.prefix setting."); + exit(EXIT_FAILURE); + } + json_ctx->file_ctx->prefix_len = strlen(prefix); + } - if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME) < 0) { + if (json_ctx->json_out == LOGFILE_TYPE_FILE || + json_ctx->json_out == LOGFILE_TYPE_UNIX_DGRAM || + json_ctx->json_out == LOGFILE_TYPE_UNIX_STREAM) + { + if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); SCFree(output_ctx); @@ -479,7 +646,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) exit(EXIT_FAILURE); } } - } else if (json_out == ALERT_SYSLOG) { + } else if (json_ctx->json_out == LOGFILE_TYPE_SYSLOG) { const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); if (facility_s == NULL) { facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; @@ -497,7 +664,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) if (level_s != NULL) { int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap()); if (level != -1) { - alert_syslog_level = level; + json_ctx->file_ctx->syslog_setup.alert_syslog_level = level; } } @@ -508,6 +675,29 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) openlog(ident, LOG_PID|LOG_NDELAY, facility); } +#ifdef HAVE_LIBHIREDIS + else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { + ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); + if (!json_ctx->file_ctx->sensor_name) { + char hostname[1024]; + gethostname(hostname, 1023); + json_ctx->file_ctx->sensor_name = SCStrdup(hostname); + } + if (json_ctx->file_ctx->sensor_name == NULL) { + LogFileFreeCtx(json_ctx->file_ctx); + SCFree(json_ctx); + SCFree(output_ctx); + return NULL; + } + + if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) { + LogFileFreeCtx(json_ctx->file_ctx); + SCFree(json_ctx); + SCFree(output_ctx); + return NULL; + } + } +#endif const char *sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id"); if (sensor_id_s != NULL) { @@ -519,11 +709,10 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf) } } - format = json_ctx->format; - json_out = json_ctx->json_out; + json_ctx->file_ctx->type = json_ctx->json_out; } - SCLogInfo("returning output_ctx %p", output_ctx); + SCLogDebug("returning output_ctx %p", output_ctx); return output_ctx; } @@ -531,27 +720,14 @@ static void OutputJsonDeInitCtx(OutputCtx *output_ctx) { OutputJsonCtx *json_ctx = (OutputJsonCtx *)output_ctx->data; LogFileCtx *logfile_ctx = json_ctx->file_ctx; - OutputUnregisterFileRotationFlag(&logfile_ctx->rotation_flag); + if (logfile_ctx->dropped) { + SCLogWarning(SC_WARN_EVENT_DROPPED, + "%"PRIu64" events were dropped due to slow or " + "disconnected socket", logfile_ctx->dropped); + } LogFileFreeCtx(logfile_ctx); SCFree(json_ctx); SCFree(output_ctx); } -/*------------------------------Unittests-------------------------------------*/ - -#ifdef UNITTESTS - -#endif /* UNITTESTS */ - -/** - * \brief This function registers unit tests for AlertFastLog API. - */ -void OutputJsonRegisterTests(void) -{ - -#ifdef UNITTESTS - -#endif /* UNITTESTS */ - -} #endif diff --git a/src/output-json.h b/src/output-json.h index e35b81be4581..5f42e7657a49 100644 --- a/src/output-json.h +++ b/src/output-json.h @@ -24,25 +24,30 @@ #ifndef __OUTPUT_JSON_H__ #define __OUTPUT_JSON_H__ -void TmModuleOutputJsonRegister (void); - -#ifdef HAVE_LIBJANSSON - #include "suricata-common.h" #include "util-buffer.h" #include "util-logopenfile.h" +void OutputJsonRegister(void); + +#ifdef HAVE_LIBJANSSON +/* helper struct for OutputJSONMemBufferCallback */ +typedef struct OutputJSONMemBufferWrapper_ { + MemBuffer **buffer; /**< buffer to use & expand as needed */ + size_t expand_by; /**< expand by this size */ +} OutputJSONMemBufferWrapper; + +int OutputJSONMemBufferCallback(const char *str, size_t size, void *data); + +void JsonAddVars(const Packet *p, const Flow *f, json_t *js); void CreateJSONFlowId(json_t *js, const Flow *f); void JsonTcpFlags(uint8_t flags, json_t *js); -json_t *CreateJSONHeader(Packet *p, int direction_sensative, char *event_type); -TmEcode OutputJSON(json_t *js, void *data, uint64_t *count); -int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer); +void JsonFiveTuple(const Packet *, int, json_t *); +json_t *CreateJSONHeader(const Packet *p, int direction_sensative, const char *event_type); +json_t *CreateJSONHeaderWithTxId(const Packet *p, int direction_sensitive, const char *event_type, uint64_t tx_id); +int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer **buffer); OutputCtx *OutputJsonInitCtx(ConfNode *); -enum JsonOutput { ALERT_FILE, - ALERT_SYSLOG, - ALERT_UNIX_DGRAM, - ALERT_UNIX_STREAM }; enum JsonFormat { COMPACT, INDENT }; /* @@ -50,11 +55,10 @@ enum JsonFormat { COMPACT, INDENT }; */ typedef struct OutputJsonCtx_ { LogFileCtx *file_ctx; - enum JsonOutput json_out; + enum LogFileType json_out; enum JsonFormat format; } OutputJsonCtx; - typedef struct AlertJsonThread_ { /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ LogFileCtx *file_ctx; diff --git a/src/output-lua.c b/src/output-lua.c index 1e15de44c66d..081a0bd4417f 100644 --- a/src/output-lua.c +++ b/src/output-lua.c @@ -40,6 +40,8 @@ #include "output.h" #include "app-layer-htp.h" #include "app-layer.h" +#include "app-layer-ssl.h" +#include "app-layer-ssh.h" #include "app-layer-parser.h" #include "util-privs.h" #include "util-buffer.h" @@ -56,6 +58,10 @@ #include "util-lua.h" #include "util-lua-common.h" #include "util-lua-http.h" +#include "util-lua-dns.h" +#include "util-lua-tls.h" +#include "util-lua-ssh.h" +#include "util-lua-smtp.h" #define MODULE_NAME "LuaLog" @@ -78,6 +84,9 @@ typedef struct LogLuaThreadCtx_ { LogLuaCtx *lua_ctx; } LogLuaThreadCtx; +static TmEcode LuaLogThreadInit(ThreadVars *t, void *initdata, void **data); +static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data); + /** \internal * \brief TX logger for lua scripts * @@ -97,7 +106,7 @@ static int LuaTxLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); LuaStateSetTX(td->lua_ctx->luastate, txptr); - LuaStateSetFlow(td->lua_ctx->luastate, f, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, f); /* prepare data to pass to script */ lua_getglobal(td->lua_ctx->luastate, "log"); @@ -141,7 +150,7 @@ static int LuaStreamingLogger(ThreadVars *tv, void *thread_data, const Flow *f, LuaStateSetThreadVars(td->lua_ctx->luastate, tv); if (flags & OUTPUT_STREAMING_FLAG_TRANSACTION) LuaStateSetTX(td->lua_ctx->luastate, txptr); - LuaStateSetFlow(td->lua_ctx->luastate, (Flow *)f, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, (Flow *)f); LuaStateSetStreamingBuffer(td->lua_ctx->luastate, &b); /* prepare data to pass to script */ @@ -204,7 +213,7 @@ static int LuaPacketLoggerAlerts(ThreadVars *tv, void *thread_data, const Packet LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); LuaStateSetPacketAlert(td->lua_ctx->luastate, (PacketAlert *)pa); /* prepare data to pass to script */ @@ -263,7 +272,7 @@ static int LuaPacketLogger(ThreadVars *tv, void *thread_data, const Packet *p) LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* unlocked */LUA_FLOW_NOT_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); /* prepare data to pass to script */ lua_newtable(td->lua_ctx->luastate); @@ -306,7 +315,7 @@ static int LuaFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, con /* Get the TX so the script can get more context about it. * TODO hardcoded to HTTP currently */ void *txptr = NULL; - if (p && p->flow && p->flow->alstate) + if (p->flow && p->flow->alstate) txptr = AppLayerParserGetTx(p->proto, ALPROTO_HTTP, p->flow->alstate, ff->txid); SCMutexLock(&td->lua_ctx->m); @@ -314,7 +323,7 @@ static int LuaFileLogger(ThreadVars *tv, void *thread_data, const Packet *p, con LuaStateSetThreadVars(td->lua_ctx->luastate, tv); LuaStateSetPacket(td->lua_ctx->luastate, (Packet *)p); LuaStateSetTX(td->lua_ctx->luastate, txptr); - LuaStateSetFlow(td->lua_ctx->luastate, p->flow, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, p->flow); LuaStateSetFile(td->lua_ctx->luastate, (File *)ff); /* get the lua function to call */ @@ -345,7 +354,7 @@ static int LuaFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) SCMutexLock(&td->lua_ctx->m); LuaStateSetThreadVars(td->lua_ctx->luastate, tv); - LuaStateSetFlow(td->lua_ctx->luastate, f, /* locked */LUA_FLOW_LOCKED_BY_PARENT); + LuaStateSetFlow(td->lua_ctx->luastate, f); /* get the lua function to call */ lua_getglobal(td->lua_ctx->luastate, "log"); @@ -358,6 +367,60 @@ static int LuaFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) return 0; } + + +static int LuaStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st) +{ + SCEnter(); + LogLuaThreadCtx *td = (LogLuaThreadCtx *)thread_data; + + SCMutexLock(&td->lua_ctx->m); + + lua_State *luastate = td->lua_ctx->luastate; + /* get the lua function to call */ + lua_getglobal(td->lua_ctx->luastate, "log"); + + /* create lua array, which is really just a table. The key is an int (1-x), + * the value another table with named fields: name, tm_name, value, pvalue. + * { 1, { name=, tmname=, value=, pvalue=}} + * { 2, { name=, tmname=, value=, pvalue=}} + * etc + */ + lua_newtable(luastate); + uint32_t u = 0; + for (; u < st->nstats; u++) { + lua_pushinteger(luastate, u + 1); + + lua_newtable(luastate); + + lua_pushstring(luastate, "name"); + lua_pushstring(luastate, st->stats[u].name); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "tmname"); + lua_pushstring(luastate, st->stats[u].tm_name); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "value"); + lua_pushinteger(luastate, st->stats[u].value); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "pvalue"); + lua_pushinteger(luastate, st->stats[u].pvalue); + lua_settable(luastate, -3); + + lua_settable(luastate, -3); + } + + int retval = lua_pcall(td->lua_ctx->luastate, 1, 0, 0); + if (retval != 0) { + SCLogInfo("failed to run script: %s", lua_tostring(td->lua_ctx->luastate, -1)); + } + SCMutexUnlock(&td->lua_ctx->m); + return 0; + +} + typedef struct LogLuaScriptOptions_ { AppProto alproto; int packet; @@ -367,6 +430,7 @@ typedef struct LogLuaScriptOptions_ { int tcp_data; int http_body; int flow; + int stats; } LogLuaScriptOptions; /** \brief load and evaluate the script @@ -382,7 +446,7 @@ typedef struct LogLuaScriptOptions_ { static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { int status; - lua_State *luastate = luaL_newstate(); + lua_State *luastate = LuaGetState(); if (luastate == NULL) goto error; luaL_openlibs(luastate); @@ -459,6 +523,14 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { if (strcmp(k,"protocol") == 0 && strcmp(v, "http") == 0) options->alproto = ALPROTO_HTTP; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "dns") == 0) + options->alproto = ALPROTO_DNS; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "tls") == 0) + options->alproto = ALPROTO_TLS; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "ssh") == 0) + options->alproto = ALPROTO_SSH; + else if (strcmp(k,"protocol") == 0 && strcmp(v, "smtp") == 0) + options->alproto = ALPROTO_SMTP; else if (strcmp(k, "type") == 0 && strcmp(v, "packet") == 0) options->packet = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "alerts") == 0) @@ -471,11 +543,13 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { options->flow = 1; else if (strcmp(k, "filter") == 0 && strcmp(v, "tcp") == 0) options->tcp_data = 1; + else if (strcmp(k, "type") == 0 && strcmp(v, "stats") == 0) + options->stats = 1; else SCLogInfo("unknown key and/or value: k='%s', v='%s'", k, v); } - if (options->alproto + options->packet + options->file > 1) { + if (((options->alproto != ALPROTO_UNKNOWN)) + options->packet + options->file > 1) { SCLogError(SC_ERR_LUA_ERROR, "invalid combination of 'needs' in the script"); goto error; } @@ -500,10 +574,11 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { /* pop the table */ lua_pop(luastate, 1); - lua_close(luastate); + LuaReturnState(luastate); return 0; error: - lua_close(luastate); + if (luastate) + LuaReturnState(luastate); return -1; } @@ -515,7 +590,7 @@ static int LuaScriptInit(const char *filename, LogLuaScriptOptions *options) { */ static lua_State *LuaScriptSetup(const char *filename) { - lua_State *luastate = luaL_newstate(); + lua_State *luastate = LuaGetState(); if (luastate == NULL) { SCLogError(SC_ERR_LUA_ERROR, "luaL_newstate failed"); goto error; @@ -556,6 +631,10 @@ static lua_State *LuaScriptSetup(const char *filename) /* unconditionally register http function. They will only work * if the tx is registered in the state at runtime though. */ LuaRegisterHttpFunctions(luastate); + LuaRegisterDnsFunctions(luastate); + LuaRegisterTlsFunctions(luastate); + LuaRegisterSshFunctions(luastate); + LuaRegisterSmtpFunctions(luastate); if (lua_pcall(luastate, 0, 0, 0) != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'setup' function: %s", lua_tostring(luastate, -1)); @@ -565,10 +644,17 @@ static lua_State *LuaScriptSetup(const char *filename) SCLogDebug("lua_State %p is set up", luastate); return luastate; error: - lua_close(luastate); + if (luastate) + LuaReturnState(luastate); return NULL; } +static void LogLuaSubFree(OutputCtx *oc) { + if (oc->data) + SCFree(oc->data); + SCFree(oc); +} + /** \brief initialize output for a script instance * * Runs script 'setup' function. @@ -610,7 +696,7 @@ static OutputCtx *OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) SCLogDebug("lua_ctx %p", lua_ctx); output_ctx->data = lua_ctx; - output_ctx->DeInit = NULL; + output_ctx->DeInit = LogLuaSubFree; return output_ctx; error: @@ -620,10 +706,16 @@ static OutputCtx *OutputLuaLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) return NULL; } -static void LogLuaMasterFree(OutputCtx *oc) { - BUG_ON(oc == NULL); +static void LogLuaMasterFree(OutputCtx *oc) +{ if (oc->data) SCFree(oc->data); + + OutputModule *om, *tom; + TAILQ_FOREACH_SAFE(om, &oc->submodules, entries, tom) { + SCFree(om); + } + SCFree(oc); } /** \internal @@ -635,7 +727,7 @@ static void LogLuaMasterFree(OutputCtx *oc) { */ static OutputCtx *OutputLuaLogInit(ConfNode *conf) { - const char *dir = ConfNodeLookupChildValue(conf, "script-dir"); + const char *dir = ConfNodeLookupChildValue(conf, "scripts-dir"); if (dir == NULL) dir = ""; @@ -651,12 +743,12 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) if (unlikely(output_ctx == NULL)) { return NULL; } + output_ctx->DeInit = LogLuaMasterFree; output_ctx->data = SCCalloc(1, sizeof(LogLuaMasterCtx)); if (unlikely(output_ctx->data == NULL)) { SCFree(output_ctx); return NULL; } - output_ctx->DeInit = LogLuaMasterFree; LogLuaMasterCtx *master_config = output_ctx->data; strlcpy(master_config->path, dir, sizeof(master_config->path)); TAILQ_INIT(&output_ctx->submodules); @@ -675,7 +767,7 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) int r = LuaScriptInit(path, &opts); if (r != 0) { SCLogError(SC_ERR_LUA_ERROR, "couldn't initialize scipt"); - continue; + goto error; } /* create an OutputModule for this script, based @@ -683,12 +775,14 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) OutputModule *om = SCCalloc(1, sizeof(*om)); if (om == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "calloc() failed"); - continue; + goto error; } om->name = MODULE_NAME; om->conf_name = script->val; om->InitSubFunc = OutputLuaLogInitSub; + om->ThreadInit = LuaLogThreadInit; + om->ThreadDeinit = LuaLogThreadDeinit; if (opts.alproto == ALPROTO_HTTP && opts.streaming) { om->StreamingLogFunc = LuaStreamingLogger; @@ -698,7 +792,32 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) } else if (opts.alproto == ALPROTO_HTTP) { om->TxLogFunc = LuaTxLogger; om->alproto = ALPROTO_HTTP; + om->ts_log_progress = -1; + om->tc_log_progress = -1; AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_HTTP); + } else if (opts.alproto == ALPROTO_TLS) { + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_TLS; + om->tc_log_progress = TLS_HANDSHAKE_DONE; + om->ts_log_progress = TLS_HANDSHAKE_DONE; + } else if (opts.alproto == ALPROTO_DNS) { + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_DNS; + om->ts_log_progress = -1; + om->tc_log_progress = -1; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_DNS); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_DNS); + } else if (opts.alproto == ALPROTO_SSH) { + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_SSH; + om->tc_log_progress = SSH_STATE_BANNER_DONE; + om->ts_log_progress = SSH_STATE_BANNER_DONE; + } else if (opts.alproto == ALPROTO_SMTP) { + om->TxLogFunc = LuaTxLogger; + om->alproto = ALPROTO_SMTP; + om->ts_log_progress = -1; + om->tc_log_progress = -1; + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_SMTP); } else if (opts.packet && opts.alerts) { om->PacketLogFunc = LuaPacketLoggerAlerts; om->PacketConditionFunc = LuaPacketConditionAlerts; @@ -712,16 +831,23 @@ static OutputCtx *OutputLuaLogInit(ConfNode *conf) om->StreamingLogFunc = LuaStreamingLogger; } else if (opts.flow) { om->FlowLogFunc = LuaFlowLogger; + } else if (opts.stats) { + om->StatsLogFunc = LuaStatsLogger; } else { SCLogError(SC_ERR_LUA_ERROR, "failed to setup thread module"); SCFree(om); - continue; + goto error; } TAILQ_INSERT_TAIL(&output_ctx->submodules, om, entries); } return output_ctx; + +error: + if (output_ctx->DeInit) + output_ctx->DeInit(output_ctx); + return NULL; } /** \internal @@ -742,6 +868,7 @@ static void OutputLuaLogDoDeinit(LogLuaCtx *lua_ctx) SCLogError(SC_ERR_LUA_ERROR, "couldn't run script 'deinit' function: %s", lua_tostring(luastate, -1)); return; } + LuaReturnState(luastate); } /** \internal @@ -795,21 +922,14 @@ static TmEcode LuaLogThreadDeinit(ThreadVars *t, void *data) return TM_ECODE_OK; } -void TmModuleLuaLogRegister (void) { - tmm_modules[TMM_LUALOG].name = MODULE_NAME; - tmm_modules[TMM_LUALOG].ThreadInit = LuaLogThreadInit; - tmm_modules[TMM_LUALOG].ThreadDeinit = LuaLogThreadDeinit; - tmm_modules[TMM_LUALOG].RegisterTests = NULL; - tmm_modules[TMM_LUALOG].cap_flags = 0; - tmm_modules[TMM_LUALOG].flags = TM_FLAG_LOGAPI_TM; - +void LuaLogRegister(void) { /* register as separate module */ OutputRegisterModule(MODULE_NAME, "lua", OutputLuaLogInit); } #else -void TmModuleLuaLogRegister (void) { +void LuaLogRegister (void) { /* no-op */ } diff --git a/src/output-lua.h b/src/output-lua.h index 627cdc37a25e..c8c5ebbf4565 100644 --- a/src/output-lua.h +++ b/src/output-lua.h @@ -24,6 +24,6 @@ #ifndef __OUTPUT_LUA_H__ #define __OUTPUT_LUA_H__ -void TmModuleLuaLogRegister (void); +void LuaLogRegister(void); #endif /* __OUTPUT_LUA_H__ */ diff --git a/src/output-packet.c b/src/output-packet.c index d2cd901c88bb..fe4cc2fee825 100644 --- a/src/output-packet.c +++ b/src/output-packet.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-packet.h" #include "util-profiling.h" @@ -48,17 +49,20 @@ typedef struct OutputPacketLogger_ { OutputCtx *output_ctx; struct OutputPacketLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputPacketLogger; static OutputPacketLogger *list = NULL; -int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, PacketLogCondition ConditionFunc, OutputCtx *output_ctx) +int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, + PacketLogger LogFunc, PacketLogCondition ConditionFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputPacketLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -68,7 +72,10 @@ int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, PacketLog op->ConditionFunc = ConditionFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; + op->logger_id = logger_id; if (list == NULL) list = op; @@ -83,10 +90,14 @@ int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, PacketLog return 0; } -static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputPacketLogger *logger = list; @@ -100,9 +111,9 @@ static TmEcode OutputPacketLog(ThreadVars *tv, Packet *p, void *thread_data, Pac BUG_ON(logger->LogFunc == NULL || logger->ConditionFunc == NULL); if ((logger->ConditionFunc(tv, (const Packet *)p)) == TRUE) { - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Packet *)p); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); } logger = logger->next; @@ -131,16 +142,9 @@ static TmEcode OutputPacketLogThreadInit(ThreadVars *tv, void *initdata, void ** OutputPacketLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -174,15 +178,8 @@ static TmEcode OutputPacketLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputPacketLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -191,6 +188,8 @@ static TmEcode OutputPacketLogThreadDeinit(ThreadVars *tv, void *thread_data) logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } @@ -201,15 +200,8 @@ static void OutputPacketLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputPacketLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; @@ -217,14 +209,11 @@ static void OutputPacketLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModulePacketLoggerRegister (void) +void OutputPacketLoggerRegister(void) { - tmm_modules[TMM_PACKETLOGGER].name = "__packet_logger__"; - tmm_modules[TMM_PACKETLOGGER].ThreadInit = OutputPacketLogThreadInit; - tmm_modules[TMM_PACKETLOGGER].Func = OutputPacketLog; - tmm_modules[TMM_PACKETLOGGER].ThreadExitPrintStats = OutputPacketLogExitPrintStats; - tmm_modules[TMM_PACKETLOGGER].ThreadDeinit = OutputPacketLogThreadDeinit; - tmm_modules[TMM_PACKETLOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputPacketLogThreadInit, + OutputPacketLogThreadDeinit, OutputPacketLogExitPrintStats, + OutputPacketLog); } void OutputPacketShutdown(void) diff --git a/src/output-packet.h b/src/output-packet.h index 5ae1adf8e487..da40ccde47c1 100644 --- a/src/output-packet.h +++ b/src/output-packet.h @@ -27,6 +27,7 @@ #define __OUTPUT_PACKET_H__ #include "decode.h" +#include "output.h" /** packet logger function pointer type */ typedef int (*PacketLogger)(ThreadVars *, void *thread_data, const Packet *); @@ -36,10 +37,11 @@ typedef int (*PacketLogger)(ThreadVars *, void *thread_data, const Packet *); */ typedef int (*PacketLogCondition)(ThreadVars *, const Packet *); -int OutputRegisterPacketLogger(const char *name, PacketLogger LogFunc, - PacketLogCondition ConditionFunc, OutputCtx *); +int OutputRegisterPacketLogger(LoggerId logger_id, const char *name, + PacketLogger LogFunc, PacketLogCondition ConditionFunc, OutputCtx *, + ThreadInitFunc, ThreadDeinitFunc, ThreadExitPrintStatsFunc); -void TmModulePacketLoggerRegister (void); +void OutputPacketLoggerRegister(void); void OutputPacketShutdown(void); diff --git a/src/output-stats.c b/src/output-stats.c new file mode 100644 index 000000000000..2eb9c9323fa9 --- /dev/null +++ b/src/output-stats.c @@ -0,0 +1,223 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Stats Logger Output registration functions + */ + +#include "suricata-common.h" +#include "tm-modules.h" +#include "output-stats.h" + +typedef struct OutputLoggerThreadStore_ { + void *thread_data; + struct OutputLoggerThreadStore_ *next; +} OutputLoggerThreadStore; + +/** per thread data for this module, contains a list of per thread + * data for the packet loggers. */ +typedef struct OutputLoggerThreadData_ { + OutputLoggerThreadStore *store; +} OutputLoggerThreadData; + +/* logger instance, a module + a output ctx, + * it's perfectly valid that have multiple instances of the same + * log module (e.g. http.log) with different output ctx'. */ +typedef struct OutputStatsLogger_ { + StatsLogger LogFunc; + OutputCtx *output_ctx; + struct OutputStatsLogger_ *next; + const char *name; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; +} OutputStatsLogger; + +static OutputStatsLogger *list = NULL; + +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, + OutputCtx *output_ctx, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputStatsLogger *op = SCMalloc(sizeof(*op)); + if (op == NULL) + return -1; + memset(op, 0x00, sizeof(*op)); + + op->LogFunc = LogFunc; + op->output_ctx = output_ctx; + op->name = name; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; + + if (list == NULL) + list = op; + else { + OutputStatsLogger *t = list; + while (t->next) + t = t->next; + t->next = op; + } + + SCLogDebug("OutputRegisterStatsLogger happy"); + return 0; +} + +TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st) +{ + BUG_ON(thread_data == NULL); + BUG_ON(list == NULL); + + OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; + OutputStatsLogger *logger = list; + OutputLoggerThreadStore *store = op_thread_data->store; + + BUG_ON(logger == NULL && store != NULL); + BUG_ON(logger != NULL && store == NULL); + BUG_ON(logger == NULL && store == NULL); + + logger = list; + store = op_thread_data->store; + while (logger && store) { + BUG_ON(logger->LogFunc == NULL); + + logger->LogFunc(tv, store->thread_data, st); + + logger = logger->next; + store = store->next; + + BUG_ON(logger == NULL && store != NULL); + BUG_ON(logger != NULL && store == NULL); + } + + return TM_ECODE_OK; +} + +/** \brief thread init for the tx logger + * This will run the thread init functions for the individual registered + * loggers */ +static TmEcode OutputStatsLogThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + OutputLoggerThreadData *td = SCMalloc(sizeof(*td)); + if (td == NULL) + return TM_ECODE_FAILED; + memset(td, 0x00, sizeof(*td)); + + *data = (void *)td; + + SCLogDebug("OutputStatsLogThreadInit happy (*data %p)", *data); + + OutputStatsLogger *logger = list; + while (logger) { + if (logger->ThreadInit) { + void *retptr = NULL; + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); +/* todo */ BUG_ON(ts == NULL); + memset(ts, 0x00, sizeof(*ts)); + + /* store thread handle */ + ts->thread_data = retptr; + + if (td->store == NULL) { + td->store = ts; + } else { + OutputLoggerThreadStore *tmp = td->store; + while (tmp->next != NULL) + tmp = tmp->next; + tmp->next = ts; + } + + SCLogDebug("%s is now set up", logger->name); + } + } + + logger = logger->next; + } + + SCLogDebug("OutputStatsLogThreadInit happy (*data %p)", *data); + return TM_ECODE_OK; +} + +static TmEcode OutputStatsLogThreadDeinit(ThreadVars *tv, void *thread_data) +{ + OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; + OutputLoggerThreadStore *store = op_thread_data->store; + OutputStatsLogger *logger = list; + + while (logger && store) { + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); + } + OutputLoggerThreadStore *next_store = store->next; + SCFree(store); + store = next_store; + logger = logger->next; + } + + SCFree(op_thread_data); + return TM_ECODE_OK; +} + +static void OutputStatsLogExitPrintStats(ThreadVars *tv, void *thread_data) +{ + OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; + OutputLoggerThreadStore *store = op_thread_data->store; + OutputStatsLogger *logger = list; + + while (logger && store) { + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); + } + + logger = logger->next; + store = store->next; + } +} + +void TmModuleStatsLoggerRegister (void) +{ + tmm_modules[TMM_STATSLOGGER].name = "__stats_logger__"; + tmm_modules[TMM_STATSLOGGER].ThreadInit = OutputStatsLogThreadInit; + tmm_modules[TMM_STATSLOGGER].ThreadExitPrintStats = OutputStatsLogExitPrintStats; + tmm_modules[TMM_STATSLOGGER].ThreadDeinit = OutputStatsLogThreadDeinit; + tmm_modules[TMM_STATSLOGGER].cap_flags = 0; +} + +int OutputStatsLoggersRegistered(void) +{ + if (list != NULL) + return 1; + return 0; +} + +void OutputStatsShutdown(void) +{ + OutputStatsLogger *logger = list; + while (logger) { + OutputStatsLogger *next_logger = logger->next; + SCFree(logger); + logger = next_logger; + } + list = NULL; +} diff --git a/src/output-stats.h b/src/output-stats.h new file mode 100644 index 000000000000..eba72f36e410 --- /dev/null +++ b/src/output-stats.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2007-2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Stats Logger Output registration functions + */ + +#ifndef __OUTPUT_STATS_H__ +#define __OUTPUT_STATS_H__ + +typedef struct StatsRecord_ { + const char *name; + const char *tm_name; + uint64_t value; /**< total value */ + uint64_t pvalue; /**< prev value (may be higher for memuse counters) */ +} StatsRecord; + +typedef struct StatsTable_ { + StatsRecord *stats; /**< array of global stats, indexed by counters gid */ + StatsRecord *tstats; /**< array of arrays with per thread stats */ + uint32_t nstats; /**< size in records of 'stats' */ + uint32_t ntstats; /**< number of threads for which tstats stores stats */ + time_t start_time; + struct timeval ts; +} StatsTable; + +TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st); + +typedef int (*StatsLogger)(ThreadVars *, void *thread_data, const StatsTable *); + +int OutputRegisterStatsLogger(const char *name, StatsLogger LogFunc, + OutputCtx *, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void TmModuleStatsLoggerRegister (void); + +int OutputStatsLoggersRegistered(void); + +void OutputStatsShutdown(void); + +#endif /* __OUTPUT_STATS_H__ */ diff --git a/src/output-streaming.c b/src/output-streaming.c index 41bbae266ad7..aae5ec550136 100644 --- a/src/output-streaming.c +++ b/src/output-streaming.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-streaming.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -53,19 +54,21 @@ typedef struct OutputStreamingLogger_ { OutputCtx *output_ctx; struct OutputStreamingLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; enum OutputStreamingType type; + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; } OutputStreamingLogger; static OutputStreamingLogger *list = NULL; -int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, - OutputCtx *output_ctx, enum OutputStreamingType type ) +int OutputRegisterStreamingLogger(LoggerId id, const char *name, + StreamingLogger LogFunc, OutputCtx *output_ctx, + enum OutputStreamingType type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) - return -1; - OutputStreamingLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) return -1; @@ -74,8 +77,11 @@ int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, op->LogFunc = LogFunc; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->logger_id = id; op->type = type; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; if (list == NULL) list = op; @@ -86,7 +92,7 @@ int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, t->next = op; } - SCLogDebug("OutputRegisterTxLogger happy"); + SCLogDebug("OutputRegisterStreamingLogger happy"); return 0; } @@ -98,7 +104,7 @@ typedef struct StreamerCallbackData_ { enum OutputStreamingType type; } StreamerCallbackData; -int Streamer(void *cbdata, Flow *f, uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) +int Streamer(void *cbdata, Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags) { StreamerCallbackData *streamer_cbdata = (StreamerCallbackData *)cbdata; BUG_ON(streamer_cbdata == NULL); @@ -116,9 +122,9 @@ int Streamer(void *cbdata, Flow *f, uint8_t *data, uint32_t data_len, uint64_t t if (logger->type == streamer_cbdata->type) { SCLogDebug("logger %p", logger); - PACKET_PROFILING_TMM_START(p, logger->module_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, (const Flow *)f, data, data_len, tx_id, flags); - PACKET_PROFILING_TMM_END(p, logger->module_id); + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); } logger = logger->next; @@ -147,9 +153,11 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) HtpState *s = f->alstate; if (s != NULL && s->conn != NULL) { int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP, 0); + AppLayerParserGetStateProgressCompletionStatus(ALPROTO_HTTP, + STREAM_TOSERVER); int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_HTTP, 1); + AppLayerParserGetStateProgressCompletionStatus(ALPROTO_HTTP, + STREAM_TOCLIENT); // for each tx uint64_t tx_id = 0; @@ -161,9 +169,11 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) int tx_done = 0; int tx_logged = 0; - int tx_progress_ts = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, 0); + int tx_progress_ts = AppLayerParserGetStateProgress( + IPPROTO_TCP, ALPROTO_HTTP, tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER)); if (tx_progress_ts >= tx_progress_done_value_ts) { - int tx_progress_tc = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, 1); + int tx_progress_tc = AppLayerParserGetStateProgress( + IPPROTO_TCP, ALPROTO_HTTP, tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); if (tx_progress_tc >= tx_progress_done_value_tc) { tx_done = 1; } @@ -201,7 +211,7 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) } uint8_t flags = iflags | OUTPUT_STREAMING_FLAG_TRANSACTION; - if (chunk->stream_offset == 0) + if (chunk->sbseg.stream_offset == 0) flags |= OUTPUT_STREAMING_FLAG_OPEN; /* if we need to close and we're at the last segment in the list * we add the 'close' flag so the logger can close up. */ @@ -209,9 +219,13 @@ int HttpBodyIterator(Flow *f, int close, void *cbdata, uint8_t iflags) flags |= OUTPUT_STREAMING_FLAG_CLOSE; } + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len); + // invoke Streamer - Streamer(cbdata, f, chunk->data, (uint32_t)chunk->len, tx_id, flags); - //PrintRawDataFp(stdout, chunk->data, chunk->len); + Streamer(cbdata, f, data, data_len, tx_id, flags); + //PrintRawDataFp(stdout, data, data_len); chunk->logged = 1; tx_logged = 1; } @@ -284,10 +298,14 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t return 0; } -static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + + if (list == NULL) { + /* No child loggers. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputStreamingLogger *logger = list; @@ -312,8 +330,6 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, else flags |= OUTPUT_STREAMING_FLAG_TOSERVER; - FLOWLOCK_WRLOCK(f); - if (op_thread_data->loggers & (1<protoctx; if (ssn) { @@ -341,7 +357,6 @@ static TmEcode OutputStreamingLog(ThreadVars *tv, Packet *p, void *thread_data, } } - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } @@ -360,16 +375,9 @@ static TmEcode OutputStreamingLogThreadInit(ThreadVars *tv, void *initdata, void OutputStreamingLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -404,21 +412,17 @@ static TmEcode OutputStreamingLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputStreamingLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } + OutputLoggerThreadStore *next_store = store->next; + SCFree(store); logger = logger->next; - store = store->next; + store = next_store; } + SCFree(op_thread_data); return TM_ECODE_OK; } @@ -428,15 +432,8 @@ static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputStreamingLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; @@ -444,11 +441,19 @@ static void OutputStreamingLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleStreamingLoggerRegister (void) { - tmm_modules[TMM_STREAMINGLOGGER].name = "__streaming_logger__"; - tmm_modules[TMM_STREAMINGLOGGER].ThreadInit = OutputStreamingLogThreadInit; - tmm_modules[TMM_STREAMINGLOGGER].Func = OutputStreamingLog; - tmm_modules[TMM_STREAMINGLOGGER].ThreadExitPrintStats = OutputStreamingLogExitPrintStats; - tmm_modules[TMM_STREAMINGLOGGER].ThreadDeinit = OutputStreamingLogThreadDeinit; - tmm_modules[TMM_STREAMINGLOGGER].cap_flags = 0; +void OutputStreamingLoggerRegister(void) { + OutputRegisterRootLogger(OutputStreamingLogThreadInit, + OutputStreamingLogThreadDeinit, OutputStreamingLogExitPrintStats, + OutputStreamingLog); +} + +void OutputStreamingShutdown(void) +{ + OutputStreamingLogger *logger = list; + while (logger) { + OutputStreamingLogger *next_logger = logger->next; + SCFree(logger); + logger = next_logger; + } + list = NULL; } diff --git a/src/output-streaming.h b/src/output-streaming.h index ff924dc0022a..bc02fe543be5 100644 --- a/src/output-streaming.h +++ b/src/output-streaming.h @@ -45,9 +45,13 @@ typedef int (*StreamingLogger)(ThreadVars *, void *thread_data, const Flow *f, const uint8_t *data, uint32_t data_len, uint64_t tx_id, uint8_t flags); -int OutputRegisterStreamingLogger(const char *name, StreamingLogger LogFunc, OutputCtx *, - enum OutputStreamingType); +int OutputRegisterStreamingLogger(LoggerId id, const char *name, + StreamingLogger LogFunc, OutputCtx *, enum OutputStreamingType, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); -void TmModuleStreamingLoggerRegister (void); +void OutputStreamingLoggerRegister (void); + +void OutputStreamingShutdown(void); #endif /* __OUTPUT_STREAMING_H__ */ diff --git a/src/output-tx.c b/src/output-tx.c index 9bb7c277db6b..482fa087d9ad 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "tm-modules.h" +#include "output.h" #include "output-tx.h" #include "app-layer.h" #include "app-layer-parser.h" @@ -47,19 +48,34 @@ typedef struct OutputLoggerThreadData_ { typedef struct OutputTxLogger_ { AppProto alproto; TxLogger LogFunc; + TxLoggerCondition LogCondition; OutputCtx *output_ctx; struct OutputTxLogger_ *next; const char *name; - TmmId module_id; + LoggerId logger_id; + uint32_t id; + int tc_log_progress; + int ts_log_progress; + TmEcode (*ThreadInit)(ThreadVars *, void *, void **); + TmEcode (*ThreadDeinit)(ThreadVars *, void *); + void (*ThreadExitPrintStats)(ThreadVars *, void *); } OutputTxLogger; static OutputTxLogger *list = NULL; -int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *output_ctx) +int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, + TxLogger LogFunc, + OutputCtx *output_ctx, int tc_log_progress, + int ts_log_progress, TxLoggerCondition LogCondition, + ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + void (*ThreadExitPrintStats)(ThreadVars *, void *)) { - int module_id = TmModuleGetIdByName(name); - if (module_id < 0) + if (!(AppLayerParserIsTxAware(alproto))) { + SCLogNotice("%s logger not enabled: protocol %s is disabled", + name, AppProtoToString(alproto)); return -1; + } OutputTxLogger *op = SCMalloc(sizeof(*op)); if (op == NULL) @@ -68,16 +84,42 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, op->alproto = alproto; op->LogFunc = LogFunc; + op->LogCondition = LogCondition; op->output_ctx = output_ctx; op->name = name; - op->module_id = (TmmId) module_id; + op->logger_id = id; + op->ThreadInit = ThreadInit; + op->ThreadDeinit = ThreadDeinit; + op->ThreadExitPrintStats = ThreadExitPrintStats; + + if (tc_log_progress < 0) { + op->tc_log_progress = + AppLayerParserGetStateProgressCompletionStatus(alproto, + STREAM_TOCLIENT); + } else { + op->tc_log_progress = tc_log_progress; + } - if (list == NULL) + if (ts_log_progress < 0) { + op->ts_log_progress = + AppLayerParserGetStateProgressCompletionStatus(alproto, + STREAM_TOSERVER); + } else { + op->ts_log_progress = ts_log_progress; + } + + if (list == NULL) { + op->id = 1; list = op; - else { + } else { OutputTxLogger *t = list; while (t->next) t = t->next; + if (t->id * 2 > UINT32_MAX) { + SCLogError(SC_ERR_FATAL, "Too many loggers registered."); + exit(EXIT_FAILURE); + } + op->id = t->id * 2; t->next = op; } @@ -85,10 +127,13 @@ int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, return 0; } -static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQueue *pq, PacketQueue *postpq) +static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) { BUG_ON(thread_data == NULL); - BUG_ON(list == NULL); + if (list == NULL) { + /* No child loggers registered. */ + return TM_ECODE_OK; + } OutputLoggerThreadData *op_thread_data = (OutputLoggerThreadData *)thread_data; OutputTxLogger *logger = list; @@ -103,15 +148,14 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ Flow * const f = p->flow; - FLOWLOCK_WRLOCK(f); /* WRITE lock before we updated flow logged id */ - AppProto alproto = f->alproto;//AppLayerGetProtoFromPacket(p); + AppProto alproto = f->alproto; if (AppLayerParserProtocolIsTxAware(p->proto, alproto) == 0) goto end; if (AppLayerParserProtocolHasLogger(p->proto, alproto) == 0) goto end; - void *alstate = f->alstate;//AppLayerGetProtoStateFromPacket((const Packet *)p); + void *alstate = f->alstate; if (alstate == NULL) { SCLogDebug("no alstate"); goto end; @@ -119,34 +163,32 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ uint64_t total_txs = AppLayerParserGetTxCnt(p->proto, alproto, alstate); uint64_t tx_id = AppLayerParserGetTransactionLogId(f->alparser); - int tx_progress_done_value_ts = - AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, 0); - int tx_progress_done_value_tc = - AppLayerParserGetStateProgressCompletionStatus(p->proto, alproto, 1); - int proto_logged = 0; + uint64_t max_id = tx_id; + int logged = 0; + int gap = 0; for (; tx_id < total_txs; tx_id++) { + /* Track the number of loggers, of the eligible loggers that + * actually logged this transaction. They all must have logged + * before the transaction is considered logged. */ + int number_of_loggers = 0; + int loggers_that_logged = 0; + void *tx = AppLayerParserGetTx(p->proto, alproto, alstate, tx_id); if (tx == NULL) { SCLogDebug("tx is NULL not logging"); continue; } - if (!(AppLayerParserStateIssetFlag(f->alparser, APP_LAYER_PARSER_EOF))) - { - int tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, tx, 0); - if (tx_progress < tx_progress_done_value_ts) { - SCLogDebug("progress not far enough, not logging"); - break; - } + int tx_progress_ts = AppLayerParserGetStateProgress(p->proto, alproto, + tx, FlowGetDisruptionFlags(f, STREAM_TOSERVER)); - tx_progress = AppLayerParserGetStateProgress(p->proto, alproto, tx, 1); - if (tx_progress < tx_progress_done_value_tc) { - SCLogDebug("progress not far enough, not logging"); - break; - } - } + int tx_progress_tc = AppLayerParserGetStateProgress(p->proto, alproto, + tx, FlowGetDisruptionFlags(f, STREAM_TOCLIENT)); + + SCLogDebug("tx_progress_ts %d tx_progress_tc %d", + tx_progress_ts, tx_progress_tc); // call each logger here (pseudo code) logger = list; @@ -154,15 +196,54 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ while (logger && store) { BUG_ON(logger->LogFunc == NULL); - SCLogDebug("logger %p", logger); + SCLogDebug("logger %p, LogCondition %p, ts_log_progress %d " + "tc_log_progress %d", logger, logger->LogCondition, + logger->ts_log_progress, logger->tc_log_progress); if (logger->alproto == alproto) { - SCLogDebug("alproto match, logging tx_id %ju", tx_id); - PACKET_PROFILING_TMM_START(p, logger->module_id); + SCLogDebug("alproto match, logging tx_id %"PRIu64, tx_id); + + number_of_loggers++; + + if (AppLayerParserGetTxLogged(p->proto, alproto, alstate, tx, + logger->id)) { + SCLogDebug("logger has already logged this transaction"); + loggers_that_logged++; + goto next; + } + + if (!(AppLayerParserStateIssetFlag(f->alparser, + APP_LAYER_PARSER_EOF))) { + if (logger->LogCondition) { + int r = logger->LogCondition(tv, p, alstate, tx, tx_id); + if (r == FALSE) { + SCLogDebug("conditions not met, not logging"); + goto next; + } + } else { + if (tx_progress_tc < logger->tc_log_progress) { + SCLogDebug("progress not far enough, not logging"); + goto next; + } + + if (tx_progress_ts < logger->ts_log_progress) { + SCLogDebug("progress not far enough, not logging"); + goto next; + } + } + } + + SCLogDebug("Logging tx_id %"PRIu64" to logger %d", tx_id, + logger->logger_id); + PACKET_PROFILING_LOGGER_START(p, logger->logger_id); logger->LogFunc(tv, store->thread_data, p, f, alstate, tx, tx_id); - PACKET_PROFILING_TMM_END(p, logger->module_id); - proto_logged = 1; + PACKET_PROFILING_LOGGER_END(p, logger->logger_id); + + AppLayerParserSetTxLogged(p->proto, alproto, alstate, tx, + logger->id); + loggers_that_logged++; } +next: logger = logger->next; store = store->next; @@ -170,14 +251,28 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data, PacketQ BUG_ON(logger != NULL && store == NULL); } - if (proto_logged) { - SCLogDebug("updating log tx_id %ju", tx_id); - AppLayerParserSetTransactionLogId(f->alparser); + /* If all loggers logged set a flag and update the last tx_id + * that was logged. + * + * If not all loggers were logged we flag that there was a gap + * so any subsequent transactions in this loop don't increase + * the maximum ID that was logged. */ + if (!gap && loggers_that_logged == number_of_loggers) { + logged = 1; + max_id = tx_id; + } else { + gap = 1; } } + /* Update the the last ID that has been logged with all + * transactions before it. */ + if (logged) { + SCLogDebug("updating log tx_id %"PRIu64, max_id); + AppLayerParserSetTransactionLogId(f->alparser, max_id + 1); + } + end: - FLOWLOCK_UNLOCK(f); return TM_ECODE_OK; } @@ -192,21 +287,13 @@ static TmEcode OutputTxLogThreadInit(ThreadVars *tv, void *initdata, void **data memset(td, 0x00, sizeof(*td)); *data = (void *)td; - SCLogDebug("OutputTxLogThreadInit happy (*data %p)", *data); OutputTxLogger *logger = list; while (logger) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadInit) { + if (logger->ThreadInit) { void *retptr = NULL; - if (tm_module->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { + if (logger->ThreadInit(tv, (void *)logger->output_ctx, &retptr) == TM_ECODE_OK) { OutputLoggerThreadStore *ts = SCMalloc(sizeof(*ts)); /* todo */ BUG_ON(ts == NULL); memset(ts, 0x00, sizeof(*ts)); @@ -240,15 +327,8 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) OutputTxLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadDeinit) { - tm_module->ThreadDeinit(tv, store->thread_data); + if (logger->ThreadDeinit) { + logger->ThreadDeinit(tv, store->thread_data); } OutputLoggerThreadStore *next_store = store->next; @@ -256,6 +336,8 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) store = next_store; logger = logger->next; } + + SCFree(op_thread_data); return TM_ECODE_OK; } @@ -266,15 +348,8 @@ static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data) OutputTxLogger *logger = list; while (logger && store) { - TmModule *tm_module = TmModuleGetByName((char *)logger->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", logger->name); - exit(EXIT_FAILURE); - } - - if (tm_module->ThreadExitPrintStats) { - tm_module->ThreadExitPrintStats(tv, store->thread_data); + if (logger->ThreadExitPrintStats) { + logger->ThreadExitPrintStats(tv, store->thread_data); } logger = logger->next; @@ -282,14 +357,10 @@ static void OutputTxLogExitPrintStats(ThreadVars *tv, void *thread_data) } } -void TmModuleTxLoggerRegister (void) +void OutputTxLoggerRegister (void) { - tmm_modules[TMM_TXLOGGER].name = "__tx_logger__"; - tmm_modules[TMM_TXLOGGER].ThreadInit = OutputTxLogThreadInit; - tmm_modules[TMM_TXLOGGER].Func = OutputTxLog; - tmm_modules[TMM_TXLOGGER].ThreadExitPrintStats = OutputTxLogExitPrintStats; - tmm_modules[TMM_TXLOGGER].ThreadDeinit = OutputTxLogThreadDeinit; - tmm_modules[TMM_TXLOGGER].cap_flags = 0; + OutputRegisterRootLogger(OutputTxLogThreadInit, OutputTxLogThreadDeinit, + OutputTxLogExitPrintStats, OutputTxLog); } void OutputTxShutdown(void) diff --git a/src/output-tx.h b/src/output-tx.h index 7ffb8a6d25e8..847d0b472b7f 100644 --- a/src/output-tx.h +++ b/src/output-tx.h @@ -34,11 +34,16 @@ typedef int (*TxLogger)(ThreadVars *, void *thread_data, const Packet *, Flow *f /** packet logger condition function pointer type, * must return true for packets that should be logged */ -//typedef int (*TxLogCondition)(ThreadVars *, const Packet *); +typedef int (*TxLoggerCondition)(ThreadVars *, const Packet *, void *state, void *tx, uint64_t tx_id); -int OutputRegisterTxLogger(const char *name, AppProto alproto, TxLogger LogFunc, OutputCtx *); +int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, + TxLogger LogFunc, + OutputCtx *, int tc_log_progress, int ts_log_progress, + TxLoggerCondition LogCondition, + ThreadInitFunc, ThreadDeinitFunc, + void (*ThreadExitPrintStats)(ThreadVars *, void *)); -void TmModuleTxLoggerRegister (void); +void OutputTxLoggerRegister (void); void OutputTxShutdown(void); diff --git a/src/output.c b/src/output.c index 9229eb17b448..4b8d1f1c3d95 100644 --- a/src/output.c +++ b/src/output.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -18,9 +18,18 @@ /** * \file * + * \author OISF, Jason Ish * \author Endace Technology Limited, Jason Ish * - * Output registration functions + * The root logging output for all non-application logging. + * + * The loggers are made up of a hierarchy of loggers. At the top we + * have the root logger which is the main entry point to + * logging. Under the root there exists parent loggers that are the + * entry point for specific types of loggers such as packet logger, + * transaction loggers, etc. Each parent logger may have 0 or more + * loggers that actual handle the job of producing output to something + * like a file. */ #include "suricata-common.h" @@ -31,8 +40,63 @@ #include "util-debug.h" #include "output.h" -static TAILQ_HEAD(, OutputModule_) output_modules = - TAILQ_HEAD_INITIALIZER(output_modules); +#include "alert-fastlog.h" +#include "alert-hpfeeds.h" +#include "alert-unified2-alert.h" +#include "alert-debuglog.h" +#include "alert-prelude.h" +#include "alert-syslog.h" +#include "output-json-alert.h" +#include "output-json-flow.h" +#include "output-json-netflow.h" +#include "log-cf-common.h" +#include "log-droplog.h" +#include "output-json-drop.h" +#include "log-httplog.h" +#include "output-json-http.h" +#include "log-dnslog.h" +#include "output-json-dns.h" +#include "log-tlslog.h" +#include "log-tlsstore.h" +#include "output-json-tls.h" +#include "output-json-ssh.h" +#include "log-pcap.h" +#include "log-file.h" +#include "output-json-file.h" +#include "output-json-smtp.h" +#include "output-json-stats.h" +#include "log-filestore.h" +#include "log-tcp-data.h" +#include "log-stats.h" +#include "output-json.h" +#include "output-json-template.h" +#include "output-lua.h" +#include "output-json-dnp3.h" +#include "output-json-vars.h" + +typedef struct RootLogger_ { + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; + OutputLogFunc LogFunc; + + TAILQ_ENTRY(RootLogger_) entries; +} RootLogger; + +static TAILQ_HEAD(, RootLogger_) RootLoggers = + TAILQ_HEAD_INITIALIZER(RootLoggers); + +typedef struct LoggerThreadStoreNode_ { + void *thread_data; + TAILQ_ENTRY(LoggerThreadStoreNode_) entries; +} LoggerThreadStoreNode; + +typedef TAILQ_HEAD(LoggerThreadStore_, LoggerThreadStoreNode_) LoggerThreadStore; + +/** + * The list of all registered (known) output modules. + */ +OutputModuleList output_modules = TAILQ_HEAD_INITIALIZER(output_modules); /** * Registry of flags to be updated on file rotation notification. @@ -46,6 +110,9 @@ typedef struct OutputFileRolloverFlag_ { TAILQ_HEAD(, OutputFileRolloverFlag_) output_file_rotation_flags = TAILQ_HEAD_INITIALIZER(output_file_rotation_flags); +void OutputRegisterRootLoggers(void); +void OutputRegisterLoggers(void); + /** * \brief Register an output module. * @@ -54,9 +121,8 @@ TAILQ_HEAD(, OutputFileRolloverFlag_) output_file_rotation_flags = * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *)) +void OutputRegisterModule(const char *name, const char *conf_name, + OutputInitFunc InitFunc) { OutputModule *module = SCCalloc(1, sizeof(*module)); if (unlikely(module == NULL)) @@ -84,10 +150,11 @@ OutputRegisterModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterPacketModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), - PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc) +void OutputRegisterPacketModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(PacketLogFunc == NULL || PacketConditionFunc == NULL)) { goto error; @@ -98,11 +165,15 @@ OutputRegisterPacketModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; module->PacketLogFunc = PacketLogFunc; module->PacketConditionFunc = PacketConditionFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Packet logger \"%s\" registered.", name); @@ -120,10 +191,11 @@ OutputRegisterPacketModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterPacketSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc) +void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + PacketLogger PacketLogFunc, PacketLogCondition PacketConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(PacketLogFunc == NULL || PacketConditionFunc == NULL)) { goto error; @@ -134,12 +206,16 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->PacketLogFunc = PacketLogFunc; module->PacketConditionFunc = PacketConditionFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Packet logger \"%s\" registered.", name); @@ -150,17 +226,19 @@ OutputRegisterPacketSubModule(const char *parent_name, const char *name, } /** - * \brief Register a tx output module. + * \brief Wrapper function for tx output modules. * * This function will register an output module so it can be * configured with the configuration file. * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterTxModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc) +void OutputRegisterTxModuleWrapper(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -171,11 +249,18 @@ OutputRegisterTxModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; module->TxLogFunc = TxLogFunc; + module->TxLogCondition = TxLogCondition; module->alproto = alproto; + module->tc_log_progress = tc_log_progress; + module->ts_log_progress = ts_log_progress; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Tx logger \"%s\" registered.", name); @@ -185,10 +270,12 @@ OutputRegisterTxModule(const char *name, const char *conf_name, exit(EXIT_FAILURE); } -void -OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc) +void OutputRegisterTxSubModuleWrapper(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(TxLogFunc == NULL)) { goto error; @@ -199,12 +286,19 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->TxLogFunc = TxLogFunc; + module->TxLogCondition = TxLogCondition; module->alproto = alproto; + module->tc_log_progress = tc_log_progress; + module->ts_log_progress = ts_log_progress; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Tx logger \"%s\" registered.", name); @@ -214,6 +308,98 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, exit(EXIT_FAILURE); } +/** + * \brief Register a tx output module with condition. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, + TxLogFunc, -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); +} + +void OutputRegisterTxSubModuleWithCondition(LoggerId id, + const char *parent_name, const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + TxLoggerCondition TxLogCondition, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, + alproto, TxLogFunc, -1, -1, TxLogCondition, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); +} + +/** + * \brief Register a tx output module with progress. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, + TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, + ThreadDeinit, ThreadExitPrintStats); +} + +void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, + int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, InitFunc, + alproto, TxLogFunc, tc_log_progress, ts_log_progress, NULL, ThreadInit, + ThreadDeinit, ThreadExitPrintStats); +} + +/** + * \brief Register a tx output module. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterTxModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputRegisterTxModuleWrapper(id, name, conf_name, InitFunc, alproto, + TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); +} + +void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + OutputRegisterTxSubModuleWrapper(id, parent_name, name, conf_name, + InitFunc, alproto, TxLogFunc, -1, -1, NULL, ThreadInit, ThreadDeinit, + ThreadExitPrintStats); +} + /** * \brief Register a file output module. * @@ -222,9 +408,10 @@ OutputRegisterTxSubModule(const char *parent_name, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFileModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc) +void OutputRegisterFileModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, FileLogger FileLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FileLogFunc == NULL)) { goto error; @@ -235,10 +422,14 @@ OutputRegisterFileModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; module->FileLogFunc = FileLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("File logger \"%s\" registered.", name); @@ -256,10 +447,11 @@ OutputRegisterFileModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFileSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FileLogger FileLogFunc) +void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + FileLogger FileLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FileLogFunc == NULL)) { goto error; @@ -270,11 +462,15 @@ OutputRegisterFileSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->FileLogFunc = FileLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("File logger \"%s\" registered.", name); @@ -292,9 +488,11 @@ OutputRegisterFileSubModule(const char *parent_name, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFiledataModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc) +void OutputRegisterFiledataModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { goto error; @@ -305,10 +503,14 @@ OutputRegisterFiledataModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; module->FiledataLogFunc = FiledataLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Filedata logger \"%s\" registered.", name); @@ -326,10 +528,11 @@ OutputRegisterFiledataModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFiledataSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FiledataLogger FiledataLogFunc) +void OutputRegisterFiledataSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FiledataLogFunc == NULL)) { goto error; @@ -340,11 +543,15 @@ OutputRegisterFiledataSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->FiledataLogFunc = FiledataLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Filedata logger \"%s\" registered.", name); @@ -362,9 +569,10 @@ OutputRegisterFiledataSubModule(const char *parent_name, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFlowModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc) +void OutputRegisterFlowModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, FlowLogger FlowLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FlowLogFunc == NULL)) { goto error; @@ -375,10 +583,14 @@ OutputRegisterFlowModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; module->FlowLogFunc = FlowLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Flow logger \"%s\" registered.", name); @@ -396,10 +608,11 @@ OutputRegisterFlowModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterFlowSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FlowLogger FlowLogFunc) +void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(FlowLogFunc == NULL)) { goto error; @@ -410,11 +623,15 @@ OutputRegisterFlowSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->FlowLogFunc = FlowLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Flow logger \"%s\" registered.", name); @@ -432,10 +649,12 @@ OutputRegisterFlowSubModule(const char *parent_name, const char *name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterStreamingModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type) +void OutputRegisterStreamingModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StreamingLogFunc == NULL)) { goto error; @@ -446,11 +665,15 @@ OutputRegisterStreamingModule(const char *name, const char *conf_name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->InitFunc = InitFunc; module->StreamingLogFunc = StreamingLogFunc; module->stream_type = stream_type; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Streaming logger \"%s\" registered.", name); @@ -468,10 +691,11 @@ OutputRegisterStreamingModule(const char *name, const char *conf_name, * * \retval Returns 0 on success, -1 on failure. */ -void -OutputRegisterStreamingSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type) +void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) { if (unlikely(StreamingLogFunc == NULL)) { goto error; @@ -482,12 +706,16 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, goto error; } + module->logger_id = id; module->name = name; module->conf_name = conf_name; module->parent_name = parent_name; module->InitSubFunc = InitFunc; module->StreamingLogFunc = StreamingLogFunc; module->stream_type = stream_type; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; TAILQ_INSERT_TAIL(&output_modules, module, entries); SCLogDebug("Streaming logger \"%s\" registered.", name); @@ -497,14 +725,93 @@ OutputRegisterStreamingSubModule(const char *parent_name, const char *name, exit(EXIT_FAILURE); } +/** + * \brief Register a stats data output module. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterStatsModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, StatsLogger StatsLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + if (unlikely(StatsLogFunc == NULL)) { + goto error; + } + + OutputModule *module = SCCalloc(1, sizeof(*module)); + if (unlikely(module == NULL)) { + goto error; + } + + module->logger_id = id; + module->name = name; + module->conf_name = conf_name; + module->InitFunc = InitFunc; + module->StatsLogFunc = StatsLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; + TAILQ_INSERT_TAIL(&output_modules, module, entries); + + SCLogDebug("Stats logger \"%s\" registered.", name); + return; +error: + SCLogError(SC_ERR_FATAL, "Fatal error encountered. Exiting..."); + exit(EXIT_FAILURE); +} + +/** + * \brief Register a stats data output sub-module. + * + * This function will register an output module so it can be + * configured with the configuration file. + * + * \retval Returns 0 on success, -1 on failure. + */ +void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats) +{ + if (unlikely(StatsLogFunc == NULL)) { + goto error; + } + + OutputModule *module = SCCalloc(1, sizeof(*module)); + if (unlikely(module == NULL)) { + goto error; + } + + module->logger_id = id; + module->name = name; + module->conf_name = conf_name; + module->parent_name = parent_name; + module->InitSubFunc = InitFunc; + module->StatsLogFunc = StatsLogFunc; + module->ThreadInit = ThreadInit; + module->ThreadDeinit = ThreadDeinit; + module->ThreadExitPrintStats = ThreadExitPrintStats; + TAILQ_INSERT_TAIL(&output_modules, module, entries); + + SCLogDebug("Stats logger \"%s\" registered.", name); + return; +error: + SCLogError(SC_ERR_FATAL, "Fatal error encountered. Exiting..."); + exit(EXIT_FAILURE); +} + /** * \brief Get an output module by name. * * \retval The OutputModule with the given name or NULL if no output module * with the given name is registered. */ -OutputModule * -OutputGetModuleByConfName(const char *conf_name) +OutputModule *OutputGetModuleByConfName(const char *conf_name) { OutputModule *module; @@ -519,8 +826,7 @@ OutputGetModuleByConfName(const char *conf_name) /** * \brief Deregister all modules. Useful for a memory clean exit. */ -void -OutputDeregisterAll(void) +void OutputDeregisterAll(void) { OutputModule *module; @@ -546,38 +852,6 @@ void OutputDropLoggerDisable(void) drop_loggers--; } -static int tls_loggers = 0; - -int OutputTlsLoggerEnable(void) -{ - if (tls_loggers) - return -1; - tls_loggers++; - return 0; -} - -void OutputTlsLoggerDisable(void) -{ - if (tls_loggers) - tls_loggers--; -} - -static int ssh_loggers = 0; - -int OutputSshLoggerEnable(void) -{ - if (ssh_loggers) - return -1; - ssh_loggers++; - return 0; -} - -void OutputSshLoggerDisable(void) -{ - if (ssh_loggers) - ssh_loggers--; -} - /** * \brief Register a flag for file rotation notification. * @@ -629,3 +903,187 @@ void OutputNotifyFileRotation(void) { *(flag->flag) = 1; } } + +TmEcode OutputLoggerLog(ThreadVars *tv, Packet *p, void *thread_data) +{ + LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; + RootLogger *logger = TAILQ_FIRST(&RootLoggers); + LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); + while (logger && thread_store_node) { + if (logger->LogFunc != NULL) { + logger->LogFunc(tv, p, thread_store_node->thread_data); + } + logger = TAILQ_NEXT(logger, entries); + thread_store_node = TAILQ_NEXT(thread_store_node, entries); + } + + return TM_ECODE_OK; +} + +TmEcode OutputLoggerThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + LoggerThreadStore *thread_store = SCCalloc(1, sizeof(*thread_store)); + if (thread_store == NULL) { + return TM_ECODE_FAILED; + } + TAILQ_INIT(thread_store); + *data = (void *)thread_store; + + RootLogger *logger; + TAILQ_FOREACH(logger, &RootLoggers, entries) { + + void *child_thread_data = NULL; + if (logger->ThreadInit != NULL) { + if (logger->ThreadInit(tv, initdata, &child_thread_data) == TM_ECODE_OK) { + LoggerThreadStoreNode *thread_store_node = + SCCalloc(1, sizeof(*thread_store_node)); + if (thread_store_node == NULL) { + /* Undo everything, calling de-init will take care + * of that. */ + OutputLoggerThreadDeinit(tv, thread_store); + return TM_ECODE_FAILED; + } + thread_store_node->thread_data = child_thread_data; + TAILQ_INSERT_TAIL(thread_store, thread_store_node, entries); + } + } + } + return TM_ECODE_OK; +} + +TmEcode OutputLoggerThreadDeinit(ThreadVars *tv, void *thread_data) +{ + LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; + RootLogger *logger = TAILQ_FIRST(&RootLoggers); + LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); + while (logger && thread_store_node) { + if (logger->ThreadDeinit != NULL) { + logger->ThreadDeinit(tv, thread_store_node->thread_data); + } + logger = TAILQ_NEXT(logger, entries); + thread_store_node = TAILQ_NEXT(thread_store_node, entries); + } + + /* Free the thread store. */ + while ((thread_store_node = TAILQ_FIRST(thread_store)) != NULL) { + TAILQ_REMOVE(thread_store, thread_store_node, entries); + SCFree(thread_store_node); + } + SCFree(thread_store); + + return TM_ECODE_OK; +} + +void OutputLoggerExitPrintStats(ThreadVars *tv, void *thread_data) +{ + LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data; + RootLogger *logger = TAILQ_FIRST(&RootLoggers); + LoggerThreadStoreNode *thread_store_node = TAILQ_FIRST(thread_store); + while (logger && thread_store_node) { + if (logger->ThreadExitPrintStats != NULL) { + logger->ThreadExitPrintStats(tv, thread_store_node->thread_data); + } + logger = TAILQ_NEXT(logger, entries); + thread_store_node = TAILQ_NEXT(thread_store_node, entries); + } +} + +void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats, + OutputLogFunc LogFunc) +{ + RootLogger *logger = SCCalloc(1, sizeof(*logger)); + if (logger == NULL) { + return; + } + logger->ThreadInit = ThreadInit; + logger->ThreadDeinit = ThreadDeinit; + logger->ThreadExitPrintStats = ThreadExitPrintStats; + logger->LogFunc = LogFunc; + TAILQ_INSERT_TAIL(&RootLoggers, logger, entries); +} + +void TmModuleLoggerRegister(void) +{ + OutputRegisterRootLoggers(); + OutputRegisterLoggers(); +} + +/** + * \brief Register all root loggers. + */ +void OutputRegisterRootLoggers(void) +{ + OutputPacketLoggerRegister(); + OutputTxLoggerRegister(); + OutputFiledataLoggerRegister(); + OutputFileLoggerRegister(); + OutputStreamingLoggerRegister(); +} + +/** + * \brief Register all non-root logging modules. + */ +void OutputRegisterLoggers(void) +{ + /* custom format log*/ + LogCustomFormatRegister(); + + LuaLogRegister(); + /* fast log */ + AlertFastLogRegister(); + /* hpfeeds log */ + AlertHPFeeds(); + /* debug log */ + AlertDebugLogRegister(); + /* prelue log */ + AlertPreludeRegister(); + /* syslog log */ + AlertSyslogRegister(); + /* unified2 log */ + Unified2AlertRegister(); + /* drop log */ + LogDropLogRegister(); + JsonDropLogRegister(); + /* json log */ + OutputJsonRegister(); + /* email logs */ + JsonSmtpLogRegister(); + /* http log */ + LogHttpLogRegister(); + JsonHttpLogRegister(); + /* tls log */ + LogTlsLogRegister(); + JsonTlsLogRegister(); + LogTlsStoreRegister(); + /* ssh */ + JsonSshLogRegister(); + /* pcap log */ + PcapLogRegister(); + /* file log */ + LogFileLogRegister(); + JsonFileLogRegister(); + LogFilestoreRegister(); + /* dns log */ + LogDnsLogRegister(); + JsonDnsLogRegister(); + /* tcp streaming data */ + LogTcpDataLogRegister(); + /* log stats */ + LogStatsLogRegister(); + + JsonAlertLogRegister(); + /* flow/netflow */ + JsonFlowLogRegister(); + JsonNetFlowLogRegister(); + /* json stats */ + JsonStatsLogRegister(); + + /* DNP3. */ + JsonDNP3LogRegister(); + JsonVarsLogRegister(); + + /* Template JSON logger. */ + JsonTemplateLogRegister(); +} diff --git a/src/output.h b/src/output.h index 85092c31413c..59469f4ae653 100644 --- a/src/output.h +++ b/src/output.h @@ -36,67 +36,147 @@ #include "output-filedata.h" #include "output-flow.h" #include "output-streaming.h" +#include "output-stats.h" + +typedef OutputCtx *(*OutputInitFunc)(ConfNode *); +typedef OutputCtx *(*OutputInitSubFunc)(ConfNode *, OutputCtx *); +typedef TmEcode (*OutputLogFunc)(ThreadVars *, Packet *, void *); typedef struct OutputModule_ { + LoggerId logger_id; const char *name; const char *conf_name; const char *parent_name; - OutputCtx *(*InitFunc)(ConfNode *); - OutputCtx *(*InitSubFunc)(ConfNode *, OutputCtx *parent_ctx); + OutputInitFunc InitFunc; + OutputInitSubFunc InitSubFunc; + + ThreadInitFunc ThreadInit; + ThreadDeinitFunc ThreadDeinit; + ThreadExitPrintStatsFunc ThreadExitPrintStats; PacketLogger PacketLogFunc; PacketLogCondition PacketConditionFunc; TxLogger TxLogFunc; + TxLoggerCondition TxLogCondition; FileLogger FileLogFunc; FiledataLogger FiledataLogFunc; FlowLogger FlowLogFunc; StreamingLogger StreamingLogFunc; + StatsLogger StatsLogFunc; AppProto alproto; enum OutputStreamingType stream_type; + int tc_log_progress; + int ts_log_progress; TAILQ_ENTRY(OutputModule_) entries; } OutputModule; -void OutputRegisterModule(const char *, const char *, OutputCtx *(*)(ConfNode *)); - -void OutputRegisterPacketModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), - PacketLogger LogFunc, PacketLogCondition ConditionFunc); -void OutputRegisterPacketSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - PacketLogger LogFunc, PacketLogCondition ConditionFunc); - -void OutputRegisterTxModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), AppProto alproto, - TxLogger TxLogFunc); -void OutputRegisterTxSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *parent_ctx), - AppProto alproto, TxLogger TxLogFunc); - -void OutputRegisterFileModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FileLogger FileLogFunc); -void OutputRegisterFileSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FileLogger FileLogFunc); - -void OutputRegisterFiledataModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FiledataLogger FiledataLogFunc); -void OutputRegisterFiledataSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FiledataLogger FiledataLogFunc); - -void OutputRegisterFlowModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), FlowLogger FlowLogFunc); -void OutputRegisterFlowSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - FlowLogger FlowLogFunc); - -void OutputRegisterStreamingModule(const char *name, const char *conf_name, - OutputCtx *(*InitFunc)(ConfNode *), StreamingLogger StreamingLogFunc, - enum OutputStreamingType stream_type); -void OutputRegisterStreamingSubModule(const char *parent_name, const char *name, - const char *conf_name, OutputCtx *(*InitFunc)(ConfNode *, OutputCtx *), - StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type); +typedef TAILQ_HEAD(OutputModuleList_, OutputModule_) OutputModuleList; +extern OutputModuleList output_modules; + +void OutputRegisterModule(const char *, const char *, OutputInitFunc); + +void OutputRegisterPacketModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, PacketLogger LogFunc, + PacketLogCondition ConditionFunc, ThreadInitFunc, ThreadDeinitFunc, + ThreadExitPrintStatsFunc); +void OutputRegisterPacketSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + PacketLogger LogFunc, PacketLogCondition ConditionFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterTxModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterTxModuleWithCondition(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModuleWithCondition(LoggerId id, + const char *parent_name, const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, TxLoggerCondition TxLogCondition, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterTxModuleWithProgress(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, AppProto alproto, + TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, + int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterFileModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + FileLogger FileLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterFileSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, FileLogger FileLogFunc, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterFiledataModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterFiledataSubModule(LoggerId, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + FiledataLogger FiledataLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterFlowModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterFlowSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, OutputInitSubFunc InitFunc, + FlowLogger FlowLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterStreamingModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + StreamingLogger StreamingLogFunc, enum OutputStreamingType stream_type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterStreamingSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, StreamingLogger StreamingLogFunc, + enum OutputStreamingType stream_type, + ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); + +void OutputRegisterStatsModule(LoggerId id, const char *name, + const char *conf_name, OutputInitFunc InitFunc, + StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); +void OutputRegisterStatsSubModule(LoggerId id, const char *parent_name, + const char *name, const char *conf_name, + OutputInitSubFunc InitFunc, + StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats); OutputModule *OutputGetModuleByConfName(const char *name); void OutputDeregisterAll(void); @@ -104,14 +184,19 @@ void OutputDeregisterAll(void); int OutputDropLoggerEnable(void); void OutputDropLoggerDisable(void); -int OutputTlsLoggerEnable(void); -void OutputTlsLoggerDisable(void); - -int OutputSshLoggerEnable(void); -void OutputSshLoggerDisable(void); - void OutputRegisterFileRotationFlag(int *flag); void OutputUnregisterFileRotationFlag(int *flag); void OutputNotifyFileRotation(void); +void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, + ThreadDeinitFunc ThreadDeinit, + ThreadExitPrintStatsFunc ThreadExitPrintStats, + OutputLogFunc LogFunc); +void TmModuleLoggerRegister(void); + +TmEcode OutputLoggerLog(ThreadVars *, Packet *, void *); +TmEcode OutputLoggerThreadInit(ThreadVars *, void *, void **); +TmEcode OutputLoggerThreadDeinit(ThreadVars *, void *); +void OutputLoggerExitPrintStats(ThreadVars *, void *); + #endif /* ! __OUTPUT_H__ */ diff --git a/src/packet-queue.c b/src/packet-queue.c index c500971bd120..cb766ff1b65c 100644 --- a/src/packet-queue.c +++ b/src/packet-queue.c @@ -175,12 +175,11 @@ Packet *PacketDequeue (PacketQueue *q) /* pull the bottom packet from the queue */ p = q->bot; + /* Weird issue: sometimes it looks that two thread arrive * here at the same time so the bot ptr is NULL (only on OS X?) */ - if (p == NULL) { - return NULL; - } + BUG_ON (p == NULL); /* more packets in queue */ if (q->bot->prev != NULL) { @@ -193,6 +192,8 @@ Packet *PacketDequeue (PacketQueue *q) } //PacketQueueValidateDebug(q); + p->next = NULL; + p->prev = NULL; return p; } diff --git a/src/pkt-var.c b/src/pkt-var.c index b3878bde049a..a81af35e1af2 100644 --- a/src/pkt-var.c +++ b/src/pkt-var.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -34,59 +34,78 @@ #include "pkt-var.h" #include "util-debug.h" -/* puts a new value into a pktvar */ -void PktVarUpdate(PktVar *pv, uint8_t *value, uint16_t size) -{ - if (pv->value) SCFree(pv->value); - pv->value = value; - pv->value_len = size; -} - /* get the pktvar with name 'name' from the pkt * * name is a normal string*/ -PktVar *PktVarGet(Packet *p, char *name) +PktVar *PktVarGet(Packet *p, uint32_t id) { PktVar *pv = p->pktvar; for (;pv != NULL; pv = pv->next) { - if (pv->name && strcmp(pv->name, name) == 0) + if (pv->id == id) return pv; } return NULL; } -/* add a pktvar to the pkt, or update it */ -void PktVarAdd(Packet *p, char *name, uint8_t *value, uint16_t size) +/** + * \brief add a key-value pktvar to the pkt + * \retval r 0 ok, -1 error + */ +int PktVarAddKeyValue(Packet *p, uint8_t *key, uint16_t ksize, uint8_t *value, uint16_t size) { - //printf("Adding packet var \"%s\" with value(%" PRId32 ") \"%s\"\n", name, size, value); + PktVar *pv = SCCalloc(1, sizeof(PktVar)); + if (unlikely(pv == NULL)) + return -1; + + pv->key = key; + pv->key_len = ksize; + pv->value = value; + pv->value_len = size; + + PktVar *tpv = p->pktvar; + if (p->pktvar == NULL) + p->pktvar = pv; + else { + while(tpv) { + if (tpv->next == NULL) { + tpv->next = pv; + return 0; + } + tpv = tpv->next; + } + } + return 0; +} - PktVar *pv = PktVarGet(p, name); - if (pv == NULL) { - pv = SCMalloc(sizeof(PktVar)); - if (unlikely(pv == NULL)) - return; +/** + * \brief add a key-value pktvar to the pkt + * \retval r 0 ok, -1 error + */ +int PktVarAdd(Packet *p, uint32_t id, uint8_t *value, uint16_t size) +{ + PktVar *pv = SCCalloc(1, sizeof(PktVar)); + if (unlikely(pv == NULL)) + return -1; - pv->name = name; - pv->value = value; - pv->value_len = size; - pv->next = NULL; + pv->id = id; + pv->value = value; + pv->value_len = size; - PktVar *tpv = p->pktvar; - if (p->pktvar == NULL) p->pktvar = pv; - else { - while(tpv) { - if (tpv->next == NULL) { - tpv->next = pv; - return; - } - tpv = tpv->next; + PktVar *tpv = p->pktvar; + if (p->pktvar == NULL) + p->pktvar = pv; + else { + while(tpv) { + if (tpv->next == NULL) { + tpv->next = pv; + return 0; } + tpv = tpv->next; } - } else { - PktVarUpdate(pv, value, size); } + return 0; } void PktVarFree(PktVar *pv) @@ -94,7 +113,8 @@ void PktVarFree(PktVar *pv) if (pv == NULL) return; - pv->name = NULL; + if (pv->key != NULL) + SCFree(pv->key); if (pv->value != NULL) SCFree(pv->value); PktVar *pv_next = pv->next; @@ -104,21 +124,3 @@ void PktVarFree(PktVar *pv) if (pv_next != NULL) PktVarFree(pv_next); } - -void PktVarPrint(PktVar *pv) -{ - uint16_t i; - - if (pv == NULL) - return; - - printf("Name \"%s\", Value \"", pv->name); - for (i = 0; i < pv->value_len; i++) { - if (isprint(pv->value[i])) printf("%c", pv->value[i]); - else printf("\\%02X", pv->value[i]); - } - printf("\", Len \"%" PRIu32 "\"\n", pv->value_len); - - PktVarPrint(pv->next); -} - diff --git a/src/pkt-var.h b/src/pkt-var.h index 0ba875721320..0a261c9ffaaf 100644 --- a/src/pkt-var.h +++ b/src/pkt-var.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -24,10 +24,10 @@ #ifndef __PKT_VAR_H__ #define __PKT_VAR_H__ -void PktVarAdd(Packet *, char *, uint8_t *, uint16_t); -PktVar *PktVarGet(Packet *, char *); +int WARN_UNUSED PktVarAddKeyValue(Packet *, uint8_t *, uint16_t, uint8_t *, uint16_t); +int WARN_UNUSED PktVarAdd(Packet *, uint32_t id, uint8_t *, uint16_t); +PktVar *PktVarGet(Packet *, uint32_t id); void PktVarFree(PktVar *); -void PktVarPrint(PktVar *); #endif /* __PKT_VAR_H__ */ diff --git a/src/queue.h b/src/queue.h index 13455aa42905..5e2a7b1366f4 100644 --- a/src/queue.h +++ b/src/queue.h @@ -82,12 +82,18 @@ * For details on the use of these macros, see the queue(3) manual page. */ -#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#if defined(__clang_analyzer__) || defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) #define _Q_INVALIDATE(a) ((a) = ((void *)-1)) #else #define _Q_INVALIDATE(a) #endif +#if defined(__clang_analyzer__) +#define _Q_ASSERT(a) assert((a)) +#else +#define _Q_ASSERT(a) +#endif + /* * Singly-linked List definitions. */ @@ -377,9 +383,12 @@ struct { \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ + _Q_ASSERT((elm)); \ + _Q_ASSERT((head)); \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ + _Q_ASSERT(*(head)->tqh_last); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) @@ -407,6 +416,7 @@ struct { \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_ASSERT((head)->tqh_first != (elm)); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) diff --git a/src/reputation.c b/src/reputation.c index f84c1a8808f9..232871817c14 100644 --- a/src/reputation.c +++ b/src/reputation.c @@ -25,12 +25,12 @@ * IP Reputation Module, initial API for IPV4 and IPV6 feed */ +#include "suricata-common.h" #include "util-error.h" #include "util-debug.h" #include "util-ip.h" #include "util-radix-tree.h" #include "util-unittest.h" -#include "suricata-common.h" #include "threads.h" #include "util-print.h" #include "host.h" @@ -57,11 +57,116 @@ static uint32_t SRepGetVersion(void) return srep_version; } +void SRepResetVersion(void) +{ + srep_version = 0; +} + static uint32_t SRepGetEffectiveVersion(void) { return SC_ATOMIC_GET(srep_eversion); } +static void SRepCIDRFreeUserData(void *data) +{ + if (data != NULL) + SCFree(data); + + return; +} + +static void SRepCIDRAddNetblock(SRepCIDRTree *cidr_ctx, char *ip, int cat, int value) +{ + SReputation *user_data = NULL; + if ((user_data = SCMalloc(sizeof(SReputation))) == NULL) { + SCLogError(SC_ERR_FATAL, "Error allocating memory. Exiting"); + exit(EXIT_FAILURE); + } + memset(user_data, 0x00, sizeof(SReputation)); + + user_data->version = SRepGetVersion(); + user_data->rep[cat] = value; + + if (strchr(ip, ':') != NULL) { + if (cidr_ctx->srepIPV6_tree[cat] == NULL) { + cidr_ctx->srepIPV6_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); + if (cidr_ctx->srepIPV6_tree[cat] == NULL) { + SCLogDebug("Error initializing Reputation IPV6 with CIDR module for cat %d", cat); + exit(EXIT_FAILURE); + } + SCLogDebug("Reputation IPV6 with CIDR module for cat %d initialized", cat); + } + + SCLogDebug("adding ipv6 host %s", ip); + if (SCRadixAddKeyIPV6String(ip, cidr_ctx->srepIPV6_tree[cat], (void *)user_data) == NULL) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "failed to add ipv6 host %s", ip); + } + + } else { + if (cidr_ctx->srepIPV4_tree[cat] == NULL) { + cidr_ctx->srepIPV4_tree[cat] = SCRadixCreateRadixTree(SRepCIDRFreeUserData, NULL); + if (cidr_ctx->srepIPV4_tree[cat] == NULL) { + SCLogDebug("Error initializing Reputation IPV4 with CIDR module for cat %d", cat); + exit(EXIT_FAILURE); + } + SCLogDebug("Reputation IPV4 with CIDR module for cat %d initialized", cat); + } + + SCLogDebug("adding ipv4 host %s", ip); + if (SCRadixAddKeyIPV4String(ip, cidr_ctx->srepIPV4_tree[cat], (void *)user_data) == NULL) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "failed to add ipv4 host %s", ip); + } + } +} + +static uint8_t SRepCIDRGetIPv4IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv4_addr, uint8_t cat) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV4BestMatch(ipv4_addr, cidr_ctx->srepIPV4_tree[cat], &user_data); + if (user_data == NULL) + return 0; + + SReputation *r = (SReputation *)user_data; + return r->rep[cat]; +} + +static uint8_t SRepCIDRGetIPv6IPRep(SRepCIDRTree *cidr_ctx, uint8_t *ipv6_addr, uint8_t cat) +{ + void *user_data = NULL; + (void)SCRadixFindKeyIPV6BestMatch(ipv6_addr, cidr_ctx->srepIPV6_tree[cat], &user_data); + if (user_data == NULL) + return 0; + + SReputation *r = (SReputation *)user_data; + return r->rep[cat]; +} + +uint8_t SRepCIDRGetIPRepSrc(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version) +{ + uint8_t rep = 0; + + if (PKT_IS_IPV4(p)) + rep = SRepCIDRGetIPv4IPRep(cidr_ctx, (uint8_t *)GET_IPV4_SRC_ADDR_PTR(p), cat); + else if (PKT_IS_IPV6(p)) + rep = SRepCIDRGetIPv6IPRep(cidr_ctx, (uint8_t *)GET_IPV6_SRC_ADDR(p), cat); + + return rep; +} + +uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version) +{ + uint8_t rep = 0; + + if (PKT_IS_IPV4(p)) + rep = SRepCIDRGetIPv4IPRep(cidr_ctx, (uint8_t *)GET_IPV4_DST_ADDR_PTR(p), cat); + else if (PKT_IS_IPV6(p)) + rep = SRepCIDRGetIPv6IPRep(cidr_ctx, (uint8_t *)GET_IPV6_DST_ADDR(p), cat); + + return rep; +} + /** \brief Increment effective reputation version after * a rule/reputatio reload is complete. */ void SRepReloadComplete(void) @@ -162,7 +267,7 @@ static int SRepCatSplitLine(char *line, uint8_t *cat, char *shortname, size_t sh * \retval 1 header * \retval -1 boo */ -static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) +static int SRepSplitLine(SRepCIDRTree *cidr_ctx, char *line, Address *ip, uint8_t *cat, uint8_t *value) { size_t line_len = strlen(line); char *ptrs[3] = {NULL,NULL,NULL}; @@ -200,11 +305,6 @@ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) if (strcmp(ptrs[0], "ip") == 0) return 1; - uint32_t addr; - if (inet_pton(AF_INET, ptrs[0], &addr) <= 0) { - return -1; - } - int c = atoi(ptrs[1]); if (c < 0 || c >= SREP_MAX_CATS) { return -1; @@ -215,9 +315,22 @@ static int SRepSplitLine(char *line, uint32_t *ip, uint8_t *cat, uint8_t *value) return -1; } - *ip = addr; - *cat = c; - *value = v; + if (strchr(ptrs[0], '/') != NULL) { + SRepCIDRAddNetblock(cidr_ctx, ptrs[0], c, v); + return 1; + } else { + if (inet_pton(AF_INET, ptrs[0], &ip->address) == 1) { + ip->family = AF_INET; + } else if (inet_pton(AF_INET6, ptrs[0], &ip->address) == 1) { + ip->family = AF_INET6; + } else { + return -1; + } + + *cat = c; + *value = v; + } + return 0; } @@ -246,7 +359,24 @@ uint8_t SRepCatGetByShortname(char *shortname) return 0; } -int SRepLoadCatFile(char *filename) +static int SRepLoadCatFile(char *filename) +{ + int r = 0; + FILE *fp = fopen(filename, "r"); + + if (fp == NULL) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); + return -1; + } + + r = SRepLoadCatFileFromFD(fp); + + fclose(fp); + fp = NULL; + return r; +} + +int SRepLoadCatFileFromFD(FILE *fp) { char line[8192] = ""; Address a; @@ -256,12 +386,6 @@ int SRepLoadCatFile(char *filename) BUG_ON(SRepGetVersion() > 0); - FILE *fp = fopen(filename, "r"); - if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); - return -1; - } - while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) @@ -290,8 +414,6 @@ int SRepLoadCatFile(char *filename) SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } } - fclose(fp); - fp = NULL; SCLogDebug("IP Rep categories:"); int i; @@ -303,19 +425,31 @@ int SRepLoadCatFile(char *filename) return 0; } -static int SRepLoadFile(char *filename) +static int SRepLoadFile(SRepCIDRTree *cidr_ctx, char *filename) { - char line[8192] = ""; - Address a; - memset(&a, 0x00, sizeof(a)); - a.family = AF_INET; - + int r = 0; FILE *fp = fopen(filename, "r"); + if (fp == NULL) { - SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file \"%s\": %s", filename, strerror(errno)); + SCLogError(SC_ERR_OPENING_RULE_FILE, "opening ip rep file %s: %s", filename, strerror(errno)); return -1; } + r = SRepLoadFileFromFD(cidr_ctx, fp); + + fclose(fp); + fp = NULL; + return r; + +} + +int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp) +{ + char line[8192] = ""; + Address a; + memset(&a, 0x00, sizeof(a)); + a.family = AF_INET; + while(fgets(line, (int)sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len == 0) @@ -336,17 +470,21 @@ static int SRepLoadFile(char *filename) line[len - 1] = '\0'; } - uint32_t ip = 0; uint8_t cat = 0, value = 0; - int r = SRepSplitLine(line, &ip, &cat, &value); + int r = SRepSplitLine(cidr_ctx, line, &a, &cat, &value); if (r < 0) { SCLogError(SC_ERR_NO_REPUTATION, "bad line \"%s\"", line); } else if (r == 0) { - char ipstr[16]; - PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); - SCLogDebug("%s %u %u", ipstr, cat, value); + if (a.family == AF_INET) { + char ipstr[16]; + PrintInet(AF_INET, (const void *)&a.address, ipstr, sizeof(ipstr)); + SCLogDebug("%s %u %u", ipstr, cat, value); + } else { + char ipstr[128]; + PrintInet(AF_INET6, (const void *)&a.address, ipstr, sizeof(ipstr)); + SCLogDebug("%s %u %u", ipstr, cat, value); + } - a.addr_data32[0] = ip; Host *h = HostGetHostFromHash(&a); if (h == NULL) { SCLogError(SC_ERR_NO_REPUTATION, "failed to get a host, increase host.memcap"); @@ -394,8 +532,6 @@ static int SRepLoadFile(char *filename) } } } - fclose(fp); - fp = NULL; return 0; } @@ -459,6 +595,18 @@ int SRepInit(DetectEngineCtx *de_ctx) char *sfile = NULL; char *filename = NULL; int init = 0; + int i = 0; + + de_ctx->srepCIDR_ctx = (SRepCIDRTree *)SCMalloc(sizeof(SRepCIDRTree)); + if (de_ctx->srepCIDR_ctx == NULL) + exit(EXIT_FAILURE); + memset(de_ctx->srepCIDR_ctx, 0, sizeof(SRepCIDRTree)); + SRepCIDRTree *cidr_ctx = de_ctx->srepCIDR_ctx; + + for (i = 0; i < SREP_MAX_CATS; i++) { + cidr_ctx->srepIPV4_tree[i] = NULL; + cidr_ctx->srepIPV6_tree[i] = NULL; + } if (SRepGetVersion() == 0) { SC_ATOMIC_INIT(srep_eversion); @@ -469,7 +617,7 @@ int SRepInit(DetectEngineCtx *de_ctx) (void)ConfGet("reputation-categories-file", &filename); files = ConfGetNode("reputation-files"); if (filename == NULL && files == NULL) { - SCLogInfo("IP reputation disabled"); + SCLogConfig("IP reputation disabled"); return 0; } @@ -502,7 +650,7 @@ int SRepInit(DetectEngineCtx *de_ctx) sfile = SRepCompleteFilePath(file->val); SCLogInfo("Loading reputation file: %s", sfile); - r = SRepLoadFile(sfile); + r = SRepLoadFile(cidr_ctx, sfile); if (r < 0){ if (de_ctx->failure_fatal == 1) { exit(EXIT_FAILURE); @@ -522,42 +670,89 @@ int SRepInit(DetectEngineCtx *de_ctx) return 0; } +void SRepDestroy(DetectEngineCtx *de_ctx) { + if (de_ctx->srepCIDR_ctx != NULL) { + int i; + for (i = 0; i < SREP_MAX_CATS; i++) { + if (de_ctx->srepCIDR_ctx->srepIPV4_tree[i] != NULL) { + SCRadixReleaseRadixTree(de_ctx->srepCIDR_ctx->srepIPV4_tree[i]); + de_ctx->srepCIDR_ctx->srepIPV4_tree[i] = NULL; + } + + if (de_ctx->srepCIDR_ctx->srepIPV6_tree[i] != NULL) { + SCRadixReleaseRadixTree(de_ctx->srepCIDR_ctx->srepIPV6_tree[i]); + de_ctx->srepCIDR_ctx->srepIPV6_tree[i] = NULL; + } + } + + SCFree(de_ctx->srepCIDR_ctx); + de_ctx->srepCIDR_ctx = NULL; + } +} + #ifdef UNITTESTS +#include "conf-yaml-loader.h" +#include "detect-engine.h" +#include "stream-tcp-private.h" +#include "stream-tcp-reassemble.h" +#include "stream-tcp.h" +#include "util-unittest-helper.h" + static int SRepTest01(void) { char str[] = "1.2.3.4,1,2"; + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return 0; + } - uint32_t ip = 0; + SRepInit(de_ctx); + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(str, &ip, &cat, &value) != 0) { - return 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 0) { + goto end; } char ipstr[16]; - PrintInet(AF_INET, (const void *)&ip, ipstr, sizeof(ipstr)); + PrintInet(AF_INET, (const void *)&a.address, ipstr, sizeof(ipstr)); if (strcmp(ipstr, "1.2.3.4") != 0) - return 0; + goto end; if (cat != 1) - return 0; + goto end; if (value != 2) - return 0; + goto end; - return 1; + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; } static int SRepTest02(void) { char str[] = "1.1.1.1,"; + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return 0; + } - uint32_t ip = 0; + SRepInit(de_ctx); + Address a; uint8_t cat = 0, value = 0; - if (SRepSplitLine(str, &ip, &cat, &value) == 0) { - return 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) == 0) { + goto end; } - return 1; + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; } static int SRepTest03(void) @@ -585,7 +780,135 @@ static int SRepTest03(void) return 1; } +static int SRepTest04(void) +{ + int result = 0; + DetectEngineCtx *de_ctx; + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + SRepInit(de_ctx); + + char str[] = "10.0.0.0/16,1,2"; + + Address a; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 1) { + goto end; + } + + result = 1; + +end: + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SRepTest05(void) +{ + Packet *p = NULL; + int result = 0; + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + if (p == NULL) { + return result; + } + + p->src.addr_data32[0] = UTHSetIPv4Address("10.0.0.1"); + + DetectEngineCtx *de_ctx; + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return result; + } + SRepInit(de_ctx); + + char str[] = "10.0.0.0/16,1,20"; + + Address a; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 1) { + goto end; + } + cat = 1; + value = SRepCIDRGetIPRepSrc(de_ctx->srepCIDR_ctx, p, cat, 0); + if (value != 20) { + goto end; + } + result = 1; + +end: + UTHFreePacket(p); + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SRepTest06(void) +{ + Packet *p = NULL; + int result = 0; + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + + p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + if (p == NULL) { + return result; + } + + p->src.addr_data32[0] = UTHSetIPv4Address("192.168.0.1"); + + DetectEngineCtx *de_ctx; + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return result; + } + SRepInit(de_ctx); + + char str[] = + "0.0.0.0/0,1,10\n" + "192.168.0.0/16,2,127"; + + Address a; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) != 1) { + goto end; + } + cat = 1; + value = SRepCIDRGetIPRepSrc(de_ctx->srepCIDR_ctx, p, cat, 0); + if (value != 10) { + goto end; + } + result = 1; + +end: + UTHFreePacket(p); + DetectEngineCtxFree(de_ctx); + return result; +} + +static int SRepTest07(void) { + char str[] = "2000:0000:0000:0000:0000:0000:0000:0001,"; + int result = 0; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return 0; + } + + SRepInit(de_ctx); + Address a; + uint8_t cat = 0, value = 0; + if (SRepSplitLine(de_ctx->srepCIDR_ctx, str, &a, &cat, &value) == 0) { + goto end; + } + result = 1; +end: + DetectEngineCtxFree(de_ctx); + return result; +} #endif /** Global trees that hold host reputation for IPV4 and IPV6 hosts */ @@ -786,17 +1109,17 @@ Reputation *SCReputationClone(Reputation *orig) return rep; } -void SCReputationFreeCtx(IPReputationCtx *rep_ctx) +void SCReputationFreeCtx(IPReputationCtx *ctx) { - if (rep_ctx->reputationIPV4_tree != NULL) { - SCRadixReleaseRadixTree(rep_ctx->reputationIPV4_tree); - rep_ctx->reputationIPV4_tree = NULL; - SCMutexDestroy(&rep_ctx->reputationIPV4_lock); + if (ctx->reputationIPV4_tree != NULL) { + SCRadixReleaseRadixTree(ctx->reputationIPV4_tree); + ctx->reputationIPV4_tree = NULL; + SCMutexDestroy(&ctx->reputationIPV4_lock); } - if (rep_ctx->reputationIPV6_tree != NULL) { - SCRadixReleaseRadixTree(rep_ctx->reputationIPV6_tree); - rep_ctx->reputationIPV6_tree = NULL; - SCMutexDestroy(&rep_ctx->reputationIPV6_lock); + if (ctx->reputationIPV6_tree != NULL) { + SCRadixReleaseRadixTree(ctx->reputationIPV6_tree); + ctx->reputationIPV6_tree = NULL; + SCMutexDestroy(&ctx->reputationIPV6_lock); } } @@ -2000,26 +2323,30 @@ void SCReputationRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("SCReputationTestIPV4AddRemoveHost01", - SCReputationTestIPV4AddRemoveHost01, 1); + SCReputationTestIPV4AddRemoveHost01); UtRegisterTest("SCReputationTestIPV6AddRemoveHost01", - SCReputationTestIPV6AddRemoveHost01, 1); + SCReputationTestIPV6AddRemoveHost01); UtRegisterTest("SCReputationTestIPV4BestExactMatch01", - SCReputationTestIPV4BestExactMatch01, 1); + SCReputationTestIPV4BestExactMatch01); UtRegisterTest("SCReputationTestIPV4AddRemoveHost02", - SCReputationTestIPV4AddRemoveHost02, 1); + SCReputationTestIPV4AddRemoveHost02); UtRegisterTest("SCReputationTestIPV6AddRemoveHost02", - SCReputationTestIPV6AddRemoveHost02, 1); + SCReputationTestIPV6AddRemoveHost02); UtRegisterTest("SCReputationTestIPV4Update01", - SCReputationTestIPV4Update01, 1); + SCReputationTestIPV4Update01); UtRegisterTest("SCReputationTestIPV6Update01", - SCReputationTestIPV6Update01, 1); - - UtRegisterTest("SRepTest01", SRepTest01, 1); - UtRegisterTest("SRepTest02", SRepTest02, 1); - UtRegisterTest("SRepTest03", SRepTest03, 1); + SCReputationTestIPV6Update01); + + UtRegisterTest("SRepTest01", SRepTest01); + UtRegisterTest("SRepTest02", SRepTest02); + UtRegisterTest("SRepTest03", SRepTest03); + UtRegisterTest("SRepTest04", SRepTest04); + UtRegisterTest("SRepTest05", SRepTest05); + UtRegisterTest("SRepTest06", SRepTest06); + UtRegisterTest("SRepTest07", SRepTest07); #endif /* UNITTESTS */ } diff --git a/src/reputation.h b/src/reputation.h index 4e35830d82ff..347731fe7b4c 100644 --- a/src/reputation.h +++ b/src/reputation.h @@ -26,17 +26,23 @@ #ifndef __REPUTATION_H__ #define __REPUTATION_H__ -#include "detect.h" #include "host.h" #define SREP_MAX_CATS 60 + +typedef struct SRepCIDRTree_ { + SCRadixTree *srepIPV4_tree[SREP_MAX_CATS]; + SCRadixTree *srepIPV6_tree[SREP_MAX_CATS]; +} SRepCIDRTree; + typedef struct SReputation_ { uint32_t version; uint8_t rep[SREP_MAX_CATS]; } SReputation; uint8_t SRepCatGetByShortname(char *shortname); -int SRepInit(DetectEngineCtx *de_ctx); +int SRepInit(struct DetectEngineCtx_ *de_ctx); +void SRepDestroy(struct DetectEngineCtx_ *de_ctx); void SRepReloadComplete(void); int SRepHostTimedOut(Host *); @@ -76,6 +82,12 @@ typedef struct IPReputationCtx_ { SCMutex reputationIPV6_lock; }IPReputationCtx; +uint8_t SRepCIDRGetIPRepSrc(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version); +uint8_t SRepCIDRGetIPRepDst(SRepCIDRTree *cidr_ctx, Packet *p, uint8_t cat, uint32_t version); +void SRepResetVersion(); +int SRepLoadCatFileFromFD(FILE *fp); +int SRepLoadFileFromFD(SRepCIDRTree *cidr_ctx, FILE *fp); + /** Reputation Data */ //TODO: Add a timestamp here to know the last update of this reputation. typedef struct Reputation_ { diff --git a/src/respond-reject-libnet11.c b/src/respond-reject-libnet11.c index b27b74e9d98f..ae238db873dd 100644 --- a/src/respond-reject-libnet11.c +++ b/src/respond-reject-libnet11.c @@ -51,6 +51,12 @@ #ifdef HAVE_LIBNET11 +#ifndef HAVE_LIBNET_INIT_CONST +#define LIBNET_INIT_CAST (char *) +#else +#define LIBNET_INIT_CAST +#endif + /** set to true in main if we're setting caps. We need it here if we're using * reject rules as libnet 1.1 is not compatible with caps. */ extern int sc_set_caps; @@ -79,7 +85,7 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -91,7 +97,7 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir) devname = p->livedev->dev; SCLogDebug("Will emit reject packet on dev %s", devname); } - if ((c = libnet_init(LIBNET_RAW4, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW4, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf); return 1; } @@ -203,7 +209,7 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -216,7 +222,7 @@ int RejectSendLibnet11L3IPv4ICMP(ThreadVars *tv, Packet *p, void *data, int dir) if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) { devname = p->livedev->dev; } - if ((c = libnet_init(LIBNET_RAW4, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW4, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf); return 1; } @@ -291,7 +297,7 @@ int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -302,7 +308,7 @@ int RejectSendLibnet11L3IPv6TCP(ThreadVars *tv, Packet *p, void *data, int dir) if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) { devname = p->livedev->dev; } - if ((c = libnet_init(LIBNET_RAW6, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW6, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_init failed: %s", ebuf); return 1; } @@ -414,7 +420,7 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir) libnet_t *c; /* libnet context */ char ebuf[LIBNET_ERRBUF_SIZE]; int result; - char *devname = NULL; + const char *devname = NULL; /* fill in struct defaults */ lpacket.ttl = 0; @@ -428,7 +434,7 @@ int RejectSendLibnet11L3IPv6ICMP(ThreadVars *tv, Packet *p, void *data, int dir) if (IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) && (p->livedev)) { devname = p->livedev->dev; } - if ((c = libnet_init(LIBNET_RAW6, devname, ebuf)) == NULL) { + if ((c = libnet_init(LIBNET_RAW6, LIBNET_INIT_CAST devname, ebuf)) == NULL) { SCLogError(SC_ERR_LIBNET_INIT,"libnet_inint failed: %s", ebuf); return 1; } diff --git a/src/respond-reject.c b/src/respond-reject.c index 42aabbaa816a..ea756d7e720e 100644 --- a/src/respond-reject.c +++ b/src/respond-reject.c @@ -70,18 +70,14 @@ TmEcode RespondRejectFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq if (PKT_IS_IPV4(p)) { if (PKT_IS_TCP(p)) { ret = RejectSendIPv4TCP(tv, p, data); - } else if(PKT_IS_UDP(p)) { - ret = RejectSendIPv4ICMP(tv, p, data); } else { - return TM_ECODE_OK; + ret = RejectSendIPv4ICMP(tv, p, data); } } else if (PKT_IS_IPV6(p)) { if (PKT_IS_TCP(p)) { ret = RejectSendIPv6TCP(tv, p, data); - } else if(PKT_IS_UDP(p)){ - ret = RejectSendIPv6ICMP(tv, p, data); } else { - return TM_ECODE_OK; + ret = RejectSendIPv6ICMP(tv, p, data); } } else { /* we're only supporting IPv4 and IPv6 */ diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 9d38d30680b7..959617889b91 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -52,23 +52,21 @@ #include "util-affinity.h" #include "util-device.h" #include "util-runmodes.h" +#include "util-ioctl.h" #include "source-af-packet.h" extern int max_pending_packets; -static const char *default_mode_autofp = NULL; +static const char *default_mode_workers = NULL; const char *RunModeAFPGetDefaultMode(void) { - return default_mode_autofp; + return default_mode_workers; } void RunModeIdsAFPRegister(void) { - RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto", - "Multi threaded af-packet mode", - RunModeIdsAFPAuto); RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single", "Single threaded af-packet mode", RunModeIdsAFPSingle); @@ -76,7 +74,7 @@ void RunModeIdsAFPRegister(void) "Workers af-packet mode, each thread does all" " tasks from acquisition to logging", RunModeIdsAFPWorkers); - default_mode_autofp = "autofp"; + default_mode_workers = "workers"; RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp", "Multi socket AF_PACKET mode. Packets from " "each flow are assigned to a single detect " @@ -85,6 +83,9 @@ void RunModeIdsAFPRegister(void) return; } + +#ifdef HAVE_AF_PACKET + void AFPDerefConfig(void *conf) { AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf; @@ -94,6 +95,10 @@ void AFPDerefConfig(void *conf) } } +/* if cluster id is not set, assign it automagically, uniq value per + * interface. */ +static int cluster_id_auto = 1; + /** * \brief extract information from config file * @@ -110,7 +115,6 @@ void *ParseAFPConfig(const char *iface) ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *af_packet_node; - AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpclusterid; char *tmpctype; char *copymodestr; @@ -118,35 +122,38 @@ void *ParseAFPConfig(const char *iface) int boolval; char *bpf_filter = NULL; char *out_iface = NULL; + int cluster_type = PACKET_FANOUT_HASH; - if (unlikely(aconf == NULL)) { + if (iface == NULL) { return NULL; } - if (iface == NULL) { - SCFree(aconf); + AFPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf)); + if (unlikely(aconf == NULL)) { return NULL; } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); - aconf->threads = 1; + aconf->threads = 0; SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; - aconf->cluster_type = PACKET_FANOUT_HASH; + aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; - aconf->flags = 0; + aconf->flags = AFP_RING_MODE; aconf->bpf_filter = NULL; aconf->out_iface = NULL; aconf->copy_mode = AFP_COPY_MODE_NONE; + aconf->block_timeout = 10; + aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; - SCLogInfo("Going to use command-line provided bpf filter '%s'", + SCLogConfig("Going to use command-line provided bpf filter '%s'", aconf->bpf_filter); } } @@ -154,19 +161,18 @@ void *ParseAFPConfig(const char *iface) /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); if (af_packet_node == NULL) { - SCLogInfo("Unable to find af-packet config using default value"); - return aconf; + SCLogInfo("unable to find af-packet config using default values"); + goto finalize; } - if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface); - - if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); + if_root = ConfFindDeviceConfig(af_packet_node, iface); + if_default = ConfFindDeviceConfig(af_packet_node, "default"); if (if_root == NULL && if_default == NULL) { - SCLogInfo("Unable to find af-packet config for " - "interface \"%s\" or \"default\", using default value", + SCLogInfo("unable to find af-packet config for " + "interface \"%s\" or \"default\", using default values", iface); - return aconf; + goto finalize; } /* If there is no setting for current interface use default one as main iface */ @@ -176,15 +182,16 @@ void *ParseAFPConfig(const char *iface) } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { - aconf->threads = 1; + aconf->threads = 0; } else { if (threadsstr != NULL) { - aconf->threads = (uint8_t)atoi(threadsstr); + if (strcmp(threadsstr, "auto") == 0) { + aconf->threads = 0; + } else { + aconf->threads = (uint8_t)atoi(threadsstr); + } } } - if (aconf->threads == 0) { - aconf->threads = 1; - } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { @@ -192,19 +199,55 @@ void *ParseAFPConfig(const char *iface) } } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval); - if (boolval) { - SCLogInfo("Enabling mmaped capture on iface %s", - aconf->iface); - aconf->flags |= AFP_RING_MODE; - } - (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "use-emergency-flush", (int *)&boolval); - if (boolval) { - SCLogInfo("Enabling ring emergency flush on iface %s", - aconf->iface); - aconf->flags |= AFP_EMERGENCY_MODE; + if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) { + if (!boolval) { + SCLogConfig("Disabling mmaped capture on iface %s", + aconf->iface); + aconf->flags &= ~(AFP_RING_MODE|AFP_TPACKET_V3); + } } + if (aconf->flags & AFP_RING_MODE) { + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, + "mmap-locked", (int *)&boolval); + if (boolval) { + SCLogConfig("Enabling locked memory for mmap on iface %s", + aconf->iface); + aconf->flags |= AFP_MMAP_LOCKED; + } + + if (ConfGetChildValueBoolWithDefault(if_root, if_default, + "tpacket-v3", (int *)&boolval) == 1) + { + if (boolval) { + if (strcasecmp(RunmodeGetActive(), "workers") == 0) { +#ifdef HAVE_TPACKET_V3 + SCLogConfig("Enabling tpacket v3 capture on iface %s", + aconf->iface); + aconf->flags |= AFP_TPACKET_V3; +#else + SCLogNotice("System too old for tpacket v3 switching to v2"); + aconf->flags &= ~AFP_TPACKET_V3; +#endif + } else { + SCLogWarning(SC_ERR_RUNMODE, + "tpacket v3 is only implemented for 'workers' runmode." + " Switching to tpacket v2."); + aconf->flags &= ~AFP_TPACKET_V3; + } + } else { + aconf->flags &= ~AFP_TPACKET_V3; + } + } + + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, + "use-emergency-flush", (int *)&boolval); + if (boolval) { + SCLogConfig("Enabling ring emergency flush on iface %s", + aconf->iface); + aconf->flags |= AFP_EMERGENCY_MODE; + } + } aconf->copy_mode = AFP_COPY_MODE_NONE; if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { @@ -231,44 +274,68 @@ void *ParseAFPConfig(const char *iface) } } - SC_ATOMIC_RESET(aconf->ref); - (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); - if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { - SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); + aconf->cluster_id = (uint16_t)(cluster_id_auto++); } else { aconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); } if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { - SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config"); + /* default to our safest choice: flow hashing + defrag enabled */ + aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; + cluster_type = PACKET_FANOUT_HASH; } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { - SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_LB; + cluster_type = PACKET_FANOUT_LB; } else if (strcmp(tmpctype, "cluster_flow") == 0) { /* In hash mode, we also ask for defragmentation needed to * compute the hash */ uint16_t defrag = 0; int conf_val = 0; - SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using flow cluster mode for AF_PACKET (iface %s)", aconf->iface); ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", &conf_val); if (conf_val) { - SCLogInfo("Using defrag kernel functionality for AF_PACKET (iface %s)", + SCLogConfig("Using defrag kernel functionality for AF_PACKET (iface %s)", aconf->iface); defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; + cluster_type = PACKET_FANOUT_HASH; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { - SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", + SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; + cluster_type = PACKET_FANOUT_CPU; + } else if (strcmp(tmpctype, "cluster_qm") == 0) { + SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type = PACKET_FANOUT_QM; + cluster_type = PACKET_FANOUT_QM; + } else if (strcmp(tmpctype, "cluster_random") == 0) { + SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type = PACKET_FANOUT_RND; + cluster_type = PACKET_FANOUT_RND; + } else if (strcmp(tmpctype, "cluster_rollover") == 0) { + SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type = PACKET_FANOUT_ROLLOVER; + cluster_type = PACKET_FANOUT_ROLLOVER; + } else { - SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); - SCFree(aconf); - return NULL; + SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); + } + + int conf_val = 0; + ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val); + if (conf_val) { + SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)", + aconf->iface); + aconf->cluster_type |= PACKET_FANOUT_FLAG_ROLLOVER; } /*load af_packet bpf filter*/ @@ -277,7 +344,7 @@ void *ParseAFPConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; - SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); + SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter); } } } @@ -289,23 +356,25 @@ void *ParseAFPConfig(const char *iface) } if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) { aconf->ring_size = value; - if (value * aconf->threads < max_pending_packets) { - aconf->ring_size = max_pending_packets / aconf->threads + 1; - SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " - "Resetting to decent value %d.", aconf->ring_size); - /* We want at least that max_pending_packets packets can be handled by the - * interface. This is generous if we have multiple interfaces listening. */ + } + + if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) { + if (value % getpagesize()) { + SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize."); + } else { + aconf->block_size = value; } + } + + if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { + aconf->block_timeout = value; } else { - /* We want that max_pending_packets packets can be handled by suricata - * for this interface. To take burst into account we multiply the obtained - * size by 2. */ - aconf->ring_size = max_pending_packets * 2 / aconf->threads; + aconf->block_timeout = 10; } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { - SCLogInfo("Disabling promiscuous mode on iface %s", + SCLogConfig("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } @@ -313,9 +382,9 @@ void *ParseAFPConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "kernel") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; @@ -324,6 +393,98 @@ void *ParseAFPConfig(const char *iface) } } +finalize: + + /* if the number of threads is not 1, we need to first check if fanout + * functions on this system. */ + if (aconf->threads != 1) { + if (AFPIsFanoutSupported() == 0) { + if (aconf->threads != 0) { + SCLogNotice("fanout not supported on this system, falling " + "back to 1 capture thread"); + } + aconf->threads = 1; + } + } + + /* try to automagically set the proper number of threads */ + if (aconf->threads == 0) { + /* for cluster_flow use core count */ + if (cluster_type == PACKET_FANOUT_HASH) { + aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); + SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads); + + /* for cluster_qm use RSS queue count */ + } else if (cluster_type == PACKET_FANOUT_QM) { + int rss_queues = GetIfaceRSSQueuesNum(iface); + if (rss_queues > 0) { + aconf->threads = rss_queues; + SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads); + } + } + + if (aconf->threads) { + SCLogPerf("Using %d AF_PACKET threads for interface %s", + aconf->threads, iface); + } + } + if (aconf->threads <= 0) { + aconf->threads = 1; + } + SC_ATOMIC_RESET(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); + + if (aconf->ring_size != 0) { + if (aconf->ring_size * aconf->threads < max_pending_packets) { + aconf->ring_size = max_pending_packets / aconf->threads + 1; + SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " + "Resetting to decent value %d.", aconf->ring_size); + /* We want at least that max_pending_packets packets can be handled by the + * interface. This is generous if we have multiple interfaces listening. */ + } + } else { + /* We want that max_pending_packets packets can be handled by suricata + * for this interface. To take burst into account we multiply the obtained + * size by 2. */ + aconf->ring_size = max_pending_packets * 2 / aconf->threads; + } + + int ltype = AFPGetLinkType(iface); + switch (ltype) { + case LINKTYPE_ETHERNET: + /* af-packet can handle csum offloading */ + if (LiveGetOffload() == 0) { + if (GetIfaceOffloading(iface, 0, 1) == 1) { + SCLogWarning(SC_ERR_AFP_CREATE, + "Using AF_PACKET with offloading activated leads to capture problems"); + } + } else { + DisableIfaceOffloading(LiveGetDevice(iface), 0, 1); + } + break; + case -1: + default: + break; + } + + char *active_runmode = RunmodeGetActive(); + if (active_runmode && !strcmp("workers", active_runmode)) { + aconf->flags |= AFP_ZERO_COPY; + } else { + /* If we are using copy mode we need a lock */ + aconf->flags |= AFP_SOCK_PROTECT; + } + + /* If we are in RING mode, then we can use ZERO copy + * by using the data release mechanism */ + if (aconf->flags & AFP_RING_MODE) { + aconf->flags |= AFP_ZERO_COPY; + } + + if (aconf->flags & AFP_ZERO_COPY) { + SCLogConfig("%s: enabling zero copy mode by using data release call", iface); + } + return aconf; } @@ -352,13 +513,13 @@ int AFPRunModeIsIPS() if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev = LiveGetDeviceName(ldev); + const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; } char *copymodestr = NULL; - if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev); + if_root = ConfFindDeviceConfig(af_packet_node, live_dev); if (if_root == NULL) { if (if_default == NULL) { @@ -382,7 +543,7 @@ int AFPRunModeIsIPS() if (has_ids && has_ips) { SCLogInfo("AF_PACKET mode using IPS and IDS mode"); for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev = LiveGetDeviceName(ldev); + const char *live_dev = LiveGetDeviceName(ldev); if (live_dev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); return 0; @@ -411,66 +572,10 @@ int AFPRunModeIsIPS() return has_ips; } -/** - * \brief RunModeIdsAFPAuto set up the following thread packet handlers: - * - Receive thread (from live iface) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - -#ifdef HAVE_AF_PACKET - int ret; - char *live_dev = NULL; - - RunModeInitialize(); - - TimeModeSetLive(); - - (void)ConfGet("af-packet.live-interface", &live_dev); - - if (AFPPeersListInit() != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); - exit(EXIT_FAILURE); - } - - ret = RunModeSetLiveCaptureAuto(de_ctx, - ParseAFPConfig, - AFPConfigGeThreadsCount, - "ReceiveAFP", - "DecodeAFP", "RecvAFP", - live_dev); - if (ret != 0) { - SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); - exit(EXIT_FAILURE); - } - - /* In IPS mode each threads must have a peer */ - if (AFPPeersListCheck() != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); - exit(EXIT_FAILURE); - } - - SCLogInfo("RunModeIdsAFPAuto initialised"); #endif - SCReturnInt(0); -} -int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) + +int RunModeIdsAFPAutoFp(void) { SCEnter(); @@ -492,11 +597,10 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParseAFPConfig, + ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", - "DecodeAFP", "RxAFP", + "DecodeAFP", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -509,7 +613,7 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsAFPAutoFp initialised"); + SCLogDebug("RunModeIdsAFPAutoFp initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); @@ -518,14 +622,12 @@ int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx) /** * \brief Single thread version of the AF_PACKET processing. */ -int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) +int RunModeIdsAFPSingle(void) { + SCEnter(); #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; -#endif - SCEnter(); -#ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); @@ -537,11 +639,10 @@ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParseAFPConfig, + ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", - "DecodeAFP", "AFPacket", + "DecodeAFP", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -554,7 +655,7 @@ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsAFPSingle initialised"); + SCLogDebug("RunModeIdsAFPSingle initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); @@ -566,14 +667,12 @@ int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx) * Start N threads with each thread doing all the work. * */ -int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsAFPWorkers(void) { + SCEnter(); #ifdef HAVE_AF_PACKET int ret; char *live_dev = NULL; -#endif - SCEnter(); -#ifdef HAVE_AF_PACKET RunModeInitialize(); TimeModeSetLive(); @@ -585,11 +684,10 @@ int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParseAFPConfig, + ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig, AFPConfigGeThreadsCount, "ReceiveAFP", - "DecodeAFP", "AFPacket", + "DecodeAFP", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -602,7 +700,7 @@ int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - SCLogInfo("RunModeIdsAFPWorkers initialised"); + SCLogDebug("RunModeIdsAFPWorkers initialised"); #endif /* HAVE_AF_PACKET */ SCReturnInt(0); diff --git a/src/runmode-af-packet.h b/src/runmode-af-packet.h index 0e1c764dd764..79fe436a692f 100644 --- a/src/runmode-af-packet.h +++ b/src/runmode-af-packet.h @@ -23,10 +23,9 @@ #ifndef __RUNMODE_AF_PACKET_H__ #define __RUNMODE_AF_PACKET_H__ -int RunModeIdsAFPAuto(DetectEngineCtx *); -int RunModeIdsAFPSingle(DetectEngineCtx *); -int RunModeIdsAFPAutoFp(DetectEngineCtx *); -int RunModeIdsAFPWorkers(DetectEngineCtx *); +int RunModeIdsAFPSingle(void); +int RunModeIdsAFPAutoFp(void); +int RunModeIdsAFPWorkers(void); void RunModeIdsAFPRegister(void); const char *RunModeAFPGetDefaultMode(void); int AFPRunModeIsIPS(); diff --git a/src/runmode-erf-dag.c b/src/runmode-erf-dag.c index 4fa9a6fccb92..a27544f22fab 100644 --- a/src/runmode-erf-dag.c +++ b/src/runmode-erf-dag.c @@ -20,14 +20,9 @@ #include "conf.h" #include "runmodes.h" #include "runmode-erf-dag.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" #include "util-debug.h" #include "util-time.h" @@ -76,7 +71,7 @@ void RunModeErfDagRegister(void) return; } -int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) +int RunModeIdsErfDagSingle(void) { int ret; @@ -86,12 +81,11 @@ int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) TimeModeSetLive(); - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParseDagConfig, + ret = RunModeSetLiveCaptureSingle(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", - "RxDAG", + thread_name_single, NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG single runmode failed to start"); @@ -103,7 +97,7 @@ int RunModeIdsErfDagSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsErfDagAutoFp(void) { int ret; @@ -113,12 +107,11 @@ int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) TimeModeSetLive(); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParseDagConfig, + ret = RunModeSetLiveCaptureAutoFp(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", - "RxDAG", + thread_name_autofp, NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG autofp runmode failed to start"); @@ -130,7 +123,7 @@ int RunModeIdsErfDagAutoFp(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsErfDagWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsErfDagWorkers(void) { int ret; @@ -140,12 +133,11 @@ int RunModeIdsErfDagWorkers(DetectEngineCtx *de_ctx) TimeModeSetLive(); - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParseDagConfig, + ret = RunModeSetLiveCaptureWorkers(ParseDagConfig, DagConfigGetThreadCount, "ReceiveErfDag", "DecodeErfDag", - "RxDAG", + thread_name_workers, NULL); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "DAG workers runmode failed to start"); diff --git a/src/runmode-erf-dag.h b/src/runmode-erf-dag.h index 2a4b20ea520c..c4b2a59cee5e 100644 --- a/src/runmode-erf-dag.h +++ b/src/runmode-erf-dag.h @@ -23,9 +23,9 @@ #ifndef __RUNMODE_ERF_DAG_H__ #define __RUNMODE_ERF_DAG_H__ -int RunModeIdsErfDagAutoFp(DetectEngineCtx *); -int RunModeIdsErfDagSingle(DetectEngineCtx *); -int RunModeIdsErfDagWorkers(DetectEngineCtx *); +int RunModeIdsErfDagAutoFp(void); +int RunModeIdsErfDagSingle(void); +int RunModeIdsErfDagWorkers(void); void RunModeErfDagRegister(void); const char *RunModeErfDagGetDefaultMode(void); diff --git a/src/runmode-erf-file.c b/src/runmode-erf-file.c index dad86caaaa27..76bc49214726 100644 --- a/src/runmode-erf-file.c +++ b/src/runmode-erf-file.c @@ -20,14 +20,9 @@ #include "conf.h" #include "runmodes.h" #include "runmode-erf-file.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" #include "util-debug.h" #include "util-time.h" @@ -59,7 +54,7 @@ void RunModeErfFileRegister(void) return; } -int RunModeErfFileSingle(DetectEngineCtx *de_ctx) +int RunModeErfFileSingle(void) { char *file; @@ -76,7 +71,7 @@ int RunModeErfFileSingle(DetectEngineCtx *de_ctx) /* Basically the same setup as PCAP files. */ - ThreadVars *tv = TmThreadCreatePacketHandler("ErfFile", + ThreadVars *tv = TmThreadCreatePacketHandler(thread_name_single, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -99,24 +94,13 @@ int RunModeErfFileSingle(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName Detect failed\n"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); - } - - SetupOutputs(tv); - if (TmThreadSpawn(tv) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(EXIT_FAILURE); @@ -127,7 +111,7 @@ int RunModeErfFileSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) +int RunModeErfFileAutoFp(void) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -156,7 +140,7 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) cpu = 1; /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) @@ -170,7 +154,7 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) /* create the threads */ ThreadVars *tv = - TmThreadCreatePacketHandler("ReceiveErfFile", + TmThreadCreatePacketHandler(thread_name_autofp, "packetpool", "packetpool", queues, "flow", "pktacqloop"); @@ -206,20 +190,15 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - printf("ERROR: Can't allocate thread name\n"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); + SCLogDebug("Assigning %s affinity to cpu %u", tname, cpu); ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "packetpool", "packetpool", "varslot"); @@ -227,22 +206,14 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) printf("ERROR: TmThreadsCreate failed\n"); exit(EXIT_FAILURE); } - tm_module = TmModuleGetByName("StreamTcp"); + + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName Detect failed\n"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); - } - if (threading_set_cpu_affinity) { TmThreadSetCPUAffinity(tv_detect_ncpu, (int)cpu); /* If we have more than one core/cpu, the first Detect thread @@ -256,15 +227,7 @@ int RunModeErfFileAutoFp(DetectEngineCtx *de_ctx) } } - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - /* add outputs as well */ - SetupOutputs(tv_detect_ncpu); + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); diff --git a/src/runmode-erf-file.h b/src/runmode-erf-file.h index 0612e9fa436c..54a8ba8972fa 100644 --- a/src/runmode-erf-file.h +++ b/src/runmode-erf-file.h @@ -23,8 +23,8 @@ #ifndef __RUNMODE_ERF_FILE_H__ #define __RUNMODE_ERF_FILE_H__ -int RunModeErfFileSingle(DetectEngineCtx *); -int RunModeErfFileAutoFp(DetectEngineCtx *); +int RunModeErfFileSingle(void); +int RunModeErfFileAutoFp(void); void RunModeErfFileRegister(void); const char *RunModeErfFileGetDefaultMode(void); diff --git a/src/runmode-ipfw.c b/src/runmode-ipfw.c index 718f859a4f9f..841692e1166b 100644 --- a/src/runmode-ipfw.c +++ b/src/runmode-ipfw.c @@ -31,14 +31,7 @@ #include "conf.h" #include "runmodes.h" #include "runmode-ipfw.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -58,9 +51,6 @@ const char *RunModeIpsIPFWGetDefaultMode(void) void RunModeIpsIPFWRegister(void) { default_mode = "autofp"; - RunModeRegisterNewRunMode(RUNMODE_IPFW, "auto", - "Multi threaded IPFW IPS mode", - RunModeIpsIPFWAuto); RunModeRegisterNewRunMode(RUNMODE_IPFW, "autofp", "Multi threaded IPFW IPS mode with respect to flow", @@ -73,29 +63,7 @@ void RunModeIpsIPFWRegister(void) return; } -int RunModeIpsIPFWAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - int ret = 0; -#ifdef IPFW - - RunModeInitialize(); - - TimeModeSetLive(); - - LiveDeviceHasNoStats(); - - ret = RunModeSetIPSAuto(de_ctx, - IPFWGetThread, - "ReceiveIPFW", - "VerdictIPFW", - "DecodeIPFW"); -#endif /* IPFW */ - return ret; -} - - -int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) +int RunModeIpsIPFWAutoFp(void) { SCEnter(); int ret = 0; @@ -107,8 +75,7 @@ int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(de_ctx, - IPFWGetThread, + ret = RunModeSetIPSAutoFp(IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); @@ -116,7 +83,7 @@ int RunModeIpsIPFWAutoFp(DetectEngineCtx *de_ctx) return ret; } -int RunModeIpsIPFWWorker(DetectEngineCtx *de_ctx) +int RunModeIpsIPFWWorker(void) { SCEnter(); int ret = 0; @@ -128,8 +95,7 @@ int RunModeIpsIPFWWorker(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSWorker(de_ctx, - IPFWGetThread, + ret = RunModeSetIPSWorker(IPFWGetThread, "ReceiveIPFW", "VerdictIPFW", "DecodeIPFW"); diff --git a/src/runmode-ipfw.h b/src/runmode-ipfw.h index 92fae6b8ad32..5c8345b17455 100644 --- a/src/runmode-ipfw.h +++ b/src/runmode-ipfw.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_IPFW_H__ #define __RUNMODE_IPFW_H__ -int RunModeIpsIPFWAuto(DetectEngineCtx *); -int RunModeIpsIPFWAutoFp(DetectEngineCtx *); -int RunModeIpsIPFWWorker(DetectEngineCtx *); +int RunModeIpsIPFWAutoFp(void); +int RunModeIpsIPFWWorker(void); void RunModeIpsIPFWRegister(void); const char *RunModeIpsIPFWGetDefaultMode(void); diff --git a/src/runmode-napatech.c b/src/runmode-napatech.c index e064bb1674d5..6d883f740201 100644 --- a/src/runmode-napatech.c +++ b/src/runmode-napatech.c @@ -25,14 +25,8 @@ #include "tm-threads.h" #include "conf.h" #include "runmodes.h" -#include "log-httplog.h" #include "output.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" - #include "util-debug.h" #include "util-time.h" #include "util-cpu.h" @@ -45,9 +39,8 @@ // need NapatechStreamDevConf structure #include "source-napatech.h" -#define NT_RUNMODE_AUTO 1 -#define NT_RUNMODE_AUTOFP 2 -#define NT_RUNMODE_WORKERS 4 +#define NT_RUNMODE_AUTOFP 1 +#define NT_RUNMODE_WORKERS 2 static const char *default_mode = NULL; #ifdef HAVE_NAPATECH @@ -63,9 +56,6 @@ void RunModeNapatechRegister(void) { #ifdef HAVE_NAPATECH default_mode = "autofp"; - RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "auto", - "Multi threaded Napatech mode", - RunModeNapatechAuto); RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "autofp", "Multi threaded Napatech mode. Packets from " "each flow are assigned to a single detect " @@ -189,7 +179,7 @@ int NapatechGetThreadsCount(void *conf __attribute__((unused))) { return 1; } -int NapatechInit(DetectEngineCtx *de_ctx, int runmode) +static int NapatechInit(int runmode) { int ret; char errbuf[100]; @@ -211,20 +201,15 @@ int NapatechInit(DetectEngineCtx *de_ctx, int runmode) } switch(runmode) { - case NT_RUNMODE_AUTO: - ret = RunModeSetLiveCaptureAuto(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, - "NapatechStream", "NapatechDecode", - "RxNT", NULL); - break; case NT_RUNMODE_AUTOFP: - ret = RunModeSetLiveCaptureAutoFp(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, + ret = RunModeSetLiveCaptureAutoFp(NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", - "RxNT", NULL); + thread_name_autofp, NULL); break; case NT_RUNMODE_WORKERS: - ret = RunModeSetLiveCaptureWorkers(de_ctx, NapatechConfigParser, NapatechGetThreadsCount, + ret = RunModeSetLiveCaptureWorkers(NapatechConfigParser, NapatechGetThreadsCount, "NapatechStream", "NapatechDecode", - "RxNT", NULL); + thread_name_workers, NULL); break; default: ret = -1; @@ -237,19 +222,14 @@ int NapatechInit(DetectEngineCtx *de_ctx, int runmode) return 0; } -int RunModeNapatechAuto(DetectEngineCtx *de_ctx) -{ - return NapatechInit(de_ctx, NT_RUNMODE_AUTO); -} - -int RunModeNapatechAutoFp(DetectEngineCtx *de_ctx) +int RunModeNapatechAutoFp(void) { - return NapatechInit(de_ctx, NT_RUNMODE_AUTOFP); + return NapatechInit(NT_RUNMODE_AUTOFP); } -int RunModeNapatechWorkers(DetectEngineCtx *de_ctx) +int RunModeNapatechWorkers(void) { - return NapatechInit(de_ctx, NT_RUNMODE_WORKERS); + return NapatechInit(NT_RUNMODE_WORKERS); } #endif diff --git a/src/runmode-napatech.h b/src/runmode-napatech.h index ffb1d42efe09..d10b406376d0 100644 --- a/src/runmode-napatech.h +++ b/src/runmode-napatech.h @@ -29,9 +29,8 @@ #include #endif -int RunModeNapatechAuto(DetectEngineCtx *); -int RunModeNapatechAutoFp(DetectEngineCtx *); -int RunModeNapatechWorkers(DetectEngineCtx *); +int RunModeNapatechAutoFp(void); +int RunModeNapatechWorkers(void); void RunModeNapatechRegister(void); const char *RunModeNapatechGetDefaultMode(void); diff --git a/src/runmode-netmap.c b/src/runmode-netmap.c new file mode 100644 index 000000000000..3ea6c7a55cd7 --- /dev/null +++ b/src/runmode-netmap.c @@ -0,0 +1,472 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** +* \ingroup netmap +* +* @{ +*/ + +/** +* \file +* +* \author Aleksey Katargin +* +* Netmap runmode +* +*/ + +#include "suricata-common.h" +#include "config.h" +#include "tm-threads.h" +#include "conf.h" +#include "runmodes.h" +#include "runmode-netmap.h" +#include "log-httplog.h" +#include "output.h" +#include "detect-engine-mpm.h" + +#include "alert-fastlog.h" +#include "alert-prelude.h" +#include "alert-unified2-alert.h" +#include "alert-debuglog.h" + +#include "util-debug.h" +#include "util-time.h" +#include "util-cpu.h" +#include "util-affinity.h" +#include "util-device.h" +#include "util-runmodes.h" +#include "util-ioctl.h" + +#include "source-netmap.h" + +extern int max_pending_packets; + +static const char *default_mode_workers = NULL; + +const char *RunModeNetmapGetDefaultMode(void) +{ + return default_mode_workers; +} + +void RunModeIdsNetmapRegister(void) +{ + RunModeRegisterNewRunMode(RUNMODE_NETMAP, "single", + "Single threaded netmap mode", + RunModeIdsNetmapSingle); + RunModeRegisterNewRunMode(RUNMODE_NETMAP, "workers", + "Workers netmap mode, each thread does all" + " tasks from acquisition to logging", + RunModeIdsNetmapWorkers); + default_mode_workers = "workers"; + RunModeRegisterNewRunMode(RUNMODE_NETMAP, "autofp", + "Multi threaded netmap mode. Packets from " + "each flow are assigned to a single detect " + "thread.", + RunModeIdsNetmapAutoFp); + return; +} + +#ifdef HAVE_NETMAP + +static void NetmapDerefConfig(void *conf) +{ + NetmapIfaceConfig *pfp = (NetmapIfaceConfig *)conf; + /* config is used only once but cost of this low. */ + if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { + SCFree(pfp); + } +} + +static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, + ConfNode *if_root, ConfNode *if_default) +{ + ns->threads = 0; + ns->promisc = 1; + ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; + ns->copy_mode = NETMAP_COPY_MODE_NONE; + + strlcpy(ns->iface, iface, sizeof(ns->iface)); + if (ns->iface[0]) { + size_t len = strlen(ns->iface); + if (ns->iface[len-1] == '+') { + ns->iface[len-1] = '\0'; + ns->sw_ring = 1; + } + } + + char *bpf_filter = NULL; + if (ConfGet("bpf-filter", &bpf_filter) == 1) { + if (strlen(bpf_filter) > 0) { + ns->bpf_filter = bpf_filter; + SCLogInfo("Going to use command-line provided bpf filter '%s'", + ns->bpf_filter); + } + } + + if (if_root == NULL && if_default == NULL) { + SCLogInfo("Unable to find netmap config for " + "interface \"%s\" or \"default\", using default values", + iface); + goto finalize; + + /* If there is no setting for current interface use default one as main iface */ + } else if (if_root == NULL) { + if_root = if_default; + if_default = NULL; + } + + char *threadsstr = NULL; + if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { + ns->threads = 0; + } else { + if (strcmp(threadsstr, "auto") == 0) { + ns->threads = 0; + } else { + ns->threads = (uint8_t)atoi(threadsstr); + } + } + + /* load netmap bpf filter */ + /* command line value has precedence */ + if (ns->bpf_filter == NULL) { + if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { + if (strlen(bpf_filter) > 0) { + ns->bpf_filter = bpf_filter; + SCLogInfo("Going to use bpf filter %s", ns->bpf_filter); + } + } + } + + int boolval = 0; + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); + if (boolval) { + SCLogInfo("Disabling promiscuous mode on iface %s", ns->iface); + ns->promisc = 0; + } + + char *tmpctype; + if (ConfGetChildValueWithDefault(if_root, if_default, + "checksum-checks", &tmpctype) == 1) + { + if (strcmp(tmpctype, "auto") == 0) { + ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; + } else if (ConfValIsTrue(tmpctype)) { + ns->checksum_mode = CHECKSUM_VALIDATION_ENABLE; + } else if (ConfValIsFalse(tmpctype)) { + ns->checksum_mode = CHECKSUM_VALIDATION_DISABLE; + } else { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid value for " + "checksum-checks for %s", iface); + } + } + + char *copymodestr; + if (ConfGetChildValueWithDefault(if_root, if_default, + "copy-mode", ©modestr) == 1) + { + if (strcmp(copymodestr, "ips") == 0) { + ns->copy_mode = NETMAP_COPY_MODE_IPS; + } else if (strcmp(copymodestr, "tap") == 0) { + ns->copy_mode = NETMAP_COPY_MODE_TAP; + } else { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid copy-mode " + "(valid are tap, ips)"); + } + } + +finalize: + + if (ns->sw_ring) { + /* just one thread per interface supported */ + ns->threads = 1; + } else if (ns->threads == 0) { + /* As NetmapGetRSSCount is broken on Linux, first run + * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */ + ns->threads = GetIfaceRSSQueuesNum(ns->iface); + if (ns->threads == 0) { + ns->threads = NetmapGetRSSCount(ns->iface); + } + } + if (ns->threads <= 0) { + ns->threads = 1; + } + + /* netmap needs all offloading to be disabled */ + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading(ns->iface, 1, 1); + } else { + DisableIfaceOffloading(LiveGetDevice(ns->iface), 1, 1); + } + + return 0; +} + +/** +* \brief extract information from config file +* +* The returned structure will be freed by the thread init function. +* This is thus necessary to or copy the structure before giving it +* to thread or to reparse the file for each thread (and thus have +* new structure. +* +* \return a NetmapIfaceConfig corresponding to the interface name +*/ +static void *ParseNetmapConfig(const char *iface_name) +{ + ConfNode *if_root = NULL; + ConfNode *if_default = NULL; + ConfNode *netmap_node; + char *out_iface = NULL; + + if (iface_name == NULL) { + return NULL; + } + + NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); + if (unlikely(aconf == NULL)) { + return NULL; + } + + memset(aconf, 0, sizeof(*aconf)); + aconf->DerefFunc = NetmapDerefConfig; + strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); + SC_ATOMIC_INIT(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, 1); + + /* Find initial node */ + netmap_node = ConfGetNode("netmap"); + if (netmap_node == NULL) { + SCLogInfo("Unable to find netmap config using default value"); + } else { + if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); + if_default = ConfFindDeviceConfig(netmap_node, "default"); + } + + /* parse settings for capture iface */ + ParseNetmapSettings(&aconf->in, aconf->iface_name, if_root, if_default); + + /* if we have a copy iface, parse that as well */ + if (netmap_node != NULL) { + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { + if (strlen(out_iface) > 0) { + if_root = ConfFindDeviceConfig(netmap_node, out_iface); + ParseNetmapSettings(&aconf->out, out_iface, if_root, if_default); + } + } + } + + SC_ATOMIC_RESET(aconf->ref); + (void) SC_ATOMIC_ADD(aconf->ref, aconf->in.threads); + SCLogPerf("Using %d threads for interface %s", aconf->in.threads, + aconf->iface_name); + + return aconf; +} + +static int NetmapConfigGeThreadsCount(void *conf) +{ + NetmapIfaceConfig *aconf = (NetmapIfaceConfig *)conf; + return aconf->in.threads; +} + +int NetmapRunModeIsIPS() +{ + int nlive = LiveGetDeviceCount(); + int ldev; + ConfNode *if_root; + ConfNode *if_default = NULL; + ConfNode *netmap_node; + int has_ips = 0; + int has_ids = 0; + + /* Find initial node */ + netmap_node = ConfGetNode("netmap"); + if (netmap_node == NULL) { + return 0; + } + + if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default"); + + for (ldev = 0; ldev < nlive; ldev++) { + const char *live_dev = LiveGetDeviceName(ldev); + if (live_dev == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + char *copymodestr = NULL; + if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev); + + if (if_root == NULL) { + if (if_default == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + if_root = if_default; + } + + if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { + if (strcmp(copymodestr, "ips") == 0) { + has_ips = 1; + } else { + has_ids = 1; + } + } else { + has_ids = 1; + } + } + + if (has_ids && has_ips) { + SCLogInfo("Netmap mode using IPS and IDS mode"); + for (ldev = 0; ldev < nlive; ldev++) { + const char *live_dev = LiveGetDeviceName(ldev); + if (live_dev == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev); + char *copymodestr = NULL; + + if (if_root == NULL) { + if (if_default == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); + return 0; + } + if_root = if_default; + } + + if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) && + (strcmp(copymodestr, "ips") == 0))) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "Netmap IPS mode used and interface '%s' is in IDS or TAP mode. " + "Sniffing '%s' but expect bad result as stream-inline is activated.", + live_dev, live_dev); + } + } + } + + return has_ips; +} + +#endif // #ifdef HAVE_NETMAP + +int RunModeIdsNetmapAutoFp(void) +{ + SCEnter(); + +#ifdef HAVE_NETMAP + int ret; + char *live_dev = NULL; + + RunModeInitialize(); + + TimeModeSetLive(); + + (void)ConfGet("netmap.live-interface", &live_dev); + + SCLogDebug("live_dev %s", live_dev); + + ret = RunModeSetLiveCaptureAutoFp( + ParseNetmapConfig, + NetmapConfigGeThreadsCount, + "ReceiveNetmap", + "DecodeNetmap", thread_name_autofp, + live_dev); + if (ret != 0) { + SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); + exit(EXIT_FAILURE); + } + + SCLogDebug("RunModeIdsNetmapAutoFp initialised"); +#endif /* HAVE_NETMAP */ + + SCReturnInt(0); +} + +/** +* \brief Single thread version of the netmap processing. +*/ +int RunModeIdsNetmapSingle(void) +{ + SCEnter(); + +#ifdef HAVE_NETMAP + int ret; + char *live_dev = NULL; + + RunModeInitialize(); + TimeModeSetLive(); + + (void)ConfGet("netmap.live-interface", &live_dev); + + ret = RunModeSetLiveCaptureSingle( + ParseNetmapConfig, + NetmapConfigGeThreadsCount, + "ReceiveNetmap", + "DecodeNetmap", thread_name_single, + live_dev); + if (ret != 0) { + SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); + exit(EXIT_FAILURE); + } + + SCLogDebug("RunModeIdsNetmapSingle initialised"); + +#endif /* HAVE_NETMAP */ + SCReturnInt(0); +} + +/** +* \brief Workers version of the netmap processing. +* +* Start N threads with each thread doing all the work. +* +*/ +int RunModeIdsNetmapWorkers(void) +{ + SCEnter(); + +#ifdef HAVE_NETMAP + int ret; + char *live_dev = NULL; + + RunModeInitialize(); + TimeModeSetLive(); + + (void)ConfGet("netmap.live-interface", &live_dev); + + ret = RunModeSetLiveCaptureWorkers( + ParseNetmapConfig, + NetmapConfigGeThreadsCount, + "ReceiveNetmap", + "DecodeNetmap", thread_name_workers, + live_dev); + if (ret != 0) { + SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); + exit(EXIT_FAILURE); + } + + SCLogDebug("RunModeIdsNetmapWorkers initialised"); + +#endif /* HAVE_NETMAP */ + SCReturnInt(0); +} + +/** +* @} +*/ diff --git a/src/runmode-netmap.h b/src/runmode-netmap.h new file mode 100644 index 000000000000..988c349ab5a2 --- /dev/null +++ b/src/runmode-netmap.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file +* +* \author Aleksey Katargin +*/ + +#ifndef __RUNMODE_NETMAP_H__ +#define __RUNMODE_NETMAP_H__ + +int RunModeIdsNetmapSingle(void); +int RunModeIdsNetmapAutoFp(void); +int RunModeIdsNetmapWorkers(void); +void RunModeIdsNetmapRegister(void); +const char *RunModeNetmapGetDefaultMode(void); +int NetmapRunModeIsIPS(); + +#endif /* __RUNMODE_NETMAP_H__ */ diff --git a/src/runmode-nflog.c b/src/runmode-nflog.c index 17725622b5e8..f312ad642038 100644 --- a/src/runmode-nflog.c +++ b/src/runmode-nflog.c @@ -169,7 +169,7 @@ int NflogConfigGeThreadsCount(void *conf) return 1; } -int RunModeIdsNflogAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsNflogAutoFp(void) { SCEnter(); @@ -180,12 +180,11 @@ int RunModeIdsNflogAutoFp(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetLive(); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParseNflogConfig, + ret = RunModeSetLiveCaptureAutoFp(ParseNflogConfig, NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", - "RecvNFLOG", + thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -198,7 +197,7 @@ int RunModeIdsNflogAutoFp(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsNflogSingle(DetectEngineCtx *de_ctx) +int RunModeIdsNflogSingle(void) { SCEnter(); @@ -209,12 +208,11 @@ int RunModeIdsNflogSingle(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetLive(); - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParseNflogConfig, + ret = RunModeSetLiveCaptureSingle(ParseNflogConfig, NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", - "RecvNFLOG", + thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); @@ -227,7 +225,7 @@ int RunModeIdsNflogSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } -int RunModeIdsNflogWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsNflogWorkers(void) { SCEnter(); @@ -238,12 +236,11 @@ int RunModeIdsNflogWorkers(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetLive(); - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParseNflogConfig, + ret = RunModeSetLiveCaptureWorkers(ParseNflogConfig, NflogConfigGeThreadsCount, "ReceiveNFLOG", "DecodeNFLOG", - "RecvNFLOG", + thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); diff --git a/src/runmode-nflog.h b/src/runmode-nflog.h index 2dd4e7a6358f..9c70c69397de 100644 --- a/src/runmode-nflog.h +++ b/src/runmode-nflog.h @@ -23,9 +23,9 @@ #ifndef __RUNMODE_NFLOG_H__ #define __RUNMODE_NFLOG_H__ -int RunModeIdsNflogAutoFp(DetectEngineCtx *); -int RunModeIdsNflogSingle(DetectEngineCtx *); -int RunModeIdsNflogWorkers(DetectEngineCtx *); +int RunModeIdsNflogAutoFp(void); +int RunModeIdsNflogSingle(void); +int RunModeIdsNflogWorkers(void); void RunModeIdsNflogRegister(void); const char *RunModeIdsNflogGetDefaultMode(void); diff --git a/src/runmode-nfq.c b/src/runmode-nfq.c index 4f8fe808aa3f..67fa5bcbe969 100644 --- a/src/runmode-nfq.c +++ b/src/runmode-nfq.c @@ -30,14 +30,7 @@ #include "conf.h" #include "runmodes.h" #include "runmode-nfq.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -56,10 +49,6 @@ const char *RunModeIpsNFQGetDefaultMode(void) void RunModeIpsNFQRegister(void) { default_mode = "autofp"; - RunModeRegisterNewRunMode(RUNMODE_NFQ, "auto", - "Multi threaded NFQ IPS mode", - RunModeIpsNFQAuto); - RunModeRegisterNewRunMode(RUNMODE_NFQ, "autofp", "Multi threaded NFQ IPS mode with respect to flow", RunModeIpsNFQAutoFp); @@ -70,48 +59,7 @@ void RunModeIpsNFQRegister(void) return; } -/** - * \brief RunModeIpsNFQAuto set up the following thread packet handlers: - * - Receive thread (from NFQ) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Veredict thread (NFQ) - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIpsNFQAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - int ret = 0; -#ifdef NFQ - - RunModeInitialize(); - - TimeModeSetLive(); - - LiveDeviceHasNoStats(); - - ret = RunModeSetIPSAuto(de_ctx, - NFQGetThread, - "ReceiveNFQ", - "VerdictNFQ", - "DecodeNFQ"); -#endif /* NFQ */ - return ret; -} - - -int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) +int RunModeIpsNFQAutoFp(void) { SCEnter(); int ret = 0; @@ -123,8 +71,7 @@ int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSAutoFp(de_ctx, - NFQGetThread, + ret = RunModeSetIPSAutoFp(NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); @@ -132,7 +79,7 @@ int RunModeIpsNFQAutoFp(DetectEngineCtx *de_ctx) return ret; } -int RunModeIpsNFQWorker(DetectEngineCtx *de_ctx) +int RunModeIpsNFQWorker(void) { SCEnter(); int ret = 0; @@ -144,8 +91,7 @@ int RunModeIpsNFQWorker(DetectEngineCtx *de_ctx) LiveDeviceHasNoStats(); - ret = RunModeSetIPSWorker(de_ctx, - NFQGetThread, + ret = RunModeSetIPSWorker(NFQGetThread, "ReceiveNFQ", "VerdictNFQ", "DecodeNFQ"); diff --git a/src/runmode-nfq.h b/src/runmode-nfq.h index 677fff682bb4..6ad880146639 100644 --- a/src/runmode-nfq.h +++ b/src/runmode-nfq.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_NFQ_H__ #define __RUNMODE_NFQ_H__ -int RunModeIpsNFQAuto(DetectEngineCtx *); -int RunModeIpsNFQAutoFp(DetectEngineCtx *); -int RunModeIpsNFQWorker(DetectEngineCtx *); +int RunModeIpsNFQAutoFp(void); +int RunModeIpsNFQWorker(void); void RunModeIpsNFQRegister(void); const char *RunModeIpsNFQGetDefaultMode(void); diff --git a/src/runmode-pcap-file.c b/src/runmode-pcap-file.c index ffc3d3ea0779..6bf44ae7d55b 100644 --- a/src/runmode-pcap-file.c +++ b/src/runmode-pcap-file.c @@ -20,15 +20,10 @@ #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "detect-engine-mpm.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" +#include "source-pcap-file.h" #include "util-debug.h" #include "util-time.h" @@ -49,9 +44,6 @@ void RunModeFilePcapRegister(void) RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "single", "Single threaded pcap file mode", RunModeFilePcapSingle); - RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "auto", - "Multi threaded pcap file mode", - RunModeFilePcapAuto); default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PCAP_FILE, "autofp", "Multi threaded pcap file mode. Packets from " @@ -67,9 +59,11 @@ void RunModeFilePcapRegister(void) /** * \brief Single thread version of the Pcap file processing. */ -int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) +int RunModeFilePcapSingle(void) { char *file = NULL; + char tname[TM_THREAD_NAME_MAX]; + if (ConfGet("pcap-file.file", &file) == 0) { SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); exit(EXIT_FAILURE); @@ -78,8 +72,12 @@ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) RunModeInitialize(); TimeModeSetOffline(); + PcapFileGlobalInit(); + + snprintf(tname, sizeof(tname), "%s#01", thread_name_single); + /* create the threads */ - ThreadVars *tv = TmThreadCreatePacketHandler("PcapFile", + ThreadVars *tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -102,191 +100,31 @@ int RunModeFilePcapSingle(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); - } - - SetupOutputs(tv); - - TmThreadSetCPU(tv, DETECT_CPU_SET); + TmThreadSetCPU(tv, WORKER_CPU_SET); +#ifndef AFLFUZZ_PCAP_RUNMODE if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); } - - return 0; -} - -/* - * \brief RunModeFilePcapAuto set up the following thread packet handlers: - * - Receive thread (from pcap file) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeFilePcapAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); - char tname[TM_THREAD_NAME_MAX]; - uint16_t cpu = 0; - TmModule *tm_module; - RunModeInitialize(); - - if (de_ctx == NULL) { - SCLogError(SC_ERR_RUNMODE, "can't mix runmode 'auto' and disabled detect"); - return -1; - } - - /* Available cpus */ - uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - - char *file = NULL; - if (ConfGet("pcap-file.file", &file) == 0) { - SCLogError(SC_ERR_RUNMODE, "Failed retrieving pcap-file from Conf"); - exit(EXIT_FAILURE); - } - SCLogDebug("file %s", file); - - TimeModeSetOffline(); - - /* create the threads */ - ThreadVars *tv_receivepcap = - TmThreadCreatePacketHandler("ReceivePcapFile", - "packetpool", "packetpool", - "detect-queue1", "simple", - "pktacqloop"); - if (tv_receivepcap == NULL) { - SCLogError(SC_ERR_FATAL, "threading setup failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("ReceivePcapFile"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for ReceivePcap"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivepcap, tm_module, file); - - tm_module = TmModuleGetByName("DecodePcapFile"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName DecodePcap failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivepcap, tm_module, NULL); - - tm_module = TmModuleGetByName("StreamTcp"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivepcap, tm_module, (void *)de_ctx); - - TmThreadSetCPU(tv_receivepcap, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - /* start with cpu 1 so that if we're creating an odd number of detect - * threads we're not creating the most on CPU0. */ - if (ncpus > 0) - cpu = 1; - - /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); - if (thread_max == 0) - thread_max = ncpus * threading_detect_ratio; - if (thread_max < 1) - thread_max = 1; - - int thread; - for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, - "detect-queue1", "simple", - "alert-queue1", "simple", - "1slot"); - if (tv_detect_ncpu == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - if ((cpu + 1) == ncpus) - cpu = 0; - else - cpu++; - } - - ThreadVars *tv_outputs = - TmThreadCreatePacketHandler("Outputs", - "alert-queue1", "simple", - "packetpool", "packetpool", - "varslot"); - if (tv_outputs == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); - exit(EXIT_FAILURE); - } - - SetupOutputs(tv_outputs); - - TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); - - if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); +#else + /* in afl mode we don't spawn a new thread, but run the pipeline + * in the main thread */ + tv->tm_func(tv); + int afl_runmode_exit_immediately = 0; + (void)ConfGetBool("afl.exit_after_pcap", &afl_runmode_exit_immediately); + if (afl_runmode_exit_immediately) { + SCLogNotice("exit because of afl-runmode-exit-after-pcap commandline option"); + exit(EXIT_SUCCESS); } +#endif return 0; } @@ -303,12 +141,10 @@ int RunModeFilePcapAuto(DetectEngineCtx *de_ctx) * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * - * \param de_ctx Pointer to the Detection Engine - * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ -int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) +int RunModeFilePcapAutoFp(void) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -328,6 +164,8 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) TimeModeSetOffline(); + PcapFileGlobalInit(); + /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); @@ -337,7 +175,7 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) cpu = 1; /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; if (thread_max < 1) @@ -349,9 +187,11 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } + snprintf(tname, sizeof(tname), "%s#01", thread_name_autofp); + /* create the threads */ ThreadVars *tv_receivepcap = - TmThreadCreatePacketHandler("ReceivePcapFile", + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); @@ -383,20 +223,14 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "%s#%02u", thread_name_workers, thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to strdup thread name"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity to cpu %u", thread_name, cpu); + SCLogDebug("Assigning %s affinity to cpu %u", tname, cpu); ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "packetpool", "packetpool", "varslot"); @@ -404,33 +238,17 @@ int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx) SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - tm_module = TmModuleGetByName("StreamTcp"); + + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, (void *)de_ctx); - } - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - /* add outputs as well */ - SetupOutputs(tv_detect_ncpu); + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); diff --git a/src/runmode-pcap-file.h b/src/runmode-pcap-file.h index 5dbd3a9c2631..52cab02228f0 100644 --- a/src/runmode-pcap-file.h +++ b/src/runmode-pcap-file.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_PCAP_FILE_H__ #define __RUNMODE_PCAP_FILE_H__ -int RunModeFilePcapSingle(DetectEngineCtx *); -int RunModeFilePcapAuto(DetectEngineCtx *); -int RunModeFilePcapAutoFp(DetectEngineCtx *de_ctx); +int RunModeFilePcapSingle(void); +int RunModeFilePcapAutoFp(void); void RunModeFilePcapRegister(void); const char *RunModeFilePcapGetDefaultMode(void); diff --git a/src/runmode-pcap.c b/src/runmode-pcap.c index 1ea1ba5976a6..bcd8358ece6a 100644 --- a/src/runmode-pcap.c +++ b/src/runmode-pcap.c @@ -22,13 +22,6 @@ #include "runmode-pcap.h" #include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "detect-engine-mpm.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -46,16 +39,13 @@ const char *RunModeIdsGetDefaultMode(void) return default_mode; } -int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx); +int RunModeIdsPcapWorkers(void); void RunModeIdsPcapRegister(void) { RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "single", "Single threaded pcap live mode", RunModeIdsPcapSingle); - RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "auto", - "Multi threaded pcap live mode", - RunModeIdsPcapAuto); default_mode = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "autofp", "Multi threaded pcap live mode. Packets from " @@ -131,9 +121,9 @@ void *ParsePcapConfig(const char *iface) return aconf; } - if_root = ConfNodeLookupKeyValue(pcap_node, "interface", iface); + if_root = ConfFindDeviceConfig(pcap_node, iface); - if_default = ConfNodeLookupKeyValue(pcap_node, "interface", "default"); + if_default = ConfFindDeviceConfig(pcap_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find pcap config for " @@ -201,9 +191,9 @@ void *ParsePcapConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); @@ -237,7 +227,7 @@ int PcapConfigGeThreadsCount(void *conf) /** * \brief Single thread version of the Pcap live processing. */ -int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) +int RunModeIdsPcapSingle(void) { int ret; char *live_dev = NULL; @@ -249,11 +239,10 @@ int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) (void)ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureSingle(de_ctx, - ParsePcapConfig, + ret = RunModeSetLiveCaptureSingle(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", - "DecodePcap", "PcapLive", + "DecodePcap", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -265,54 +254,6 @@ int RunModeIdsPcapSingle(DetectEngineCtx *de_ctx) SCReturnInt(0); } - -/** - * \brief RunModeIdsPcapAuto set up the following thread packet handlers: - * - Receive thread (from iface pcap) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx) -{ - /* tname = Detect + cpuid, this is 11bytes length as max */ - char *live_dev = NULL; - int ret; - - SCEnter(); - - RunModeInitialize(); - TimeModeSetLive(); - - (void) ConfGet("pcap.single-pcap-dev", &live_dev); - - ret = RunModeSetLiveCaptureAuto(de_ctx, - ParsePcapConfig, - PcapConfigGeThreadsCount, - "ReceivePcap", - "DecodePcap", "RecvPcap", - live_dev); - if (ret != 0) { - SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); - exit(EXIT_FAILURE); - } - - SCLogInfo("RunModeIdsPcapAuto initialised"); - - SCReturnInt(0); -} - /** * \brief RunModIdsPcapAutoFp set up the following thread packet handlers: * - Receive thread (from pcap device) @@ -325,12 +266,10 @@ int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx) * By default the threads will use the first cpu available * except the Detection threads if we have more than one cpu. * - * \param de_ctx Pointer to the Detection Engine - * * \retval 0 If all goes well. (If any problem is detected the engine will * exit()). */ -int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsPcapAutoFp(void) { int ret; char *live_dev = NULL; @@ -341,11 +280,10 @@ int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) (void) ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - ParsePcapConfig, + ret = RunModeSetLiveCaptureAutoFp(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", - "DecodePcap", "RxPcap", + "DecodePcap", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -363,7 +301,7 @@ int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx) * Start N threads with each thread doing all the work. * */ -int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsPcapWorkers(void) { int ret; char *live_dev = NULL; @@ -374,11 +312,10 @@ int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx) (void) ConfGet("pcap.single-pcap-dev", &live_dev); - ret = RunModeSetLiveCaptureWorkers(de_ctx, - ParsePcapConfig, + ret = RunModeSetLiveCaptureWorkers(ParsePcapConfig, PcapConfigGeThreadsCount, "ReceivePcap", - "DecodePcap", "RxPcap", + "DecodePcap", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); diff --git a/src/runmode-pcap.h b/src/runmode-pcap.h index 9e88c6d90f8b..b68c6ddcfc7f 100644 --- a/src/runmode-pcap.h +++ b/src/runmode-pcap.h @@ -23,9 +23,8 @@ #ifndef __RUNMODE_PCAP_H__ #define __RUNMODE_PCAP_H__ -int RunModeIdsPcapAuto(DetectEngineCtx *); -int RunModeIdsPcapSingle(DetectEngineCtx *); -int RunModeIdsPcapAutoFp(DetectEngineCtx *de_ctx); +int RunModeIdsPcapSingle(void); +int RunModeIdsPcapAutoFp(void); void RunModeIdsPcapRegister(void); const char *RunModeIdsGetDefaultMode(void); diff --git a/src/runmode-pfring.c b/src/runmode-pfring.c index 287594642876..5332252570f5 100644 --- a/src/runmode-pfring.c +++ b/src/runmode-pfring.c @@ -21,14 +21,7 @@ #include "runmodes.h" #include "runmode-pfring.h" #include "source-pfring.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -54,9 +47,6 @@ const char *RunModeIdsPfringGetDefaultMode(void) void RunModeIdsPfringRegister(void) { - RunModeRegisterNewRunMode(RUNMODE_PFRING, "auto", - "Multi threaded pfring mode", - RunModeIdsPfringAuto); default_mode_autofp = "autofp"; RunModeRegisterNewRunMode(RUNMODE_PFRING, "autofp", "Multi threaded pfring mode. Packets from " @@ -119,6 +109,7 @@ void *OldParsePfringConfig(const char *iface) } strlcpy(pfconf->iface, iface, sizeof(pfconf->iface)); + pfconf->flags = 0; pfconf->threads = 1; pfconf->cluster_id = 1; #ifdef HAVE_PFRING @@ -153,6 +144,7 @@ void *OldParsePfringConfig(const char *iface) SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); + pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } @@ -238,13 +230,11 @@ void *ParsePfringConfig(const char *iface) return pfconf; } - if_root = ConfNodeLookupKeyValue(pf_ring_node, "interface", iface); + if_root = ConfFindDeviceConfig(pf_ring_node, iface); - if_default = ConfNodeLookupKeyValue(pf_ring_node, "interface", "default"); + if_default = ConfFindDeviceConfig(pf_ring_node, "default"); if (if_root == NULL && if_default == NULL) { - /* Switch to old mode */ - if_root = pf_ring_node; SCLogInfo("Unable to find pfring config for " "interface %s, using default value or 1.0 " "configuration system. ", @@ -275,6 +265,7 @@ void *ParsePfringConfig(const char *iface) /* command line value has precedence */ if (ConfGet("pfring.cluster-id", &tmpclusterid) == 1) { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); + pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use command-line provided cluster-id %" PRId32, pfconf->cluster_id); } else { @@ -290,6 +281,7 @@ void *ParsePfringConfig(const char *iface) "Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); + pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } } @@ -362,9 +354,9 @@ void *ParsePfringConfig(const char *iface) if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpctype, "yes") == 0) { + } else if (ConfValIsTrue(tmpctype)) { pfconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpctype, "no") == 0) { + } else if (ConfValIsFalse(tmpctype)) { pfconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "rx-only") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_RXONLY; @@ -421,56 +413,7 @@ static int GetDevAndParser(char **live_dev, ConfigIfaceParserFunc *parser) } #endif -/** - * \brief RunModeIdsPfringAuto set up the following thread packet handlers: - * - Receive thread (from pfring) - * - Decode thread - * - Stream thread - * - Detect: If we have only 1 cpu, it will setup one Detect thread - * If we have more than one, it will setup num_cpus - 1 - * starting from the second cpu available. - * - Respond/Reject thread - * - Outputs thread - * By default the threads will use the first cpu available - * except the Detection threads if we have more than one cpu. - * - * \param de_ctx Pointer to the Detection Engine. - * - * \retval 0 If all goes well. (If any problem is detected the engine will - * exit()). - */ -int RunModeIdsPfringAuto(DetectEngineCtx *de_ctx) -{ - SCEnter(); -/* We include only if pfring is enabled */ -#ifdef HAVE_PFRING - int ret; - char *live_dev = NULL; - ConfigIfaceParserFunc tparser; - - RunModeInitialize(); - - TimeModeSetLive(); - - ret = GetDevAndParser(&live_dev, &tparser); - if (ret != 0) { - SCLogError(SC_ERR_MISSING_CONFIG_PARAM, - "Unable to get parser and interface params"); - exit(EXIT_FAILURE); - } - - ret = RunModeSetLiveCaptureAuto(de_ctx, tparser, PfringConfigGeThreadsCount, - "ReceivePfring", "DecodePfring", - "RxPFR", live_dev); - if (ret != 0) { - SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); - exit(EXIT_FAILURE); - } -#endif /* HAVE_PFRING */ - return 0; -} - -int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) +int RunModeIdsPfringAutoFp(void) { SCEnter(); @@ -491,11 +434,10 @@ int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureAutoFp(de_ctx, - tparser, + ret = RunModeSetLiveCaptureAutoFp(tparser, PfringConfigGeThreadsCount, "ReceivePfring", - "DecodePfring", "RxPFR", + "DecodePfring", thread_name_autofp, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -508,7 +450,7 @@ int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx) return 0; } -int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) +int RunModeIdsPfringSingle(void) { SCEnter(); @@ -529,11 +471,10 @@ int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureSingle(de_ctx, - tparser, + ret = RunModeSetLiveCaptureSingle(tparser, PfringConfigGeThreadsCount, "ReceivePfring", - "DecodePfring", "RxPFR", + "DecodePfring", thread_name_single, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); @@ -546,7 +487,7 @@ int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx) return 0; } -int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx) +int RunModeIdsPfringWorkers(void) { SCEnter(); @@ -567,11 +508,10 @@ int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - ret = RunModeSetLiveCaptureWorkers(de_ctx, - tparser, + ret = RunModeSetLiveCaptureWorkers(tparser, PfringConfigGeThreadsCount, "ReceivePfring", - "DecodePfring", "RxPFR", + "DecodePfring", thread_name_workers, live_dev); if (ret != 0) { SCLogError(SC_ERR_RUNMODE, "Runmode start failed"); diff --git a/src/runmode-pfring.h b/src/runmode-pfring.h index 9ba7d5c93f04..316c82f74af6 100644 --- a/src/runmode-pfring.h +++ b/src/runmode-pfring.h @@ -25,10 +25,9 @@ #include "suricata-common.h" -int RunModeIdsPfringAuto(DetectEngineCtx *); -int RunModeIdsPfringAutoFp(DetectEngineCtx *de_ctx); -int RunModeIdsPfringSingle(DetectEngineCtx *de_ctx); -int RunModeIdsPfringWorkers(DetectEngineCtx *de_ctx); +int RunModeIdsPfringAutoFp(void); +int RunModeIdsPfringSingle(void); +int RunModeIdsPfringWorkers(void); void RunModeIdsPfringRegister(void); const char *RunModeIdsPfringGetDefaultMode(void); diff --git a/src/runmode-tile.c b/src/runmode-tile.c index 9e12fd9e8512..4e94e24dab4e 100644 --- a/src/runmode-tile.c +++ b/src/runmode-tile.c @@ -29,14 +29,10 @@ #include "conf.h" #include "runmodes.h" #include "runmode-tile.h" -#include "log-httplog.h" #include "output.h" #include "source-mpipe.h" -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" +#include "detect-engine.h" #include "util-debug.h" #include "util-time.h" @@ -130,7 +126,8 @@ void *ParseMpipeConfig(const char *iface) aconf->out_iface); aconf->copy_mode = MPIPE_COPY_MODE_TAP; } else { - SCLogInfo("Invalid mode (no in tap, ips)"); + SCLogError(SC_ERR_RUNMODE, "Invalid mode (expected tap or ips)"); + exit(EXIT_FAILURE); } } return aconf; @@ -139,13 +136,12 @@ void *ParseMpipeConfig(const char *iface) /** * \brief RunModeTileMpipeWorkers set up to process all modules in each thread. * - * \param de_ctx pointer to the Detection Engine * \param iface pointer to the name of the interface from which we will * fetch the packets * \retval 0 if all goes well. (If any problem is detected the engine will * exit()) */ -int RunModeTileMpipeWorkers(DetectEngineCtx *de_ctx) +int RunModeTileMpipeWorkers(void) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; @@ -217,16 +213,11 @@ int RunModeTileMpipeWorkers(DetectEngineCtx *de_ctx) exit(EXIT_FAILURE); } - snprintf(tname, sizeof(tname), "Worker%d", pipe+1); - thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - printf("ERROR: SCStrdup failed for ReceiveMpipe\n"); - exit(EXIT_FAILURE); - } + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, pipe+1); /* create the threads */ ThreadVars *tv_worker = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -254,22 +245,13 @@ int RunModeTileMpipeWorkers(DetectEngineCtx *de_ctx) } TmSlotSetFuncAppend(tv_worker, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName StreamTcp failed\n"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_worker, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName Detect failed\n"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_worker, tm_module, (void *)de_ctx); - } - tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { printf("ERROR: TmModuleGetByName for RespondReject failed\n"); diff --git a/src/runmode-tile.h b/src/runmode-tile.h index 8e0af793a99b..ec6c9e5042dd 100644 --- a/src/runmode-tile.h +++ b/src/runmode-tile.h @@ -34,7 +34,7 @@ void RunModeTileMpipeRegister(void); extern int tile_num_pipelines; -int RunModeTileMpipeWorkers(DetectEngineCtx *); +int RunModeTileMpipeWorkers(void); void *ParseMpipeConfig(const char *iface); diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index 479e1323d479..6d1632dc4e75 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -38,7 +38,6 @@ #include "detect-engine-uri.h" #include "detect-engine-hcbd.h" #include "detect-engine-hsbd.h" -#include "detect-engine-hhd.h" #include "detect-engine-hrhd.h" #include "detect-engine-hmd.h" #include "detect-engine-hcd.h" @@ -50,6 +49,8 @@ #include "detect-engine-hrhhd.h" #include "detect-engine-state.h" #include "detect-engine-tag.h" +#include "detect-engine-modbus.h" +#include "detect-engine-filedata-smtp.h" #include "detect-fast-pattern.h" #include "flow.h" #include "flow-timeout.h" @@ -59,8 +60,13 @@ #include "pkt-var.h" #include "host.h" +#include "host-bit.h" +#include "ippair.h" +#include "ippair-bit.h" #include "unix-manager.h" +#include "stream-tcp.h" + #include "app-layer-detect-proto.h" #include "app-layer-parser.h" #include "app-layer.h" @@ -103,7 +109,7 @@ #include "util-memrchr.h" #include "util-mpm-ac.h" -#include "detect-engine-mpm.h" +#include "util-mpm-hs.h" #include "util-decode-asn1.h" @@ -113,74 +119,20 @@ #include "defrag.h" #include "detect-engine-siggroup.h" +#include "util-streaming-buffer.h" +#include "util-lua.h" + #endif /* UNITTESTS */ void RegisterAllModules(); void TmqhSetup (void); -/** - * Run or list unittests - * - * \param list_unittests If set to 1, list unittests. Run them if set to 0. - * \param regex_arg A regular expression to select unittests to run - * - * This function is terminal and will call exit after being called. - */ - -void RunUnittests(int list_unittests, char *regex_arg) -{ #ifdef UNITTESTS - /* Initializations for global vars, queues, etc (memsets, mutex init..) */ - GlobalInits(); - TimeInit(); - SupportFastPatternForSigMatchTypes(); - - default_packet_size = DEFAULT_PACKET_SIZE; -#ifdef __SC_CUDA_SUPPORT__ - /* Init the CUDA environment */ - SCCudaInitCudaEnvironment(); - CudaBufferInit(); -#endif - /* load the pattern matchers */ - MpmTableSetup(); -#ifdef __SC_CUDA_SUPPORT__ - MpmCudaEnvironmentSetup(); -#endif - - AppLayerSetup(); - - /* hardcoded initialization code */ - SigTableSetup(); /* load the rule keywords */ - TmqhSetup(); - - StorageInit(); - CIDRInit(); - SigParsePrepare(); - -#ifdef DBG_MEM_ALLOC - SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); -#endif - SCReputationInitCtx(); - SCProtoNameInit(); - - TagInitCtx(); - - RegisterAllModules(); - - DetectEngineRegisterAppInspectionEngines(); - - StorageFinalize(); - /* test and initialize the unittesting subsystem */ - if(regex_arg == NULL){ - regex_arg = ".*"; - UtRunSelftest(regex_arg); /* inits and cleans up again */ - } - - AppLayerHtpEnableRequestBodyCallback(); - AppLayerHtpNeedFileInspection(); - - UtInitialize(); +static void RegisterUnittests(void) +{ UTHRegisterTests(); + StreamTcpRegisterTests(); + SigRegisterTests(); SCReputationRegisterTests(); TmModuleRegisterTests(); SigTableRegisterTests(); @@ -192,10 +144,11 @@ void RunUnittests(int list_unittests, char *regex_arg) ByteRegisterTests(); MpmRegisterTests(); FlowBitRegisterTests(); - SCPerfRegisterTests(); + HostBitRegisterTests(); + IPPairBitRegisterTests(); + StatsRegisterTests(); DecodePPPRegisterTests(); DecodeVLANRegisterTests(); - HTPParserRegisterTests(); DecodeRawRegisterTests(); DecodePPPOERegisterTests(); DecodeICMPV4RegisterTests(); @@ -212,6 +165,8 @@ void RunUnittests(int list_unittests, char *regex_arg) ConfYamlRegisterTests(); TmqhFlowRegisterTests(); FlowRegisterTests(); + HostRegisterUnittests(); + IPPairRegisterUnittests(); SCSigRegisterSignatureOrderingTests(); SCRadixRegisterTests(); DefragRegisterTests(); @@ -239,7 +194,6 @@ void RunUnittests(int list_unittests, char *regex_arg) MemcmpRegisterTests(); DetectEngineHttpClientBodyRegisterTests(); DetectEngineHttpServerBodyRegisterTests(); - DetectEngineHttpHeaderRegisterTests(); DetectEngineHttpRawHeaderRegisterTests(); DetectEngineHttpMethodRegisterTests(); DetectEngineHttpCookieRegisterTests(); @@ -249,7 +203,9 @@ void RunUnittests(int list_unittests, char *regex_arg) DetectEngineHttpUARegisterTests(); DetectEngineHttpHHRegisterTests(); DetectEngineHttpHRHRegisterTests(); + DetectEngineInspectModbusRegisterTests(); DetectEngineRegisterTests(); + DetectEngineSMTPFiledataRegisterTests(); SCLogRegisterTests(); MagicRegisterTests(); UtilMiscRegisterTests(); @@ -262,11 +218,92 @@ void RunUnittests(int list_unittests, char *regex_arg) CudaBufferRegisterUnittests(); #endif AppLayerUnittestsRegister(); + MimeDecRegisterTests(); + StreamingBufferRegisterTests(); +} +#endif + +/** + * Run or list unittests + * + * \param list_unittests If set to 1, list unittests. Run them if set to 0. + * \param regex_arg A regular expression to select unittests to run + * + * This function is terminal and will call exit after being called. + */ + +void RunUnittests(int list_unittests, char *regex_arg) +{ +#ifdef UNITTESTS + /* Initializations for global vars, queues, etc (memsets, mutex init..) */ + GlobalsInitPreConfig(); + +#ifdef HAVE_LUAJIT + if (LuajitSetupStatesPool() != 0) { + exit(EXIT_FAILURE); + } +#endif + + default_packet_size = DEFAULT_PACKET_SIZE; + /* load the pattern matchers */ + MpmTableSetup(); +#ifdef __SC_CUDA_SUPPORT__ + MpmCudaEnvironmentSetup(); +#endif + SpmTableSetup(); + + AppLayerSetup(); + + /* hardcoded initialization code */ + SigTableSetup(); /* load the rule keywords */ + TmqhSetup(); + + StorageInit(); + CIDRInit(); + SigParsePrepare(); + +#ifdef DBG_MEM_ALLOC + SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); +#endif + SCReputationInitCtx(); + SCProtoNameInit(); + + TagInitCtx(); + SCReferenceConfInit(); + SCClassConfInit(); + + UtInitialize(); + + RegisterAllModules(); + + HostBitInitCtx(); + + StorageFinalize(); + /* test and initialize the unittesting subsystem */ + if(regex_arg == NULL){ + regex_arg = ".*"; + UtRunSelftest(regex_arg); /* inits and cleans up again */ + } + + AppLayerHtpEnableRequestBodyCallback(); + AppLayerHtpNeedFileInspection(); + + RegisterUnittests(); + if (list_unittests) { UtListTests(regex_arg); } else { + /* global packet pool */ + extern intmax_t max_pending_packets; + max_pending_packets = 128; + PacketPoolInit(); + uint32_t failed = UtRunTests(regex_arg); + PacketPoolDestroy(); UtCleanup(); +#ifdef BUILD_HYPERSCAN + MpmHSGlobalCleanup(); +#endif #ifdef __SC_CUDA_SUPPORT__ if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) MpmCudaBufferDeSetup(); @@ -277,6 +314,9 @@ void RunUnittests(int list_unittests, char *regex_arg) } } +#ifdef HAVE_LUAJIT + LuajitFreeStatesPool(); +#endif #ifdef DBG_MEM_ALLOC SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); #endif diff --git a/src/runmode-unix-socket.c b/src/runmode-unix-socket.c index ec53b3f6fffd..7d9ef8ed2670 100644 --- a/src/runmode-unix-socket.c +++ b/src/runmode-unix-socket.c @@ -20,15 +20,7 @@ #include "conf.h" #include "runmodes.h" #include "runmode-pcap-file.h" -#include "log-httplog.h" #include "output.h" -#include "source-pfring.h" -#include "detect-engine-mpm.h" - -#include "alert-fastlog.h" -#include "alert-prelude.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" #include "util-debug.h" #include "util-time.h" @@ -36,12 +28,20 @@ #include "util-affinity.h" #include "unix-manager.h" +#include "detect-engine.h" + #include "flow-manager.h" #include "flow-timeout.h" #include "stream-tcp.h" -#include "output.h" #include "host.h" #include "defrag.h" +#include "ippair.h" +#include "app-layer.h" +#include "host-bit.h" + +#include "util-profiling.h" + +#include "conf-yaml-loader.h" static const char *default_mode = NULL; @@ -50,11 +50,11 @@ int unix_socket_mode_is_running = 0; typedef struct PcapFiles_ { char *filename; char *output_dir; + int tenant_id; TAILQ_ENTRY(PcapFiles_) next; } PcapFiles; typedef struct PcapCommand_ { - DetectEngineCtx *de_ctx; TAILQ_HEAD(, PcapFiles_) files; int running; char *currentfile; @@ -153,7 +153,8 @@ static void PcapFilesFree(PcapFiles *cfile) * * \retval 0 in case of error, 1 in case of success */ -TmEcode UnixListAddFile(PcapCommand *this, const char *filename, const char *output_dir) +static TmEcode UnixListAddFile(PcapCommand *this, + const char *filename, const char *output_dir, int tenant_id) { PcapFiles *cfile = NULL; if (filename == NULL || this == NULL) @@ -182,6 +183,8 @@ TmEcode UnixListAddFile(PcapCommand *this, const char *filename, const char *out } } + cfile->tenant_id = tenant_id; + TAILQ_INSERT_TAIL(&this->files, cfile, next); return TM_ECODE_OK; } @@ -199,6 +202,7 @@ TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) int ret; const char *filename; const char *output_dir; + int tenant_id = 0; #ifdef OS_WIN32 struct _stat st; #else @@ -244,7 +248,16 @@ TmEcode UnixSocketAddPcapFile(json_t *cmd, json_t* answer, void *data) return TM_ECODE_FAILED; } - ret = UnixListAddFile(this, filename, output_dir); + json_t *targ = json_object_get(cmd, "tenant"); + if (targ != NULL) { + if(!json_is_number(targ)) { + json_object_set_new(answer, "message", json_string("tenant is not a number")); + return TM_ECODE_FAILED; + } + tenant_id = json_number_value(targ); + } + + ret = UnixListAddFile(this, filename, output_dir, tenant_id); switch(ret) { case TM_ECODE_FAILED: json_object_set_new(answer, "message", json_string("Unable to add file to list")); @@ -287,65 +300,57 @@ TmEcode UnixSocketPcapFilesCheck(void *data) } this->currentfile = NULL; - /* handle graceful shutdown of the flow engine, it's helper - * threads and the packet threads */ - FlowKillFlowManagerThread(); - TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM); - FlowForceReassembly(); - TmThreadKillThreadsFamily(TVT_PPT); - TmThreadClearThreadsFamily(TVT_PPT); - FlowKillFlowRecyclerThread(); - RunModeShutDown(); - - /* kill remaining mgt threads */ - TmThreadKillThreadsFamily(TVT_MGMT); - TmThreadClearThreadsFamily(TVT_MGMT); - SCPerfReleaseResources(); - - /* mgt and ppt threads killed, we can run non thread-safe - * shutdown functions */ - FlowShutdown(); - HostCleanup(); - StreamTcpFreeConfig(STREAM_VERBOSE); - DefragDestroy(); - TmqResetQueues(); - } - if (!TAILQ_EMPTY(&this->files)) { - PcapFiles *cfile = TAILQ_FIRST(&this->files); - TAILQ_REMOVE(&this->files, cfile, next); - SCLogInfo("Starting run for '%s'", cfile->filename); - unix_manager_file_task_running = 1; - this->running = 1; - if (ConfSet("pcap-file.file", cfile->filename) != 1) { - SCLogInfo("Can not set working file to '%s'", cfile->filename); + PostRunDeinit(RUNMODE_PCAP_FILE, NULL /* no ts */); + } + if (TAILQ_EMPTY(&this->files)) { + // nothing to do + return TM_ECODE_OK; + } + + PcapFiles *cfile = TAILQ_FIRST(&this->files); + TAILQ_REMOVE(&this->files, cfile, next); + SCLogInfo("Starting run for '%s'", cfile->filename); + unix_manager_file_task_running = 1; + this->running = 1; + if (ConfSet("pcap-file.file", cfile->filename) != 1) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set working file to '%s'", cfile->filename); + PcapFilesFree(cfile); + return TM_ECODE_FAILED; + } + if (cfile->output_dir) { + if (ConfSet("default-log-dir", cfile->output_dir) != 1) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set output dir to '%s'", cfile->output_dir); PcapFilesFree(cfile); return TM_ECODE_FAILED; } - if (cfile->output_dir) { - if (ConfSet("default-log-dir", cfile->output_dir) != 1) { - SCLogInfo("Can not set output dir to '%s'", cfile->output_dir); - PcapFilesFree(cfile); - return TM_ECODE_FAILED; - } - } - this->currentfile = SCStrdup(cfile->filename); - if (unlikely(this->currentfile == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed file name allocation"); + } + if (cfile->tenant_id > 0) { + char tstr[16]; + snprintf(tstr, sizeof(tstr), "%d", cfile->tenant_id); + if (ConfSet("pcap-file.tenant-id", tstr) != 1) { + SCLogError(SC_ERR_INVALID_ARGUMENTS, + "Can not set working tenant-id to '%s'", tstr); + PcapFilesFree(cfile); return TM_ECODE_FAILED; } - PcapFilesFree(cfile); - SCPerfInitCounterApi(); - DefragInit(); - FlowInitConfig(FLOW_QUIET); - StreamTcpInitConfig(STREAM_VERBOSE); - RunModeInitializeOutputs(); - RunModeDispatch(RUNMODE_PCAP_FILE, NULL, this->de_ctx); - FlowManagerThreadSpawn(); - FlowRecyclerThreadSpawn(); - SCPerfSpawnThreads(); - /* Un-pause all the paused threads */ - TmThreadContinueThreads(); + } else { + SCLogInfo("pcap-file.tenant-id not set"); } + this->currentfile = SCStrdup(cfile->filename); + if (unlikely(this->currentfile == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed file name allocation"); + return TM_ECODE_FAILED; + } + PcapFilesFree(cfile); + + PreRunInit(RUNMODE_PCAP_FILE); + PreRunPostPrivsDropInit(RUNMODE_PCAP_FILE); + RunModeDispatch(RUNMODE_PCAP_FILE, NULL); + + /* Un-pause all the paused threads */ + TmThreadContinueThreads(); return TM_ECODE_OK; } #endif @@ -378,10 +383,634 @@ void UnixSocketPcapFile(TmEcode tm) #endif } +#ifdef BUILD_UNIX_SOCKET +/** + * \brief Command to add a tenant handler + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data) +{ + const char *htype; + json_int_t traffic_id = -1; + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant handler type */ + jarg = json_object_get(cmd, "htype"); + if (!json_is_string(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + htype = json_string_value(jarg); + + SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype); + + /* 3 get optional hargs */ + json_t *hargs = json_object_get(cmd, "hargs"); + if (hargs != NULL) { + if (!json_is_integer(hargs)) { + SCLogInfo("error: hargs not a number"); + json_object_set_new(answer, "message", json_string("hargs not a number")); + return TM_ECODE_FAILED; + } + traffic_id = json_integer_value(hargs); + } + + /* 4 add to system */ + int r = -1; + if (strcmp(htype, "pcap") == 0) { + r = DetectEngineTentantRegisterPcapFile(tenant_id); + } else if (strcmp(htype, "vlan") == 0) { + if (traffic_id < 0) { + json_object_set_new(answer, "message", json_string("vlan requires argument")); + return TM_ECODE_FAILED; + } + if (traffic_id > USHRT_MAX) { + json_object_set_new(answer, "message", json_string("vlan argument out of range")); + return TM_ECODE_FAILED; + } + + SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id); + r = DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)traffic_id); + } + if (r != 0) { + json_object_set_new(answer, "message", json_string("handler setup failure")); + return TM_ECODE_FAILED; + } + + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("handler added")); + return TM_ECODE_OK; +} + +/** + * \brief Command to remove a tenant handler + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data) +{ + const char *htype; + json_int_t traffic_id = -1; + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant handler type */ + jarg = json_object_get(cmd, "htype"); + if (!json_is_string(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + htype = json_string_value(jarg); + + SCLogDebug("add-tenant-handler: %d %s", tenant_id, htype); + + /* 3 get optional hargs */ + json_t *hargs = json_object_get(cmd, "hargs"); + if (hargs != NULL) { + if (!json_is_integer(hargs)) { + SCLogInfo("error: hargs not a number"); + json_object_set_new(answer, "message", json_string("hargs not a number")); + return TM_ECODE_FAILED; + } + traffic_id = json_integer_value(hargs); + } + + /* 4 add to system */ + int r = -1; + if (strcmp(htype, "pcap") == 0) { + r = DetectEngineTentantUnregisterPcapFile(tenant_id); + } else if (strcmp(htype, "vlan") == 0) { + if (traffic_id < 0) { + json_object_set_new(answer, "message", json_string("vlan requires argument")); + return TM_ECODE_FAILED; + } + if (traffic_id > USHRT_MAX) { + json_object_set_new(answer, "message", json_string("vlan argument out of range")); + return TM_ECODE_FAILED; + } + + SCLogInfo("VLAN handler: id %u maps to tenant %u", (uint32_t)traffic_id, tenant_id); + r = DetectEngineTentantUnregisterVlanId(tenant_id, (uint32_t)traffic_id); + } + if (r != 0) { + json_object_set_new(answer, "message", json_string("handler unregister failure")); + return TM_ECODE_FAILED; + } + + /* 5 apply it */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("handler added")); + return TM_ECODE_OK; +} + +/** + * \brief Command to add a tenant + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data) +{ + const char *filename; +#ifdef OS_WIN32 + struct _stat st; +#else + struct stat st; +#endif /* OS_WIN32 */ + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant yaml */ + jarg = json_object_get(cmd, "filename"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + filename = json_string_value(jarg); +#ifdef OS_WIN32 + if(_stat(filename, &st) != 0) { +#else + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + json_object_set_new(answer, "message", json_string("file does not exist")); + return TM_ECODE_FAILED; + } + + SCLogDebug("add-tenant: %d %s", tenant_id, filename); + + /* setup the yaml in this loop so that it's not done by the loader + * threads. ConfYamlLoadFileWithPrefix is not thread safe. */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", filename); + json_object_set_new(answer, "message", json_string("failed to load yaml")); + return TM_ECODE_FAILED; + } + + /* 3 load into the system */ + if (DetectEngineLoadTenantBlocking(tenant_id, filename) != 0) { + json_object_set_new(answer, "message", json_string("adding tenant failed")); + return TM_ECODE_FAILED; + } + + /* 4 apply to the running system */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("adding tenant succeeded")); + return TM_ECODE_OK; +} + +static int reload_cnt = 1; +/** + * \brief Command to reload a tenant + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data) +{ + const char *filename; +#ifdef OS_WIN32 + struct _stat st; +#else + struct stat st; +#endif /* OS_WIN32 */ + + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + /* 2 get tenant yaml */ + jarg = json_object_get(cmd, "filename"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("command is not a string")); + return TM_ECODE_FAILED; + } + filename = json_string_value(jarg); +#ifdef OS_WIN32 + if(_stat(filename, &st) != 0) { +#else + if(stat(filename, &st) != 0) { +#endif /* OS_WIN32 */ + json_object_set_new(answer, "message", json_string("file does not exist")); + return TM_ECODE_FAILED; + } + + SCLogDebug("reload-tenant: %d %s", tenant_id, filename); + + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt); + SCLogInfo("prefix %s", prefix); + + if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) { + json_object_set_new(answer, "message", json_string("failed to load yaml")); + return TM_ECODE_FAILED; + } + + /* 3 load into the system */ + if (DetectEngineReloadTenantBlocking(tenant_id, filename, reload_cnt) != 0) { + json_object_set_new(answer, "message", json_string("reload tenant failed")); + return TM_ECODE_FAILED; + } + + reload_cnt++; + + /* apply to the running system */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + json_object_set_new(answer, "message", json_string("reloading tenant succeeded")); + return TM_ECODE_OK; +} + +/** + * \brief Command to remove a tenant + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * \param data pointer to data defining the context here a PcapCommand:: + */ +TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data) +{ + if (!(DetectEngineMultiTenantEnabled())) { + SCLogInfo("error: multi-tenant support not enabled"); + json_object_set_new(answer, "message", json_string("multi-tenant support not enabled")); + return TM_ECODE_FAILED; + } + + /* 1 get tenant id */ + json_t *jarg = json_object_get(cmd, "id"); + if (!json_is_integer(jarg)) { + SCLogInfo("error: command is not a string"); + json_object_set_new(answer, "message", json_string("id is not an integer")); + return TM_ECODE_FAILED; + } + int tenant_id = json_integer_value(jarg); + + SCLogInfo("remove-tenant: %d TODO", tenant_id); + + /* 2 remove it from the system */ + char prefix[64]; + snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id); + + DetectEngineCtx *de_ctx = DetectEngineGetByTenantId(tenant_id); + if (de_ctx == NULL) { + json_object_set_new(answer, "message", json_string("tenant detect engine not found")); + return TM_ECODE_FAILED; + } + + /* move to free list */ + DetectEngineMoveToFreeList(de_ctx); + DetectEngineDeReference(&de_ctx); + + /* update the threads */ + if (DetectEngineMTApply() < 0) { + json_object_set_new(answer, "message", json_string("couldn't apply settings")); + // TODO cleanup + return TM_ECODE_FAILED; + } + + /* walk free list, freeing the removed de_ctx */ + DetectEnginePruneFreeList(); + + json_object_set_new(answer, "message", json_string("work in progress")); + return TM_ECODE_OK; +} + +/** + * \brief Command to add a hostbit + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + */ +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data_usused) +{ + /* 1 get ip address */ + json_t *jarg = json_object_get(cmd, "ipaddress"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("ipaddress is not an string")); + return TM_ECODE_FAILED; + } + const char *ipaddress = json_string_value(jarg); + + Address a; + struct in_addr in; + memset(&in, 0, sizeof(in)); + if (inet_pton(AF_INET, ipaddress, &in) != 1) { + uint32_t in6[4]; + memset(&in6, 0, sizeof(in6)); + if (inet_pton(AF_INET6, ipaddress, &in) != 1) { + json_object_set_new(answer, "message", json_string("invalid address string")); + return TM_ECODE_FAILED; + } else { + a.family = AF_INET6; + a.addr_data32[0] = in6[0]; + a.addr_data32[1] = in6[1]; + a.addr_data32[2] = in6[2]; + a.addr_data32[3] = in6[3]; + } + } else { + a.family = AF_INET; + a.addr_data32[0] = in.s_addr; + a.addr_data32[1] = 0; + a.addr_data32[2] = 0; + a.addr_data32[3] = 0; + } + + /* 2 get variable name */ + jarg = json_object_get(cmd, "hostbit"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("hostbit is not a string")); + return TM_ECODE_FAILED; + } + const char *hostbit = json_string_value(jarg); + uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT); + if (idx == 0) { + json_object_set_new(answer, "message", json_string("hostbit not found")); + return TM_ECODE_FAILED; + } + + /* 3 get expire */ + jarg = json_object_get(cmd, "expire"); + if (!json_is_integer(jarg)) { + json_object_set_new(answer, "message", json_string("expire is not an integer")); + return TM_ECODE_FAILED; + } + uint32_t expire = json_integer_value(jarg); + + SCLogInfo("add-hostbit: ip %s hostbit %s expire %us", ipaddress, hostbit, expire); + + struct timeval current_time; + TimeGet(¤t_time); + Host *host = HostGetHostFromHash(&a); + if (host) { + HostBitSet(host, idx, current_time.tv_sec + expire); + HostUnlock(host); + + json_object_set_new(answer, "message", json_string("hostbit added")); + return TM_ECODE_OK; + } else { + json_object_set_new(answer, "message", json_string("couldn't create host")); + return TM_ECODE_FAILED; + } +} + +/** + * \brief Command to remove a hostbit + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + */ +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data_unused) +{ + /* 1 get ip address */ + json_t *jarg = json_object_get(cmd, "ipaddress"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("ipaddress is not an string")); + return TM_ECODE_FAILED; + } + const char *ipaddress = json_string_value(jarg); + + Address a; + struct in_addr in; + memset(&in, 0, sizeof(in)); + if (inet_pton(AF_INET, ipaddress, &in) != 1) { + uint32_t in6[4]; + memset(&in6, 0, sizeof(in6)); + if (inet_pton(AF_INET6, ipaddress, &in) != 1) { + json_object_set_new(answer, "message", json_string("invalid address string")); + return TM_ECODE_FAILED; + } else { + a.family = AF_INET6; + a.addr_data32[0] = in6[0]; + a.addr_data32[1] = in6[1]; + a.addr_data32[2] = in6[2]; + a.addr_data32[3] = in6[3]; + } + } else { + a.family = AF_INET; + a.addr_data32[0] = in.s_addr; + a.addr_data32[1] = 0; + a.addr_data32[2] = 0; + a.addr_data32[3] = 0; + } + + /* 2 get variable name */ + jarg = json_object_get(cmd, "hostbit"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("hostbit is not a string")); + return TM_ECODE_FAILED; + } + + const char *hostbit = json_string_value(jarg); + uint32_t idx = VarNameStoreLookupByName(hostbit, VAR_TYPE_HOST_BIT); + if (idx == 0) { + json_object_set_new(answer, "message", json_string("hostbit not found")); + return TM_ECODE_FAILED; + } + + SCLogInfo("remove-hostbit: %s %s", ipaddress, hostbit); + + Host *host = HostLookupHostFromHash(&a); + if (host) { + HostBitUnset(host, idx); + HostUnlock(host); + json_object_set_new(answer, "message", json_string("hostbit removed")); + return TM_ECODE_OK; + } else { + json_object_set_new(answer, "message", json_string("host not found")); + return TM_ECODE_FAILED; + } +} + +/** + * \brief Command to list hostbits for an ip + * + * \param cmd the content of command Arguments as a json_t object + * \param answer the json_t object that has to be used to answer + * + * Message looks like: + * {"message": {"count": 1, "hostbits": [{"expire": 3222, "name": "firefox-users"}]}, "return": "OK"} + * + * \retval r TM_ECODE_OK or TM_ECODE_FAILED + */ +TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data_unused) +{ + /* 1 get ip address */ + json_t *jarg = json_object_get(cmd, "ipaddress"); + if (!json_is_string(jarg)) { + json_object_set_new(answer, "message", json_string("ipaddress is not an string")); + return TM_ECODE_FAILED; + } + const char *ipaddress = json_string_value(jarg); + + Address a; + struct in_addr in; + memset(&in, 0, sizeof(in)); + if (inet_pton(AF_INET, ipaddress, &in) != 1) { + uint32_t in6[4]; + memset(&in6, 0, sizeof(in6)); + if (inet_pton(AF_INET6, ipaddress, &in) != 1) { + json_object_set_new(answer, "message", json_string("invalid address string")); + return TM_ECODE_FAILED; + } else { + a.family = AF_INET6; + a.addr_data32[0] = in6[0]; + a.addr_data32[1] = in6[1]; + a.addr_data32[2] = in6[2]; + a.addr_data32[3] = in6[3]; + } + } else { + a.family = AF_INET; + a.addr_data32[0] = in.s_addr; + a.addr_data32[1] = 0; + a.addr_data32[2] = 0; + a.addr_data32[3] = 0; + } + + SCLogInfo("list-hostbit: %s", ipaddress); + + struct timeval ts; + memset(&ts, 0, sizeof(ts)); + TimeGet(&ts); + + struct Bit { + uint32_t id; + uint32_t expire; + } bits[256]; + memset(&bits, 0, sizeof(bits)); + int i = 0, use = 0; + + Host *host = HostLookupHostFromHash(&a); + if (!host) { + json_object_set_new(answer, "message", json_string("host not found")); + return TM_ECODE_FAILED; + } + + XBit *iter = NULL; + while (use < 256 && HostBitList(host, &iter) == 1) { + bits[use].id = iter->idx; + bits[use].expire = iter->expire; + use++; + } + HostUnlock(host); + + json_t *jdata = json_object(); + json_t *jarray = json_array(); + if (jarray == NULL || jdata == NULL) { + if (jdata != NULL) + json_decref(jdata); + if (jarray != NULL) + json_decref(jarray); + json_object_set_new(answer, "message", + json_string("internal error at json object creation")); + return TM_ECODE_FAILED; + } + + for (i = 0; i < use; i++) { + json_t *bitobject = json_object(); + if (bitobject == NULL) + continue; + uint32_t expire = 0; + if ((uint32_t)ts.tv_sec < bits[i].expire) + expire = bits[i].expire - (uint32_t)ts.tv_sec; + + const char *name = VarNameStoreLookupById(bits[i].id, VAR_TYPE_HOST_BIT); + if (name == NULL) + continue; + json_object_set_new(bitobject, "name", json_string(name)); + SCLogDebug("xbit %s expire %u", name, expire); + json_object_set_new(bitobject, "expire", json_integer(expire)); + json_array_append_new(jarray, bitobject); + } + + json_object_set_new(jdata, "count", json_integer(i)); + json_object_set_new(jdata, "hostbits", jarray); + json_object_set_new(answer, "message", jdata); + return TM_ECODE_OK; +} +#endif /* BUILD_UNIX_SOCKET */ + /** * \brief Single thread version of the Pcap file processing. */ -int RunModeUnixSocketSingle(DetectEngineCtx *de_ctx) +int RunModeUnixSocketSingle(void) { #ifdef BUILD_UNIX_SOCKET PcapCommand *pcapcmd = SCMalloc(sizeof(PcapCommand)); @@ -390,12 +1019,11 @@ int RunModeUnixSocketSingle(DetectEngineCtx *de_ctx) SCLogError(SC_ERR_MEM_ALLOC, "Can not allocate pcap command"); return 1; } - pcapcmd->de_ctx = de_ctx; TAILQ_INIT(&pcapcmd->files); pcapcmd->running = 0; pcapcmd->currentfile = NULL; - UnixManagerThreadSpawn(de_ctx, 1); + UnixManagerThreadSpawn(1); unix_socket_mode_is_running = 1; diff --git a/src/runmode-unix-socket.h b/src/runmode-unix-socket.h index c2674f2d4a3d..78ef53626514 100644 --- a/src/runmode-unix-socket.h +++ b/src/runmode-unix-socket.h @@ -23,7 +23,7 @@ #ifndef __RUNMODE_UNIX_SOCKET_H__ #define __RUNMODE_UNIX_SOCKET_H__ -int RunModeUnixSocketSingle(DetectEngineCtx *); +int RunModeUnixSocketSingle(void); void RunModeUnixSocketRegister(void); const char *RunModeUnixSocketGetDefaultMode(void); @@ -31,4 +31,15 @@ int RunModeUnixSocketIsActive(void); void UnixSocketPcapFile(TmEcode tm); +#ifdef BUILD_UNIX_SOCKET +TmEcode UnixSocketRegisterTenantHandler(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketUnregisterTenantHandler(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketRegisterTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketReloadTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketUnregisterTenant(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitAdd(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitRemove(json_t *cmd, json_t* answer, void *data); +TmEcode UnixSocketHostbitList(json_t *cmd, json_t* answer, void *data); +#endif + #endif /* __RUNMODE_UNIX_SOCKET_H__ */ diff --git a/src/runmodes.c b/src/runmodes.c index 847fadcb1070..fdedea8f1886 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -49,8 +49,29 @@ #include "source-pfring.h" +#include "tmqh-flow.h" +#include "flow-manager.h" +#include "counters.h" + +#ifdef __SC_CUDA_SUPPORT__ +#include "util-cuda-buffer.h" +#include "util-mpm-ac.h" +#endif + int debuglog_enabled = 0; +/* Runmode Global Thread Names */ +const char *thread_name_autofp = "RX"; +const char *thread_name_single = "W"; +const char *thread_name_workers = "W"; +const char *thread_name_verdict = "TX"; +const char *thread_name_flow_mgr = "FM"; +const char *thread_name_flow_rec = "FR"; +const char *thread_name_unix_socket = "US"; +const char *thread_name_detect_loader = "DL"; +const char *thread_name_counter_stats = "CS"; +const char *thread_name_counter_wakeup = "CW"; + /** * \brief Holds description for a runmode. */ @@ -60,7 +81,7 @@ typedef struct RunMode_ { const char *name; const char *description; /* runmode function */ - int (*RunModeFunc)(DetectEngineCtx *); + int (*RunModeFunc)(void); } RunMode; typedef struct RunModes_ { @@ -68,30 +89,18 @@ typedef struct RunModes_ { RunMode *runmodes; } RunModes; -/** - * A list of output modules that will be active for the run mode. - */ -typedef struct RunModeOutput_ { - TmModule *tm_module; - OutputCtx *output_ctx; - - TAILQ_ENTRY(RunModeOutput_) entries; -} RunModeOutput; -TAILQ_HEAD(, RunModeOutput_) RunModeOutputs = - TAILQ_HEAD_INITIALIZER(RunModeOutputs); - static RunModes runmodes[RUNMODE_USER_MAX]; static char *active_runmode; /* free list for our outputs */ typedef struct OutputFreeList_ { - TmModule *tm_module; + OutputModule *output_module; OutputCtx *output_ctx; TAILQ_ENTRY(OutputFreeList_) entries; } OutputFreeList; -TAILQ_HEAD(, OutputFreeList_) output_free_list = +static TAILQ_HEAD(, OutputFreeList_) output_free_list = TAILQ_HEAD_INITIALIZER(output_free_list); /** @@ -133,6 +142,12 @@ static const char *RunModeTranslateModeToName(int runmode) return "MPIPE"; case RUNMODE_AFP_DEV: return "AF_PACKET_DEV"; + case RUNMODE_NETMAP: +#ifdef HAVE_NETMAP + return "NETMAP"; +#else + return "NETMAP(DISABLED)"; +#endif case RUNMODE_UNIX_SOCKET: return "UNIX_SOCKET"; default: @@ -148,7 +163,6 @@ static const char *RunModeTranslateModeToName(int runmode) * * \param runmode The runmode type. * \param runmode_customd_id The runmode custom id. - * \param de_ctx Detection Engine Context. */ static RunMode *RunModeGetCustomMode(int runmode, const char *custom_mode) { @@ -205,6 +219,7 @@ void RunModeRegisterRunModes(void) RunModeErfDagRegister(); RunModeNapatechRegister(); RunModeIdsAFPRegister(); + RunModeIdsNetmapRegister(); RunModeIdsNflogRegister(); RunModeTileMpipeRegister(); RunModeUnixSocketRegister(); @@ -223,7 +238,7 @@ void RunModeListRunmodes(void) "-----------------------\n"); printf("| %-17s | %-17s | %-10s \n", - "RunMode Type", "Custom Mode ", "Descripition"); + "RunMode Type", "Custom Mode ", "Description"); printf("|-----------------------------------------------------------------" "-----------------------\n"); int i = RUNMODE_UNKNOWN + 1; @@ -249,17 +264,18 @@ void RunModeListRunmodes(void) if (mode_displayed == 0) mode_displayed = 1; } - printf("|-----------------------------------------------------------------" - "-----------------------\n"); + if (mode_displayed == 1) { + printf("|-----------------------------------------------------------------" + "-----------------------\n"); + } } return; } /** - * \param de_ctx Detection engine ctx. Can be NULL is detect is disabled. */ -void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_ctx) +void RunModeDispatch(int runmode, const char *custom_mode) { char *local_custom_mode = NULL; @@ -272,7 +288,7 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c } } - if (custom_mode == NULL) { + if (custom_mode == NULL || strcmp(custom_mode, "auto") == 0) { switch (runmode) { case RUNMODE_PCAP_DEV: custom_mode = RunModeIdsGetDefaultMode(); @@ -306,6 +322,9 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c case RUNMODE_AFP_DEV: custom_mode = RunModeAFPGetDefaultMode(); break; + case RUNMODE_NETMAP: + custom_mode = RunModeNetmapGetDefaultMode(); + break; case RUNMODE_UNIX_SOCKET: custom_mode = RunModeUnixSocketGetDefaultMode(); break; @@ -349,17 +368,38 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c } /* Export the custom mode */ + if (active_runmode) { + SCFree(active_runmode); + } active_runmode = SCStrdup(custom_mode); if (unlikely(active_runmode == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup active mode"); exit(EXIT_FAILURE); } - mode->RunModeFunc(de_ctx); + if (strcasecmp(active_runmode, "autofp") == 0) { + TmqhFlowPrintAutofpHandler(); + } + + mode->RunModeFunc(); if (local_custom_mode != NULL) SCFree(local_custom_mode); - return; + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) + SCACCudaStartDispatcher(); +#endif + + /* Check if the alloted queues have at least 1 reader and writer */ + TmValidateQueueState(); + + if (runmode != RUNMODE_UNIX_SOCKET) { + /* spawn management threads */ + FlowManagerThreadSpawn(); + FlowRecyclerThreadSpawn(); + StatsSpawnThreads(); + } } /** @@ -373,7 +413,7 @@ void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_c */ void RunModeRegisterNewRunMode(int runmode, const char *name, const char *description, - int (*RunModeFunc)(DetectEngineCtx *)) + int (*RunModeFunc)(void)) { void *ptmp; if (RunModeGetCustomMode(runmode, name) != NULL) { @@ -416,11 +456,12 @@ void RunModeRegisterNewRunMode(int runmode, const char *name, * \param tv The ThreadVars for the thread the outputs will be * appended to. */ -void RunOutputFreeList(void) +static void RunOutputFreeList(void) { OutputFreeList *output; while ((output = TAILQ_FIRST(&output_free_list))) { - SCLogDebug("output %s %p %p", output->tm_module->name, output, output->output_ctx); + SCLogDebug("output %s %p %p", output->output_module->name, output, + output->output_ctx); if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL) output->output_ctx->DeInit(output->output_ctx); @@ -430,11 +471,18 @@ void RunOutputFreeList(void) } } -static TmModule *pkt_logger_module = NULL; -static TmModule *tx_logger_module = NULL; -static TmModule *file_logger_module = NULL; -static TmModule *filedata_logger_module = NULL; -static TmModule *streaming_logger_module = NULL; +static int file_logger_count = 0; +static int filedata_logger_count = 0; + +int RunModeOutputFileEnabled(void) +{ + return file_logger_count > 0; +} + +int RunModeOutputFiledataEnabled(void) +{ + return filedata_logger_count > 0; +} /** * Cleanup the run mode. @@ -447,20 +495,13 @@ void RunModeShutDown(void) OutputTxShutdown(); OutputFileShutdown(); OutputFiledataShutdown(); + OutputStreamingShutdown(); + OutputStatsShutdown(); + OutputFlowShutdown(); - /* Close any log files. */ - RunModeOutput *output; - while ((output = TAILQ_FIRST(&RunModeOutputs))) { - SCLogDebug("Shutting down output %s.", output->tm_module->name); - TAILQ_REMOVE(&RunModeOutputs, output, entries); - SCFree(output); - } - - /* reset logger pointers */ - pkt_logger_module = NULL; - tx_logger_module = NULL; - file_logger_module = NULL; - filedata_logger_module = NULL; + /* Reset logger counts. */ + file_logger_count = 0; + filedata_logger_count = 0; } /** \internal @@ -468,16 +509,10 @@ void RunModeShutDown(void) * the output ctx at shutdown and unix socket reload */ static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx) { - TmModule *tm_module = TmModuleGetByName(module->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", module->name); - exit(EXIT_FAILURE); - } OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList)); if (unlikely(fl_output == NULL)) return; - fl_output->tm_module = tm_module; + fl_output->output_module = module; fl_output->output_ctx = output_ctx; TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); } @@ -487,136 +522,150 @@ static void SetupOutput(const char *name, OutputModule *module, OutputCtx *outpu { /* flow logger doesn't run in the packet path */ if (module->FlowLogFunc) { - OutputRegisterFlowLogger(module->name, module->FlowLogFunc, output_ctx); + OutputRegisterFlowLogger(module->name, module->FlowLogFunc, + output_ctx, module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); return; } - - TmModule *tm_module = TmModuleGetByName(module->name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for %s failed", module->name); - exit(EXIT_FAILURE); + /* stats logger doesn't run in the packet path */ + if (module->StatsLogFunc) { + OutputRegisterStatsLogger(module->name, module->StatsLogFunc, + output_ctx,module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); + return; } - if (strcmp(tmm_modules[TMM_ALERTDEBUGLOG].name, tm_module->name) == 0) + + if (module->logger_id == LOGGER_ALERT_DEBUG) { debuglog_enabled = 1; + } if (module->PacketLogFunc) { SCLogDebug("%s is a packet logger", module->name); - OutputRegisterPacketLogger(module->name, module->PacketLogFunc, - module->PacketConditionFunc, output_ctx); - - /* need one instance of the packet logger module */ - if (pkt_logger_module == NULL) { - pkt_logger_module = TmModuleGetByName("__packet_logger__"); - if (pkt_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __packet_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->tm_module = pkt_logger_module; - runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__packet_logger__ added"); - } + OutputRegisterPacketLogger(module->logger_id, module->name, + module->PacketLogFunc, module->PacketConditionFunc, output_ctx, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); } else if (module->TxLogFunc) { SCLogDebug("%s is a tx logger", module->name); - OutputRegisterTxLogger(module->name, module->alproto, - module->TxLogFunc, output_ctx); - - /* need one instance of the tx logger module */ - if (tx_logger_module == NULL) { - tx_logger_module = TmModuleGetByName("__tx_logger__"); - if (tx_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __tx_logger__ failed"); - exit(EXIT_FAILURE); - } - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->tm_module = tx_logger_module; - runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__tx_logger__ added"); - } + OutputRegisterTxLogger(module->logger_id, module->name, module->alproto, + module->TxLogFunc, output_ctx, module->tc_log_progress, + module->ts_log_progress, module->TxLogCondition, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); + } else if (module->FiledataLogFunc) { + SCLogDebug("%s is a filedata logger", module->name); + OutputRegisterFiledataLogger(module->logger_id, module->name, + module->FiledataLogFunc, output_ctx, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); + filedata_logger_count++; } else if (module->FileLogFunc) { SCLogDebug("%s is a file logger", module->name); - OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx); - - /* need one instance of the tx logger module */ - if (file_logger_module == NULL) { - file_logger_module = TmModuleGetByName("__file_logger__"); - if (file_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __file_logger__ failed"); - exit(EXIT_FAILURE); - } + OutputRegisterFileLogger(module->logger_id, module->name, + module->FileLogFunc, output_ctx, module->ThreadInit, + module->ThreadDeinit, module->ThreadExitPrintStats); + file_logger_count++; + } else if (module->StreamingLogFunc) { + SCLogDebug("%s is a streaming logger", module->name); + OutputRegisterStreamingLogger(module->logger_id, module->name, + module->StreamingLogFunc, output_ctx, module->stream_type, + module->ThreadInit, module->ThreadDeinit, + module->ThreadExitPrintStats); + } else { + SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown logger type: name=%s", + module->name); + } +} - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->tm_module = file_logger_module; - runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__file_logger__ added"); - } - } else if (module->FiledataLogFunc) { - SCLogDebug("%s is a filedata logger", module->name); - OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, output_ctx); - - /* need one instance of the tx logger module */ - if (filedata_logger_module == NULL) { - filedata_logger_module = TmModuleGetByName("__filedata_logger__"); - if (filedata_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __filedata_logger__ failed"); - exit(EXIT_FAILURE); +static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx) +{ + ConfNode *types = ConfNodeLookupChild(conf, "types"); + SCLogDebug("types %p", types); + if (types == NULL) { + return; + } + + ConfNode *type = NULL; + TAILQ_FOREACH(type, &types->head, next) { + SCLogConfig("enabling 'eve-log' module '%s'", type->val); + + int sub_count = 0; + char subname[256]; + snprintf(subname, sizeof(subname), "eve-log.%s", type->val); + + /* Now setup all registers logger of this name. */ + OutputModule *sub_module; + TAILQ_FOREACH(sub_module, &output_modules, entries) { + if (strcmp(subname, sub_module->conf_name) == 0) { + sub_count++; + + if (sub_module->parent_name == NULL || + strcmp(sub_module->parent_name, "eve-log") != 0) { + FatalError(SC_ERR_INVALID_ARGUMENT, + "bad parent for %s", subname); + } + if (sub_module->InitSubFunc == NULL) { + FatalError(SC_ERR_INVALID_ARGUMENT, + "bad sub-module for %s", subname); + } + ConfNode *sub_output_config = + ConfNodeLookupChild(type, type->val); + // sub_output_config may be NULL if no config + + /* pass on parent output_ctx */ + OutputCtx *sub_output_ctx = + sub_module->InitSubFunc(sub_output_config, + parent_ctx); + if (sub_output_ctx == NULL) { + continue; + } + + AddOutputToFreeList(sub_module, sub_output_ctx); + SetupOutput(sub_module->name, sub_module, + sub_output_ctx); } + } - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->tm_module = filedata_logger_module; - runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__filedata_logger__ added"); + /* Error is no registered loggers with this name + * were found .*/ + if (!sub_count) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", subname); + continue; } - } else if (module->StreamingLogFunc) { - SCLogDebug("%s is a streaming logger", module->name); - OutputRegisterStreamingLogger(module->name, module->StreamingLogFunc, - output_ctx, module->stream_type); - - /* need one instance of the streaming logger module */ - if (streaming_logger_module == NULL) { - streaming_logger_module = TmModuleGetByName("__streaming_logger__"); - if (streaming_logger_module == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, - "TmModuleGetByName for __streaming_logger__ failed"); - exit(EXIT_FAILURE); + } +} + +static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputModule *lua_module = OutputGetModuleByConfName("lua"); + BUG_ON(lua_module == NULL); + + ConfNode *scripts = ConfNodeLookupChild(conf, "scripts"); + BUG_ON(scripts == NULL); //TODO + + OutputModule *m; + TAILQ_FOREACH(m, &parent_ctx->submodules, entries) { + SCLogDebug("m %p %s:%s", m, m->name, m->conf_name); + + ConfNode *script = NULL; + TAILQ_FOREACH(script, &scripts->head, next) { + SCLogDebug("script %s", script->val); + if (strcmp(script->val, m->conf_name) == 0) { + break; } + } + BUG_ON(script == NULL); - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->tm_module = streaming_logger_module; - runmode_output->output_ctx = NULL; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); - SCLogDebug("__streaming_logger__ added"); + /* pass on parent output_ctx */ + OutputCtx *sub_output_ctx = + m->InitSubFunc(script, parent_ctx); + if (sub_output_ctx == NULL) { + SCLogInfo("sub_output_ctx NULL, skipping"); + continue; } - } else { - SCLogDebug("%s is a regular logger", module->name); - - RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); - if (unlikely(runmode_output == NULL)) - return; - runmode_output->tm_module = tm_module; - runmode_output->output_ctx = output_ctx; - TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries); + + AddOutputToFreeList(m, sub_output_ctx); + SetupOutput(m->name, m, sub_output_ctx); } } @@ -633,18 +682,20 @@ void RunModeInitializeOutputs(void) ConfNode *output, *output_config; const char *enabled; + char tls_log_enabled = 0; + char tls_store_present = 0; TAILQ_FOREACH(output, &outputs->head, next) { - if (strcmp(output->val, "stats") == 0) - continue; - output_config = ConfNodeLookupChild(output, output->val); if (output_config == NULL) { /* Shouldn't happen. */ - SCLogError(SC_ERR_INVALID_ARGUMENT, - "Failed to lookup configuration child node: fast"); - exit(1); + FatalError(SC_ERR_INVALID_ARGUMENT, + "Failed to lookup configuration child node: %s", output->val); + } + + if (strcmp(output->val, "tls-store") == 0) { + tls_store_present = 1; } enabled = ConfNodeLookupChildValue(output_config, "enabled"); @@ -683,126 +734,91 @@ void RunModeInitializeOutputs(void) "files installed to add lua support."); continue; #endif + } else if (strcmp(output->val, "tls-log") == 0) { + tls_log_enabled = 1; } - OutputModule *module = OutputGetModuleByConfName(output->val); - if (module == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "No output module named %s, ignoring", output->val); - continue; - } - - OutputCtx *output_ctx = NULL; - if (module->InitFunc != NULL) { - output_ctx = module->InitFunc(output_config); - if (output_ctx == NULL) { - /* In most cases the init function will have logged the - * error. Maybe we should exit on init errors? */ + OutputModule *module; + int count = 0; + TAILQ_FOREACH(module, &output_modules, entries) { + if (strcmp(module->conf_name, output->val) != 0) { continue; } - } else if (module->InitSubFunc != NULL) { - SCLogInfo("skipping submodule"); - continue; - } - // TODO if module == parent, find it's children - if (strcmp(output->val, "eve-log") == 0) { - ConfNode *types = ConfNodeLookupChild(output_config, "types"); - SCLogDebug("types %p", types); - if (types != NULL) { - ConfNode *type = NULL; - TAILQ_FOREACH(type, &types->head, next) { - SCLogInfo("enabling 'eve-log' module '%s'", type->val); - - char subname[256]; - snprintf(subname, sizeof(subname), "%s.%s", output->val, type->val); - - OutputModule *sub_module = OutputGetModuleByConfName(subname); - if (sub_module == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "No output module named %s, ignoring", subname); - continue; - } - if (sub_module->parent_name == NULL || - strcmp(sub_module->parent_name,output->val) != 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "bad parent for %s, ignoring", subname); - continue; - } - if (sub_module->InitSubFunc == NULL) { - SCLogWarning(SC_ERR_INVALID_ARGUMENT, - "bad sub-module for %s, ignoring", subname); - continue; - } - ConfNode *sub_output_config = ConfNodeLookupChild(type, type->val); - // sub_output_config may be NULL if no config - - /* pass on parent output_ctx */ - OutputCtx *sub_output_ctx = - sub_module->InitSubFunc(sub_output_config, output_ctx); - if (sub_output_ctx == NULL) { - continue; - } + count++; - AddOutputToFreeList(sub_module, sub_output_ctx); - SetupOutput(sub_module->name, sub_module, sub_output_ctx); + OutputCtx *output_ctx = NULL; + if (module->InitFunc != NULL) { + output_ctx = module->InitFunc(output_config); + if (output_ctx == NULL) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "output module setup failed"); + continue; } + } else if (module->InitSubFunc != NULL) { + SCLogInfo("skipping submodule"); + continue; } - /* add 'eve-log' to free list as it's the owner of the - * main output ctx from which the sub-modules share the - * LogFileCtx */ - AddOutputToFreeList(module, output_ctx); - } else if (strcmp(output->val, "lua") == 0) { - SCLogDebug("handle lua"); + // TODO if module == parent, find it's children + if (strcmp(output->val, "eve-log") == 0) { + RunModeInitializeEveOutput(output_config, output_ctx); + + /* add 'eve-log' to free list as it's the owner of the + * main output ctx from which the sub-modules share the + * LogFileCtx */ + AddOutputToFreeList(module, output_ctx); + } else if (strcmp(output->val, "lua") == 0) { + SCLogDebug("handle lua"); + if (output_ctx == NULL) + continue; + RunModeInitializeLuaOutput(output_config, output_ctx); + AddOutputToFreeList(module, output_ctx); + } else { + AddOutputToFreeList(module, output_ctx); + SetupOutput(module->name, module, output_ctx); + } + } + if (count == 0) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", output->val); + continue; + } + } - ConfNode *scripts = ConfNodeLookupChild(output_config, "scripts"); - BUG_ON(scripts == NULL); //TODO + /* Backward compatibility code */ + if (!tls_store_present && tls_log_enabled) { + /* old YAML with no "tls-store" in outputs. "tls-log" value needs + * to be started using 'tls-log' config as own config */ + SCLogWarning(SC_ERR_CONF_YAML_ERROR, + "Please use 'tls-store' in YAML to configure TLS storage"); - OutputModule *m; - TAILQ_FOREACH(m, &output_ctx->submodules, entries) { - SCLogDebug("m %p %s:%s", m, m->name, m->conf_name); + TAILQ_FOREACH(output, &outputs->head, next) { + output_config = ConfNodeLookupChild(output, output->val); - ConfNode *script = NULL; - TAILQ_FOREACH(script, &scripts->head, next) { - SCLogDebug("script %s", script->val); - if (strcmp(script->val, m->conf_name) == 0) { - break; - } - } - BUG_ON(script == NULL); + if (strcmp(output->val, "tls-log") == 0) { - /* pass on parent output_ctx */ - OutputCtx *sub_output_ctx = - m->InitSubFunc(script, output_ctx); - if (sub_output_ctx == NULL) { - SCLogInfo("sub_output_ctx NULL, skipping"); + OutputModule *module = OutputGetModuleByConfName("tls-store"); + if (module == NULL) { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, + "No output module named %s, ignoring", "tls-store"); continue; } - SetupOutput(m->name, m, sub_output_ctx); - } + OutputCtx *output_ctx = NULL; + if (module->InitFunc != NULL) { + output_ctx = module->InitFunc(output_config); + if (output_ctx == NULL) { + continue; + } + } - } else { - AddOutputToFreeList(module, output_ctx); - SetupOutput(module->name, module, output_ctx); + AddOutputToFreeList(module, output_ctx); + SetupOutput(module->name, module, output_ctx); + } } } -} -/** - * Setup the outputs for this run mode. - * - * \param tv The ThreadVars for the thread the outputs will be - * appended to. - */ -void SetupOutputs(ThreadVars *tv) -{ - RunModeOutput *output; - TAILQ_FOREACH(output, &RunModeOutputs, entries) { - tv->cap_flags |= output->tm_module->cap_flags; - TmSlotSetFuncAppend(tv, output->tm_module, output->output_ctx); - } } float threading_detect_ratio = 1; diff --git a/src/runmodes.h b/src/runmodes.h index caf09a945747..2a38fb50244e 100644 --- a/src/runmodes.h +++ b/src/runmodes.h @@ -24,7 +24,7 @@ #define __RUNMODES_H__ /* Run mode */ -enum { +enum RunModes { RUNMODE_UNKNOWN = 0, RUNMODE_PCAP_DEV, RUNMODE_PCAP_FILE, @@ -35,6 +35,7 @@ enum { RUNMODE_ERF_FILE, RUNMODE_DAG, RUNMODE_AFP_DEV, + RUNMODE_NETMAP, RUNMODE_TILERA_MPIPE, RUNMODE_UNITTEST, RUNMODE_NAPATECH, @@ -59,19 +60,35 @@ enum { RUNMODE_MAX, }; +/* Run Mode Global Thread Names */ +extern const char *thread_name_autofp; +extern const char *thread_name_single; +extern const char *thread_name_workers; +extern const char *thread_name_verdict; +extern const char *thread_name_flow_mgr; +extern const char *thread_name_flow_rec; +extern const char *thread_name_unix_socket; +extern const char *thread_name_detect_loader; +extern const char *thread_name_counter_stats; +extern const char *thread_name_counter_wakeup; + char *RunmodeGetActive(void); const char *RunModeGetMainMode(void); void RunModeListRunmodes(void); -void RunModeDispatch(int, const char *, DetectEngineCtx *); +void RunModeDispatch(int, const char *); void RunModeRegisterRunModes(void); void RunModeRegisterNewRunMode(int, const char *, const char *, - int (*RunModeFunc)(DetectEngineCtx *)); + int (*RunModeFunc)(void)); void RunModeInitialize(void); void RunModeInitializeOutputs(void); -void SetupOutputs(ThreadVars *); void RunModeShutDown(void); +/* bool indicating if file logger is enabled */ +int RunModeOutputFileEnabled(void); +/* bool indicating if filedata logger is enabled */ +int RunModeOutputFiledataEnabled(void); + #include "runmode-pcap.h" #include "runmode-pcap-file.h" #include "runmode-pfring.h" @@ -84,6 +101,7 @@ void RunModeShutDown(void); #include "runmode-af-packet.h" #include "runmode-nflog.h" #include "runmode-unix-socket.h" +#include "runmode-netmap.h" int threading_set_cpu_affinity; extern float threading_detect_ratio; diff --git a/src/source-af-packet.c b/src/source-af-packet.c index f5858ac52248..2f3191620808 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2014 Open Information Security Foundation +/* Copyright (C) 2011-2017 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -94,9 +94,12 @@ #include #endif +#ifdef HAVE_HW_TIMESTAMPING +#include +#endif + #endif /* HAVE_AF_PACKET */ -extern uint8_t suricata_ctl_flags; extern int max_pending_packets; #ifndef HAVE_AF_PACKET @@ -180,6 +183,9 @@ enum { union thdr { struct tpacket2_hdr *h2; +#ifdef HAVE_TPACKET_V3 + struct tpacket3_hdr *h3; +#endif void *raw; }; @@ -188,61 +194,75 @@ union thdr { */ typedef struct AFPThreadVars_ { - /* thread specific socket */ - int socket; - /* handle state */ - unsigned char afp_state; - - /* data link type for the thread */ - int datalink; - int cooked; + union { + char *ring_v2; + struct iovec *ring_v3; + }; /* counters */ uint64_t pkts; - uint64_t bytes; - uint64_t errs; ThreadVars *tv; TmSlot *slot; + LiveDevice *livedev; + /* data link type for the thread */ + uint32_t datalink; + + unsigned int frame_offset; + ChecksumValidationMode checksum_mode; + + /* references to packet and drop counters */ + uint16_t capture_kernel_packets; + uint16_t capture_kernel_drops; + + /* handle state */ + uint8_t afp_state; + uint8_t copy_mode; + uint8_t flags; + + /* IPS peer */ + AFPPeer *mpeer; + + /* no mmap mode */ uint8_t *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ + int cooked; - int vlan_disabled; + /* + * Init related members + */ - char iface[AFP_IFACE_NAME_LENGTH]; - LiveDevice *livedev; - int down_count; + /* thread specific socket */ + int socket; + int ring_size; + int block_size; + int block_timeout; + /* socket buffer size */ + int buffer_size; /* Filter */ char *bpf_filter; - /* socket buffer size */ - int buffer_size; int promisc; - ChecksumValidationMode checksum_mode; - /* IPS stuff */ - char out_iface[AFP_IFACE_NAME_LENGTH]; - AFPPeer *mpeer; - - int flags; - uint16_t capture_kernel_packets; - uint16_t capture_kernel_drops; + int down_count; int cluster_id; int cluster_type; int threads; - int copy_mode; - struct tpacket_req req; - unsigned int tp_hdrlen; - unsigned int ring_buflen; - char *ring_buf; - char *frame_buf; - unsigned int frame_offset; - int ring_size; + union { + struct tpacket_req req; +#ifdef HAVE_TPACKET_V3 + struct tpacket_req3 req3; +#endif + }; + + char iface[AFP_IFACE_NAME_LENGTH]; + /* IPS output iface */ + char out_iface[AFP_IFACE_NAME_LENGTH]; } AFPThreadVars; @@ -272,6 +292,7 @@ void TmModuleReceiveAFPRegister (void) tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; tmm_modules[TMM_RECEIVEAFP].Func = NULL; tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop; + tmm_modules[TMM_RECEIVEAFP].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats; tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; @@ -512,8 +533,8 @@ static inline void AFPDumpCounters(AFPThreadVars *ptv) SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", ptv->tv->name, kstats.tp_packets, kstats.tp_drops); - SCPerfCounterAddUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, kstats.tp_packets); - SCPerfCounterAddUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, kstats.tp_drops); + StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, kstats.tp_packets); + StatsAddUI64(ptv->tv, ptv->capture_kernel_drops, kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t) kstats.tp_drops); (void) SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t) kstats.tp_packets); } @@ -583,7 +604,6 @@ int AFPRead(AFPThreadVars *ptv) } ptv->pkts++; - ptv->bytes += caplen + offset; p->livedev = ptv->livedev; /* add forged header */ @@ -642,10 +662,25 @@ int AFPRead(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } -TmEcode AFPWritePacket(Packet *p) +/** + * \brief AF packet write function. + * + * This function has to be called before the memory + * related to Packet in ring buffer is released. + * + * \param pointer to Packet + * \param version of capture: TPACKET_V2 or TPACKET_V3 + * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success + * + */ +static TmEcode AFPWritePacket(Packet *p, int version) { struct sockaddr_ll socket_address; int socket; + uint8_t *pstart; + size_t plen; + union thdr h; + uint16_t vlan_tci = 0; if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) { if (PACKET_TEST_ACTION(p, ACTION_DROP)) { @@ -671,7 +706,41 @@ TmEcode AFPWritePacket(Packet *p) if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) SCMutexLock(&p->afp_v.peer->sock_protect); socket = SC_ATOMIC_GET(p->afp_v.peer->socket); - if (sendto(socket, GET_PKT_DATA(p), GET_PKT_LEN(p), 0, + + h.raw = p->afp_v.relptr; + + if (version == TPACKET_V2) { + /* Copy VLAN header from ring memory. For post june 2011 kernel we test + * the flag. It is not defined for older kernel so we go best effort + * and test for non zero value of the TCI header. */ + if (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci) { + vlan_tci = h.h2->tp_vlan_tci; + } + } else { +#ifdef HAVE_TPACKET_V3 + if (h.h3->tp_status & TP_STATUS_VLAN_VALID || h.h3->hv1.tp_vlan_tci) { + vlan_tci = h.h3->hv1.tp_vlan_tci; + } +#else + /* Should not get here */ + BUG_ON(1); +#endif + } + + if (vlan_tci != 0) { + pstart = GET_PKT_DATA(p) - VLAN_HEADER_LEN; + plen = GET_PKT_LEN(p) + VLAN_HEADER_LEN; + /* move ethernet addresses */ + memmove(pstart, GET_PKT_DATA(p), 2 * ETH_ALEN); + /* write vlan info */ + *(uint16_t *)(pstart + 2 * ETH_ALEN) = htons(0x8100); + *(uint16_t *)(pstart + 2 * ETH_ALEN + 2) = htons(vlan_tci); + } else { + pstart = GET_PKT_DATA(p); + plen = GET_PKT_LEN(p); + } + + if (sendto(socket, pstart, plen, 0, (struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll)) < 0) { SCLogWarning(SC_ERR_SOCKET, "Sending packet failed on socket %d: %s", @@ -692,7 +761,7 @@ void AFPReleaseDataFromRing(Packet *p) /* Need to be in copy mode and need to detect early release where Ethernet header could not be set (and pseudo packet) */ if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { - AFPWritePacket(p); + AFPWritePacket(p, TPACKET_V2); } if (AFPDerefSocket(p->afp_v.mpeer) == 0) @@ -708,6 +777,18 @@ void AFPReleaseDataFromRing(Packet *p) AFPV_CLEANUP(&p->afp_v); } +#ifdef HAVE_TPACKET_V3 +void AFPReleasePacketV3(Packet *p) +{ + /* Need to be in copy mode and need to detect early release + where Ethernet header could not be set (and pseudo packet) */ + if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { + AFPWritePacket(p, TPACKET_V3); + } + PacketFreeOrRelease(p); +} +#endif + void AFPReleasePacket(Packet *p) { AFPReleaseDataFromRing(p); @@ -727,7 +808,6 @@ int AFPReadFromRing(AFPThreadVars *ptv) { Packet *p = NULL; union thdr h; - struct sockaddr_ll *from; uint8_t emergency_flush = 0; int read_pkts = 0; int loop_start = -1; @@ -740,7 +820,7 @@ int AFPReadFromRing(AFPThreadVars *ptv) } /* Read packet from ring */ - h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); + h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); if (h.raw == NULL) { SCReturnInt(AFP_FAILURE); } @@ -789,29 +869,19 @@ int AFPReadFromRing(AFPThreadVars *ptv) * function. */ h.h2->tp_status |= TP_STATUS_USER_BUSY; - from = (void *)h.raw + TPACKET_ALIGN(ptv->tp_hdrlen); - ptv->pkts++; - ptv->bytes += h.h2->tp_len; p->livedev = ptv->livedev; - - /* add forged header */ - if (ptv->cooked) { - SllHdr * hdrp = (SllHdr *)ptv->data; - /* XXX this is minimalist, but this seems enough */ - hdrp->sll_protocol = from->sll_protocol; - } - p->datalink = ptv->datalink; + if (h.h2->tp_len > h.h2->tp_snaplen) { SCLogDebug("Packet length (%d) > snaplen (%d), truncating", h.h2->tp_len, h.h2->tp_snaplen); } /* get vlan id from header */ - if ((!ptv->vlan_disabled) && + if ((!(ptv->flags & AFP_VLAN_DISABLED)) && (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci)) { - p->vlan_id[0] = h.h2->tp_vlan_tci; + p->vlan_id[0] = h.h2->tp_vlan_tci & 0x0fff; p->vlan_idx = 1; p->vlanh[0] = NULL; } @@ -892,6 +962,147 @@ int AFPReadFromRing(AFPThreadVars *ptv) SCReturnInt(AFP_READ_OK); } +#ifdef HAVE_TPACKET_V3 +static inline void AFPFlushBlock(struct tpacket_block_desc *pbd) +{ + pbd->hdr.bh1.block_status = TP_STATUS_KERNEL; +} + +static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc *pbd, struct tpacket3_hdr *ppd) +{ + Packet *p = PacketGetFromQueueOrAlloc(); + if (p == NULL) { + SCReturnInt(AFP_FAILURE); + } + PKT_SET_SRC(p, PKT_SRC_WIRE); + + ptv->pkts++; + p->livedev = ptv->livedev; + p->datalink = ptv->datalink; + + if ((!(ptv->flags & AFP_VLAN_DISABLED)) && + (ppd->tp_status & TP_STATUS_VLAN_VALID || ppd->hv1.tp_vlan_tci)) { + p->vlan_id[0] = ppd->hv1.tp_vlan_tci & 0x0fff; + p->vlan_idx = 1; + p->vlanh[0] = NULL; + } + + if (ptv->flags & AFP_ZERO_COPY) { + if (PacketSetData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) { + TmqhOutputPacketpool(ptv->tv, p); + SCReturnInt(AFP_FAILURE); + } + p->afp_v.relptr = ppd; + p->ReleasePacket = AFPReleasePacketV3; + p->afp_v.mpeer = ptv->mpeer; + AFPRefSocket(ptv->mpeer); + + p->afp_v.copy_mode = ptv->copy_mode; + if (p->afp_v.copy_mode != AFP_COPY_MODE_NONE) { + p->afp_v.peer = ptv->mpeer->peer; + } else { + p->afp_v.peer = NULL; + } + } else { + if (PacketCopyData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) { + TmqhOutputPacketpool(ptv->tv, p); + SCReturnInt(AFP_FAILURE); + } + } + /* Timestamp */ + p->ts.tv_sec = ppd->tp_sec; + p->ts.tv_usec = ppd->tp_nsec/1000; + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", + GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + + /* We only check for checksum disable */ + if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { + if (ptv->livedev->ignore_checksum) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ChecksumAutoModeCheck(ptv->pkts, + SC_ATOMIC_GET(ptv->livedev->pkts), + SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { + ptv->livedev->ignore_checksum = 1; + p->flags |= PKT_IGNORE_CHECKSUM; + } + } else { + if (ppd->tp_status & TP_STATUS_CSUMNOTREADY) { + p->flags |= PKT_IGNORE_CHECKSUM; + } + } + + if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { + TmqhOutputPacketpool(ptv->tv, p); + SCReturnInt(AFP_FAILURE); + } + + SCReturnInt(AFP_READ_OK); +} + +static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pbd) +{ + int num_pkts = pbd->hdr.bh1.num_pkts, i; + uint8_t *ppd; + + ppd = (uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt; + for (i = 0; i < num_pkts; ++i) { + if (unlikely(AFPParsePacketV3(ptv, pbd, + (struct tpacket3_hdr *)ppd) == AFP_FAILURE)) { + SCReturnInt(AFP_READ_FAILURE); + } + ppd = ppd + ((struct tpacket3_hdr *)ppd)->tp_next_offset; + } + + SCReturnInt(AFP_READ_OK); +} +#endif /* HAVE_TPACKET_V3 */ + +/** + * \brief AF packet read function for ring + * + * This function fills + * From here the packets are picked up by the DecodeAFP thread. + * + * \param user pointer to AFPThreadVars + * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success + */ +int AFPReadFromRingV3(AFPThreadVars *ptv) +{ +#ifdef HAVE_TPACKET_V3 + struct tpacket_block_desc *pbd; + + /* Loop till we have packets available */ + while (1) { + if (unlikely(suricata_ctl_flags != 0)) { + SCLogInfo("Exiting AFP V3 read loop"); + break; + } + + pbd = (struct tpacket_block_desc *) ptv->ring_v3[ptv->frame_offset].iov_base; + + /* block is not ready to be read */ + if ((pbd->hdr.bh1.block_status & TP_STATUS_USER) == 0) { + SCReturnInt(AFP_READ_OK); + } + + if (unlikely(AFPWalkBlock(ptv, pbd) != AFP_READ_OK)) { + AFPFlushBlock(pbd); + SCReturnInt(AFP_READ_FAILURE); + } + + AFPFlushBlock(pbd); + ptv->frame_offset = (ptv->frame_offset + 1) % ptv->req3.tp_block_nr; + /* return to maintenance task after one loop on the ring */ + if (ptv->frame_offset == 0) { + SCReturnInt(AFP_READ_OK); + } + } +#endif + SCReturnInt(AFP_READ_OK); +} + /** * \brief Reference socket * @@ -936,11 +1147,22 @@ void AFPSwitchState(AFPThreadVars *ptv, int state) /* Do cleaning if switching to down state */ if (state == AFP_STATE_DOWN) { - if (ptv->frame_buf) { - /* only used in reading phase, we can free it */ - SCFree(ptv->frame_buf); - ptv->frame_buf = NULL; +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + if (!ptv->ring_v3) { + SCFree(ptv->ring_v3); + ptv->ring_v3 = NULL; + } + } else { +#endif + if (ptv->ring_v2) { + /* only used in reading phase, we can free it */ + SCFree(ptv->ring_v2); + ptv->ring_v2 = NULL; + } +#ifdef HAVE_TPACKET_V3 } +#endif if (ptv->socket != -1) { /* we need to wait for all packets to return data */ if (SC_ATOMIC_SUB(ptv->mpeer->sock_usage, 1) == 0) { @@ -955,7 +1177,8 @@ void AFPSwitchState(AFPThreadVars *ptv, int state) } } -static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) +static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv, + uint64_t *discarded_pkts) { struct sockaddr_ll from; struct iovec iov; @@ -982,7 +1205,7 @@ static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) iov.iov_len = ptv->datalen; iov.iov_base = ptv->data; - recvmsg(ptv->socket, &msg, MSG_TRUNC); + (void)recvmsg(ptv->socket, &msg, MSG_TRUNC); if (ioctl(ptv->socket, SIOCGSTAMP, &ts) == -1) { /* FIXME */ @@ -997,7 +1220,8 @@ static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) return 0; } -static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) +static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv, + uint64_t *discarded_pkts) { union thdr h; @@ -1005,21 +1229,34 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) return 1; } - /* Read packet from ring */ - h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); - if (h.raw == NULL) { - return -1; - } - - if (((time_t)h.h2->tp_sec > synctv->tv_sec) || - ((time_t)h.h2->tp_sec == synctv->tv_sec && - (suseconds_t) (h.h2->tp_nsec / 1000) > synctv->tv_usec)) { +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + struct tpacket_block_desc *pbd; + pbd = (struct tpacket_block_desc *) ptv->ring_v3[ptv->frame_offset].iov_base; + *discarded_pkts += pbd->hdr.bh1.num_pkts; + AFPFlushBlock(pbd); + ptv->frame_offset = (ptv->frame_offset + 1) % ptv->req3.tp_block_nr; return 1; - } - h.h2->tp_status = TP_STATUS_KERNEL; - if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { - ptv->frame_offset = 0; + } else +#endif + { + /* Read packet from ring */ + h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]); + if (h.raw == NULL) { + return -1; + } + (*discarded_pkts)++; + if (((time_t)h.h2->tp_sec > synctv->tv_sec) || + ((time_t)h.h2->tp_sec == synctv->tv_sec && + (suseconds_t) (h.h2->tp_nsec / 1000) > synctv->tv_usec)) { + return 1; + } + + h.h2->tp_status = TP_STATUS_KERNEL; + if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { + ptv->frame_offset = 0; + } } @@ -1035,7 +1272,7 @@ static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) * * \retval r 1 = happy, otherwise unhappy */ -static int AFPSynchronizeStart(AFPThreadVars *ptv) +static int AFPSynchronizeStart(AFPThreadVars *ptv, uint64_t *discarded_pkts) { int r; struct timeval synctv; @@ -1060,21 +1297,21 @@ static int AFPSynchronizeStart(AFPThreadVars *ptv) gettimeofday(&synctv, NULL); } if (ptv->flags & AFP_RING_MODE) { - r = AFPReadAndDiscardFromRing(ptv, &synctv); + r = AFPReadAndDiscardFromRing(ptv, &synctv, discarded_pkts); } else { - r = AFPReadAndDiscard(ptv, &synctv); + r = AFPReadAndDiscard(ptv, &synctv, discarded_pkts); } SCLogDebug("Discarding on %s", ptv->tv->name); switch (r) { case 1: - SCLogInfo("Starting to read on %s", ptv->tv->name); + SCLogDebug("Starting to read on %s", ptv->tv->name); return 1; case -1: return r; } /* no packets */ } else if (r == 0 && AFPPeersListStarted()) { - SCLogInfo("Starting to read on %s", ptv->tv->name); + SCLogDebug("Starting to read on %s", ptv->tv->name); return 1; } else if (r < 0) { /* only exit on error */ SCLogWarning(SC_ERR_AFP_READ, "poll failed with retval %d", r); @@ -1127,10 +1364,22 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) int r; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; - struct timeval current_time; + time_t current_time; + int (*AFPReadFunc) (AFPThreadVars *); + uint64_t discarded_pkts = 0; ptv->slot = s->slot_next; + if (ptv->flags & AFP_RING_MODE) { + if (ptv->flags & AFP_TPACKET_V3) { + AFPReadFunc = AFPReadFromRingV3; + } else { + AFPReadFunc = AFPReadFromRing; + } + } else { + AFPReadFunc = AFPRead; + } + if (ptv->afp_state == AFP_STATE_DOWN) { /* Wait for our turn, threads before us must have opened the socket */ while (AFPPeersListWaitTurn(ptv->mpeer)) { @@ -1144,9 +1393,6 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) switch (-r) { case AFP_FATAL_ERROR: SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket, fatal error"); - /* fatal is fatal, we want suri to exit */ - EngineKill(); - //tv->aof = THV_ENGINE_EXIT; SCReturnInt(TM_ECODE_FAILED); case AFP_RECOVERABLE_ERROR: SCLogWarning(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket, retrying soon"); @@ -1155,8 +1401,27 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPPeersListReachedInc(); } if (ptv->afp_state == AFP_STATE_UP) { - SCLogInfo("Thread %s using socket %d", tv->name, ptv->socket); - AFPSynchronizeStart(ptv); + SCLogDebug("Thread %s using socket %d", tv->name, ptv->socket); + if ((ptv->flags & AFP_TPACKET_V3) != 0) { + AFPSynchronizeStart(ptv, &discarded_pkts); + } + /* let's reset counter as we will start the capture at the + * next function call */ +#ifdef PACKET_STATISTICS + struct tpacket_stats kstats; + socklen_t len = sizeof (struct tpacket_stats); + if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, + &kstats, &len) > -1) { + uint64_t pkts = 0; + SCLogDebug("(%s) Kernel socket startup: Packets %" PRIu32 + ", dropped %" PRIu32 "", + ptv->tv->name, + kstats.tp_packets, kstats.tp_drops); + pkts = kstats.tp_packets - discarded_pkts - kstats.tp_drops; + StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, pkts); + (void) SC_ATOMIC_ADD(ptv->livedev->pkts, pkts); + } +#endif } fds.fd = ptv->socket; @@ -1211,13 +1476,16 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) continue; } } else if (r > 0) { - if (ptv->flags & AFP_RING_MODE) { - r = AFPReadFromRing(ptv); - } else { - /* AFPRead will call TmThreadsSlotProcessPkt on read packets */ - r = AFPRead(ptv); - } + r = AFPReadFunc(ptv); switch (r) { + case AFP_READ_OK: + /* Trigger one dump of stats every second */ + current_time = time(NULL); + if (current_time != last_dump) { + AFPDumpCounters(ptv); + last_dump = current_time; + } + break; case AFP_READ_FAILURE: /* AFPRead in error: best to reset the socket */ SCLogError(SC_ERR_AFP_READ, @@ -1229,18 +1497,14 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPSwitchState(ptv, AFP_STATE_DOWN); SCReturnInt(TM_ECODE_FAILED); break; - case AFP_READ_OK: - /* Trigger one dump of stats every second */ - TimeGet(¤t_time); - if (current_time.tv_sec != last_dump) { - AFPDumpCounters(ptv); - last_dump = current_time.tv_sec; - } - break; case AFP_KERNEL_DROP: AFPDumpCounters(ptv); break; } + } else if (unlikely(r == 0)) { + /* poll timed out, lets see if we need to inject a fake packet */ + TmThreadsCaptureInjectPacket(tv, ptv->slot, NULL); + } else if ((r < 0) && (errno != EINTR)) { SCLogError(SC_ERR_AFP_READ, "Error reading data from iface '%s': (%d" PRIu32 ") %s", ptv->iface, @@ -1248,11 +1512,11 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) AFPSwitchState(ptv, AFP_STATE_DOWN); continue; } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } AFPDumpCounters(ptv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCReturnInt(TM_ECODE_OK); } @@ -1307,12 +1571,29 @@ static int AFPGetDevLinktype(int fd, const char *ifname) case ARPHRD_LOOPBACK: return LINKTYPE_ETHERNET; case ARPHRD_PPP: + case ARPHRD_NONE: return LINKTYPE_RAW; default: return ifr.ifr_hwaddr.sa_family; } } +int AFPGetLinkType(const char *ifname) +{ + int ltype; + + int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (fd == -1) { + SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno)); + return LINKTYPE_RAW; + } + + ltype = AFPGetDevLinktype(fd, ifname); + close(fd); + + return ltype; +} + static int AFPComputeRingParams(AFPThreadVars *ptv, int order) { /* Compute structure: @@ -1341,31 +1622,295 @@ frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + siz int tp_hdrlen = sizeof(struct tpacket_hdr); int snaplen = default_packet_size; + if (snaplen == 0) { + snaplen = GetIfaceMaxPacketSize(ptv->iface); + if (snaplen <= 0) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "Unable to get MTU, setting snaplen to sane default of 1514"); + snaplen = 1514; + } + } + ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); ptv->req.tp_block_size = getpagesize() << order; int frames_per_block = ptv->req.tp_block_size / ptv->req.tp_frame_size; if (frames_per_block == 0) { - SCLogInfo("frame size to big"); + SCLogError(SC_ERR_INVALID_VALUE, "Frame size bigger than block size"); return -1; } ptv->req.tp_frame_nr = ptv->ring_size; ptv->req.tp_block_nr = ptv->req.tp_frame_nr / frames_per_block + 1; /* exact division */ ptv->req.tp_frame_nr = ptv->req.tp_block_nr * frames_per_block; - SCLogInfo("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", + SCLogPerf("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", ptv->req.tp_block_size, ptv->req.tp_block_nr, ptv->req.tp_frame_size, ptv->req.tp_frame_nr); return 1; } +#ifdef HAVE_TPACKET_V3 +static int AFPComputeRingParamsV3(AFPThreadVars *ptv) +{ + ptv->req3.tp_block_size = ptv->block_size; + ptv->req3.tp_frame_size = 2048; + int frames_per_block = 0; + int tp_hdrlen = sizeof(struct tpacket3_hdr); + int snaplen = default_packet_size; + + if (snaplen == 0) { + snaplen = GetIfaceMaxPacketSize(ptv->iface); + if (snaplen <= 0) { + SCLogWarning(SC_ERR_INVALID_VALUE, + "Unable to get MTU, setting snaplen to sane default of 1514"); + snaplen = 1514; + } + } + + ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); + frames_per_block = ptv->req3.tp_block_size / ptv->req3.tp_frame_size; + + if (frames_per_block == 0) { + SCLogError(SC_ERR_INVALID_VALUE, + "Block size is too small, it should be at least %d", + ptv->req3.tp_frame_size); + return -1; + } + ptv->req3.tp_block_nr = ptv->ring_size / frames_per_block + 1; + /* exact division */ + ptv->req3.tp_frame_nr = ptv->req3.tp_block_nr * frames_per_block; + ptv->req3.tp_retire_blk_tov = ptv->block_timeout; + ptv->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; + SCLogPerf("AF_PACKET V3 RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d (mem: %d)", + ptv->req3.tp_block_size, ptv->req3.tp_block_nr, + ptv->req3.tp_frame_size, ptv->req3.tp_frame_nr, + ptv->req3.tp_block_size * ptv->req3.tp_block_nr + ); + return 1; +} +#endif + +static int AFPSetupRing(AFPThreadVars *ptv, char *devname) +{ + int val; + unsigned int len = sizeof(val), i; + unsigned int ring_buflen; + uint8_t * ring_buf; + int order; + int r, mmap_flag; + +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + val = TPACKET_V3; + } else +#endif + { + val = TPACKET_V2; + } + if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { + if (errno == ENOPROTOOPT) { + if (ptv->flags & AFP_TPACKET_V3) { + SCLogError(SC_ERR_AFP_CREATE, + "Too old kernel giving up (need 3.2 for TPACKET_V3)"); + } else { + SCLogError(SC_ERR_AFP_CREATE, + "Too old kernel giving up (need 2.6.27 at least)"); + } + } + SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); + return AFP_FATAL_ERROR; + } + + val = TPACKET_V2; +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + val = TPACKET_V3; + } +#endif + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, + sizeof(val)) < 0) { + SCLogError(SC_ERR_AFP_CREATE, + "Can't activate TPACKET_V2/TPACKET_V3 on packet socket: %s", + strerror(errno)); + return AFP_FATAL_ERROR; + } + +#ifdef HAVE_HW_TIMESTAMPING + int req = SOF_TIMESTAMPING_RAW_HARDWARE; + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, + sizeof(req)) < 0) { + SCLogWarning(SC_ERR_AFP_CREATE, + "Can't activate hardware timestamping on packet socket: %s", + strerror(errno)); + } +#endif + + /* Let's reserve head room so we can add the VLAN header in IPS + * or TAP mode before write the packet */ + if (ptv->copy_mode != AFP_COPY_MODE_NONE) { + /* Only one vlan is extracted from AFP header so + * one VLAN header length is enough. */ + int reserve = VLAN_HEADER_LEN; + if (setsockopt(ptv->socket, SOL_PACKET, PACKET_RESERVE, (void *) &reserve, + sizeof(reserve)) < 0) { + SCLogError(SC_ERR_AFP_CREATE, + "Can't activate reserve on packet socket: %s", + strerror(errno)); + return AFP_FATAL_ERROR; + } + } + + /* Allocate RX ring */ +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + if (AFPComputeRingParamsV3(ptv) != 1) { + return AFP_FATAL_ERROR; + } + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, + (void *) &ptv->req3, sizeof(ptv->req3)); + if (r < 0) { + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s: (%d) %s", + devname, + errno, + strerror(errno)); + return AFP_FATAL_ERROR; + } + } else { +#endif + for (order = AFP_BLOCK_SIZE_DEFAULT_ORDER; order >= 0; order--) { + if (AFPComputeRingParams(ptv, order) != 1) { + SCLogInfo("Ring parameter are incorrect. Please correct the devel"); + return AFP_FATAL_ERROR; + } + + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, + (void *) &ptv->req, sizeof(ptv->req)); + + if (r < 0) { + if (errno == ENOMEM) { + SCLogInfo("Memory issue with ring parameters. Retrying."); + continue; + } + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s: (%d) %s", + devname, + errno, + strerror(errno)); + return AFP_FATAL_ERROR; + } else { + break; + } + } + if (order < 0) { + SCLogError(SC_ERR_MEM_ALLOC, + "Unable to allocate RX Ring for iface %s (order 0 failed)", + devname); + return AFP_FATAL_ERROR; + } +#ifdef HAVE_TPACKET_V3 + } +#endif + + /* Allocate the Ring */ +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + ring_buflen = ptv->req3.tp_block_nr * ptv->req3.tp_block_size; + } else { +#endif + ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; +#ifdef HAVE_TPACKET_V3 + } +#endif + mmap_flag = MAP_SHARED; + if (ptv->flags & AFP_MMAP_LOCKED) + mmap_flag |= MAP_LOCKED; + ring_buf = mmap(0, ring_buflen, PROT_READ|PROT_WRITE, + mmap_flag, ptv->socket, 0); + if (ring_buf == MAP_FAILED) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap, error %s", + strerror(errno)); + goto mmap_err; + } +#ifdef HAVE_TPACKET_V3 + if (ptv->flags & AFP_TPACKET_V3) { + ptv->ring_v3 = SCMalloc(ptv->req3.tp_block_nr * sizeof(*ptv->ring_v3)); + if (!ptv->ring_v3) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to malloc ptv ring_v3"); + goto postmmap_err; + } + for (i = 0; i < ptv->req3.tp_block_nr; ++i) { + ptv->ring_v3[i].iov_base = ring_buf + (i * ptv->req3.tp_block_size); + ptv->ring_v3[i].iov_len = ptv->req3.tp_block_size; + } + } else { +#endif + /* allocate a ring for each frame header pointer*/ + ptv->ring_v2 = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); + if (ptv->ring_v2 == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); + goto postmmap_err; + } + memset(ptv->ring_v2, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); + /* fill the header ring with proper frame ptr*/ + ptv->frame_offset = 0; + for (i = 0; i < ptv->req.tp_block_nr; ++i) { + void *base = &ring_buf[i * ptv->req.tp_block_size]; + unsigned int j; + for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { + (((union thdr **)ptv->ring_v2)[ptv->frame_offset]) = base; + base += ptv->req.tp_frame_size; + } + } + ptv->frame_offset = 0; +#ifdef HAVE_TPACKET_V3 + } +#endif + + return 0; + +postmmap_err: + munmap(ring_buf, ring_buflen); + if (ptv->ring_v2) + SCFree(ptv->ring_v2); + if (ptv->ring_v3) + SCFree(ptv->ring_v3); +mmap_err: + /* Packet mmap does the cleaning when socket is closed */ + return AFP_FATAL_ERROR; +} + +/** \brief test if we can use FANOUT. Older kernels like those in + * CentOS6 have HAVE_PACKET_FANOUT defined but fail to work + */ +int AFPIsFanoutSupported(void) +{ +#ifdef HAVE_PACKET_FANOUT + int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (fd < 0) + return 0; + + uint16_t mode = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; + uint16_t id = 1; + uint32_t option = (mode << 16) | (id & 0xffff); + int r = setsockopt(fd, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); + close(fd); + + if (r < 0) { + SCLogPerf("fanout not supported by kernel: %s", strerror(errno)); + return 0; + } + return 1; +#else + return 0; +#endif +} + static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) { int r; int ret = AFP_FATAL_ERROR; struct packet_mreq sock_params; struct sockaddr_ll bind_address; - int order; - unsigned int i; int if_idx; /* open socket */ @@ -1397,7 +1942,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) SCLogError(SC_ERR_AFP_CREATE, "Couldn't switch iface %s to promiscuous, error %s", devname, strerror(errno)); - goto frame_err; + goto socket_err; } } @@ -1406,7 +1951,7 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, sizeof(val)) == -1 && errno != ENOPROTOOPT) { SCLogWarning(SC_ERR_NO_AF_PACKET, - "'kernel' checksum mode not supported, failling back to full mode."); + "'kernel' checksum mode not supported, falling back to full mode."); ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } } @@ -1416,14 +1961,14 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) /* * Set the socket buffer size to the specified value. */ - SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); + SCLogPerf("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, &ptv->buffer_size, sizeof(ptv->buffer_size)) == -1) { SCLogError(SC_ERR_AFP_CREATE, "Couldn't set buffer size to %d on iface %s, error %s", ptv->buffer_size, devname, strerror(errno)); - goto frame_err; + goto socket_err; } } @@ -1441,22 +1986,21 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) } } ret = AFP_RECOVERABLE_ERROR; - goto frame_err; + goto socket_err; } #ifdef HAVE_PACKET_FANOUT /* add binded socket to fanout group */ if (ptv->threads > 1) { - uint32_t option = 0; uint16_t mode = ptv->cluster_type; uint16_t id = ptv->cluster_id; - option = (mode << 16) | (id & 0xffff); + uint32_t option = (mode << 16) | (id & 0xffff); r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); if (r < 0) { SCLogError(SC_ERR_AFP_CREATE, - "Coudn't set fanout mode, error %s", + "Couldn't set fanout mode, error %s", strerror(errno)); - goto frame_err; + goto socket_err; } } #endif @@ -1465,11 +2009,11 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) if (if_flags == -1) { if (verbose) { SCLogError(SC_ERR_AFP_READ, - "Can not acces to interface '%s'", + "Couldn't get flags for interface '%s'", ptv->iface); } ret = AFP_RECOVERABLE_ERROR; - goto frame_err; + goto socket_err; } if ((if_flags & IFF_UP) == 0) { if (verbose) { @@ -1478,97 +2022,16 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) ptv->iface); } ret = AFP_RECOVERABLE_ERROR; - goto frame_err; + goto socket_err; } if (ptv->flags & AFP_RING_MODE) { - int val = TPACKET_V2; - unsigned int len = sizeof(val); - if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { - if (errno == ENOPROTOOPT) { - SCLogError(SC_ERR_AFP_CREATE, - "Too old kernel giving up (need 2.6.27 at least)"); - } - SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); - goto socket_err; - } - ptv->tp_hdrlen = val; - - val = TPACKET_V2; - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, - sizeof(val)) < 0) { - SCLogError(SC_ERR_AFP_CREATE, - "Can't activate TPACKET_V2 on packet socket: %s", - strerror(errno)); - goto socket_err; - } - - if (GetIfaceOffloading(devname) == 1) { - SCLogWarning(SC_ERR_AFP_CREATE, - "Using mmap mode with GRO or LRO activated can lead to capture problems"); - } - - /* Allocate RX ring */ -#define DEFAULT_ORDER 3 - for (order = DEFAULT_ORDER; order >= 0; order--) { - if (AFPComputeRingParams(ptv, order) != 1) { - SCLogInfo("Ring parameter are incorrect. Please correct the devel"); - } - - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *) &ptv->req, sizeof(ptv->req)); - if (r < 0) { - if (errno == ENOMEM) { - SCLogInfo("Memory issue with ring parameters. Retrying."); - continue; - } - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s: (%d) %s", - devname, - errno, - strerror(errno)); - goto socket_err; - } else { - break; - } - } - - if (order < 0) { - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s (order 0 failed)", - devname); + ret = AFPSetupRing(ptv, devname); + if (ret != 0) goto socket_err; - } - - /* Allocate the Ring */ - ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; - ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, - MAP_SHARED, ptv->socket, 0); - if (ptv->ring_buf == MAP_FAILED) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); - goto socket_err; - } - /* allocate a ring for each frame header pointer*/ - ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); - if (ptv->frame_buf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); - goto mmap_err; - } - memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); - /* fill the header ring with proper frame ptr*/ - ptv->frame_offset = 0; - for (i = 0; i < ptv->req.tp_block_nr; ++i) { - void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; - unsigned int j; - for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { - (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; - base += ptv->req.tp_frame_size; - } - } - ptv->frame_offset = 0; } - SCLogInfo("Using interface '%s' via socket %d", (char *)devname, ptv->socket); - + SCLogDebug("Using interface '%s' via socket %d", (char *)devname, ptv->socket); ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface); switch (ptv->datalink) { @@ -1590,10 +2053,13 @@ static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) return 0; frame_err: - if (ptv->frame_buf) - SCFree(ptv->frame_buf); -mmap_err: - /* Packet mmap does the cleaning when socket is closed */ + if (ptv->flags & AFP_TPACKET_V3) { + if (ptv->ring_v3) + SCFree(ptv->ring_v3); + } else { + if (ptv->ring_v2) + SCFree(ptv->ring_v2); + } socket_err: close(ptv->socket); ptv->socket = -1; @@ -1643,7 +2109,6 @@ TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) return TM_ECODE_FAILED; } - SCMutexUnlock(&afpacket_bpf_set_filter_lock); return TM_ECODE_OK; } @@ -1689,6 +2154,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->buffer_size = afpconfig->buffer_size; ptv->ring_size = afpconfig->ring_size; + ptv->block_size = afpconfig->block_size; ptv->promisc = afpconfig->promisc; ptv->checksum_mode = afpconfig->checksum_mode; @@ -1700,9 +2166,9 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->cluster_id = 1; /* We only set cluster info if the number of reader threads is greater than 1 */ if (afpconfig->threads > 1) { - ptv->cluster_id = afpconfig->cluster_id; - ptv->cluster_type = afpconfig->cluster_type; - ptv->threads = afpconfig->threads; + ptv->cluster_id = afpconfig->cluster_id; + ptv->cluster_type = afpconfig->cluster_type; + ptv->threads = afpconfig->threads; } #endif ptv->flags = afpconfig->flags; @@ -1712,33 +2178,12 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) } #ifdef PACKET_STATISTICS - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); #endif - char *active_runmode = RunmodeGetActive(); - - if (active_runmode && !strcmp("workers", active_runmode)) { - ptv->flags |= AFP_ZERO_COPY; - SCLogInfo("Enabling zero copy mode"); - } else { - /* If we are using copy mode we need a lock */ - ptv->flags |= AFP_SOCK_PROTECT; - } - - /* If we are in RING mode, then we can use ZERO copy - * by using the data release mechanism */ - if (ptv->flags & AFP_RING_MODE) { - ptv->flags |= AFP_ZERO_COPY; - SCLogInfo("Enabling zero copy mode by using data release call"); - } - ptv->copy_mode = afpconfig->copy_mode; if (ptv->copy_mode != AFP_COPY_MODE_NONE) { strlcpy(ptv->out_iface, afpconfig->out_iface, AFP_IFACE_NAME_LENGTH); @@ -1776,14 +2221,14 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) * the capture phase */ int vlanbool = 0; if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { - ptv->vlan_disabled = 1; + ptv->flags |= AFP_VLAN_DISABLED; } /* If kernel is older than 3.0, VLAN is not stripped so we don't * get the info from packet extended header but we will use a standard * parsing of packet data (See Linux commit bcc6d47903612c3861201cc3a866fb604f26b8b2) */ if (! SCKernelVersionIsAtLeast(3, 0)) { - ptv->vlan_disabled = 1; + ptv->flags |= AFP_VLAN_DISABLED; } SCReturnInt(TM_ECODE_OK); @@ -1801,13 +2246,11 @@ void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) #ifdef PACKET_STATISTICS AFPDumpCounters(ptv); - SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->sc_perf_pca), - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->sc_perf_pca)); + StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), + StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); #endif - - SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } /** @@ -1854,38 +2297,30 @@ TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif - - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_vlan); } /* call the decoder */ - switch(p->datalink) { - case LINKTYPE_LINUX_SLL: - DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - break; + switch (p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; + case LINKTYPE_LINUX_SLL: + DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + break; case LINKTYPE_PPP: DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; case LINKTYPE_RAW: DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; + case LINKTYPE_NULL: + DecodeNull(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeAFP", p->datalink); break; diff --git a/src/source-af-packet.h b/src/source-af-packet.h index e65a1f2a7a96..513fdc9b37ff 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -32,6 +32,11 @@ #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 #define PACKET_FANOUT_CPU 2 +#define PACKET_FANOUT_ROLLOVER 3 +#define PACKET_FANOUT_RND 4 +#define PACKET_FANOUT_QM 5 + +#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 #define PACKET_FANOUT_FLAG_DEFRAG 0x8000 #else /* HAVE_PACKET_FANOUT */ #include @@ -43,6 +48,9 @@ #define AFP_ZERO_COPY (1<<1) #define AFP_SOCK_PROTECT (1<<2) #define AFP_EMERGENCY_MODE (1<<3) +#define AFP_TPACKET_V3 (1<<4) +#define AFP_VLAN_DISABLED (1<<5) +#define AFP_MMAP_LOCKED (1<<6) #define AFP_COPY_MODE_NONE 0 #define AFP_COPY_MODE_TAP 1 @@ -51,6 +59,12 @@ #define AFP_FILE_MAX_PKTS 256 #define AFP_IFACE_NAME_LENGTH 48 +/* In kernel the allocated block size is allocated using the formula + * page_size << order. So default value is using the same formula with + * an order of 3 which guarantee we have some room in the block compared + * to standard frame size */ +#define AFP_BLOCK_SIZE_DEFAULT_ORDER 3 + typedef struct AFPIfaceConfig_ { char iface[AFP_IFACE_NAME_LENGTH]; @@ -60,6 +74,10 @@ typedef struct AFPIfaceConfig_ int buffer_size; /* ring size in number of packets */ int ring_size; + /* block size for tpacket_v3 in */ + int block_size; + /* block timeout for tpacket_v3 in milliseconds */ + int block_timeout; /* cluster param */ int cluster_id; int cluster_type; @@ -81,16 +99,16 @@ typedef struct AFPIfaceConfig_ */ typedef struct AFPPeer_ { - char iface[AFP_IFACE_NAME_LENGTH]; SC_ATOMIC_DECLARE(int, socket); SC_ATOMIC_DECLARE(int, sock_usage); SC_ATOMIC_DECLARE(int, if_idx); - SC_ATOMIC_DECLARE(uint8_t, state); - SCMutex sock_protect; int flags; + SCMutex sock_protect; int turn; /**< Field used to store initialisation order. */ + SC_ATOMIC_DECLARE(uint8_t, state); struct AFPPeer_ *peer; TAILQ_ENTRY(AFPPeer_) next; + char iface[AFP_IFACE_NAME_LENGTH]; } AFPPeer; /** @@ -102,12 +120,12 @@ typedef struct AFPPeer_ { typedef struct AFPPacketVars_ { void *relptr; - int copy_mode; AFPPeer *peer; /**< Sending peer for IPS/TAP mode */ /** Pointer to ::AFPPeer used for capture. Field is used to be able * to do reference counting. */ AFPPeer *mpeer; + uint8_t copy_mode; } AFPPacketVars; #define AFPV_CLEANUP(afpv) do { \ @@ -127,6 +145,8 @@ void TmModuleDecodeAFPRegister (void); TmEcode AFPPeersListInit(); TmEcode AFPPeersListCheck(); void AFPPeersListClean(); +int AFPGetLinkType(const char *ifname); +int AFPIsFanoutSupported(void); #endif /* __SOURCE_AFP_H__ */ diff --git a/src/source-erf-dag.c b/src/source-erf-dag.c index dbbd0774288e..db6b3d9f6459 100644 --- a/src/source-erf-dag.c +++ b/src/source-erf-dag.c @@ -91,7 +91,6 @@ NoErfDagSupportExit(ThreadVars *tv, void *initdata, void **data) #define BYTES_PER_LOOP (4 * 1024 * 1024) /* 4 MB */ extern int max_pending_packets; -extern uint8_t suricata_ctl_flags; typedef struct ErfDagThreadVars_ { ThreadVars *tv; @@ -139,6 +138,7 @@ TmModuleReceiveErfDagRegister(void) tmm_modules[TMM_RECEIVEERFDAG].ThreadInit = ReceiveErfDagThreadInit; tmm_modules[TMM_RECEIVEERFDAG].Func = NULL; tmm_modules[TMM_RECEIVEERFDAG].PktAcqLoop = ReceiveErfDagLoop; + tmm_modules[TMM_RECEIVEERFDAG].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEERFDAG].ThreadExitPrintStats = ReceiveErfDagThreadExitStats; tmm_modules[TMM_RECEIVEERFDAG].ThreadDeinit = NULL; @@ -305,10 +305,8 @@ ReceiveErfDagThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); } - ewtn->packets = SCPerfTVRegisterCounter("capture.dag_packets", - tv, SC_PERF_TYPE_UINT64, "NULL"); - ewtn->drops = SCPerfTVRegisterCounter("capture.dag_drops", - tv, SC_PERF_TYPE_UINT64, "NULL"); + ewtn->packets = StatsRegisterCounter("capture.dag_packets", tv); + ewtn->drops = StatsRegisterCounter("capture.dag_drops", tv); ewtn->tv = tv; *data = (void *)ewtn; @@ -344,7 +342,7 @@ ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) dtv->slot = s->slot_next; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -382,7 +380,7 @@ ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, dtv->dagstream, dtv->dagname); @@ -445,8 +443,7 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) break; case TYPE_ETH: if (dr->lctr) { - SCPerfCounterAddUI64(ewtn->drops, ewtn->tv->sc_perf_pca, - ntohs(dr->lctr)); + StatsAddUI64(ewtn->tv, ewtn->drops, ntohs(dr->lctr)); } break; default: @@ -539,7 +536,7 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) p->ts.tv_sec++; } - SCPerfCounterIncr(ewtn->packets, ewtn->tv->sc_perf_pca); + StatsIncr(ewtn->tv, ewtn->packets); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { @@ -562,16 +559,16 @@ ReceiveErfDagThreadExitStats(ThreadVars *tv, void *data) ErfDagThreadVars *ewtn = (ErfDagThreadVars *)data; (void)SC_ATOMIC_SET(ewtn->livedev->pkts, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->sc_perf_pca)); + StatsGetLocalCounterValue(tv, ewtn->packets)); (void)SC_ATOMIC_SET(ewtn->livedev->drop, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->sc_perf_pca)); + StatsGetLocalCounterValue(tv, ewtn->drops)); SCLogInfo("Stream: %d; Bytes: %"PRIu64"; Packets: %"PRIu64 "; Drops: %"PRIu64, ewtn->dagstream, ewtn->bytes, - (uint64_t)SCPerfGetLocalCounterValue(ewtn->packets, tv->sc_perf_pca), - (uint64_t)SCPerfGetLocalCounterValue(ewtn->drops, tv->sc_perf_pca)); + StatsGetLocalCounterValue(tv, ewtn->packets), + StatsGetLocalCounterValue(tv, ewtn->drops)); } /** @@ -625,20 +622,7 @@ DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif - - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, - GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, - GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* call the decoder */ switch(p->datalink) { diff --git a/src/source-erf-file.c b/src/source-erf-file.c index 6825e3fc3f5c..29e59358c8d3 100644 --- a/src/source-erf-file.c +++ b/src/source-erf-file.c @@ -81,6 +81,7 @@ TmModuleReceiveErfFileRegister(void) tmm_modules[TMM_RECEIVEERFFILE].ThreadInit = ReceiveErfFileThreadInit; tmm_modules[TMM_RECEIVEERFFILE].Func = NULL; tmm_modules[TMM_RECEIVEERFFILE].PktAcqLoop = ReceiveErfFileLoop; + tmm_modules[TMM_RECEIVEERFFILE].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEERFFILE].ThreadExitPrintStats = ReceiveErfFileThreadExitStats; tmm_modules[TMM_RECEIVEERFFILE].ThreadDeinit = NULL; @@ -116,7 +117,7 @@ TmEcode ReceiveErfFileLoop(ThreadVars *tv, void *data, void *slot) etv->slot = ((TmSlot *)slot)->slot_next; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -284,18 +285,7 @@ DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueu return TM_ECODE_OK; /* Update counters. */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0 ); -#endif - - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-ipfw.c b/src/source-ipfw.c index 53bb03f2891e..05392828b3ff 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -158,6 +158,7 @@ void TmModuleReceiveIPFWRegister (void) tmm_modules[TMM_RECEIVEIPFW].ThreadInit = ReceiveIPFWThreadInit; tmm_modules[TMM_RECEIVEIPFW].Func = NULL; tmm_modules[TMM_RECEIVEIPFW].PktAcqLoop = ReceiveIPFWLoop; + tmm_modules[TMM_RECEIVEIPFW].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = ReceiveIPFWThreadExitStats; tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = ReceiveIPFWThreadDeinit; tmm_modules[TMM_RECEIVEIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | @@ -299,7 +300,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) PacketCopyData(p, pkt, pktlen); SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)", - GET_PKT_LEN(p), *pkt, GET_PKT_DATA(p)); + GET_PKT_LEN(p), *pkt, *(GET_PKT_DATA(p))); if (TmThreadsSlotProcessPkt(tv, ((TmSlot *) slot)->slot_next, p) != TM_ECODE_OK) { @@ -307,7 +308,7 @@ TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); @@ -452,10 +453,7 @@ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { @@ -517,7 +515,9 @@ TmEcode DecodeIPFWThreadDeinit(ThreadVars *tv, void *data) TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) { uint32_t verdict; +#if 0 struct pollfd IPFWpoll; +#endif IPFWQueueVars *nq = NULL; SCEnter(); @@ -533,8 +533,10 @@ TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) SCReturnInt(TM_ECODE_FAILED); } +#if 0 IPFWpoll.fd = nq->fd; IPFWpoll.events = POLLWRNORM; +#endif if (PACKET_TEST_ACTION(p, ACTION_DROP)) { verdict = IPFW_DROP; diff --git a/src/source-mpipe.c b/src/source-mpipe.c index a7278463676f..0310115a0401 100644 --- a/src/source-mpipe.c +++ b/src/source-mpipe.c @@ -60,7 +60,6 @@ #include #include #include -#include /* Align "p" mod "align", assuming "p" is a "void*". */ #define ALIGN(p, align) do { (p) += -(long)(p) & ((align) - 1); } while(0) @@ -76,8 +75,6 @@ #define min(a,b) (((a) < (b)) ? (a) : (b)) -extern uint8_t suricata_ctl_flags; - /** storage for mpipe device names */ typedef struct MpipeDevice_ { char *dev; /**< the device (e.g. "xgbe1") */ @@ -175,6 +172,7 @@ void TmModuleReceiveMpipeRegister (void) tmm_modules[TMM_RECEIVEMPIPE].ThreadInit = ReceiveMpipeThreadInit; tmm_modules[TMM_RECEIVEMPIPE].Func = NULL; tmm_modules[TMM_RECEIVEMPIPE].PktAcqLoop = ReceiveMpipeLoop; + tmm_modules[TMM_RECEIVEMPIPE].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEMPIPE].ThreadExitPrintStats = ReceiveMpipeThreadExitStats; tmm_modules[TMM_RECEIVEMPIPE].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEMPIPE].RegisterTests = NULL; @@ -319,6 +317,24 @@ static uint16_t XlateStack(MpipeThreadVars *ptv, int stack_idx) } } +static void SendNoOpPacket(ThreadVars *tv, TmSlot *slot) +{ + Packet *p = PacketPoolGetPacket(); + if (p == NULL) { + return; + } + + p->datalink = DLT_RAW; + p->proto = IPPROTO_TCP; + + /* So that DecodeMpipe ignores is. */ + p->flags |= PKT_PSEUDO_STREAM_END; + + p->flow = NULL; + + TmThreadsSlotProcessPkt(tv, slot, p); +} + /** * \brief Receives packets from an interface via gxio mpipe. */ @@ -336,9 +352,9 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; if (ConfGet("mpipe.checksum-checks", &ctype) == 1) { - if (strcmp(ctype, "yes") == 0) { + if (ConfValIsTrue(ctype)) { ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(ctype, "no") == 0) { + } else if (ConfValIsFalse(ctype)) { ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, @@ -350,6 +366,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) MpipeReceiveOpenIqueue(rank); gxio_mpipe_iqueue_t* iqueue = thread_iqueue; int update_counter = 0; + uint64_t last_packet_time = get_cycle_count(); for (;;) { @@ -365,8 +382,7 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) __insn_prefetch(&idesc[i]); } if (unlikely(n > max_queued)) { - SCPerfCounterSetUI64(ptv->max_mpipe_depth, - tv->sc_perf_pca, + StatsSetUI64(tv, ptv->max_mpipe_depth, (uint64_t)n); max_queued = n; } @@ -382,11 +398,10 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) if (idesc->be) { /* Buffer Error - No buffer available, so mPipe * dropped the packet. */ - SCPerfCounterIncr(XlateStack(ptv, idesc->stack_idx), - tv->sc_perf_pca); + StatsIncr(tv, XlateStack(ptv, idesc->stack_idx)); } else { /* Bad packet. CRC error */ - SCPerfCounterIncr(ptv->mpipe_drop, tv->sc_perf_pca); + StatsIncr(tv, ptv->mpipe_drop); gxio_mpipe_iqueue_drop(iqueue, idesc); } gxio_mpipe_iqueue_release(iqueue, idesc); @@ -394,15 +409,25 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) } /* Move forward M packets in ingress ring. */ gxio_mpipe_iqueue_advance(iqueue, m); + + last_packet_time = get_cycle_count(); } if (update_counter-- <= 0) { /* Only periodically update and check for termination. */ - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); update_counter = 10000; if (suricata_ctl_flags != 0) { break; } + + // If no packet has been received for some period of time, process a NOP packet + // just to make sure that pseudo packets from the Flow manager get processed. + uint64_t now = get_cycle_count(); + if (now - last_packet_time > 100000000) { + SendNoOpPacket(ptv->tv, ptv->slot); + last_packet_time = now; + } } } SCReturnInt(TM_ECODE_OK); @@ -411,38 +436,16 @@ TmEcode ReceiveMpipeLoop(ThreadVars *tv, void *data, void *slot) static void MpipeRegisterPerfCounters(MpipeThreadVars *ptv, ThreadVars *tv) { /* register counters */ - ptv->max_mpipe_depth = SCPerfTVRegisterCounter("mpipe.max_mpipe_depth", - tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->mpipe_drop = SCPerfTVRegisterCounter("mpipe.drop", - tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_0 = SCPerfTVRegisterCounter("mpipe.no_buf0", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_1 = SCPerfTVRegisterCounter("mpipe.no_buf1", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_2 = SCPerfTVRegisterCounter("mpipe.no_buf2", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_3 = SCPerfTVRegisterCounter("mpipe.no_buf3", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_4 = SCPerfTVRegisterCounter("mpipe.no_buf4", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_5 = SCPerfTVRegisterCounter("mpipe.no_buf5", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_6 = SCPerfTVRegisterCounter("mpipe.no_buf6", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->counter_no_buffers_7 = SCPerfTVRegisterCounter("mpipe.no_buf7", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->max_mpipe_depth = StatsRegisterCounter("mpipe.max_mpipe_depth", tv); + ptv->mpipe_drop = StatsRegisterCounter("mpipe.drop", tv); + ptv->counter_no_buffers_0 = StatsRegisterCounter("mpipe.no_buf0", tv); + ptv->counter_no_buffers_1 = StatsRegisterCounter("mpipe.no_buf1", tv); + ptv->counter_no_buffers_2 = StatsRegisterCounter("mpipe.no_buf2", tv); + ptv->counter_no_buffers_3 = StatsRegisterCounter("mpipe.no_buf3", tv); + ptv->counter_no_buffers_4 = StatsRegisterCounter("mpipe.no_buf4", tv); + ptv->counter_no_buffers_5 = StatsRegisterCounter("mpipe.no_buf5", tv); + ptv->counter_no_buffers_6 = StatsRegisterCounter("mpipe.no_buf6", tv); + ptv->counter_no_buffers_7 = StatsRegisterCounter("mpipe.no_buf7", tv); } static const gxio_mpipe_buffer_size_enum_t gxio_buffer_sizes[] = { @@ -892,8 +895,8 @@ TmEcode ReceiveMpipeThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->tv = tv; int result; - char *link_name = (char *)initdata; - + const char *link_name = (char *)initdata; + MpipeRegisterPerfCounters(ptv, tv); *data = (void *)ptv; @@ -1036,13 +1039,7 @@ TmEcode DecodeMpipe(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* call the decoder */ DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-napatech.c b/src/source-napatech.c index 18abd3aa6d09..1348eaf99e16 100644 --- a/src/source-napatech.c +++ b/src/source-napatech.c @@ -79,7 +79,6 @@ TmEcode NoNapatechSupportExit(ThreadVars *tv, void *initdata, void **data) #include extern int max_pending_packets; -extern uint8_t suricata_ctl_flags; typedef struct NapatechThreadVars_ { ThreadVars *tv; @@ -111,6 +110,7 @@ void TmModuleNapatechStreamRegister(void) tmm_modules[TMM_RECEIVENAPATECH].ThreadInit = NapatechStreamThreadInit; tmm_modules[TMM_RECEIVENAPATECH].Func = NULL; tmm_modules[TMM_RECEIVENAPATECH].PktAcqLoop = NapatechStreamLoop; + tmm_modules[TMM_RECEIVENAPATECH].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENAPATECH].ThreadExitPrintStats = NapatechStreamThreadExitStats; tmm_modules[TMM_RECEIVENAPATECH].ThreadDeinit = NapatechStreamThreadDeinit; tmm_modules[TMM_RECEIVENAPATECH].RegisterTests = NULL; @@ -206,7 +206,7 @@ TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot) TmSlot *s = (TmSlot *)slot; ntv->slot = s->slot_next; - while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) { + while (!(suricata_ctl_flags & SURICATA_STOP)) { /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ PacketPoolWait(); @@ -295,7 +295,7 @@ TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot) } NT_NetRxRelease(ntv->rx_stream, packet_buffer); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); @@ -358,11 +358,7 @@ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); switch (p->datalink) { case LINKTYPE_ETHERNET: diff --git a/src/source-netmap.c b/src/source-netmap.c new file mode 100644 index 000000000000..5f81f1a69453 --- /dev/null +++ b/src/source-netmap.c @@ -0,0 +1,1085 @@ +/* Copyright (C) 2011-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** +* \defgroup netmap Netmap running mode +* +* @{ +*/ + +/** +* \file +* +* \author Aleksey Katargin +* +* Netmap socket acquisition support +* +*/ + +#include "suricata-common.h" +#include "config.h" +#include "suricata.h" +#include "decode.h" +#include "packet-queue.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-queuehandlers.h" +#include "tm-modules.h" +#include "tm-threads.h" +#include "tm-threads-common.h" +#include "conf.h" +#include "util-debug.h" +#include "util-device.h" +#include "util-error.h" +#include "util-privs.h" +#include "util-optimize.h" +#include "util-checksum.h" +#include "util-ioctl.h" +#include "util-host-info.h" +#include "tmqh-packetpool.h" +#include "source-netmap.h" +#include "runmodes.h" + +#ifdef __SC_CUDA_SUPPORT__ + +#include "util-cuda.h" +#include "util-cuda-buffer.h" +#include "util-mpm-ac.h" +#include "util-cuda-handlers.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "util-cuda-vars.h" + +#endif /* __SC_CUDA_SUPPORT__ */ + +#ifdef HAVE_NETMAP + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if HAVE_SYS_MMAN_H +#include +#endif + +#include + +#endif /* HAVE_NETMAP */ + +#include "util-ioctl.h" + +extern intmax_t max_pending_packets; + +#ifndef HAVE_NETMAP + +TmEcode NoNetmapSupportExit(ThreadVars *, void *, void **); + +void TmModuleReceiveNetmapRegister (void) +{ + tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap"; + tmm_modules[TMM_RECEIVENETMAP].ThreadInit = NoNetmapSupportExit; + tmm_modules[TMM_RECEIVENETMAP].Func = NULL; + tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = NULL; + tmm_modules[TMM_RECEIVENETMAP].RegisterTests = NULL; + tmm_modules[TMM_RECEIVENETMAP].cap_flags = 0; + tmm_modules[TMM_RECEIVENETMAP].flags = TM_FLAG_RECEIVE_TM; +} + +/** +* \brief Registration Function for DecodeNetmap. +* \todo Unit tests are needed for this module. +*/ +void TmModuleDecodeNetmapRegister (void) +{ + tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap"; + tmm_modules[TMM_DECODENETMAP].ThreadInit = NoNetmapSupportExit; + tmm_modules[TMM_DECODENETMAP].Func = NULL; + tmm_modules[TMM_DECODENETMAP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_DECODENETMAP].ThreadDeinit = NULL; + tmm_modules[TMM_DECODENETMAP].RegisterTests = NULL; + tmm_modules[TMM_DECODENETMAP].cap_flags = 0; + tmm_modules[TMM_DECODENETMAP].flags = TM_FLAG_DECODE_TM; +} + +/** +* \brief this function prints an error message and exits. +*/ +TmEcode NoNetmapSupportExit(ThreadVars *tv, void *initdata, void **data) +{ + SCLogError(SC_ERR_NO_NETMAP,"Error creating thread %s: you do not have " + "support for netmap enabled, please recompile " + "with --enable-netmap", tv->name); + exit(EXIT_FAILURE); +} + +#else /* We have NETMAP support */ + +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +#define POLL_TIMEOUT 100 + +#if defined(__linux__) +#define POLL_EVENTS (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL) + +#ifndef IFF_PPROMISC +#define IFF_PPROMISC IFF_PROMISC +#endif + +#else +#define POLL_EVENTS (POLLHUP|POLLERR|POLLNVAL) +#endif + +enum { + NETMAP_OK, + NETMAP_FAILURE, +}; + +enum { + NETMAP_FLAG_ZERO_COPY = 1, +}; + +/** + * \brief Netmap ring isntance. + */ +typedef struct NetmapRing +{ + int fd; + struct netmap_ring *rx; + struct netmap_ring *tx; + int dst_ring_from; + int dst_ring_to; + int dst_next_ring; + SCSpinlock tx_lock; +} NetmapRing; + +/** + * \brief Netmap device instance. + */ +typedef struct NetmapDevice_ +{ + char ifname[IFNAMSIZ]; + void *mem; + size_t memsize; + struct netmap_if *nif; + int rings_cnt; + int rx_rings_cnt; + int tx_rings_cnt; + /* hw rings + sw ring */ + NetmapRing *rings; + unsigned int ref; + SC_ATOMIC_DECLARE(unsigned int, threads_run); + TAILQ_ENTRY(NetmapDevice_) next; +} NetmapDevice; + +/** + * \brief Module thread local variables. + */ +typedef struct NetmapThreadVars_ +{ + /* receive inteface */ + NetmapDevice *ifsrc; + /* dst interface for IPS mode */ + NetmapDevice *ifdst; + + int src_ring_from; + int src_ring_to; + int thread_idx; + int flags; + struct bpf_program bpf_prog; + + /* internal shit */ + TmSlot *slot; + ThreadVars *tv; + LiveDevice *livedev; + + /* copy from config */ + int copy_mode; + ChecksumValidationMode checksum_mode; + + /* counters */ + uint64_t pkts; + uint64_t bytes; + uint64_t drops; + uint16_t capture_kernel_packets; + uint16_t capture_kernel_drops; + + +} NetmapThreadVars; + +typedef TAILQ_HEAD(NetmapDeviceList_, NetmapDevice_) NetmapDeviceList; + +static NetmapDeviceList netmap_devlist = TAILQ_HEAD_INITIALIZER(netmap_devlist); +static SCMutex netmap_devlist_lock = SCMUTEX_INITIALIZER; + +/** \brief get RSS RX-queue count + * \retval rx_rings RSS RX queue count or 1 on error + */ +int NetmapGetRSSCount(const char *ifname) +{ + struct nmreq nm_req; + int rx_rings = 1; + + SCMutexLock(&netmap_devlist_lock); + + /* open netmap */ + int fd = open("/dev/netmap", O_RDWR); + if (fd == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't open netmap device, error %s", + strerror(errno)); + goto error_open; + } + + /* query netmap info */ + memset(&nm_req, 0, sizeof(nm_req)); + strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name)); + nm_req.nr_version = NETMAP_API; + + if (ioctl(fd, NIOCGINFO, &nm_req) != 0) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't query netmap for %s, error %s", + ifname, strerror(errno)); + goto error_fd; + }; + + rx_rings = nm_req.nr_rx_rings; + +error_fd: + close(fd); +error_open: + SCMutexUnlock(&netmap_devlist_lock); + return rx_rings; +} + +/** + * \brief Open interface in netmap mode. + * \param ifname Interface name. + * \param promisc Enable promiscuous mode. + * \param dev Pointer to requested netmap device instance. + * \param verbose Verbose error logging. + * \return Zero on success. + */ +static int NetmapOpen(char *ifname, int promisc, NetmapDevice **pdevice, int verbose) +{ + NetmapDevice *pdev = NULL; + struct nmreq nm_req; + + *pdevice = NULL; + + SCMutexLock(&netmap_devlist_lock); + + /* search interface in our already opened list */ + TAILQ_FOREACH(pdev, &netmap_devlist, next) { + if (strcmp(ifname, pdev->ifname) == 0) { + *pdevice = pdev; + pdev->ref++; + SCMutexUnlock(&netmap_devlist_lock); + return 0; + } + } + + /* not found, create new record */ + pdev = SCMalloc(sizeof(*pdev)); + if (unlikely(pdev == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + goto error; + } + + memset(pdev, 0, sizeof(*pdev)); + SC_ATOMIC_INIT(pdev->threads_run); + strlcpy(pdev->ifname, ifname, sizeof(pdev->ifname)); + + /* open netmap */ + int fd = open("/dev/netmap", O_RDWR); + if (fd == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't open netmap device, error %s", + strerror(errno)); + goto error_pdev; + } + + /* check interface is up */ + int if_flags = GetIfaceFlags(ifname); + if (if_flags == -1) { + if (verbose) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Can not access to interface '%s'", + ifname); + } + goto error_fd; + } + if ((if_flags & IFF_UP) == 0) { + SCLogWarning(SC_ERR_NETMAP_CREATE, "Interface '%s' is down", ifname); + goto error_fd; + } + /* if needed, try to set iface in promisc mode */ + if (promisc && (if_flags & (IFF_PROMISC|IFF_PPROMISC)) == 0) { + if_flags |= IFF_PPROMISC; + SetIfaceFlags(ifname, if_flags); + } + + /* query netmap info */ + memset(&nm_req, 0, sizeof(nm_req)); + strlcpy(nm_req.nr_name, ifname, sizeof(nm_req.nr_name)); + nm_req.nr_version = NETMAP_API; + + if (ioctl(fd, NIOCGINFO, &nm_req) != 0) { + if (verbose) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't query netmap for %s, error %s", + ifname, strerror(errno)); + } + goto error_fd; + }; + + pdev->memsize = nm_req.nr_memsize; + pdev->rx_rings_cnt = nm_req.nr_rx_rings; + pdev->tx_rings_cnt = nm_req.nr_tx_rings; + pdev->rings_cnt = max(pdev->rx_rings_cnt, pdev->tx_rings_cnt); + + /* hw rings + sw ring */ + pdev->rings = SCMalloc(sizeof(*pdev->rings) * (pdev->rings_cnt + 1)); + if (unlikely(pdev->rings == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + goto error_fd; + } + memset(pdev->rings, 0, sizeof(*pdev->rings) * (pdev->rings_cnt + 1)); + + /* open individual instance for each ring */ + int success_cnt = 0; + for (int i = 0; i <= pdev->rings_cnt; i++) { + NetmapRing *pring = &pdev->rings[i]; + pring->fd = open("/dev/netmap", O_RDWR); + if (pring->fd == -1) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't open netmap device: %s", + strerror(errno)); + break; + } + + if (i < pdev->rings_cnt) { + nm_req.nr_flags = NR_REG_ONE_NIC; + nm_req.nr_ringid = i | NETMAP_NO_TX_POLL; + } else { + nm_req.nr_flags = NR_REG_SW; + nm_req.nr_ringid = NETMAP_NO_TX_POLL; + } + if (ioctl(pring->fd, NIOCREGIF, &nm_req) != 0) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't register %s with netmap: %s", + ifname, strerror(errno)); + break; + } + + if (pdev->mem == NULL) { + pdev->mem = mmap(0, pdev->memsize, PROT_WRITE | PROT_READ, + MAP_SHARED, pring->fd, 0); + if (pdev->mem == MAP_FAILED) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Couldn't mmap netmap device: %s", + strerror(errno)); + break; + } + pdev->nif = NETMAP_IF(pdev->mem, nm_req.nr_offset); + } + + if ((i < pdev->rx_rings_cnt) || (i == pdev->rings_cnt)) { + pring->rx = NETMAP_RXRING(pdev->nif, i); + } + if ((i < pdev->tx_rings_cnt) || (i == pdev->rings_cnt)) { + pring->tx = NETMAP_TXRING(pdev->nif, i); + } + SCSpinInit(&pring->tx_lock, 0); + success_cnt++; + } + + if (success_cnt != (pdev->rings_cnt + 1)) { + for(int i = 0; i < success_cnt; i++) { + close(pdev->rings[i].fd); + } + if (pdev->mem) { + munmap(pdev->mem, pdev->memsize); + } + SCFree(pdev->rings); + goto error_fd; + } + + close(fd); + *pdevice = pdev; + + TAILQ_INSERT_TAIL(&netmap_devlist, pdev, next); + SCMutexUnlock(&netmap_devlist_lock); + + return 0; + +error_fd: + close(fd); +error_pdev: + SCFree(pdev); +error: + SCMutexUnlock(&netmap_devlist_lock); + return -1; +} + +/** + * \brief Close or dereference netmap device instance. + * \param pdev Netmap device instance. + * \return Zero on success. + */ +static int NetmapClose(NetmapDevice *dev) +{ + NetmapDevice *pdev, *tmp; + + SCMutexLock(&netmap_devlist_lock); + + TAILQ_FOREACH_SAFE(pdev, &netmap_devlist, next, tmp) { + if (pdev == dev) { + pdev->ref--; + if (!pdev->ref) { + munmap(pdev->mem, pdev->memsize); + // First close SW ring (https://github.com/luigirizzo/netmap/issues/144) + for (int i = pdev->rings_cnt; i >= 0; i--) { + NetmapRing *pring = &pdev->rings[i]; + close(pring->fd); + SCSpinDestroy(&pring->tx_lock); + } + SCFree(pdev->rings); + TAILQ_REMOVE(&netmap_devlist, pdev, next); + SCFree(pdev); + } + SCMutexUnlock(&netmap_devlist_lock); + return 0; + } + } + + SCMutexUnlock(&netmap_devlist_lock); + return -1; +} + +/** + * \brief PcapDumpCounters + * \param ntv + */ +static inline void NetmapDumpCounters(NetmapThreadVars *ntv) +{ + StatsAddUI64(ntv->tv, ntv->capture_kernel_packets, ntv->pkts); + StatsAddUI64(ntv->tv, ntv->capture_kernel_drops, ntv->drops); + (void) SC_ATOMIC_ADD(ntv->livedev->drop, ntv->drops); + (void) SC_ATOMIC_ADD(ntv->livedev->pkts, ntv->pkts); + ntv->drops = 0; + ntv->pkts = 0; +} + +/** + * \brief Init function for ReceiveNetmap. + * \param tv pointer to ThreadVars + * \param initdata pointer to the interface passed from the user + * \param data pointer gets populated with NetmapThreadVars + */ +static TmEcode ReceiveNetmapThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + SCEnter(); + NetmapIfaceConfig *aconf = initdata; + + if (initdata == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); + SCReturnInt(TM_ECODE_FAILED); + } + + NetmapThreadVars *ntv = SCMalloc(sizeof(*ntv)); + if (unlikely(ntv == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + goto error; + } + memset(ntv, 0, sizeof(*ntv)); + + ntv->tv = tv; + ntv->checksum_mode = aconf->in.checksum_mode; + ntv->copy_mode = aconf->in.copy_mode; + + ntv->livedev = LiveGetDevice(aconf->iface_name); + if (ntv->livedev == NULL) { + SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); + goto error_ntv; + } + + if (NetmapOpen(aconf->in.iface, aconf->in.promisc, &ntv->ifsrc, 1) != 0) { + goto error_ntv; + } + + if (unlikely(!aconf->in.sw_ring && !ntv->ifsrc->rx_rings_cnt)) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Input interface '%s' does not have Rx rings", + aconf->iface_name); + goto error_src; + } + + if (unlikely(aconf->in.sw_ring && aconf->in.threads > 1)) { + SCLogError(SC_ERR_INVALID_VALUE, + "Interface '%s+'. " + "Thread count can't be greater than 1 for SW ring.", + aconf->iface_name); + goto error_src; + } else if (unlikely(aconf->in.threads > ntv->ifsrc->rx_rings_cnt)) { + SCLogError(SC_ERR_INVALID_VALUE, + "Thread count can't be greater than Rx ring count. " + "Configured %d threads for interface '%s' with %d Rx rings.", + aconf->in.threads, aconf->iface_name, ntv->ifsrc->rx_rings_cnt); + goto error_src; + } + + if (aconf->in.sw_ring) { + ntv->thread_idx = 0; + } else { + do { + ntv->thread_idx = SC_ATOMIC_GET(ntv->ifsrc->threads_run); + } while (SC_ATOMIC_CAS(&ntv->ifsrc->threads_run, ntv->thread_idx, ntv->thread_idx + 1) == 0); + } + + /* calculate thread rings binding */ + if (aconf->in.sw_ring) { + ntv->src_ring_from = ntv->src_ring_to = ntv->ifsrc->rings_cnt; + } else { + int tmp = (ntv->ifsrc->rx_rings_cnt + 1) / aconf->in.threads; + ntv->src_ring_from = ntv->thread_idx * tmp; + ntv->src_ring_to = ntv->src_ring_from + tmp - 1; + if (ntv->thread_idx == (aconf->in.threads - 1)) { + ntv->src_ring_to = ntv->ifsrc->rx_rings_cnt - 1; + } + } + SCLogDebug("netmap: %s thread:%d rings:%d-%d", aconf->iface_name, + ntv->thread_idx, ntv->src_ring_from, ntv->src_ring_to); + + if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) { + if (NetmapOpen(aconf->out.iface, aconf->out.promisc, &ntv->ifdst, 1) != 0) { + goto error_src; + } + + if (unlikely(!aconf->out.sw_ring && !ntv->ifdst->tx_rings_cnt)) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Output interface '%s' does not have Tx rings", + aconf->out.iface); + goto error_dst; + } + + /* calculate dst rings bindings */ + for (int i = ntv->src_ring_from; i <= ntv->src_ring_to; i++) { + NetmapRing *ring = &ntv->ifsrc->rings[i]; + if (aconf->out.sw_ring) { + ring->dst_ring_from = ring->dst_ring_to = ntv->ifdst->rings_cnt; + } else if (ntv->ifdst->tx_rings_cnt > ntv->ifsrc->rx_rings_cnt) { + int tmp = (ntv->ifdst->tx_rings_cnt + 1) / ntv->ifsrc->rx_rings_cnt; + ring->dst_ring_from = i * tmp; + ring->dst_ring_to = ring->dst_ring_from + tmp - 1; + if (i == (ntv->src_ring_to - 1)) { + ring->dst_ring_to = ntv->ifdst->tx_rings_cnt - 1; + } + } else { + ring->dst_ring_from = ring->dst_ring_to = + i % ntv->ifdst->tx_rings_cnt; + } + ring->dst_next_ring = ring->dst_ring_from; + + SCLogDebug("netmap: %s(%d)->%s(%d-%d)", + aconf->in.iface, i, aconf->out.iface, + ring->dst_ring_from, ring->dst_ring_to); + } + } + + /* basic counters */ + ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ntv->tv); + ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ntv->tv); + + /* enable zero-copy mode for workers runmode */ + char const *active_runmode = RunmodeGetActive(); + if ((aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) && active_runmode && + strcmp("workers", active_runmode) == 0) { + ntv->flags |= NETMAP_FLAG_ZERO_COPY; + SCLogPerf("Enabling zero copy mode for %s->%s", + aconf->in.iface, aconf->out.iface); + } else { + uint16_t ring_size = ntv->ifsrc->rings[0].rx->num_slots; + if (ring_size > max_pending_packets) { + SCLogError(SC_ERR_NETMAP_CREATE, + "Packet pool size (%" PRIuMAX ") must be greater or equal than %s ring size (%" PRIu16 "). " + "Increase max_pending_packets option.", + max_pending_packets, aconf->iface_name, ring_size); + goto error_dst; + } + } + + if (aconf->in.bpf_filter) { + SCLogConfig("Using BPF '%s' on iface '%s'", + aconf->in.bpf_filter, ntv->ifsrc->ifname); + if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */ + LINKTYPE_ETHERNET, /* linktype_arg */ + &ntv->bpf_prog, /* program */ + aconf->in.bpf_filter, /* const char *buf */ + 1, /* optimize */ + PCAP_NETMASK_UNKNOWN /* mask */ + ) == -1) + { + SCLogError(SC_ERR_NETMAP_CREATE, "Filter compilation failed."); + goto error_dst; + } + } + + *data = (void *)ntv; + aconf->DerefFunc(aconf); + SCReturnInt(TM_ECODE_OK); + +error_dst: + if (aconf->in.copy_mode != NETMAP_COPY_MODE_NONE) { + NetmapClose(ntv->ifdst); + } +error_src: + NetmapClose(ntv->ifsrc); +error_ntv: + SCFree(ntv); +error: + aconf->DerefFunc(aconf); + SCReturnInt(TM_ECODE_FAILED); +} + +/** + * \brief Output packet to destination interface or drop. + * \param ntv Thread local variables. + * \param p Source packet. + */ +static TmEcode NetmapWritePacket(NetmapThreadVars *ntv, Packet *p) +{ + if (ntv->copy_mode == NETMAP_COPY_MODE_IPS) { + if (PACKET_TEST_ACTION(p, ACTION_DROP)) { + return TM_ECODE_OK; + } + } + + /* map src ring_id to dst ring_id */ + NetmapRing *rxring = &ntv->ifsrc->rings[p->netmap_v.ring_id]; + NetmapRing *txring = &ntv->ifdst->rings[p->netmap_v.dst_ring_id]; + + SCSpinLock(&txring->tx_lock); + + if (!nm_ring_space(txring->tx)) { + ntv->drops++; + SCSpinUnlock(&txring->tx_lock); + return TM_ECODE_FAILED; + } + + struct netmap_slot *ts = &txring->tx->slot[txring->tx->cur]; + + if (ntv->flags & NETMAP_FLAG_ZERO_COPY) { + struct netmap_slot *rs = &rxring->rx->slot[p->netmap_v.slot_id]; + + /* swap slot buffers */ + uint32_t tmp_idx; + tmp_idx = ts->buf_idx; + ts->buf_idx = rs->buf_idx; + rs->buf_idx = tmp_idx; + + ts->len = rs->len; + + ts->flags |= NS_BUF_CHANGED; + rs->flags |= NS_BUF_CHANGED; + } else { + unsigned char *slot_data = (unsigned char *)NETMAP_BUF(txring->tx, ts->buf_idx); + memcpy(slot_data, GET_PKT_DATA(p), GET_PKT_LEN(p)); + ts->len = GET_PKT_LEN(p); + ts->flags |= NS_BUF_CHANGED; + } + + txring->tx->head = txring->tx->cur = nm_ring_next(txring->tx, txring->tx->cur); + if ((ntv->flags & NETMAP_FLAG_ZERO_COPY) == 0) { + ioctl(txring->fd, NIOCTXSYNC, 0); + } + + SCSpinUnlock(&txring->tx_lock); + + return TM_ECODE_OK; +} + +/** + * \brief Packet release routine. + * \param p Packet. + */ +static void NetmapReleasePacket(Packet *p) +{ + NetmapThreadVars *ntv = (NetmapThreadVars *)p->netmap_v.ntv; + + /* Need to be in copy mode and need to detect early release + where Ethernet header could not be set (and pseudo packet) */ + if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { + NetmapWritePacket(ntv, p); + } + + PacketFreeOrRelease(p); +} + +/** + * \brief Read packets from ring and pass them further. + * \param ntv Thread local variables. + * \param ring_id Ring id to read. + */ +static int NetmapRingRead(NetmapThreadVars *ntv, int ring_id) +{ + SCEnter(); + + NetmapRing *ring = &ntv->ifsrc->rings[ring_id]; + struct netmap_ring *rx = ring->rx; + uint32_t avail = nm_ring_space(rx); + uint32_t cur = rx->cur; + + if (!(ntv->flags & NETMAP_FLAG_ZERO_COPY)) { + PacketPoolWaitForN(avail); + } + + while (likely(avail-- > 0)) { + struct netmap_slot *slot = &rx->slot[cur]; + unsigned char *slot_data = (unsigned char *)NETMAP_BUF(rx, slot->buf_idx); + + if (ntv->bpf_prog.bf_len) { + struct pcap_pkthdr pkthdr = { {0, 0}, slot->len, slot->len }; + if (pcap_offline_filter(&ntv->bpf_prog, &pkthdr, slot_data) == 0) { + /* rejected by bpf */ + cur = nm_ring_next(rx, cur); + continue; + } + } + + Packet *p = PacketPoolGetPacket(); + if (unlikely(p == NULL)) { + SCReturnInt(NETMAP_FAILURE); + } + + PKT_SET_SRC(p, PKT_SRC_WIRE); + p->livedev = ntv->livedev; + p->datalink = LINKTYPE_ETHERNET; + p->ts = rx->ts; + ntv->pkts++; + ntv->bytes += slot->len; + + /* checksum validation */ + if (ntv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ntv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { + if (ntv->livedev->ignore_checksum) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (ChecksumAutoModeCheck(ntv->pkts, + SC_ATOMIC_GET(ntv->livedev->pkts), + SC_ATOMIC_GET(ntv->livedev->invalid_checksums))) { + ntv->livedev->ignore_checksum = 1; + p->flags |= PKT_IGNORE_CHECKSUM; + } + } + + if (ntv->flags & NETMAP_FLAG_ZERO_COPY) { + if (PacketSetData(p, slot_data, slot->len) == -1) { + TmqhOutputPacketpool(ntv->tv, p); + SCReturnInt(NETMAP_FAILURE); + } + } else { + if (PacketCopyData(p, slot_data, slot->len) == -1) { + TmqhOutputPacketpool(ntv->tv, p); + SCReturnInt(NETMAP_FAILURE); + } + } + + p->ReleasePacket = NetmapReleasePacket; + p->netmap_v.ring_id = ring_id; + p->netmap_v.slot_id = cur; + p->netmap_v.dst_ring_id = ring->dst_next_ring; + p->netmap_v.ntv = ntv; + + if (ring->dst_ring_from != ring->dst_ring_to) { + ring->dst_next_ring++; + if (ring->dst_next_ring == ring->dst_ring_to) { + ring->dst_next_ring = ring->dst_ring_from; + } + } + + SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", + GET_PKT_LEN(p), p, GET_PKT_DATA(p)); + + if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) { + TmqhOutputPacketpool(ntv->tv, p); + SCReturnInt(NETMAP_FAILURE); + } + + cur = nm_ring_next(rx, cur); + } + rx->head = rx->cur = cur; + + SCReturnInt(NETMAP_OK); +} + +/** + * \brief Main netmap reading loop function + */ +static TmEcode ReceiveNetmapLoop(ThreadVars *tv, void *data, void *slot) +{ + SCEnter(); + + TmSlot *s = (TmSlot *)slot; + NetmapThreadVars *ntv = (NetmapThreadVars *)data; + struct pollfd *fds; + int rings_count = ntv->src_ring_to - ntv->src_ring_from + 1; + + ntv->slot = s->slot_next; + + fds = SCMalloc(sizeof(*fds) * rings_count); + if (unlikely(fds == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + SCReturnInt(TM_ECODE_FAILED); + } + + for (int i = 0; i < rings_count; i++) { + fds[i].fd = ntv->ifsrc->rings[ntv->src_ring_from + i].fd; + fds[i].events = POLLIN; + } + + for(;;) { + if (suricata_ctl_flags != 0) { + break; + } + + /* make sure we have at least one packet in the packet pool, + * to prevent us from alloc'ing packets at line rate */ + PacketPoolWait(); + + int r = poll(fds, rings_count, POLL_TIMEOUT); + + if (r < 0) { + /* error */ + if(errno != EINTR) + SCLogError(SC_ERR_NETMAP_READ, + "Error polling netmap from iface '%s': (%d" PRIu32 ") %s", + ntv->ifsrc->ifname, errno, strerror(errno)); + continue; + } else if (r == 0) { + /* no events, timeout */ + SCLogDebug("(%s:%d-%d) Poll timeout", ntv->ifsrc->ifname, + ntv->src_ring_from, ntv->src_ring_to); + + /* poll timed out, lets see if we need to inject a fake packet */ + TmThreadsCaptureInjectPacket(tv, ntv->slot, NULL); + continue; + } + + for (int i = 0; i < rings_count; i++) { + if (fds[i].revents & POLL_EVENTS) { + if (fds[i].revents & POLLERR) { + SCLogError(SC_ERR_NETMAP_READ, + "Error reading data from iface '%s': (%d" PRIu32 ") %s", + ntv->ifsrc->ifname, errno, strerror(errno)); + } else if (fds[i].revents & POLLNVAL) { + SCLogError(SC_ERR_NETMAP_READ, + "Invalid polling request"); + } + continue; + } + + if (likely(fds[i].revents & POLLIN)) { + int src_ring_id = ntv->src_ring_from + i; + NetmapRingRead(ntv, src_ring_id); + + if ((ntv->copy_mode != NETMAP_COPY_MODE_NONE) && + (ntv->flags & NETMAP_FLAG_ZERO_COPY)) { + + NetmapRing *src_ring = &ntv->ifsrc->rings[src_ring_id]; + + /* sync dst tx rings */ + for (int j = src_ring->dst_ring_from; j <= src_ring->dst_ring_to; j++) { + NetmapRing *dst_ring = &ntv->ifdst->rings[j]; + /* if locked, another loop already do sync */ + if (SCSpinTrylock(&dst_ring->tx_lock) == 0) { + ioctl(dst_ring->fd, NIOCTXSYNC, 0); + SCSpinUnlock(&dst_ring->tx_lock); + } + } + } + } + } + + NetmapDumpCounters(ntv); + StatsSyncCountersIfSignalled(tv); + } + + SCFree(fds); + StatsSyncCountersIfSignalled(tv); + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief This function prints stats to the screen at exit. + * \param tv pointer to ThreadVars + * \param data pointer that gets cast into NetmapThreadVars for ntv + */ +static void ReceiveNetmapThreadExitStats(ThreadVars *tv, void *data) +{ + SCEnter(); + NetmapThreadVars *ntv = (NetmapThreadVars *)data; + + NetmapDumpCounters(ntv); + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 ", bytes %" PRIu64 "", + tv->name, + StatsGetLocalCounterValue(tv, ntv->capture_kernel_packets), + StatsGetLocalCounterValue(tv, ntv->capture_kernel_drops), + ntv->bytes); +} + +/** + * \brief + * \param tv + * \param data Pointer to NetmapThreadVars. + */ +static TmEcode ReceiveNetmapThreadDeinit(ThreadVars *tv, void *data) +{ + SCEnter(); + + NetmapThreadVars *ntv = (NetmapThreadVars *)data; + + if (ntv->ifsrc) { + NetmapClose(ntv->ifsrc); + ntv->ifsrc = NULL; + } + if (ntv->ifdst) { + NetmapClose(ntv->ifdst); + ntv->ifdst = NULL; + } + if (ntv->bpf_prog.bf_insns) { + pcap_freecode(&ntv->bpf_prog); + } + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief Prepare netmap decode thread. + * \param tv Thread local avariables. + * \param initdata Thread config. + * \param data Pointer to DecodeThreadVars placed here. + */ +static TmEcode DecodeNetmapThreadInit(ThreadVars *tv, void *initdata, void **data) +{ + SCEnter(); + DecodeThreadVars *dtv = NULL; + + dtv = DecodeThreadVarsAlloc(tv); + + if (dtv == NULL) + SCReturnInt(TM_ECODE_FAILED); + + DecodeRegisterPerfCounters(dtv, tv); + + *data = (void *)dtv; + +#ifdef __SC_CUDA_SUPPORT__ + if (CudaThreadVarsInit(&dtv->cuda_vars) < 0) + SCReturnInt(TM_ECODE_FAILED); +#endif + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief This function passes off to link type decoders. + * + * DecodeNetmap reads packets from the PacketQueue and passes + * them off to the proper link type decoder. + * + * \param t pointer to ThreadVars + * \param p pointer to the current packet + * \param data pointer that gets cast into NetmapThreadVars for ntv + * \param pq pointer to the current PacketQueue + * \param postpq + */ +static TmEcode DecodeNetmap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + SCEnter(); + + DecodeThreadVars *dtv = (DecodeThreadVars *)data; + + /* XXX HACK: flow timeout can call us for injected pseudo packets + * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ + if (p->flags & PKT_PSEUDO_STREAM_END) + SCReturnInt(TM_ECODE_OK); + + /* update counters */ + DecodeUpdatePacketCounters(tv, dtv, p); + + DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + + PacketDecodeFinalize(tv, dtv, p); + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief + * \param tv + * \param data Pointer to DecodeThreadVars. + */ +static TmEcode DecodeNetmapThreadDeinit(ThreadVars *tv, void *data) +{ + SCEnter(); + + if (data != NULL) + DecodeThreadVarsFree(tv, data); + + SCReturnInt(TM_ECODE_OK); +} + +/** + * \brief Registration Function for RecieveNetmap. + */ +void TmModuleReceiveNetmapRegister(void) +{ + tmm_modules[TMM_RECEIVENETMAP].name = "ReceiveNetmap"; + tmm_modules[TMM_RECEIVENETMAP].ThreadInit = ReceiveNetmapThreadInit; + tmm_modules[TMM_RECEIVENETMAP].Func = NULL; + tmm_modules[TMM_RECEIVENETMAP].PktAcqLoop = ReceiveNetmapLoop; + tmm_modules[TMM_RECEIVENETMAP].PktAcqBreakLoop = NULL; + tmm_modules[TMM_RECEIVENETMAP].ThreadExitPrintStats = ReceiveNetmapThreadExitStats; + tmm_modules[TMM_RECEIVENETMAP].ThreadDeinit = ReceiveNetmapThreadDeinit; + tmm_modules[TMM_RECEIVENETMAP].RegisterTests = NULL; + tmm_modules[TMM_RECEIVENETMAP].cap_flags = SC_CAP_NET_RAW; + tmm_modules[TMM_RECEIVENETMAP].flags = TM_FLAG_RECEIVE_TM; +} + +/** + * \brief Registration Function for DecodeNetmap. + */ +void TmModuleDecodeNetmapRegister(void) +{ + tmm_modules[TMM_DECODENETMAP].name = "DecodeNetmap"; + tmm_modules[TMM_DECODENETMAP].ThreadInit = DecodeNetmapThreadInit; + tmm_modules[TMM_DECODENETMAP].Func = DecodeNetmap; + tmm_modules[TMM_DECODENETMAP].ThreadExitPrintStats = NULL; + tmm_modules[TMM_DECODENETMAP].ThreadDeinit = DecodeNetmapThreadDeinit; + tmm_modules[TMM_DECODENETMAP].RegisterTests = NULL; + tmm_modules[TMM_DECODENETMAP].cap_flags = 0; + tmm_modules[TMM_DECODENETMAP].flags = TM_FLAG_DECODE_TM; +} + +#endif /* HAVE_NETMAP */ +/* eof */ +/** +* @} +*/ diff --git a/src/source-netmap.h b/src/source-netmap.h new file mode 100644 index 000000000000..00b0b442743b --- /dev/null +++ b/src/source-netmap.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** +* \file +* +* \author Aleksey Katargin +*/ + +#ifndef __SOURCE_NETMAP_H__ +#define __SOURCE_NETMAP_H__ + +#include "queue.h" + +/* copy modes */ +enum { + NETMAP_COPY_MODE_NONE, + NETMAP_COPY_MODE_TAP, + NETMAP_COPY_MODE_IPS, +}; + +#define NETMAP_IFACE_NAME_LENGTH 48 + +typedef struct NetmapIfaceSettings_ +{ + /* real inner interface name */ + char iface[NETMAP_IFACE_NAME_LENGTH]; + + int threads; + /* sw ring flag for out_iface */ + int sw_ring; + int promisc; + int copy_mode; + ChecksumValidationMode checksum_mode; + char *bpf_filter; +} NetmapIfaceSettings; + +typedef struct NetmapIfaceConfig_ +{ + /* semantic interface name */ + char iface_name[NETMAP_IFACE_NAME_LENGTH]; + + /* settings for out capture device*/ + NetmapIfaceSettings in; + + /* semantic interface name */ + char *out_iface_name; + + /* settings for outgoing iface for IPS/TAP */ + NetmapIfaceSettings out; + + SC_ATOMIC_DECLARE(unsigned int, ref); + void (*DerefFunc)(void *); +} NetmapIfaceConfig; + +typedef struct NetmapPacketVars_ +{ + int ring_id; + int slot_id; + int dst_ring_id; + /* NetmapThreadVars */ + void *ntv; +} NetmapPacketVars; + +int NetmapGetRSSCount(const char *ifname); + +void TmModuleReceiveNetmapRegister (void); +void TmModuleDecodeNetmapRegister (void); + +#endif /* __SOURCE_NETMAP_H__ */ diff --git a/src/source-nflog.c b/src/source-nflog.c index f7a36fa16af0..858ad76c7918 100644 --- a/src/source-nflog.c +++ b/src/source-nflog.c @@ -117,6 +117,7 @@ void TmModuleReceiveNFLOGRegister (void) tmm_modules[TMM_RECEIVENFLOG].ThreadInit = ReceiveNFLOGThreadInit; tmm_modules[TMM_RECEIVENFLOG].Func = NULL; tmm_modules[TMM_RECEIVENFLOG].PktAcqLoop = ReceiveNFLOGLoop; + tmm_modules[TMM_RECEIVENFLOG].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENFLOG].ThreadExitPrintStats = ReceiveNFLOGThreadExitStats; tmm_modules[TMM_RECEIVENFLOG].ThreadDeinit = ReceiveNFLOGThreadDeinit; tmm_modules[TMM_RECEIVENFLOG].RegisterTests = NULL; @@ -307,14 +308,10 @@ TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, void *initdata, void **data) } #ifdef PACKET_STATISTICS - ntv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ntv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ntv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ntv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ntv->tv); + ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ntv->tv); #endif char *active_runmode = RunmodeGetActive(); @@ -465,7 +462,7 @@ TmEcode ReceiveNFLOGLoop(ThreadVars *tv, void *data, void *slot) SCLogWarning(SC_ERR_NFLOG_HANDLE_PKT, "nflog_handle_packet error %" PRId32 "", ret); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); @@ -503,10 +500,7 @@ TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-nfq.c b/src/source-nfq.c index 5014d343d7d7..a53d080c3652 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -131,12 +131,13 @@ typedef struct NFQThreadVars_ char *data; /** Per function and thread data */ int datalen; /** Length of per function and thread data */ + CaptureStats stats; } NFQThreadVars; /* shared vars for all for nfq queues and threads */ static NFQGlobalVars nfq_g; -static NFQThreadVars nfq_t[NFQ_MAX_QUEUE]; -static NFQQueueVars nfq_q[NFQ_MAX_QUEUE]; +static NFQThreadVars g_nfq_t[NFQ_MAX_QUEUE]; +static NFQQueueVars g_nfq_q[NFQ_MAX_QUEUE]; static uint16_t receive_queue_num = 0; static SCMutex nfq_init_lock; @@ -167,6 +168,8 @@ typedef struct NFQCnf_ { NFQMode mode; uint32_t mark; uint32_t mask; + uint32_t bypass_mark; + uint32_t bypass_mask; uint32_t next_queue; uint32_t flags; uint8_t batchcount; @@ -184,6 +187,7 @@ void TmModuleReceiveNFQRegister (void) tmm_modules[TMM_RECEIVENFQ].ThreadInit = ReceiveNFQThreadInit; tmm_modules[TMM_RECEIVENFQ].Func = NULL; tmm_modules[TMM_RECEIVENFQ].PktAcqLoop = ReceiveNFQLoop; + tmm_modules[TMM_RECEIVENFQ].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = ReceiveNFQThreadExitStats; tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = ReceiveNFQThreadDeinit; tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL; @@ -260,6 +264,14 @@ void NFQInitConfig(char quiet) nfq_config.mask = (uint32_t)value; } + if ((ConfGetInt("nfq.bypass-mark", &value)) == 1) { + nfq_config.bypass_mark = (uint32_t)value; + } + + if ((ConfGetInt("nfq.bypass-mask", &value)) == 1) { + nfq_config.bypass_mask = (uint32_t)value; + } + if ((ConfGetInt("nfq.route-queue", &value)) == 1) { nfq_config.next_queue = ((uint32_t)value) << 16; } @@ -421,6 +433,7 @@ int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) //p->nfq_v.hw_protocol = ntohs(p->nfq_v.ph->hw_protocol); p->nfq_v.hw_protocol = ph->hw_protocol; } + /* coverity[missing_lock] */ p->nfq_v.mark = nfq_get_nfmark(tb); if (nfq_config.mode == NFQ_REPEAT_MODE) { if ((nfq_config.mark & nfq_config.mask) == @@ -471,7 +484,7 @@ int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) } ret = nfq_get_timestamp(tb, &p->ts); - if (ret != 0) { + if (ret != 0 || p->ts.tv_sec == 0) { memset (&p->ts, 0, sizeof(struct timeval)); gettimeofday(&p->ts, NULL); } @@ -489,6 +502,37 @@ static void NFQReleasePacket(Packet *p) PacketFreeOrRelease(p); } +/** + * \brief bypass callback function for NFQ + * + * \param p a Packet to use information from to trigger bypass + * \return 1 if bypass is successful, 0 if not + */ +static int NFQBypassCallback(Packet *p) +{ + if (IS_TUNNEL_PKT(p)) { + /* real tunnels may have multiple flows inside them, so bypass can't + * work for those. Rebuilt packets from IP fragments are fine. */ + if (p->flags & PKT_REBUILT_FRAGMENT) { + Packet *tp = p->root ? p->root : p; + SCMutexLock(&tp->tunnel_mutex); + tp->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) + | (tp->nfq_v.mark & ~nfq_config.bypass_mask); + tp->flags |= PKT_MARK_MODIFIED; + SCMutexUnlock(&tp->tunnel_mutex); + return 1; + } + return 0; + } else { + /* coverity[missing_lock] */ + p->nfq_v.mark = (nfq_config.bypass_mark & nfq_config.bypass_mask) + | (p->nfq_v.mark & ~nfq_config.bypass_mask); + p->flags |= PKT_MARK_MODIFIED; + } + + return 1; +} + static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { @@ -504,13 +548,17 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, PKT_SET_SRC(p, PKT_SRC_WIRE); p->nfq_v.nfq_index = ntv->nfq_index; + /* if bypass mask is set then we may want to bypass so set pointer */ + if (nfq_config.bypass_mask) { + p->BypassPacketsFlow = NFQBypassCallback; + } ret = NFQSetupPkt(p, qh, (void *)nfa); if (ret == -1) { #ifdef COUNTERS - NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); - nfq_q->errs++; - nfq_q->pkts++; - nfq_q->bytes += GET_PKT_LEN(p); + NFQQueueVars *q = NFQGetQueue(ntv->nfq_index); + q->errs++; + q->pkts++; + q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ /* NFQSetupPkt is issuing a verdict so we only recycle Packet and leave */ @@ -521,9 +569,9 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, p->ReleasePacket = NFQReleasePacket; #ifdef COUNTERS - NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); - nfq_q->pkts++; - nfq_q->bytes += GET_PKT_LEN(p); + NFQQueueVars *q = NFQGetQueue(ntv->nfq_index); + q->pkts++; + q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ if (ntv->slot) { @@ -539,20 +587,20 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, return 0; } -TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) +TmEcode NFQInitThread(NFQThreadVars *t, uint32_t queue_maxlen) { #ifndef OS_WIN32 struct timeval tv; int opt; #endif - NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index); - if (nfq_q == NULL) { + NFQQueueVars *q = NFQGetQueue(t->nfq_index); + if (q == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index"); return TM_ECODE_FAILED; } SCLogDebug("opening library handle"); - nfq_q->h = nfq_open(); - if (!nfq_q->h) { + q->h = nfq_open(); + if (q->h == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed"); return TM_ECODE_FAILED; } @@ -562,11 +610,11 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) /* VJ: on my Ubuntu Hardy system this fails the first time it's * run. Ignoring the error seems to have no bad effects. */ SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)"); - if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) { + if (nfq_unbind_pf(q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } - if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) { + if (nfq_unbind_pf(q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } @@ -574,23 +622,22 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6"); - if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) { + if (nfq_bind_pf(q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } - if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) { + if (nfq_bind_pf(q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } } - SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num); + SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", t->nfq_index, q->queue_num); /* pass the thread memory as a void ptr so the * callback function has access to it. */ - nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t); - if (nfq_q->qh == NULL) - { + q->qh = nfq_create_queue(q->h, q->queue_num, &NFQCallBack, (void *)t); + if (q->qh == NULL) { SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed"); return TM_ECODE_FAILED; } @@ -599,7 +646,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) /* 05DC = 1500 */ //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { - if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { + if (nfq_set_mode(q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode"); return TM_ECODE_FAILED; } @@ -609,7 +656,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen); /* non-fatal if it fails */ - if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) { + if (nfq_set_queue_maxlen(q->qh, queue_maxlen) < 0) { SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably " "doesn't support setting the queue length"); } @@ -618,18 +665,18 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) #ifndef OS_WIN32 /* set netlink buffer size to a decent value */ - nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500); + nfnl_rcvbufsiz(nfq_nfnlh(q->h), queue_maxlen * 1500); SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500); - nfq_q->nh = nfq_nfnlh(nfq_q->h); - nfq_q->fd = nfnl_fd(nfq_q->nh); - NFQMutexInit(nfq_q); + q->nh = nfq_nfnlh(q->h); + q->fd = nfnl_fd(q->nh); + NFQMutexInit(q); /* Set some netlink specific option on the socket to increase performance */ opt = 1; #ifdef NETLINK_BROADCAST_SEND_ERROR - if (setsockopt(nfq_q->fd, SOL_NETLINK, + if (setsockopt(q->fd, SOL_NETLINK, NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set netlink broadcast error: %s", @@ -639,7 +686,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) /* Don't send error about no buffer space available but drop the packets instead */ #ifdef NETLINK_NO_ENOBUFS - if (setsockopt(nfq_q->fd, SOL_NETLINK, + if (setsockopt(q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set netlink enobufs: %s", @@ -651,7 +698,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) { uint32_t flags = NFQA_CFG_F_FAIL_OPEN; uint32_t mask = NFQA_CFG_F_FAIL_OPEN; - int r = nfq_set_queue_flags(nfq_q->qh, mask, flags); + int r = nfq_set_queue_flags(q->qh, mask, flags); if (r == -1) { SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s", @@ -664,7 +711,7 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) #ifdef HAVE_NFQ_SET_VERDICT_BATCH if (runmode_workers) { - nfq_q->verdict_cache.maxlen = nfq_config.batchcount; + q->verdict_cache.maxlen = nfq_config.batchcount; } else if (nfq_config.batchcount) { SCLogError(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount is only valid in workers runmode."); } @@ -675,17 +722,17 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) tv.tv_sec = 1; tv.tv_usec = 0; - if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { + if(setsockopt(q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno)); } SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", - nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd); + q->h, q->nh, q->qh, q->fd); #else /* OS_WIN32 */ - NFQMutexInit(nfq_q); - nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - nfq_q->fd = nfq_fd(nfq_q->h); - SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd); + NFQMutexInit(q); + q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + q->fd = nfq_fd(q->h); + SCLogDebug("q->h %p, q->qh %p, q->fd %p", q->h, q->qh, q->fd); #endif /* OS_WIN32 */ return TM_ECODE_OK; @@ -707,7 +754,7 @@ TmEcode ReceiveNFQThreadInit(ThreadVars *tv, void *initdata, void **data) ntv->tv = tv; int r = NFQInitThread(ntv, (max_pending_packets * NFQ_BURST_FACTOR)); - if (r < 0) { + if (r != TM_ECODE_OK) { SCLogError(SC_ERR_NFQ_THREAD_INIT, "nfq thread failed to initialize"); SCMutexUnlock(&nfq_init_lock); @@ -755,9 +802,11 @@ TmEcode ReceiveNFQThreadDeinit(ThreadVars *t, void *data) TmEcode VerdictNFQThreadInit(ThreadVars *tv, void *initdata, void **data) { + NFQThreadVars *ntv = (NFQThreadVars *) initdata; - *data = (void *)initdata; + CaptureStatsSetup(tv, &ntv->stats); + *data = (void *)ntv; return TM_ECODE_OK; } @@ -807,14 +856,14 @@ int NFQRegisterQueue(char *queue) return -1; } if (receive_queue_num == 0) { - memset(&nfq_t, 0, sizeof(nfq_t)); - memset(&nfq_q, 0, sizeof(nfq_q)); + memset(&g_nfq_t, 0, sizeof(g_nfq_t)); + memset(&g_nfq_q, 0, sizeof(g_nfq_q)); } - ntv = &nfq_t[receive_queue_num]; + ntv = &g_nfq_t[receive_queue_num]; ntv->nfq_index = receive_queue_num; - nq = &nfq_q[receive_queue_num]; + nq = &g_nfq_q[receive_queue_num]; nq->queue_num = queue_num; receive_queue_num++; SCMutexUnlock(&nfq_init_lock); @@ -839,7 +888,7 @@ void *NFQGetQueue(int number) if (number >= receive_queue_num) return NULL; - return (void *)&nfq_q[number]; + return (void *)&g_nfq_q[number]; } /** @@ -857,7 +906,7 @@ void *NFQGetThread(int number) if (number >= receive_queue_num) return NULL; - return (void *)&nfq_t[number]; + return (void *)&g_nfq_t[number]; } /** @@ -1003,7 +1052,7 @@ TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot) } NFQRecvPkt(nq, ntv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); } @@ -1032,7 +1081,7 @@ TmEcode NFQSetVerdict(Packet *p) int ret = 0; uint32_t verdict = NF_ACCEPT; /* we could also have a direct pointer but we need to have a ref counf in this case */ - NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index; + NFQQueueVars *t = g_nfq_q + p->nfq_v.nfq_index; /** \todo add a test on validity of the entry NFQQueueVars could have been * wipeout @@ -1169,6 +1218,10 @@ TmEcode NFQSetVerdict(Packet *p) */ TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { + NFQThreadVars *ntv = (NFQThreadVars *)data; + /* update counters */ + CaptureStatsUpdate(tv, &ntv->stats, p); + int ret; /* if this is a tunnel packet we check if we are ready to verdict * already. */ @@ -1223,15 +1276,7 @@ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packet if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif + DecodeUpdatePacketCounters(tv, dtv, p); if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index d4232bcebb6c..c6b1c3bbf3d2 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -57,14 +57,11 @@ #endif /* __SC_CUDA_SUPPORT__ */ -extern uint8_t suricata_ctl_flags; extern int max_pending_packets; -//static int pcap_max_read_packets = 0; - typedef struct PcapFileGlobalVars_ { pcap_t *pcap_handle; - int (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, u_int8_t *, u_int16_t, PacketQueue *); + int (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); int datalink; struct bpf_program filter; uint64_t cnt; /** packet counter */ @@ -74,11 +71,10 @@ typedef struct PcapFileGlobalVars_ { } PcapFileGlobalVars; -/** max packets < 65536 */ -//#define PCAP_FILE_MAX_PKTS 256 - typedef struct PcapFileThreadVars_ { + uint32_t tenant_id; + /* counters */ uint32_t pkts; uint64_t bytes; @@ -107,12 +103,11 @@ TmEcode DecodePcapFileThreadDeinit(ThreadVars *tv, void *data); void TmModuleReceivePcapFileRegister (void) { - memset(&pcap_g, 0x00, sizeof(pcap_g)); - tmm_modules[TMM_RECEIVEPCAPFILE].name = "ReceivePcapFile"; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit; tmm_modules[TMM_RECEIVEPCAPFILE].Func = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqLoop = ReceivePcapFileLoop; + tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadExitPrintStats = ReceivePcapFileThreadExitStats; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit = ReceivePcapFileThreadDeinit; tmm_modules[TMM_RECEIVEPCAPFILE].RegisterTests = NULL; @@ -132,6 +127,12 @@ void TmModuleDecodePcapFileRegister (void) tmm_modules[TMM_DECODEPCAPFILE].flags = TM_FLAG_DECODE_TM; } +void PcapFileGlobalInit() +{ + memset(&pcap_g, 0x00, sizeof(pcap_g)); + SC_ATOMIC_INIT(pcap_g.invalid_checksums); +} + void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); @@ -151,6 +152,7 @@ void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) p->datalink = pcap_g.datalink; p->pcap_cnt = ++pcap_g.cnt; + p->pcap_v.tenant_id = ptv->tenant_id; ptv->pkts++; ptv->bytes += h->caplen; @@ -197,7 +199,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) ptv->cb_result = TM_ECODE_OK; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -211,10 +213,11 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) if (unlikely(r == -1)) { SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", r, pcap_geterr(pcap_g.pcap_handle)); - if (! RunModeUnixSocketIsActive()) { - /* in the error state we just kill the engine */ - EngineKill(); + if (ptv->cb_result == TM_ECODE_FAILED) { SCReturnInt(TM_ECODE_FAILED); + } + if (! RunModeUnixSocketIsActive()) { + EngineStop(); } else { pcap_close(pcap_g.pcap_handle); pcap_g.pcap_handle = NULL; @@ -235,7 +238,6 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed"); if (! RunModeUnixSocketIsActive()) { - EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else { pcap_close(pcap_g.pcap_handle); @@ -244,7 +246,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_DONE); } } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); @@ -253,8 +255,10 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); + char *tmpbpfstring = NULL; char *tmpstring = NULL; + if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); @@ -267,6 +271,16 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_FAILED); memset(ptv, 0, sizeof(PcapFileThreadVars)); + intmax_t tenant = 0; + if (ConfGetInt("pcap-file.tenant-id", &tenant) == 1) { + if (tenant > 0 && tenant < UINT_MAX) { + ptv->tenant_id = (uint32_t)tenant; + SCLogInfo("tenant %u", ptv->tenant_id); + } else { + SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant out of range"); + } + } + char errbuf[PCAP_ERRBUF_SIZE] = ""; pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf); if (pcap_g.pcap_handle == NULL) { @@ -285,14 +299,15 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) } else { SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring); - if(pcap_compile(pcap_g.pcap_handle,&pcap_g.filter,tmpbpfstring,1,0) < 0) { - SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(pcap_g.pcap_handle)); + if (pcap_compile(pcap_g.pcap_handle, &pcap_g.filter, tmpbpfstring, 1, 0) < 0) { + SCLogError(SC_ERR_BPF,"bpf compilation error %s", + pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } - if(pcap_setfilter(pcap_g.pcap_handle,&pcap_g.filter) < 0) { - SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(pcap_g.pcap_handle)); + if (pcap_setfilter(pcap_g.pcap_handle, &pcap_g.filter) < 0) { + SCLogError(SC_ERR_BPF,"could not set bpf filter %s", pcap_geterr(pcap_g.pcap_handle)); SCFree(ptv); return TM_ECODE_FAILED; } @@ -301,7 +316,7 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle); SCLogDebug("datalink %" PRId32 "", pcap_g.datalink); - switch(pcap_g.datalink) { + switch (pcap_g.datalink) { case LINKTYPE_LINUX_SLL: pcap_g.Decoder = DecodeSll; break; @@ -314,6 +329,9 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) case LINKTYPE_RAW: pcap_g.Decoder = DecodeRaw; break; + case LINKTYPE_NULL: + pcap_g.Decoder = DecodeNull; + break; default: SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not " @@ -334,9 +352,9 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) } else { if (strcmp(tmpstring, "auto") == 0) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; - } else if (strcmp(tmpstring, "yes") == 0) { + } else if (ConfValIsTrue(tmpstring)){ pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } else if (strcmp(tmpstring, "no") == 0) { + } else if (ConfValIsFalse(tmpstring)) { pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_DISABLE; } } @@ -381,7 +399,7 @@ TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data) SCReturnInt(TM_ECODE_OK); } -double prev_signaled_ts = 0; +static double prev_signaled_ts = 0; TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { @@ -394,17 +412,7 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0 ); -#endif - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { @@ -412,15 +420,11 @@ TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P FlowWakeupFlowManagerThread(); } - /* update the engine time representation based on the timestamp - * of the packet. */ - TimeSet(&p->ts); - /* call the decoder */ pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); #ifdef DEBUG - BUG_ON(p->pkt_src != PKT_SRC_WIRE && p->pkt_src != PKT_SRC_FFR_V2); + BUG_ON(p->pkt_src != PKT_SRC_WIRE && p->pkt_src != PKT_SRC_FFR); #endif PacketDecodeFinalize(tv, dtv, p); diff --git a/src/source-pcap-file.h b/src/source-pcap-file.h index 636cbdeb6da3..fa76a1a8f8e7 100644 --- a/src/source-pcap-file.h +++ b/src/source-pcap-file.h @@ -29,5 +29,7 @@ void TmModuleDecodePcapFileRegister (void); void PcapIncreaseInvalidChecksum(); +void PcapFileGlobalInit(); + #endif /* __SOURCE_PCAP_FILE_H__ */ diff --git a/src/source-pcap.c b/src/source-pcap.c index 0bc76b9ce78a..33d8c72529a8 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -54,8 +54,6 @@ #endif /* __SC_CUDA_SUPPORT__ */ -extern uint8_t suricata_ctl_flags; - #define PCAP_STATE_DOWN 0 #define PCAP_STATE_UP 1 @@ -130,6 +128,7 @@ void TmModuleReceivePcapRegister (void) tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit; tmm_modules[TMM_RECEIVEPCAP].Func = NULL; tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop; + tmm_modules[TMM_RECEIVEPCAP].PktAcqBreakLoop = NULL; tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats; tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPCAP].RegisterTests = NULL; @@ -157,10 +156,10 @@ static inline void PcapDumpCounters(PcapThreadVars *ptv) { struct pcap_stat pcap_s; if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) { - SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, pcap_s.ps_recv); - SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, pcap_s.ps_drop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, pcap_s.ps_recv); + StatsSetUI64(ptv->tv, ptv->capture_kernel_drops, pcap_s.ps_drop); (void) SC_ATOMIC_SET(ptv->livedev->drop, pcap_s.ps_drop); - SCPerfCounterSetUI64(ptv->capture_kernel_ifdrops, ptv->tv->sc_perf_pca, pcap_s.ps_ifdrop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_ifdrops, pcap_s.ps_ifdrop); } } @@ -306,7 +305,7 @@ TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) ptv->cb_result = TM_ECODE_OK; while (1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -340,13 +339,15 @@ TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot) } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapCallbackLoop failed"); SCReturnInt(TM_ECODE_FAILED); + } else if (unlikely(r == 0)) { + TmThreadsCaptureInjectPacket(tv, ptv->slot, NULL); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } PcapDumpCounters(ptv); - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCReturnInt(TM_ECODE_OK); } @@ -394,6 +395,12 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCLogInfo("using interface %s", (char *)pcapconfig->iface); + if (LiveGetOffload() == 0) { + (void)GetIfaceOffloading((char *)pcapconfig->iface, 1, 1); + } else { + DisableIfaceOffloading(ptv->livedev, 1, 1); + } + ptv->checksum_mode = pcapconfig->checksum_mode; if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { SCLogInfo("Running in 'auto' checksum mode. Detection of interface state will require " @@ -509,32 +516,19 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCMutexUnlock(&pcap_bpf_compile_lock); } - /* Making it conditional to Linux even if GetIfaceOffloading return 0 - * for non Linux. */ -#ifdef HAVE_LINUX_ETHTOOL_H - if (GetIfaceOffloading(pcapconfig->iface) == 1) { - SCLogWarning(SC_ERR_PCAP_CREATE, - "Using Pcap capture with GRO or LRO activated can lead to " - "capture problems."); - } -#endif /* HAVE_LINUX_ETHTOOL_H */ + /* no offloading supported at all */ + (void)GetIfaceOffloading(pcapconfig->iface, 1, 1); ptv->datalink = pcap_datalink(ptv->pcap_handle); pcapconfig->DerefFunc(pcapconfig); - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); + ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", + ptv->tv); *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); @@ -562,6 +556,7 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->livedev = LiveGetDevice(pcapconfig->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); + SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } @@ -628,18 +623,12 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->datalink = pcap_datalink(ptv->pcap_handle); - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->capture_kernel_ifdrops = SCPerfTVRegisterCounter("capture.kernel_ifdrops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); + ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", + ptv->tv); *data = (void *)ptv; @@ -718,18 +707,7 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0); -#endif - - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* call the decoder */ switch(p->datalink) { @@ -745,6 +723,9 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe case LINKTYPE_RAW: DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; + case LINKTYPE_NULL: + DecodeNull(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); + break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodePcap", p->datalink); break; diff --git a/src/source-pcap.h b/src/source-pcap.h index 335986954dc5..ac6d331ddbc3 100644 --- a/src/source-pcap.h +++ b/src/source-pcap.h @@ -39,6 +39,7 @@ char *PcapLiveGetDevice(int); /* per packet Pcap vars */ typedef struct PcapPacketVars_ { + uint32_t tenant_id; } PcapPacketVars; /** needs to be able to contain Windows adapter id's, so diff --git a/src/source-pfring.c b/src/source-pfring.c index 45527fd99b30..d8583f5f18e6 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -48,6 +48,7 @@ #include "util-device.h" #include "util-host-info.h" #include "runmodes.h" +#include "util-profiling.h" #ifdef __SC_CUDA_SUPPORT__ @@ -62,6 +63,7 @@ #endif /* __SC_CUDA_SUPPORT__ */ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot); +TmEcode PfringBreakLoop(ThreadVars *tv, void *data); TmEcode ReceivePfringThreadInit(ThreadVars *, void *, void **); void ReceivePfringThreadExitStats(ThreadVars *, void *); TmEcode ReceivePfringThreadDeinit(ThreadVars *, void *); @@ -71,7 +73,6 @@ TmEcode DecodePfring(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue TmEcode DecodePfringThreadDeinit(ThreadVars *tv, void *data); extern int max_pending_packets; -extern uint8_t suricata_ctl_flags; #ifndef HAVE_PFRING @@ -126,6 +127,10 @@ static SCMutex pfring_bpf_set_filter_lock = SCMUTEX_INITIALIZER; #define LIBPFRING_REENTRANT 0 #define LIBPFRING_WAIT_FOR_INCOMING 1 +typedef enum { + PFRING_FLAGS_ZERO_COPY = 0x1 +} PfringThreadVarsFlags; + /** * \brief Structure to hold thread specific variables. */ @@ -141,6 +146,8 @@ typedef struct PfringThreadVars_ uint16_t capture_kernel_packets; uint16_t capture_kernel_drops; + uint32_t flags; + ThreadVars *tv; TmSlot *slot; @@ -170,6 +177,7 @@ void TmModuleReceivePfringRegister (void) tmm_modules[TMM_RECEIVEPFRING].ThreadInit = ReceivePfringThreadInit; tmm_modules[TMM_RECEIVEPFRING].Func = NULL; tmm_modules[TMM_RECEIVEPFRING].PktAcqLoop = ReceivePfringLoop; + tmm_modules[TMM_RECEIVEPFRING].PktAcqBreakLoop = PfringBreakLoop; tmm_modules[TMM_RECEIVEPFRING].ThreadExitPrintStats = ReceivePfringThreadExitStats; tmm_modules[TMM_RECEIVEPFRING].ThreadDeinit = ReceivePfringThreadDeinit; tmm_modules[TMM_RECEIVEPFRING].RegisterTests = NULL; @@ -199,14 +207,12 @@ static inline void PfringDumpCounters(PfringThreadVars *ptv) * So to get the number of packet on the interface we can add * the newly seen packets and drops for this thread and add it * to the interface counter */ - uint64_t th_pkts = SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, - ptv->tv->sc_perf_pca); - uint64_t th_drops = SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, - ptv->tv->sc_perf_pca); + uint64_t th_pkts = StatsGetLocalCounterValue(ptv->tv, ptv->capture_kernel_packets); + uint64_t th_drops = StatsGetLocalCounterValue(ptv->tv, ptv->capture_kernel_drops); SC_ATOMIC_ADD(ptv->livedev->pkts, pfring_s.recv - th_pkts); SC_ATOMIC_ADD(ptv->livedev->drop, pfring_s.drop - th_drops); - SCPerfCounterSetUI64(ptv->capture_kernel_packets, ptv->tv->sc_perf_pca, pfring_s.recv); - SCPerfCounterSetUI64(ptv->capture_kernel_drops, ptv->tv->sc_perf_pca, pfring_s.drop); + StatsSetUI64(ptv->tv, ptv->capture_kernel_packets, pfring_s.recv); + StatsSetUI64(ptv->tv, ptv->capture_kernel_drops, pfring_s.drop); } } @@ -246,7 +252,7 @@ static inline void PfringProcessPacket(void *user, struct pfring_pkthdr *h, Pack * is not defined nor used in PF_RING code. And vlan_id is set to 0 * in PF_RING kernel code when there is no VLAN. */ if ((!ptv->vlan_disabled) && h->extended_hdr.parsed_pkt.vlan_id) { - p->vlan_id[0] = h->extended_hdr.parsed_pkt.vlan_id; + p->vlan_id[0] = h->extended_hdr.parsed_pkt.vlan_id & 0x0fff; p->vlan_idx = 1; p->vlanh[0] = NULL; } @@ -298,7 +304,8 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) struct pfring_pkthdr hdr; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; - struct timeval current_time; + u_int buffer_size; + u_char *pkt_buffer; ptv->slot = s->slot_next; @@ -311,7 +318,7 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) } while(1) { - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { SCReturnInt(TM_ECODE_OK); } @@ -328,20 +335,29 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) /* Some flavours of PF_RING may fail to set timestamp - see PF-RING-enabled libpcap code*/ hdr.ts.tv_sec = hdr.ts.tv_usec = 0; - /* Depending on what compile time options are used for pfring we either return 0 or -1 on error and always 1 for success */ - u_char *pkt_buffer = GET_PKT_DIRECT_DATA(p); - u_int buffer_size = GET_PKT_DIRECT_MAX_SIZE(p); + /* Check for Zero-copy mode */ + if (ptv->flags & PFRING_FLAGS_ZERO_COPY) { + buffer_size = 0; + pkt_buffer = NULL; + } else { + buffer_size = GET_PKT_DIRECT_MAX_SIZE(p); + pkt_buffer = GET_PKT_DIRECT_DATA(p); + } + int r = pfring_recv(ptv->pd, &pkt_buffer, buffer_size, &hdr, LIBPFRING_WAIT_FOR_INCOMING); + if (likely(r == 1)) { + /* profiling started before blocking pfring_recv call, so + * reset it here */ + PACKET_PROFILING_RESTART(p); + + /* Check for Zero-copy mode */ + if (ptv->flags & PFRING_FLAGS_ZERO_COPY) { + PacketSetData(p, pkt_buffer, hdr.caplen); + } - /* Check for Zero-copy if buffer size is zero */ - if (buffer_size == 0) { - PacketSetData(p, pkt_buffer, hdr.caplen); - } - - if (r == 1) { //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n", // hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port); @@ -353,22 +369,54 @@ TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot) } /* Trigger one dump of stats every second */ - TimeGet(¤t_time); - if (current_time.tv_sec != last_dump) { + if (p->ts.tv_sec != last_dump) { PfringDumpCounters(ptv); - last_dump = current_time.tv_sec; + last_dump = p->ts.tv_sec; + } + } else if (unlikely(r == 0)) { + if (suricata_ctl_flags & SURICATA_STOP) { + SCReturnInt(TM_ECODE_OK); } + + /* pfring didn't use the packet yet */ + TmThreadsCaptureInjectPacket(tv, ptv->slot, p); + } else { SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error %" PRId32 "", r); TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); } return TM_ECODE_OK; } +/** + * \brief Stop function for ReceivePfringLoop. + * + * This function forces ReceivePfringLoop to stop the + * execution, exiting the packet capture loop. + * + * \param tv pointer to ThreadVars + * \param data pointer that gets cast into PfringThreadVars for ptv + * \retval TM_ECODE_OK on success + * \retval TM_ECODE_FAILED on failure + */ +TmEcode PfringBreakLoop(ThreadVars *tv, void *data) +{ + PfringThreadVars *ptv = (PfringThreadVars *)data; + + /* Safety check */ + if (ptv->pd == NULL) { + return TM_ECODE_FAILED; + } + + pfring_breakloop(ptv->pd); + + return TM_ECODE_OK; +} + /** * \brief Init function for RecievePfring. * @@ -389,7 +437,7 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) u_int32_t version = 0; PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata; unsigned int opflag; - + char const *active_runmode = RunmodeGetActive(); if (pfconf == NULL) return TM_ECODE_FAILED; @@ -407,18 +455,26 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->interface = SCStrdup(pfconf->iface); if (unlikely(ptv->interface == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate device string"); + SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } ptv->livedev = LiveGetDevice(pfconf->iface); if (ptv->livedev == NULL) { SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); + SCFree(ptv); SCReturnInt(TM_ECODE_FAILED); } + /* enable zero-copy mode for workers runmode */ + if (active_runmode && strcmp("workers", active_runmode) == 0) { + ptv->flags |= PFRING_FLAGS_ZERO_COPY; + SCLogPerf("Enabling zero-copy for %s", ptv->interface); + } + ptv->checksum_mode = pfconf->checksum_mode; - opflag = PF_RING_REENTRANT | PF_RING_PROMISC; + opflag = PF_RING_PROMISC; /* if suri uses VLAN and if we have a recent kernel, we need * to use parsed_pkt to get VLAN info */ @@ -444,12 +500,13 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->interface, ptv->interface); pfconf->DerefFunc(pfconf); + SCFree(ptv); return TM_ECODE_FAILED; - } else { - pfring_set_application_name(ptv->pd, PROG_NAME); - pfring_version(ptv->pd, &version); } + pfring_set_application_name(ptv->pd, PROG_NAME); + pfring_version(ptv->pd, &version); + /* We only set cluster info if the number of pfring threads is greater than 1 */ ptv->threads = pfconf->threads; @@ -466,17 +523,20 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) if (rc != 0) { SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " "returned %d for cluster-id: %d", rc, ptv->cluster_id); - pfconf->DerefFunc(pfconf); - return TM_ECODE_FAILED; + if (rc != PF_RING_ERROR_NOT_SUPPORTED || (pfconf->flags & PFRING_CONF_FLAGS_CLUSTER)) { + /* cluster is mandatory as explicitly specified in the configuration */ + pfconf->DerefFunc(pfconf); + return TM_ECODE_FAILED; + } } } if (ptv->threads > 1) { - SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", + SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } else { - SCLogInfo("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", + SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d, single-pfring-thread", tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8, version & 0x000000FF, ptv->interface, ptv->cluster_id); } @@ -497,14 +557,10 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) } } - ptv->capture_kernel_packets = SCPerfTVRegisterCounter("capture.kernel_packets", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); - ptv->capture_kernel_drops = SCPerfTVRegisterCounter("capture.kernel_drops", - ptv->tv, - SC_PERF_TYPE_UINT64, - "NULL"); + ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", + ptv->tv); + ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", + ptv->tv); /* A bit strange to have this here but we only have vlan information * during reading so we need to know if we want to keep vlan during @@ -521,6 +577,21 @@ TmEcode ReceivePfringThreadInit(ThreadVars *tv, void *initdata, void **data) ptv->vlan_disabled = 1; } + /* If VLAN tracking is disabled, set cluster type to 5-tuple or in case of a + * ZC interface, do nothing */ + if (ptv->vlan_disabled && ptv->ctype == CLUSTER_FLOW && + strncmp(ptv->interface, "zc", 2) != 0) { + SCLogPerf("VLAN disabled, setting cluster type to CLUSTER_FLOW_5_TUPLE"); + rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, CLUSTER_FLOW_5_TUPLE); + + if (rc != 0) { + SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster " + "returned %d for cluster-id: %d", rc, ptv->cluster_id); + pfconf->DerefFunc(pfconf); + return TM_ECODE_FAILED; + } + } + *data = (void *)ptv; pfconf->DerefFunc(pfconf); @@ -537,11 +608,11 @@ void ReceivePfringThreadExitStats(ThreadVars *tv, void *data) PfringThreadVars *ptv = (PfringThreadVars *)data; PfringDumpCounters(ptv); - SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", + SCLogPerf("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", tv->name, - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_packets, tv->sc_perf_pca), - (uint64_t) SCPerfGetLocalCounterValue(ptv->capture_kernel_drops, tv->sc_perf_pca)); - SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); + StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), + StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); + SCLogPerf("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); } /** @@ -593,22 +664,11 @@ TmEcode DecodePfring(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pac return TM_ECODE_OK; /* update counters */ - SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); -// SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); - - SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); -#if 0 - SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, - (GET_PKT_LEN(p) * 8)/1000000.0 ); -#endif - - SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); - SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); + DecodeUpdatePacketCounters(tv, dtv, p); /* If suri has set vlan during reading, we increase vlan counter */ if (p->vlan_idx) { - SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); + StatsIncr(tv, dtv->counter_vlan); } DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); diff --git a/src/source-pfring.h b/src/source-pfring.h index 7439828fb5d3..9871f458f6ee 100644 --- a/src/source-pfring.h +++ b/src/source-pfring.h @@ -31,8 +31,14 @@ #include #endif +typedef enum { + PFRING_CONF_FLAGS_CLUSTER = 0x1 +} PfringIfaceConfigFlags; + typedef struct PfringIfaceConfig_ { + uint32_t flags; + /* cluster param */ int cluster_id; #ifdef HAVE_PFRING @@ -60,5 +66,5 @@ void PfringLoadConfig(void); /* We don't have to use an enum that sucks in our code */ #define CLUSTER_FLOW 0 #define CLUSTER_ROUND_ROBIN 1 - +#define CLUSTER_FLOW_5_TUPLE 4 #endif /* __SOURCE_PFRING_H__ */ diff --git a/src/stream-tcp-inline.c b/src/stream-tcp-inline.c index b8961ba287fd..97f8555d3c65 100644 --- a/src/stream-tcp-inline.c +++ b/src/stream-tcp-inline.c @@ -645,13 +645,13 @@ static int StreamTcpInlineTest07(void) void StreamTcpInlineRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpInlineTest01", StreamTcpInlineTest01, 1); - UtRegisterTest("StreamTcpInlineTest02", StreamTcpInlineTest02, 1); - UtRegisterTest("StreamTcpInlineTest03", StreamTcpInlineTest03, 1); - UtRegisterTest("StreamTcpInlineTest04", StreamTcpInlineTest04, 1); - UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05, 1); - UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06, 1); - UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07, 1); + UtRegisterTest("StreamTcpInlineTest01", StreamTcpInlineTest01); + UtRegisterTest("StreamTcpInlineTest02", StreamTcpInlineTest02); + UtRegisterTest("StreamTcpInlineTest03", StreamTcpInlineTest03); + UtRegisterTest("StreamTcpInlineTest04", StreamTcpInlineTest04); + UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05); + UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06); + UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07); #endif /* UNITTESTS */ } diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 50c6421a872b..c13da8667173 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -142,6 +142,8 @@ enum * normal packet we assume 3whs to be completed. Only used for SYN/ACK resend * event. */ #define STREAMTCP_FLAG_3WHS_CONFIRMED 0x1000 +/** App Layer tracking/reassembly is disabled */ +#define STREAMTCP_FLAG_APP_LAYER_DISABLED 0x2000 /* * Per STREAM flags @@ -155,8 +157,7 @@ enum #define STREAMTCP_STREAM_FLAG_KEEPALIVE 0x0004 /** Stream has reached it's reassembly depth, all further packets are ignored */ #define STREAMTCP_STREAM_FLAG_DEPTH_REACHED 0x0008 -/** Stream has sent a FIN/RST */ -#define STREAMTCP_STREAM_FLAG_CLOSE_INITIATED 0x0010 +// vacancy /** Stream supports TIMESTAMP -- used to set ssn STREAMTCP_FLAG_TIMESTAMP * flag. */ #define STREAMTCP_STREAM_FLAG_TIMESTAMP 0x0020 @@ -221,6 +222,7 @@ typedef struct TcpSession_ { uint8_t tcp_packet_flags; /* coccinelle: TcpSession:flags:STREAMTCP_FLAG */ uint16_t flags; + uint32_t reassembly_depth; /**< reassembly depth for the stream */ TcpStream server; TcpStream client; struct StreamMsg_ *toserver_smsg_head; /**< list of stream msgs (for detection inspection) */ @@ -237,5 +239,9 @@ typedef struct TcpSession_ { ((stream)->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) #define StreamTcpResetStreamFlagAppProtoDetectionCompleted(stream) \ ((stream)->flags &= ~STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED); +#define StreamTcpDisableAppLayerReassembly(ssn) do { \ + SCLogDebug("setting STREAMTCP_FLAG_APP_LAYER_DISABLED on ssn %p", ssn); \ + ((ssn)->flags |= STREAMTCP_FLAG_APP_LAYER_DISABLED); \ + } while (0); #endif /* __STREAM_TCP_PRIVATE_H__ */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 2d1170a14c90..9632c116bd99 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -45,6 +45,7 @@ #include "util-host-os-info.h" #include "util-unittest-helper.h" #include "util-byte.h" +#include "util-device.h" #include "stream-tcp.h" #include "stream-tcp-private.h" @@ -135,12 +136,10 @@ void StreamTcpReassembleDecrMemuse(uint64_t size) return; } -void StreamTcpReassembleMemuseCounter(ThreadVars *tv, TcpReassemblyThreadCtx *rtv) +uint64_t StreamTcpReassembleMemuseGlobalCounter(void) { uint64_t smemuse = SC_ATOMIC_GET(ra_memuse); - if (tv != NULL && rtv != NULL) - SCPerfCounterSetUI64(rtv->counter_tcp_reass_memuse, tv->sc_perf_pca, smemuse); - return; + return smemuse; } /** @@ -279,6 +278,28 @@ void StreamTcpReturnStreamSegments (TcpStream *stream) stream->seg_list_tail = NULL; } +/** \param f locked flow */ +void StreamTcpDisableAppLayer(Flow *f) +{ + if (f->protoctx == NULL) + return; + + TcpSession *ssn = (TcpSession *)f->protoctx; + StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); + StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); + StreamTcpDisableAppLayerReassembly(ssn); +} + +/** \param f locked flow */ +int StreamTcpAppLayerIsDisabled(Flow *f) +{ + if (f->protoctx == NULL || f->proto != IPPROTO_TCP) + return 0; + + TcpSession *ssn = (TcpSession *)f->protoctx; + return (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); +} + typedef struct SegmentSizes_ { uint16_t pktsize; @@ -323,12 +344,21 @@ int StreamTcpReassemblyConfig(char quiet) SCLogDebug("segpre->val %s", segpre->val); uint16_t pktsize = 0; - if (ByteExtractStringUint16(&pktsize, 10, strlen(segsize->val), - segsize->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "segment packet size " - "of %s is invalid", segsize->val); - return -1; + if (strcmp("from_mtu", segsize->val) == 0) { + int mtu = g_default_mtu ? g_default_mtu : DEFAULT_MTU; + if (mtu < MINIMUM_MTU) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, "invalid mtu %d", mtu); + continue; + } + pktsize = mtu - 40; + } else { + if (ByteExtractStringUint16(&pktsize, 10, strlen(segsize->val), + segsize->val) == -1) + { + SCLogError(SC_ERR_INVALID_ARGUMENT, "segment packet size " + "of %s is invalid", segsize->val); + return -1; + } } uint32_t prealloc = 0; if (ByteExtractStringUint32(&prealloc, 10, strlen(segpre->val), @@ -355,9 +385,13 @@ int StreamTcpReassemblyConfig(char quiet) sizes[npools].pktsize = 0xffff; sizes[npools].prealloc = 8; npools++; - SCLogInfo("appended a segment pool for pktsize 65536"); + SCLogConfig("appended a segment pool for pktsize 65536"); } } else if (npools == 0) { + int mtu = g_default_mtu; + if (mtu < MINIMUM_MTU) + mtu = DEFAULT_MTU; + /* defaults */ sizes[0].pktsize = 4; sizes[0].prealloc = 256; @@ -371,7 +405,7 @@ int StreamTcpReassemblyConfig(char quiet) sizes[4].prealloc = 512; sizes[5].pktsize = 768; sizes[5].prealloc = 1024; - sizes[6].pktsize = 1448; + sizes[6].pktsize = mtu - 40; // min size of ipv4+tcp hdrs sizes[6].prealloc = 1024; sizes[7].pktsize = 0xffff; sizes[7].prealloc = 128; @@ -427,7 +461,7 @@ int StreamTcpReassemblyConfig(char quiet) SCLogDebug("my_segment_pktsizes[i] %u, my_segment_poolsizes[i] %u", my_segment_pktsizes[i], my_segment_poolsizes[i]); if (!quiet) - SCLogInfo("segment pool: pktsize %u, prealloc %u", + SCLogConfig("segment pool: pktsize %u, prealloc %u", my_segment_pktsizes[i], my_segment_poolsizes[i]); } @@ -464,8 +498,21 @@ int StreamTcpReassemblyConfig(char quiet) stream_chunk_prealloc = prealloc; } if (!quiet) - SCLogInfo("stream.reassembly \"chunk-prealloc\": %u", stream_chunk_prealloc); + SCLogConfig("stream.reassembly \"chunk-prealloc\": %u", stream_chunk_prealloc); StreamMsgQueuesInit(stream_chunk_prealloc); + + intmax_t zero_copy_size = 128; + if (ConfGetInt("stream.reassembly.zero-copy-size", &zero_copy_size) == 1) { + if (zero_copy_size < 0 || zero_copy_size > 0xffff) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "stream.reassembly.zero-copy-size of " + "%"PRIiMAX" is invalid: valid values are 0 to 65535", zero_copy_size); + return -1; + } + } + stream_config.zero_copy_size = (uint16_t)zero_copy_size; + if (!quiet) + SCLogConfig("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size); + return 0; } @@ -480,6 +527,9 @@ int StreamTcpReassembleInit(char quiet) SCMutexInit(&segment_pool_memuse_mutex, NULL); SCMutexInit(&segment_pool_cnt_mutex, NULL); #endif + + StatsRegisterGlobalCounter("tcp.reassembly_memuse", + StreamTcpReassembleMemuseGlobalCounter); return 0; } @@ -503,7 +553,7 @@ void StreamTcpReassembleFree(char quiet) segment_pool[u16]->allocated); if (segment_pool[u16]->max_outstanding > segment_pool[u16]->allocated) { - SCLogInfo("TCP segment pool of size %u had a peak use of %u segments, " + SCLogPerf("TCP segment pool of size %u had a peak use of %u segments, " "more than the prealloc setting of %u", segment_pool_pktsizes[u16], segment_pool[u16]->max_outstanding, segment_pool[u16]->allocated); } @@ -528,8 +578,8 @@ void StreamTcpReassembleFree(char quiet) SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); SCMutexDestroy(&segment_pool_memuse_mutex); SCMutexDestroy(&segment_pool_cnt_mutex); - SCLogInfo("dbg_app_layer_gap %u", dbg_app_layer_gap); - SCLogInfo("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate); + SCLogPerf("dbg_app_layer_gap %u", dbg_app_layer_gap); + SCLogPerf("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate); #endif } @@ -551,6 +601,10 @@ void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx) { SCEnter(); AppLayerDestroyCtxThread(ra_ctx->app_tctx); +#ifdef DEBUG + SCLogDebug("reassembly fast path stats: fp1 %"PRIu64" fp2 %"PRIu64" sp %"PRIu64, + ra_ctx->fp1, ra_ctx->fp2, ra_ctx->sp); +#endif SCFree(ra_ctx); SCReturn; } @@ -1729,14 +1783,14 @@ int StreamTcpReassembleDepthReached(Packet *p) * * \retval size Part of the size that fits in the depth, 0 if none */ -static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, +static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream, uint32_t seq, uint32_t size) { SCEnter(); /* if the configured depth value is 0, it means there is no limit on reassembly depth. Otherwise carry on my boy ;) */ - if (stream_config.reassembly_depth == 0) { + if (ssn->reassembly_depth == 0) { SCReturnUInt(size); } @@ -1749,24 +1803,25 @@ static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, * checking and just reject the rest of the packets including * retransmissions. Saves us the hassle of dealing with sequence * wraps as well */ - if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + stream_config.reassembly_depth))) { + if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + ssn->reassembly_depth))) { stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; SCReturnUInt(0); } SCLogDebug("full Depth not yet reached: %"PRIu32" <= %"PRIu32, (StreamTcpReassembleGetRaBaseSeq(stream)+1), - (stream->isn + stream_config.reassembly_depth)); + (stream->isn + ssn->reassembly_depth)); - if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + stream_config.reassembly_depth))) { + if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) { /* packet (partly?) fits the depth window */ - if (SEQ_LEQ((seq + size),(stream->isn + stream_config.reassembly_depth))) { + if (SEQ_LEQ((seq + size),(stream->isn + ssn->reassembly_depth))) { /* complete fit */ SCReturnUInt(size); } else { + stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; /* partial fit, return only what fits */ - uint32_t part = (stream->isn + stream_config.reassembly_depth) - seq; + uint32_t part = (stream->isn + ssn->reassembly_depth) - seq; #if DEBUG BUG_ON(part > size); #else @@ -1853,14 +1908,20 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre } } + if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) && + (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) { + SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn); + SCReturnInt(0); + } + /* If we have reached the defined depth for either of the stream, then stop reassembling the TCP session */ - uint32_t size = StreamTcpReassembleCheckDepth(stream, TCP_GET_SEQ(p), p->payload_len); + uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len); SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size); if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { /* increment stream depth counter */ - SCPerfCounterIncr(ra_ctx->counter_tcp_stream_depth, tv->sc_perf_pca); + StatsIncr(tv, ra_ctx->counter_tcp_stream_depth); stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY; SCLogDebug("ssn %p: reassembly depth reached, " @@ -1890,6 +1951,9 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre seg->payload_len = size; seg->seq = TCP_GET_SEQ(p); + if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) + seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; + /* if raw reassembly is disabled for new segments, flag each * segment as complete for raw before insert */ if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) { @@ -1914,40 +1978,40 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre SCReturnInt(0); } -#define STREAM_SET_FLAGS(ssn, stream, p, flag) { \ - flag = 0; \ - if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ - flag |= STREAM_START; \ - } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ - flag |= STREAM_EOF; \ - } \ - if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ - flag |= STREAM_TOCLIENT; \ - } else { \ - flag |= STREAM_TOSERVER; \ - } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { \ - flag |= STREAM_DEPTH; \ - } \ -} +static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, + Packet *p) +{ + uint8_t flag = 0; + + if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) { + flag |= STREAM_START; + } + + if (ssn->state == TCP_CLOSED) { + flag |= STREAM_EOF; + } + if (p->flags & PKT_PSEUDO_STREAM_END) { + flag |= STREAM_EOF; + } + + if (StreamTcpInlineMode() == 0) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag |= STREAM_TOCLIENT; + } else { + flag |= STREAM_TOSERVER; + } + } else { + if (p->flowflags & FLOW_PKT_TOSERVER) { + flag |= STREAM_TOSERVER; + } else { + flag |= STREAM_TOCLIENT; + } + } -#define STREAM_SET_INLINE_FLAGS(ssn, stream, p, flag) { \ - flag = 0; \ - if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {\ - flag |= STREAM_START; \ - } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) { \ - flag |= STREAM_EOF; \ - } \ - if ((p)->flowflags & FLOW_PKT_TOSERVER) { \ - flag |= STREAM_TOSERVER; \ - } else { \ - flag |= STREAM_TOCLIENT; \ - } \ - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { \ - flag |= STREAM_DEPTH; \ - } \ + if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { + flag |= STREAM_DEPTH; + } + return flag; } static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p, @@ -2026,6 +2090,58 @@ static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream, SCReturnInt(1); } +/** + * \brief see if app layer is done with a segment + * + * \retval 1 app layer is done with this segment + * \retval 0 not done yet + */ +#define StreamTcpAppLayerSegmentProcessed(ssn, stream, segment) \ + (( ( (ssn)->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || \ + ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ + ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 )) + +/** \internal + * \brief check if we can remove a segment from our segment list + * + * If a segment is entirely before the oldest smsg, we can discard it. Otherwise + * we keep it around to be able to log it. + * + * \retval 1 yes + * \retval 0 no + */ +static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg) +{ + if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) { + /* not (seg is entirely before first smsg, skip) */ + if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) { + SCReturnInt(0); + } + } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) { + /* not (seg is entirely before first smsg, skip) */ + if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) { + SCReturnInt(0); + } + } + + /* if proto detect isn't done, we're not returning */ + if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) { + SCReturnInt(0); + } + + /* check app layer conditions */ + if (!(StreamTcpAppLayerSegmentProcessed(ssn, stream, seg))) { + SCReturnInt(0); + } + + /* check raw reassembly conditions */ + if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { + SCReturnInt(0); + } + + SCReturnInt(1); +} + static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) { if (seg->prev == NULL) { @@ -2042,113 +2158,103 @@ static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) stream->seg_list_tail = seg->prev; } -/** - * \brief see if app layer is done with a segment - * - * \retval 1 app layer is done with this segment - * \retval 0 not done yet - */ -#define StreamTcpAppLayerSegmentProcessed(stream, segment) \ - (( ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \ - ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 )) - /** * \brief Update the stream reassembly upon receiving a data segment * - * Reassembly is in the same direction of the packet. + * | left edge | right edge based on sliding window size + * [aaa] + * [aaabbb] + * ... + * [aaabbbcccdddeeefff] + * [bbbcccdddeeefffggg] <- cut off aaa to adhere to the window size + * + * GAP situation: each chunk that is uninterrupted has it's own smsg + * [aaabbb].[dddeeefff] + * [aaa].[ccc].[eeefff] * - * One of the utilities called by this function AppLayerHandleTCPData(), - * has a feature where it will call this very same function for the - * stream opposing the stream it is called with. This shouldn't cause - * any issues, since processing of each stream is independent of the - * other stream. + * A flag will be set to indicate where the *NEW* payload starts. This + * is to aid the detection code for alert only sigs. * * \todo this function is too long, we need to break it up. It needs it BAD */ -int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p) +static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, Packet *p) { SCEnter(); + SCLogDebug("start p %p, seq %"PRIu32, p, TCP_GET_SEQ(p)); - uint8_t flags = 0; - - /* this function can be directly called by app layer protocol - * detection. */ - if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { - SCLogDebug("stream no reassembly flag set. Mostly called via " - "app proto detection."); + if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) SCReturnInt(0); - } - - SCLogDebug("pcap_cnt %"PRIu64", len %u", p->pcap_cnt, p->payload_len); - - SCLogDebug("stream->seg_list %p", stream->seg_list); -#ifdef DEBUG - PrintList(stream->seg_list); - //PrintRawDataFp(stdout, p->payload, p->payload_len); -#endif - if (stream->seg_list == NULL) { - /* send an empty EOF msg if we have no segments but TCP state - * is beyond ESTABLISHED */ - if (ssn->state > TCP_ESTABLISHED) { - SCLogDebug("sending empty eof message"); - /* send EOF to app layer */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - } else { - SCLogDebug("no segments in the list to reassemble"); - } - - SCReturnInt(0); - } - - if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { SCReturnInt(0); } - /* stream->ra_app_base_seq remains at stream->isn until protocol is - * detected. */ - uint32_t ra_base_seq = stream->ra_app_base_seq; - uint8_t data[4096]; - uint32_t data_len = 0; + uint32_t ra_base_seq = stream->ra_raw_base_seq; + StreamMsg *smsg = NULL; + uint32_t smsg_offset = 0; uint16_t payload_offset = 0; uint16_t payload_len = 0; + TcpSegment *seg = stream->seg_list; uint32_t next_seq = ra_base_seq + 1; - uint32_t data_sent = 0; + int gap = 0; + + uint32_t chunk_size = PKT_IS_TOSERVER(p) ? + stream_config.reassembly_toserver_chunk_size : + stream_config.reassembly_toclient_chunk_size; + + /* determine the left edge and right edge */ + uint32_t right_edge = TCP_GET_SEQ(p) + p->payload_len; + uint32_t left_edge = right_edge - chunk_size; + + /* shift the window to the right if the left edge doesn't cover segments */ + if (SEQ_GT(seg->seq,left_edge)) { + right_edge += (seg->seq - left_edge); + left_edge = seg->seq; + } - SCLogDebug("ra_base_seq %u", ra_base_seq); + SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, left_edge, right_edge); /* loop through the segments and fill one or more msgs */ - TcpSegment *seg = stream->seg_list; - SCLogDebug("pre-loop seg %p", seg); - for (; seg != NULL;) { + for (; seg != NULL && SEQ_LT(seg->seq, right_edge); ) { SCLogDebug("seg %p", seg); - if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { - if (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { - SCLogDebug("removing seg %p seq %"PRIu32 - " len %"PRIu16"", seg, seg->seq, seg->payload_len); + /* If packets are fully before ra_base_seq, skip them. We do this + * because we've reassembled up to the ra_base_seq point already, + * so we won't do anything with segments before it anyway. */ + SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" + " len %"PRIu16", combined %"PRIu32" and right_edge " + "%"PRIu32"", ra_base_seq, seg, seg->seq, + seg->payload_len, seg->seq+seg->payload_len, right_edge); + + /* Remove the segments which are completely before the ra_base_seq */ + if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size))) + { + SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" + " len %"PRIu16"", ra_base_seq, seg, seg->seq, + seg->payload_len); + /* only remove if app layer reassembly is ready too */ + if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); seg = next_seg; - continue; + /* otherwise, just flag it for removal */ } else { - break; + seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; + seg = seg->next; } + continue; + } - /* if app layer protocol has been detected, then remove all the segments - * which has been previously processed and reassembled */ - } else if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) && - (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && - StreamTcpAppLayerSegmentProcessed(stream, seg)) { + /* if app layer protocol has been detected, then remove all the segments + * which has been previously processed and reassembled + * + * If the stream is in GAP state the app layer flag won't be set */ + if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) && + (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && + StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) + { SCLogDebug("segment(%p) of length %"PRIu16" has been processed," " so return it to pool", seg, seg->payload_len); TcpSegment *next_seg = seg->next; @@ -2158,373 +2264,34 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, continue; } - /* If packets are fully before ra_base_seq, skip them. We do this - * because we've reassembled up to the ra_base_seq point already, - * so we won't do anything with segments before it anyway. */ - SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" - " len %"PRIu16", combined %"PRIu32" and stream->last_ack " - "%"PRIu32"", ra_base_seq, seg, seg->seq, - seg->payload_len, seg->seq+seg->payload_len, stream->last_ack); - - /* we've run into a sequence gap */ + /* we've run into a sequence gap, wrap up any existing smsg and + * queue it so the next chunk (if any) is in a new smsg */ if (SEQ_GT(seg->seq, next_seq)) { - - /* first, pass on data before the gap */ - if (data_len > 0) { - SCLogDebug("pre GAP data"); - - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - data_sent += data_len; - data_len = 0; + /* pass on pre existing smsg (if any) */ + if (smsg != NULL && smsg->data_len > 0) { + StreamTcpStoreStreamChunk(ssn, smsg, p, 1); + stream->ra_raw_base_seq = ra_base_seq; + smsg = NULL; } - /* don't conclude it's a gap straight away. If ra_base_seq is lower - * than last_ack - the window, we consider it a gap. */ - if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq)) - { - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); -#endif - - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; - - /* send gap signal */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("set STREAMTCP_STREAM_FLAG_GAP flag"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - break; - } else { - SCLogDebug("possible GAP, but waiting to see if out of order " - "packets might solve that"); -#ifdef DEBUG - dbg_app_layer_gap_candidate++; -#endif - break; - } + gap = 1; } - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), (ra_base_seq + 1))) { + /* if the segment ends beyond left_edge we need to consider it */ + if (SEQ_GT((seg->seq + seg->payload_len), left_edge)) { SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 "", seg->seq, - seg->payload_len, ra_base_seq); + "left_edge %" PRIu32 "", seg->seq, + seg->payload_len, left_edge); /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = ra_base_seq - seg->seq - 1; - payload_len = seg->payload_len - payload_offset; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; - payload_len = seg->payload_len; - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->next_win is %"PRIu32"", payload_offset, - payload_len, stream->next_win); - - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; - } - - /* copy the data into the smsg */ - uint16_t copy_size = sizeof(data) - data_len; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(data + data_len, seg->payload + payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); - - /* queue the smsg if it's full */ - if (data_len == sizeof(data)) { - /* process what we have so far */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - data_len = 0; - } - - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); - data_len = 0; - - copy_size = sizeof(data) - data_len; - if (copy_size > (seg->payload_len - payload_offset)) { - copy_size = (seg->payload_len - payload_offset); - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - - SCLogDebug("copy payload_offset %" PRIu32 ", data_len " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - memcpy(data + data_len, seg->payload + - payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - SCLogDebug("copied payload_offset %" PRIu32 ", " - "data_len %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - - if (data_len == sizeof(data)) { - /* process what we have so far */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - data_len = 0; - } - - /* see if we have segment payload left to process */ - if ((copy_size + payload_offset) < seg->payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } - } - - /* done with this segment, return it to the pool */ - TcpSegment *next_seg = seg->next; - next_seq = seg->seq + seg->payload_len; - seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - seg = next_seg; - } - - /* put the partly filled smsg in the queue to the l7 handler */ - if (data_len > 0) { - SCLogDebug("data_len > 0, %u", data_len); - /* process what we have so far */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - } - - if (data_sent == 0 && ssn->state > TCP_ESTABLISHED) { - SCLogDebug("sending empty eof message"); - /* send EOF to app layer */ - STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - } - - /* store ra_base_seq in the stream */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - stream->ra_app_base_seq = ra_base_seq; - } - - SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq); - SCReturnInt(0); -} - -/** - * \brief Update the stream reassembly upon receiving a data segment - * - * | left edge | right edge based on sliding window size - * [aaa] - * [aaabbb] - * ... - * [aaabbbcccdddeeefff] - * [bbbcccdddeeefffggg] <- cut off aaa to adhere to the window size - * - * GAP situation: each chunk that is uninterrupted has it's own smsg - * [aaabbb].[dddeeefff] - * [aaa].[ccc].[eeefff] - * - * A flag will be set to indicate where the *NEW* payload starts. This - * is to aid the detection code for alert only sigs. - * - * \todo this function is too long, we need to break it up. It needs it BAD - */ -static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, Packet *p) -{ - SCEnter(); - SCLogDebug("start p %p, seq %"PRIu32, p, TCP_GET_SEQ(p)); - - if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) - SCReturnInt(0); - if (stream->seg_list == NULL) { - SCReturnInt(0); - } - - uint32_t ra_base_seq = stream->ra_raw_base_seq; - StreamMsg *smsg = NULL; - uint16_t smsg_offset = 0; - uint16_t payload_offset = 0; - uint16_t payload_len = 0; - TcpSegment *seg = stream->seg_list; - uint32_t next_seq = ra_base_seq + 1; - int gap = 0; - - uint16_t chunk_size = PKT_IS_TOSERVER(p) ? - stream_config.reassembly_toserver_chunk_size : - stream_config.reassembly_toclient_chunk_size; - - /* determine the left edge and right edge */ - uint32_t right_edge = TCP_GET_SEQ(p) + p->payload_len; - uint32_t left_edge = right_edge - chunk_size; - - /* shift the window to the right if the left edge doesn't cover segments */ - if (SEQ_GT(seg->seq,left_edge)) { - right_edge += (seg->seq - left_edge); - left_edge = seg->seq; - } - - SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, left_edge, right_edge); - - /* loop through the segments and fill one or more msgs */ - for (; seg != NULL && SEQ_LT(seg->seq, right_edge); ) { - SCLogDebug("seg %p", seg); - - /* If packets are fully before ra_base_seq, skip them. We do this - * because we've reassembled up to the ra_base_seq point already, - * so we won't do anything with segments before it anyway. */ - SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" - " len %"PRIu16", combined %"PRIu32" and right_edge " - "%"PRIu32"", ra_base_seq, seg, seg->seq, - seg->payload_len, seg->seq+seg->payload_len, right_edge); - - /* Remove the segments which are completely before the ra_base_seq */ - if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size))) - { - SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32"" - " len %"PRIu16"", ra_base_seq, seg, seg->seq, - seg->payload_len); - - /* only remove if app layer reassembly is ready too */ - if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { - TcpSegment *next_seg = seg->next; - StreamTcpRemoveSegmentFromStream(stream, seg); - StreamTcpSegmentReturntoPool(seg); - seg = next_seg; - /* otherwise, just flag it for removal */ - } else { - seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; - seg = seg->next; - } - continue; - } - - /* if app layer protocol has been detected, then remove all the segments - * which has been previously processed and reassembled - * - * If the stream is in GAP state the app layer flag won't be set */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) && - (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) && - StreamTcpAppLayerSegmentProcessed(stream, seg)) - { - SCLogDebug("segment(%p) of length %"PRIu16" has been processed," - " so return it to pool", seg, seg->payload_len); - TcpSegment *next_seg = seg->next; - StreamTcpRemoveSegmentFromStream(stream, seg); - StreamTcpSegmentReturntoPool(seg); - seg = next_seg; - continue; - } - - /* we've run into a sequence gap, wrap up any existing smsg and - * queue it so the next chunk (if any) is in a new smsg */ - if (SEQ_GT(seg->seq, next_seq)) { - /* pass on pre existing smsg (if any) */ - if (smsg != NULL && smsg->data_len > 0) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 1); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; - } - - gap = 1; - } - - /* if the segment ends beyond left_edge we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), left_edge)) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "left_edge %" PRIu32 "", seg->seq, - seg->payload_len, left_edge); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(left_edge, seg->seq)) { - payload_offset = left_edge - seg->seq; - - if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) { - payload_len = (right_edge - seg->seq) - payload_offset; - } else { - payload_len = seg->payload_len - payload_offset; - } + if (SEQ_GT(left_edge, seg->seq)) { + payload_offset = left_edge - seg->seq; + + if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) { + payload_len = (right_edge - seg->seq) - payload_offset; + } else { + payload_len = seg->payload_len - payload_offset; + } if (SCLogDebugEnabled()) { BUG_ON(payload_offset > seg->payload_len); @@ -2562,12 +2329,12 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, } /* copy the data into the smsg */ - uint16_t copy_size = sizeof (smsg->data) - smsg_offset; + uint32_t copy_size = smsg->data_size - smsg_offset; if (copy_size > payload_len) { copy_size = payload_len; } if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); + BUG_ON(copy_size > smsg->data_size); } SCLogDebug("copy_size is %"PRIu16"", copy_size); memcpy(smsg->data + smsg_offset, seg->payload + payload_offset, @@ -2585,7 +2352,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, smsg->data_len += copy_size; /* queue the smsg if it's full */ - if (smsg->data_len == sizeof (smsg->data)) { + if (smsg->data_len == smsg->data_size) { StreamTcpStoreStreamChunk(ssn, smsg, p, 1); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; @@ -2624,12 +2391,12 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, StreamTcpSetupMsg(ssn, stream,p,smsg); smsg->seq = ra_base_seq + 1; - copy_size = sizeof(smsg->data) - smsg_offset; - if (copy_size > (seg->payload_len - payload_offset)) { + copy_size = smsg->data_size - smsg_offset; + if ((int32_t)copy_size > (seg->payload_len - payload_offset)) { copy_size = (seg->payload_len - payload_offset); } if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); + BUG_ON(copy_size > smsg->data_size); } SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " @@ -2646,7 +2413,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, SCLogDebug("copied payload_offset %" PRIu32 ", " "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", payload_offset, smsg_offset, copy_size); - if (smsg->data_len == sizeof (smsg->data)) { + if (smsg->data_len == smsg->data_size) { StreamTcpStoreStreamChunk(ssn, smsg, p, 1); stream->ra_raw_base_seq = ra_base_seq; smsg = NULL; @@ -2700,7 +2467,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, SCLogDebug("seg %p seq %"PRIu32", len %"PRIu16", sum %"PRIu32, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len); /* only remove if app layer reassembly is ready too */ - if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { TcpSegment *next_seg = seg->next; StreamTcpRemoveSegmentFromStream(stream, seg); StreamTcpSegmentReturntoPool(seg); @@ -2713,58 +2480,15 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } -/** \internal - * \brief check if we can remove a segment from our segment list - * - * If a segment is entirely before the oldest smsg, we can discard it. Otherwise - * we keep it around to be able to log it. +/** \brief Remove idle TcpSegments from TcpSession * - * \retval 1 yes - * \retval 0 no + * \param f flow + * \param flags direction flags */ -static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg) +void StreamTcpPruneSession(Flow *f, uint8_t flags) { - if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) { - /* not (seg is entirely before first smsg, skip) */ - if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) { - SCReturnInt(0); - } - } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) { - /* not (seg is entirely before first smsg, skip) */ - if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) { - SCReturnInt(0); - } - } - - /* if proto detect isn't done, we're not returning */ - if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) { - SCReturnInt(0); - } - - /* check app layer conditions */ - if (!(f->flags & FLOW_NO_APPLAYER_INSPECTION)) { - if (!(StreamTcpAppLayerSegmentProcessed(stream, seg))) { - SCReturnInt(0); - } - } - - /* check raw reassembly conditions */ - if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { - SCReturnInt(0); - } - - SCReturnInt(1); -} - -/** \brief Remove idle TcpSegments from TcpSession - * - * \param f flow - * \param flags direction flags - */ -void StreamTcpPruneSession(Flow *f, uint8_t flags) -{ - if (f == NULL || f->protoctx == NULL) - return; + if (f == NULL || f->protoctx == NULL) + return; TcpSession *ssn = f->protoctx; TcpStream *stream = NULL; @@ -2833,6 +2557,330 @@ static void GetSessionSize(TcpSession *ssn, Packet *p) } #endif +typedef struct ReassembleData_ { + uint32_t ra_base_seq; + uint32_t data_len; + uint8_t data[4096]; + int partial; /* last segment was processed only partially */ + uint32_t data_sent; /* data passed on this run */ +} ReassembleData; + +/** \internal + * \brief test if segment follows a gap. If so, handle the gap + * + * If in inline mode, segment may be un-ack'd. In this case we + * consider it a gap, but it's not 'final' yet. + * + * \retval bool 1 gap 0 no gap + */ +int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, + Packet *p, uint32_t next_seq) +{ + if (unlikely(SEQ_GT(seg->seq, next_seq))) { + /* we've run into a sequence gap */ + + if (StreamTcpInlineMode()) { + /* don't conclude it's a gap until we see that the data + * that is missing was acked. */ + if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED) + return 1; + } + + /* first, pass on data before the gap */ + if (rd->data_len > 0) { + SCLogDebug("pre GAP data"); + + /* process what we have so far */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd->data, rd->data_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += rd->data_len; + rd->data_len = 0; + } + +#ifdef DEBUG + uint32_t gap_len = seg->seq - next_seq; + SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " + "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", + next_seq, seg->seq, stream->last_ack, gap_len); +#endif + /* We have missed the packet and end host has ack'd it, so + * IDS should advance it's ra_base_seq and should not consider this + * packet any longer, even if it is retransmitted, as end host will + * drop it anyway */ + rd->ra_base_seq = seg->seq - 1; + + /* send gap "signal" */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + + /* set a GAP flag and make sure not bothering this stream anymore */ + SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); + stream->flags |= STREAMTCP_STREAM_FLAG_GAP; + + StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); + StatsIncr(tv, ra_ctx->counter_tcp_reass_gap); +#ifdef DEBUG + dbg_app_layer_gap++; +#endif + return 1; + } + return 0; +} + +static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd, + Packet *p) +{ + /* fast paths: send data directly into the app layer, w/o first doing + * a copy step. However, don't use the fast path until protocol detection + * has been completed + * TODO if initial data is big enough for proto detect, we could do the + * fast path anyway. */ + if (stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) { + /* fast path 1: segment is exactly what we need */ + if (likely(rd->data_len == 0 && + SEQ_EQ(seg->seq, rd->ra_base_seq+1) && + SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len)))) + { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; +#ifdef DEBUG + ra_ctx->fp1++; +#endif + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */ + } else if (rd->data_len == 0 && + SEQ_EQ(seg->seq, rd->ra_base_seq+1) && + SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) && + seg->payload_len >= stream_config.zero_copy_size) + { + /* process single segment directly */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + seg->payload, seg->payload_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += seg->payload_len; + rd->ra_base_seq += seg->payload_len; +#ifdef DEBUG + ra_ctx->fp2++; +#endif + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + return 1; + } + } +#ifdef DEBUG + ra_ctx->sp++; +#endif + uint16_t payload_offset = 0; + uint16_t payload_len = 0; + + /* start clean */ + rd->partial = FALSE; + + /* if the segment ends beyond ra_base_seq we need to consider it */ + if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) { + SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " + "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq, + seg->payload_len, rd->ra_base_seq, stream->last_ack); + + if (StreamTcpInlineMode() == 0) { + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = (rd->ra_base_seq + 1) - seg->seq; + SCLogDebug("payload_offset %u", payload_offset); + + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) { + return 1; + } else { + payload_len = (stream->last_ack - seg->seq) - payload_offset; + SCLogDebug("payload_len %u", payload_len); + } + rd->partial = TRUE; + } else { + payload_len = seg->payload_len - payload_offset; + SCLogDebug("payload_len %u", payload_len); + } + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } + } else { + payload_offset = 0; + + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + payload_len = stream->last_ack - seg->seq; + SCLogDebug("payload_len %u", payload_len); + + rd->partial = TRUE; + } else { + payload_len = seg->payload_len; + SCLogDebug("payload_len %u", payload_len); + } + } + /* inline mode, don't consider last_ack as we process un-ACK'd segments */ + } else { + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = rd->ra_base_seq - seg->seq - 1; + payload_len = seg->payload_len - payload_offset; + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } + } else { + payload_offset = 0; + payload_len = seg->payload_len; + } + } + SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" + " and stream->last_ack is %"PRIu32"", payload_offset, + payload_len, stream->last_ack); + + if (payload_len == 0) { + SCLogDebug("no payload_len, so bail out"); + return 0; + } + + /* copy the data into the buffer */ + uint16_t copy_size = sizeof(rd->data) - rd->data_len; + if (copy_size + payload_offset > seg->payload_len) { + copy_size = seg->payload_len - payload_offset; + } + if (copy_size > payload_len) { + copy_size = payload_len; + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > sizeof(rd->data)); + BUG_ON(copy_size+payload_offset > seg->payload_len); + BUG_ON(copy_size+payload_offset > seg->pool_size); + } + + SCLogDebug("copy_size is %"PRIu16"", copy_size); + memcpy(rd->data + rd->data_len, seg->payload + payload_offset, copy_size); + rd->data_len += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, rd->ra_base_seq, rd->data_len); + + /* queue the smsg if it's full */ + if (rd->data_len == sizeof(rd->data)) { + /* process what we have so far */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd->data, rd->data_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += rd->data_len; + rd->data_len = 0; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + } + + /* if the payload len is bigger than what we copied, we handle the + * rest of the payload next... */ + if (copy_size < payload_len) { + SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, + payload_len); + + payload_offset += copy_size; + payload_len -= copy_size; + SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " + "%"PRIu16" and stream->last_ack is %"PRIu32"", + payload_offset, seg->payload_len, stream->last_ack); + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + + /* we need a while loop here as the packets theoretically can be + * 64k */ + char segment_done = FALSE; + while (segment_done == FALSE) { + SCLogDebug("new msg at offset %" PRIu32 ", payload_len " + "%" PRIu32 "", payload_offset, payload_len); + rd->data_len = 0; + + copy_size = sizeof(rd->data) - rd->data_len; + if (copy_size > (seg->payload_len - payload_offset)) { + copy_size = (seg->payload_len - payload_offset); + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > sizeof(rd->data)); + } + + SCLogDebug("copy payload_offset %" PRIu32 ", data_len " + "%" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->data_len, copy_size); + memcpy(rd->data + rd->data_len, seg->payload + + payload_offset, copy_size); + rd->data_len += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq); + SCLogDebug("copied payload_offset %" PRIu32 ", " + "data_len %" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->data_len, copy_size); + + if (rd->data_len == sizeof(rd->data)) { + /* process what we have so far */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd->data, rd->data_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + rd->data_sent += rd->data_len; + rd->data_len = 0; + + /* if after the first data chunk we have no alproto yet, + * there is no point in continueing here. */ + if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("no alproto after first data chunk"); + return 0; + } + } + + /* see if we have segment payload left to process */ + if ((copy_size + payload_offset) < seg->payload_len) { + payload_offset += copy_size; + payload_len -= copy_size; + + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + } else { + payload_offset = 0; + segment_done = TRUE; + } + } + } + } + + return 1; +} + /** * \brief Update the stream reassembly upon receiving an ACK packet. * @@ -2855,20 +2903,61 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* this function can be directly called by app layer protocol * detection. */ - if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { + if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_GAP)) { SCLogDebug("stream no reassembly flag set. Mostly called via " "app proto detection."); SCReturnInt(0); } - uint8_t flags = 0; - SCLogDebug("stream->seg_list %p", stream->seg_list); #ifdef DEBUG PrintList(stream->seg_list); GetSessionSize(ssn, p); #endif + /* Check if we have a gap at the start of the stream. 2 conditions: + * 1. no segments, but last_ack moved fwd + * 2. segments, but clearly some missing: if last_ack is + * bigger than the list start and the list start is bigger than + * next_seq, we know we are missing data that has been ack'd. That + * won't get retransmitted, so it's a data gap. + */ + if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) { + int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1; + if ((stream->seg_list == NULL && /*1*/ + stream->ra_app_base_seq == stream->isn && + SEQ_GT(stream->last_ack, stream->isn + ackadd)) + || + (stream->seg_list != NULL && /*2*/ + SEQ_GT(stream->seg_list->seq, stream->ra_app_base_seq+1) && + SEQ_LT(stream->seg_list->seq, stream->last_ack))) + { + if (stream->seg_list == NULL) { + SCLogDebug("no segs, last_ack moved fwd so GAP " + "(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64, + stream->ra_app_base_seq, stream->isn, stream->last_ack, + stream->last_ack - (stream->isn + ackadd), p->pcap_cnt); + } + + /* send gap signal */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, + StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + + /* set a GAP flag and make sure not bothering this stream anymore */ + SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); + stream->flags |= STREAMTCP_STREAM_FLAG_GAP; + + StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); + StatsIncr(tv, ra_ctx->counter_tcp_reass_gap); +#ifdef DEBUG + dbg_app_layer_gap++; +#endif + SCReturnInt(0); + } + } + /* if no segments are in the list or all are already processed, * and state is beyond established, we send an empty msg */ TcpSegment *seg_tail = stream->seg_list_tail; @@ -2880,9 +2969,9 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) { SCLogDebug("sending empty eof message"); /* send EOF to app layer */ - STREAM_SET_FLAGS(ssn, stream, p, flags); AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags); + NULL, 0, + StreamGetAppLayerFlags(ssn, stream, p)); AppLayerProfilingStore(ra_ctx->app_tctx, p); SCReturnInt(0); @@ -2902,57 +2991,37 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, /* stream->ra_app_base_seq remains at stream->isn until protocol is * detected. */ - uint32_t ra_base_seq = stream->ra_app_base_seq; - uint8_t data[4096]; - uint32_t data_len = 0; - uint16_t payload_offset = 0; - uint16_t payload_len = 0; - uint32_t next_seq = ra_base_seq + 1; + ReassembleData rd; + rd.ra_base_seq = stream->ra_app_base_seq; + rd.data_len = 0; + rd.data_sent = 0; + rd.partial = FALSE; + uint32_t next_seq = rd.ra_base_seq + 1; SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, - ra_base_seq, stream->last_ack, next_seq); + rd.ra_base_seq, stream->last_ack, next_seq); /* loop through the segments and fill one or more msgs */ TcpSegment *seg = stream->seg_list; SCLogDebug("pre-loop seg %p", seg); - - /* Check if we have a gap at the start of the list. If last_ack is - * bigger than the list start and the list start is bigger than - * next_seq, we know we are missing data that has been ack'd. That - * won't get retransmitted, so it's a data gap. - */ - if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { - if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { - /* send gap signal */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; +#ifdef DEBUG_VALIDATION + uint64_t bytes = 0; #endif - SCReturnInt(0); - } - } - - for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) + for (; seg != NULL; ) { +#ifdef DEBUG_VALIDATION + bytes += seg->payload_len; +#endif + /* if in inline mode, we process all segments regardless of whether + * they are ack'd or not. In non-inline, we process only those that + * are at least partly ack'd. */ + if (StreamTcpInlineMode() == 0 && SEQ_GEQ(seg->seq, stream->last_ack)) + break; + SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len)); - if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { - SCLogDebug("FLOW_NO_APPLAYER_INSPECTION set, breaking out"); - break; - } - if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { SCLogDebug("removing segment"); TcpSegment *next_seg = seg->next; @@ -2960,252 +3029,66 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; - } else if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + } else if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) { TcpSegment *next_seg = seg->next; seg = next_seg; continue; } - /* we've run into a sequence gap */ - if (SEQ_GT(seg->seq, next_seq)) { - - /* first, pass on data before the gap */ - if (data_len > 0) { - SCLogDebug("pre GAP data"); - - STREAM_SET_FLAGS(ssn, stream, p, flags); + /* check if we have a sequence gap and if so, handle it */ + if (DoHandleGap(tv, ra_ctx, ssn, stream, seg, &rd, p, next_seq) == 1) + break; - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - } + /* process this segment */ + if (DoReassemble(tv, ra_ctx, ssn, stream, seg, &rd, p) == 0) + break; - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); + /* done with this segment, return it to the pool */ + TcpSegment *next_seg = seg->next; + next_seq = seg->seq + seg->payload_len; + if (rd.partial == FALSE) { + SCLogDebug("fully done with segment in app layer reassembly (seg %p seq %"PRIu32")", + seg, seg->seq); + seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; + SCLogDebug("flags now %02x", seg->flags); + } else { + SCLogDebug("not yet fully done with segment in app layer reassembly"); + } + seg = next_seg; + } +#ifdef DEBUG_VALIDATION /* we should never have this much data queued */ + BUG_ON(bytes > 1000000ULL && bytes > (stream->window * 1.5)); #endif - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; - /* send gap signal */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, flags|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); + /* put the partly filled smsg in the queue to the l7 handler */ + if (rd.data_len > 0) { + SCLogDebug("data_len > 0, %u", rd.data_len); + /* process what we have so far */ + BUG_ON(rd.data_len > sizeof(rd.data)); + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + rd.data, rd.data_len, + StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + } - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - break; - } - - int partial = FALSE; - - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq, - seg->payload_len, ra_base_seq, stream->last_ack); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = (ra_base_seq + 1) - seg->seq; - SCLogDebug("payload_offset %u", payload_offset); - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - if (SEQ_LT(stream->last_ack, (ra_base_seq + 1))) { - payload_len = (stream->last_ack - seg->seq); - SCLogDebug("payload_len %u", payload_len); - } else { - payload_len = (stream->last_ack - seg->seq) - payload_offset; - SCLogDebug("payload_len %u", payload_len); - } - partial = TRUE; - } else { - payload_len = seg->payload_len - payload_offset; - SCLogDebug("payload_len %u", payload_len); - } - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; - - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - payload_len = stream->last_ack - seg->seq; - SCLogDebug("payload_len %u", payload_len); - - partial = TRUE; - } else { - payload_len = seg->payload_len; - SCLogDebug("payload_len %u", payload_len); - } - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->last_ack is %"PRIu32"", payload_offset, - payload_len, stream->last_ack); - - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; - } - - /* copy the data into the smsg */ - uint16_t copy_size = sizeof(data) - data_len; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(data + data_len, seg->payload + payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); - - /* queue the smsg if it's full */ - if (data_len == sizeof(data)) { - /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - - /* if after the first data chunk we have no alproto yet, - * there is no point in continueing here. */ - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("no alproto after first data chunk"); - break; - } - } - - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); - data_len = 0; - - copy_size = sizeof(data) - data_len; - if (copy_size > (seg->payload_len - payload_offset)) { - copy_size = (seg->payload_len - payload_offset); - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - - SCLogDebug("copy payload_offset %" PRIu32 ", data_len " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - memcpy(data + data_len, seg->payload + - payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - SCLogDebug("copied payload_offset %" PRIu32 ", " - "data_len %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - - if (data_len == sizeof(data)) { - /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - - /* if after the first data chunk we have no alproto yet, - * there is no point in continueing here. */ - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("no alproto after first data chunk"); - break; - } - } - - /* see if we have segment payload left to process */ - if ((copy_size + payload_offset) < seg->payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } - } - - /* done with this segment, return it to the pool */ - TcpSegment *next_seg = seg->next; - next_seq = seg->seq + seg->payload_len; - if (partial == FALSE) { - SCLogDebug("fully done with segment in app layer reassembly (seg %p seq %"PRIu32")", - seg, seg->seq); - seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - SCLogDebug("flags now %02x", seg->flags); - } else { - SCLogDebug("not yet fully done with segment in app layer reassembly"); - } - seg = next_seg; - } - - /* put the partly filled smsg in the queue to the l7 handler */ - if (data_len > 0) { - SCLogDebug("data_len > 0, %u", data_len); - /* process what we have so far */ - STREAM_SET_FLAGS(ssn, stream, p, flags); - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, flags); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - } + /* if no data was sent to the applayer, we send it a empty 'nudge' + * when in inline mode */ + if (StreamTcpInlineMode() && rd.data_sent == 0 && ssn->state > TCP_ESTABLISHED) { + SCLogDebug("sending empty eof message"); + /* send EOF to app layer */ + AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, + NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)); + AppLayerProfilingStore(ra_ctx->app_tctx, p); + } /* store ra_base_seq in the stream */ if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - stream->ra_app_base_seq = ra_base_seq; + stream->ra_app_base_seq = rd.ra_base_seq; } else { TcpSegment *tmp_seg = stream->seg_list; while (tmp_seg != NULL) { + if (!(tmp_seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) + break; tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED; tmp_seg = tmp_seg->next; } @@ -3214,266 +3097,292 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, SCReturnInt(0); } -/** - * \brief Update the stream reassembly upon receiving an ACK packet. - * \todo this function is too long, we need to break it up. It needs it BAD - */ -static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, Packet *p) -{ - SCEnter(); - SCLogDebug("start p %p", p); - - if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) - SCReturnInt(0); +typedef struct ReassembleRawData_ { + uint32_t ra_base_seq; + int partial; /* last segment was processed only partially */ + StreamMsg *smsg; + uint32_t smsg_offset; // TODO diff with smsg->data_len? +} ReassembleRawData; - if (stream->seg_list == NULL) { - SCLogDebug("no segments in the list to reassemble"); - SCReturnInt(0); - } +static void DoHandleRawGap(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p, + ReassembleRawData *rd, uint32_t next_seq) +{ + /* we've run into a sequence gap */ + if (SEQ_GT(seg->seq, next_seq)) { + /* pass on pre existing smsg (if any) */ + if (rd->smsg != NULL && rd->smsg->data_len > 0) { + /* if app layer protocol has not been detected till yet, + then check did we have sent message to app layer already + or not. If not then sent the message and set flag that first + message has been sent. No more data till proto has not + been detected */ + StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); + stream->ra_raw_base_seq = rd->ra_base_seq; + rd->smsg = NULL; + } -#if 0 - if (ssn->state <= TCP_ESTABLISHED && - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - SCLogDebug("only starting raw reassembly after app layer protocol " - "detection has completed."); - SCReturnInt(0); - } + /* see what the length of the gap is, gap length is seg->seq - + * (ra_base_seq +1) */ +#ifdef DEBUG + uint32_t gap_len = seg->seq - next_seq; + SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " + "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", + next_seq, seg->seq, stream->last_ack, gap_len); #endif - /* check if we have enough data */ - if (StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0) { - SCLogDebug("not yet reassembling"); - SCReturnInt(0); + stream->ra_raw_base_seq = rd->ra_base_seq; + + /* We have missed the packet and end host has ack'd it, so + * IDS should advance it's ra_base_seq and should not consider this + * packet any longer, even if it is retransmitted, as end host will + * drop it anyway */ + rd->ra_base_seq = seg->seq - 1; } +} - uint32_t ra_base_seq = stream->ra_raw_base_seq; - StreamMsg *smsg = NULL; - uint16_t smsg_offset = 0; +static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p, + ReassembleRawData *rd) +{ uint16_t payload_offset = 0; uint16_t payload_len = 0; - TcpSegment *seg = stream->seg_list; - uint32_t next_seq = ra_base_seq + 1; - SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, - ra_base_seq, stream->last_ack, next_seq); + /* start clean */ + rd->partial = FALSE; - /* loop through the segments and fill one or more msgs */ - for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) - { - SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", flags %02x", - seg, seg->seq, seg->payload_len, - (uint32_t)(seg->seq + seg->payload_len), seg->flags); + /* if the segment ends beyond ra_base_seq we need to consider it */ + if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) { + SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " + "ra_base_seq %" PRIu32 "", seg->seq, + seg->payload_len, rd->ra_base_seq); - if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { - SCLogDebug("removing segment"); - TcpSegment *next_seg = seg->next; - StreamTcpRemoveSegmentFromStream(stream, seg); - StreamTcpSegmentReturntoPool(seg); - seg = next_seg; - continue; - } else if(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { - TcpSegment *next_seg = seg->next; - seg = next_seg; - continue; - } + /* handle segments partly before ra_base_seq */ + if (SEQ_GT(rd->ra_base_seq, seg->seq)) { + payload_offset = rd->ra_base_seq - seg->seq; - /* we've run into a sequence gap */ - if (SEQ_GT(seg->seq, next_seq)) { + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - /* pass on pre existing smsg (if any) */ - if (smsg != NULL && smsg->data_len > 0) { - /* if app layer protocol has not been detected till yet, - then check did we have sent message to app layer already - or not. If not then sent the message and set flag that first - message has been sent. No more data till proto has not - been detected */ - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; + if (SEQ_LT(stream->last_ack, rd->ra_base_seq)) { + return 1; + } else { + payload_len = (stream->last_ack - seg->seq) - payload_offset; + } + rd->partial = TRUE; + } else { + payload_len = seg->payload_len - payload_offset; } - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); -#endif - stream->ra_raw_base_seq = ra_base_seq; + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + BUG_ON((payload_len + payload_offset) > seg->payload_len); + } + } else { + payload_offset = 0; - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; + if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + payload_len = stream->last_ack - seg->seq; + rd->partial = TRUE; + } else { + payload_len = seg->payload_len; + } } + SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" + " and stream->last_ack is %"PRIu32"", payload_offset, + payload_len, stream->last_ack); - int partial = FALSE; - - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), ra_base_seq+1)) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 "", seg->seq, - seg->payload_len, ra_base_seq); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = ra_base_seq - seg->seq; + if (payload_len == 0) { + SCLogDebug("no payload_len, so bail out"); + return 1; // TODO + } - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { + if (rd->smsg == NULL) { + rd->smsg = StreamMsgGetFromPool(); + if (rd->smsg == NULL) { + SCLogDebug("stream_msg_pool is empty"); + return -1; + } - if (SEQ_LT(stream->last_ack, ra_base_seq)) { - payload_len = (stream->last_ack - seg->seq); - } else { - payload_len = (stream->last_ack - seg->seq) - payload_offset; - } - partial = TRUE; - } else { - payload_len = seg->payload_len - payload_offset; - } + rd->smsg_offset = 0; - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; + StreamTcpSetupMsg(ssn, stream, p, rd->smsg); + rd->smsg->seq = rd->ra_base_seq + 1; + SCLogDebug("smsg->seq %u", rd->smsg->seq); + } - if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) { - payload_len = stream->last_ack - seg->seq; - partial = TRUE; - } else { - payload_len = seg->payload_len; - } - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->last_ack is %"PRIu32"", payload_offset, - payload_len, stream->last_ack); + /* copy the data into the smsg */ + uint32_t copy_size = rd->smsg->data_size - rd->smsg_offset; + if (copy_size + payload_offset > seg->payload_len) { + copy_size = seg->payload_len - payload_offset; + } + if (copy_size > payload_len) { + copy_size = payload_len; + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > rd->smsg->data_size); + } + SCLogDebug("copy_size is %"PRIu16"", copy_size); + memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + payload_offset, + copy_size); + rd->smsg_offset += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq); + + rd->smsg->data_len += copy_size; + + /* queue the smsg if it's full */ + if (rd->smsg->data_len == rd->smsg->data_size) { + StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); + stream->ra_raw_base_seq = rd->ra_base_seq; + rd->smsg = NULL; + } - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; + /* if the payload len is bigger than what we copied, we handle the + * rest of the payload next... */ + if (copy_size < payload_len) { + SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, + payload_len); + + payload_offset += copy_size; + payload_len -= copy_size; + SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " + "%"PRIu16" and stream->last_ack is %"PRIu32"", + payload_offset, seg->payload_len, stream->last_ack); + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); } - if (smsg == NULL) { - smsg = StreamMsgGetFromPool(); - if (smsg == NULL) { + /* we need a while loop here as the packets theoretically can be + * 64k */ + char segment_done = FALSE; + while (segment_done == FALSE) { + SCLogDebug("new msg at offset %" PRIu32 ", payload_len " + "%" PRIu32 "", payload_offset, payload_len); + + /* get a new message + XXX we need a setup function */ + rd->smsg = StreamMsgGetFromPool(); + if (rd->smsg == NULL) { SCLogDebug("stream_msg_pool is empty"); - return -1; + SCReturnInt(-1); } + rd->smsg_offset = 0; - smsg_offset = 0; + StreamTcpSetupMsg(ssn, stream, p, rd->smsg); + rd->smsg->seq = rd->ra_base_seq + 1; - StreamTcpSetupMsg(ssn, stream, p, smsg); - smsg->seq = ra_base_seq + 1; - SCLogDebug("smsg->seq %u", smsg->seq); - } + copy_size = rd->smsg->data_size - rd->smsg_offset; + if (copy_size > payload_len) { + copy_size = payload_len; + } + if (SCLogDebugEnabled()) { + BUG_ON(copy_size > rd->smsg->data_size); + } - /* copy the data into the smsg */ - uint16_t copy_size = sizeof (smsg->data) - smsg_offset; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(smsg->data + smsg_offset, seg->payload + payload_offset, - copy_size); - smsg_offset += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); + SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " + "%" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->smsg_offset, copy_size); + memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + + payload_offset, copy_size); + rd->smsg_offset += copy_size; + rd->ra_base_seq += copy_size; + SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq); + rd->smsg->data_len += copy_size; + SCLogDebug("copied payload_offset %" PRIu32 ", " + "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", + payload_offset, rd->smsg_offset, copy_size); + if (rd->smsg->data_len == rd->smsg->data_size) { + StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0); + stream->ra_raw_base_seq = rd->ra_base_seq; + rd->smsg = NULL; + } - smsg->data_len += copy_size; + /* see if we have segment payload left to process */ + if (copy_size < payload_len) { + payload_offset += copy_size; + payload_len -= copy_size; - /* queue the smsg if it's full */ - if (smsg->data_len == sizeof (smsg->data)) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; + if (SCLogDebugEnabled()) { + BUG_ON(payload_offset > seg->payload_len); + } + } else { + payload_offset = 0; + segment_done = TRUE; + } } + } + } + return 1; +} - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } +/** + * \brief Update the stream reassembly upon receiving an ACK packet. + * \todo this function is too long, we need to break it up. It needs it BAD + */ +static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, + TcpSession *ssn, TcpStream *stream, Packet *p) +{ + SCEnter(); + SCLogDebug("start p %p", p); - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); + if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) + SCReturnInt(0); - /* get a new message - XXX we need a setup function */ - smsg = StreamMsgGetFromPool(); - if (smsg == NULL) { - SCLogDebug("stream_msg_pool is empty"); - SCReturnInt(-1); - } - smsg_offset = 0; + if (stream->seg_list == NULL) { + SCLogDebug("no segments in the list to reassemble"); + SCReturnInt(0); + } - StreamTcpSetupMsg(ssn, stream,p,smsg); - smsg->seq = ra_base_seq + 1; +#if 0 + if (ssn->state <= TCP_ESTABLISHED && + !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { + SCLogDebug("only starting raw reassembly after app layer protocol " + "detection has completed."); + SCReturnInt(0); + } +#endif + /* check if we have enough data */ + if (StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0) { + SCLogDebug("not yet reassembling"); + SCReturnInt(0); + } - copy_size = sizeof(smsg->data) - smsg_offset; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(smsg->data)); - } + TcpSegment *seg = stream->seg_list; + ReassembleRawData rd; + rd.smsg = NULL; + rd.ra_base_seq = stream->ra_raw_base_seq; + rd.smsg_offset = 0; + uint32_t next_seq = rd.ra_base_seq + 1; - SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, smsg_offset, copy_size); - memcpy(smsg->data + smsg_offset, seg->payload + - payload_offset, copy_size); - smsg_offset += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - smsg->data_len += copy_size; - SCLogDebug("copied payload_offset %" PRIu32 ", " - "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, smsg_offset, copy_size); - if (smsg->data_len == sizeof (smsg->data)) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - stream->ra_raw_base_seq = ra_base_seq; - smsg = NULL; - } + SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32, + rd.ra_base_seq, stream->last_ack, next_seq); - /* see if we have segment payload left to process */ - if (copy_size < payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; + /* loop through the segments and fill one or more msgs */ + for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) + { + SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", flags %02x", + seg, seg->seq, seg->payload_len, + (uint32_t)(seg->seq + seg->payload_len), seg->flags); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } + if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { + SCLogDebug("removing segment"); + TcpSegment *next_seg = seg->next; + StreamTcpRemoveSegmentFromStream(stream, seg); + StreamTcpSegmentReturntoPool(seg); + seg = next_seg; + continue; + } else if(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { + TcpSegment *next_seg = seg->next; + seg = next_seg; + continue; } + DoHandleRawGap(ssn, stream, seg, p, &rd, next_seq); + + if (DoRawReassemble(ssn, stream, seg, p, &rd) == 0) + break; + /* done with this segment, return it to the pool */ TcpSegment *next_seg = seg->next; next_seq = seg->seq + seg->payload_len; - if (partial == FALSE) { + if (rd.partial == FALSE) { SCLogDebug("fully done with segment in raw reassembly (seg %p seq %"PRIu32")", seg, seg->seq); seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; @@ -3485,10 +3394,10 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, } /* put the partly filled smsg in the queue to the l7 handler */ - if (smsg != NULL) { - StreamTcpStoreStreamChunk(ssn, smsg, p, 0); - smsg = NULL; - stream->ra_raw_base_seq = ra_base_seq; + if (rd.smsg != NULL) { + StreamTcpStoreStreamChunk(ssn, rd.smsg, p, 0); + rd.smsg = NULL; + stream->ra_raw_base_seq = rd.ra_base_seq; } SCReturnInt(0); @@ -3558,7 +3467,7 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ * functions to handle EOF */ if (StreamTcpInlineMode()) { int r = 0; - if (StreamTcpReassembleInlineAppLayer(tv, ra_ctx, ssn, stream, p) < 0) + if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0) r = -1; if (StreamTcpReassembleInlineRaw(ra_ctx, ssn, stream, p) < 0) r = -1; @@ -3568,7 +3477,6 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ } } - StreamTcpReassembleMemuseCounter(tv, ra_ctx); SCReturnInt(0); } @@ -3745,7 +3653,7 @@ TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, segment_pool[idx]->allocated); /* Increment the counter to show that we are not able to serve the segment request due to memcap limit */ - SCPerfCounterIncr(ra_ctx->counter_tcp_segment_memcap, tv->sc_perf_pca); + StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap); } else { seg->flags = stream_config.segment_init_flags; seg->next = NULL; @@ -3789,6 +3697,25 @@ void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn) #ifdef UNITTESTS /** unit tests and it's support functions below */ +static int UtTestSmsg(StreamMsg *smsg, const uint8_t *buf, uint32_t buf_len) +{ + if (smsg == NULL) + return 0; + + if (smsg->data_len != buf_len) { + return 0; + } + + if (!(memcmp(buf, smsg->data, buf_len) == 0)) { + printf("data is not what we expected:\nExpected:\n"); + PrintRawDataFp(stdout, (uint8_t *)buf, buf_len); + printf("Got:\n"); + PrintRawDataFp(stdout, smsg->data, smsg->data_len); + return 0; + } + return 1; +} + static uint32_t UtSsnSmsgCnt(TcpSession *ssn, uint8_t direction) { uint32_t cnt = 0; @@ -5174,14 +5101,14 @@ static int StreamTcpTestMissedPacket (TcpReassemblyThreadCtx *ra_ctx, s = &ssn->client; } - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, ssn, s, p, &pq) == -1) { - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return -1; } - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return 0; } @@ -5547,6 +5474,9 @@ static int StreamTcpReassembleTest30 (void) th_flag = TH_ACK|TH_PUSH; th_flags = TH_ACK; + ssn.client.last_ack = 2; + ssn.client.isn = 1; + ssn.server.last_ack = 22; ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; ssn.server.isn = 9; @@ -6230,7 +6160,7 @@ static int StreamTcpReassembleTest38 (void) ssn.server.last_ack = 60; ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; ssn.client.isn = 9; - ssn.client.last_ack = 60; + ssn.client.last_ack = 9; f.alproto = ALPROTO_UNKNOWN; f.flags |= FLOW_IPV4; @@ -6254,7 +6184,7 @@ static int StreamTcpReassembleTest38 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; @@ -6288,7 +6218,7 @@ static int StreamTcpReassembleTest38 (void) end: StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return ret; } @@ -6317,12 +6247,13 @@ static int StreamTcpReassembleTest39 (void) StreamTcpThreadInit(&tv, NULL, (void **)&stt); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); f.flags = FLOW_IPV4; f.proto = IPPROTO_TCP; p->flow = &f; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); int ret = 0; StreamTcpInitConfig(TRUE); @@ -6343,9 +6274,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6370,9 +6299,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6398,9 +6325,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6427,9 +6352,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6457,9 +6380,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6498,9 +6419,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_UNKNOWN || f.alproto_ts != ALPROTO_UNKNOWN || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6570,9 +6489,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6599,9 +6516,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6628,9 +6543,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6656,9 +6569,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6684,9 +6595,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6714,9 +6623,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6744,9 +6651,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6773,9 +6678,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list == NULL || @@ -6803,9 +6706,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list->next == NULL || @@ -6846,9 +6747,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6873,9 +6772,7 @@ static int StreamTcpReassembleTest39 (void) f.alproto != ALPROTO_HTTP || f.alproto_ts != ALPROTO_HTTP || f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - f.flags & FLOW_NO_APPLAYER_INSPECTION || + ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || ssn->client.seg_list != NULL || @@ -6892,7 +6789,7 @@ static int StreamTcpReassembleTest39 (void) StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); return ret; } @@ -6964,7 +6861,7 @@ static int StreamTcpReassembleTest40 (void) TcpStream *s = NULL; s = &ssn.client; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; @@ -7094,7 +6991,7 @@ static int StreamTcpReassembleTest40 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7169,7 +7066,7 @@ static int StreamTcpReassembleTest43 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toserver packet (1): "); goto end; @@ -7265,7 +7162,7 @@ static int StreamTcpReassembleTest43 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7347,7 +7244,7 @@ static int StreamTcpReassembleTest45 (void) ssn.server.last_ack = 60; STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9); ssn.client.isn = 9; - ssn.client.last_ack = 60; + ssn.client.last_ack = 9; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); if (f == NULL) @@ -7368,12 +7265,12 @@ static int StreamTcpReassembleTest45 (void) ssn.state = TCP_ESTABLISHED; /* set the default value of reassembly depth, as there is no config file */ - stream_config.reassembly_depth = httplen1 + 1; + ssn.reassembly_depth = httplen1 + 1; TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toclient packet: "); goto end; @@ -7425,7 +7322,7 @@ static int StreamTcpReassembleTest45 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7466,7 +7363,7 @@ static int StreamTcpReassembleTest46 (void) ssn.server.next_seq = ssn.server.isn; STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9); ssn.client.isn = 9; - ssn.client.last_ack = 60; + ssn.client.last_ack = 9; ssn.client.next_seq = ssn.client.isn; f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220); @@ -7492,7 +7389,7 @@ static int StreamTcpReassembleTest46 (void) TcpStream *s = NULL; s = &ssn.server; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { printf("failed in segments reassembly, while processing toclient packet\n"); goto end; @@ -7549,7 +7446,7 @@ static int StreamTcpReassembleTest46 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7606,7 +7503,7 @@ static int StreamTcpReassembleTest47 (void) TcpStream *s = NULL; uint8_t cnt = 0; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); for (cnt=0; cnt < httplen1; cnt++) { tcph.th_seq = htonl(ssn.client.isn + 1 + cnt); tcph.th_ack = htonl(572799782UL); @@ -7649,7 +7546,7 @@ static int StreamTcpReassembleTest47 (void) StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); SCFree(p); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -7666,6 +7563,7 @@ static int StreamTcpReassembleInlineTest01(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -7680,7 +7578,7 @@ static int StreamTcpReassembleInlineTest01(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7707,22 +7605,12 @@ static int StreamTcpReassembleInlineTest01(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload, 15) == 0) goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7744,6 +7632,7 @@ static int StreamTcpReassembleInlineTest02(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -7759,7 +7648,7 @@ static int StreamTcpReassembleInlineTest02(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7786,18 +7675,8 @@ static int StreamTcpReassembleInlineTest02(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); @@ -7817,22 +7696,12 @@ static int StreamTcpReassembleInlineTest02(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 20) == 0) goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7855,6 +7724,7 @@ static int StreamTcpReassembleInlineTest03(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -7873,7 +7743,7 @@ static int StreamTcpReassembleInlineTest03(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -7900,18 +7770,8 @@ static int StreamTcpReassembleInlineTest03(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); @@ -7933,22 +7793,12 @@ static int StreamTcpReassembleInlineTest03(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 15) == 0) goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -7971,6 +7821,7 @@ static int StreamTcpReassembleInlineTest04(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -7989,7 +7840,7 @@ static int StreamTcpReassembleInlineTest04(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8016,18 +7867,8 @@ static int StreamTcpReassembleInlineTest04(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { printf("failed to add segment 4: "); @@ -8049,22 +7890,12 @@ static int StreamTcpReassembleInlineTest04(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 16) { - printf("expected data length to be 16, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 16) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 16); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 16) == 0) goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8084,6 +7915,7 @@ static int StreamTcpReassembleInlineTest05(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8099,7 +7931,7 @@ static int StreamTcpReassembleInlineTest05(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8129,36 +7961,16 @@ static int StreamTcpReassembleInlineTest05(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 10) { - printf("expected data length to be 10, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 10) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 10); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 10) == 0) goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8178,6 +7990,7 @@ static int StreamTcpReassembleInlineTest06(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8194,7 +8007,7 @@ static int StreamTcpReassembleInlineTest06(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8224,32 +8037,12 @@ static int StreamTcpReassembleInlineTest06(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 10) { - printf("expected data length to be 10, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 10) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 10); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 10) == 0) goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); @@ -8271,22 +8064,12 @@ static int StreamTcpReassembleInlineTest06(void) } smsg = ssn.toserver_smsg_head->next->next; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload3, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload3, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload3, 20) == 0) goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8307,6 +8090,7 @@ static int StreamTcpReassembleInlineTest07(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8326,7 +8110,7 @@ static int StreamTcpReassembleInlineTest07(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8356,32 +8140,12 @@ static int StreamTcpReassembleInlineTest07(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 6) { - printf("expected data length to be 6, got %u: ", smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 6) == 0) goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 6) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 6); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); - goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { printf("failed to add segment 3: "); @@ -8403,22 +8167,12 @@ static int StreamTcpReassembleInlineTest07(void) } smsg = ssn.toserver_smsg_head->next->next; - if (smsg->data_len != 16) { - printf("expected data length to be 16, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload3, smsg->data, 16) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload3, 16); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload3, 16) == 0) goto end; - } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8442,6 +8196,7 @@ static int StreamTcpReassembleInlineTest08(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8461,7 +8216,7 @@ static int StreamTcpReassembleInlineTest08(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8488,18 +8243,8 @@ static int StreamTcpReassembleInlineTest08(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 15) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 16) { printf("ra_raw_base_seq %"PRIu32", expected 16: ", ssn.client.ra_raw_base_seq); @@ -8526,18 +8271,8 @@ static int StreamTcpReassembleInlineTest08(void) } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 15) { - printf("expected data length to be 15, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 15) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 15); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 15) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); @@ -8551,7 +8286,7 @@ static int StreamTcpReassembleInlineTest08(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8575,6 +8310,7 @@ static int StreamTcpReassembleInlineTest09(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.client, 1); FLOW_INITIALIZE(&f); @@ -8595,7 +8331,7 @@ static int StreamTcpReassembleInlineTest09(void) p->flow = &f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8622,32 +8358,12 @@ static int StreamTcpReassembleInlineTest09(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 10) { - printf("expected data length to be 10, got %u (bot): ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 10) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 10); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 10) == 0) goto end; - } smsg = ssn.toserver_smsg_head->next; - if (smsg->data_len != 5) { - printf("expected data length to be 5, got %u (top): ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload2, smsg->data, 5) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload2, 5); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload2, 5) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 11) { printf("ra_raw_base_seq %"PRIu32", expected 11: ", ssn.client.ra_raw_base_seq); @@ -8675,18 +8391,8 @@ static int StreamTcpReassembleInlineTest09(void) } smsg = ssn.toserver_smsg_head->next->next; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload3, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload3, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload3, 20) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); @@ -8700,7 +8406,7 @@ static int StreamTcpReassembleInlineTest09(void) ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8722,8 +8428,12 @@ static int StreamTcpReassembleInlineTest10(void) memset(&tv, 0x00, sizeof(tv)); StreamTcpUTInit(&ra_ctx); + StreamTcpUTInitInline(); StreamTcpUTSetupSession(&ssn); StreamTcpUTSetupStream(&ssn.server, 1); + ssn.server.last_ack = 2; + StreamTcpUTSetupStream(&ssn.client, 1); + ssn.client.last_ack = 2; f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); if (f == NULL) @@ -8744,16 +8454,16 @@ static int StreamTcpReassembleInlineTest10(void) p->flow = f; p->flowflags |= FLOW_PKT_TOSERVER; - SCMutexLock(&f->m); + FLOWLOCK_WRLOCK(f); if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 2, stream_payload1, 2) == -1) { printf("failed to add segment 1: "); goto end; } ssn.server.next_seq = 4; - int r = StreamTcpReassembleInlineAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); + int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); if (r < 0) { - printf("StreamTcpReassembleInlineAppLayer failed: "); + printf("StreamTcpReassembleAppLayer failed: "); goto end; } @@ -8773,9 +8483,9 @@ static int StreamTcpReassembleInlineTest10(void) } ssn.server.next_seq = 19; - r = StreamTcpReassembleInlineAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); + r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); if (r < 0) { - printf("StreamTcpReassembleInlineAppLayer failed: "); + printf("StreamTcpReassembleAppLayer failed: "); goto end; } @@ -8789,7 +8499,7 @@ static int StreamTcpReassembleInlineTest10(void) UTHFreePacket(p); StreamTcpUTClearSession(&ssn); StreamTcpUTDeinit(ra_ctx); - SCMutexUnlock(&f->m); + FLOWLOCK_UNLOCK(f); UTHFreeFlow(f); return ret; } @@ -8821,7 +8531,7 @@ static int StreamTcpReassembleInsertTest01(void) p->tcph->th_seq = htonl(12); p->flow = &f; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { printf("failed to add segment 1: "); goto end; @@ -8856,18 +8566,8 @@ static int StreamTcpReassembleInsertTest01(void) } StreamMsg *smsg = ssn.toserver_smsg_head; - if (smsg->data_len != 20) { - printf("expected data length to be 20, got %u: ", smsg->data_len); - goto end; - } - - if (!(memcmp(stream_payload1, smsg->data, 20) == 0)) { - printf("data is not what we expected:\nExpected:\n"); - PrintRawDataFp(stdout, stream_payload1, 20); - printf("Got:\n"); - PrintRawDataFp(stdout, smsg->data, smsg->data_len); + if (UtTestSmsg(smsg, stream_payload1, 20) == 0) goto end; - } if (ssn.client.ra_raw_base_seq != 21) { printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); @@ -8875,7 +8575,7 @@ static int StreamTcpReassembleInsertTest01(void) } ret = 1; end: - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); FLOW_DESTROY(&f); UTHFreePacket(p); StreamTcpUTClearSession(&ssn); @@ -8978,67 +8678,125 @@ static int StreamTcpReassembleInsertTest03(void) void StreamTcpReassembleRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test", StreamTcpReassembleTest01, 1); - UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test", StreamTcpReassembleTest02, 1); - UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test", StreamTcpReassembleTest03, 1); - UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test", StreamTcpReassembleTest04, 1); - UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test", StreamTcpReassembleTest05, 1); - UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test", StreamTcpReassembleTest06, 1); - UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test", StreamTcpReassembleTest07, 1); - UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test", StreamTcpReassembleTest08, 1); - UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test", StreamTcpReassembleTest09, 1); - UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test", StreamTcpReassembleTest10, 1); - UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test", StreamTcpReassembleTest11, 1); - UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test", StreamTcpReassembleTest12, 1); - UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test", StreamTcpReassembleTest13, 1); - UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test", StreamTcpReassembleTest14, 1); - UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test", StreamTcpReassembleTest15, 1); - UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test", StreamTcpReassembleTest16, 1); - UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test", StreamTcpReassembleTest17, 1); - UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test", StreamTcpReassembleTest18, 1); - UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test", StreamTcpReassembleTest19, 1); - UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test", StreamTcpReassembleTest20, 1); - UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test", StreamTcpReassembleTest21, 1); - UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test", StreamTcpReassembleTest22, 1); - UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test", StreamTcpReassembleTest23, 1); - UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test", StreamTcpReassembleTest24, 1); - UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", StreamTcpReassembleTest25, 1); - UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", StreamTcpReassembleTest26, 1); - UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", StreamTcpReassembleTest27, 1); - UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", StreamTcpReassembleTest28, 1); - UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", StreamTcpReassembleTest29, 1); - UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", StreamTcpReassembleTest30, 1); - UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", StreamTcpReassembleTest31, 1); - UtRegisterTest("StreamTcpReassembleTest32 -- Bug test", StreamTcpReassembleTest32, 1); - UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", StreamTcpReassembleTest33, 1); - UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", StreamTcpReassembleTest34, 1); - UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test", StreamTcpReassembleTest35, 1); - UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test", StreamTcpReassembleTest36, 1); - UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test", StreamTcpReassembleTest37, 1); - UtRegisterTest("StreamTcpReassembleTest38 -- app proto test", StreamTcpReassembleTest38, 1); - UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", StreamTcpReassembleTest39, 1); - UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", StreamTcpReassembleTest40, 1); - UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1); - UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1); - UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45, 1); - UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46, 1); - UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", StreamTcpReassembleTest47, 1); - - UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", StreamTcpReassembleInlineTest01, 1); - UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", StreamTcpReassembleInlineTest02, 1); - UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", StreamTcpReassembleInlineTest03, 1); - UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", StreamTcpReassembleInlineTest04, 1); - UtRegisterTest("StreamTcpReassembleInlineTest05 -- inline RAW ra 5 GAP", StreamTcpReassembleInlineTest05, 1); - UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", StreamTcpReassembleInlineTest06, 1); - UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", StreamTcpReassembleInlineTest07, 1); - UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", StreamTcpReassembleInlineTest08, 1); - UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", StreamTcpReassembleInlineTest09, 1); - - UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1); - - UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", StreamTcpReassembleInsertTest01, 1); - UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", StreamTcpReassembleInsertTest02, 1); - UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", StreamTcpReassembleInsertTest03, 1); + UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test", + StreamTcpReassembleTest01); + UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test", + StreamTcpReassembleTest02); + UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test", + StreamTcpReassembleTest03); + UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test", + StreamTcpReassembleTest04); + UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test", + StreamTcpReassembleTest05); + UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test", + StreamTcpReassembleTest06); + UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test", + StreamTcpReassembleTest07); + UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test", + StreamTcpReassembleTest08); + UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test", + StreamTcpReassembleTest09); + UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test", + StreamTcpReassembleTest10); + UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test", + StreamTcpReassembleTest11); + UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test", + StreamTcpReassembleTest12); + UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test", + StreamTcpReassembleTest13); + UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test", + StreamTcpReassembleTest14); + UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test", + StreamTcpReassembleTest15); + UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test", + StreamTcpReassembleTest16); + UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test", + StreamTcpReassembleTest17); + UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test", + StreamTcpReassembleTest18); + UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test", + StreamTcpReassembleTest19); + UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test", + StreamTcpReassembleTest20); + UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test", + StreamTcpReassembleTest21); + UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test", + StreamTcpReassembleTest22); + UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test", + StreamTcpReassembleTest23); + UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test", + StreamTcpReassembleTest24); + UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", + StreamTcpReassembleTest25); + UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", + StreamTcpReassembleTest26); + UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", + StreamTcpReassembleTest27); + UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", + StreamTcpReassembleTest28); + UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", + StreamTcpReassembleTest29); + UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", + StreamTcpReassembleTest30); + UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", + StreamTcpReassembleTest31); + UtRegisterTest("StreamTcpReassembleTest32 -- Bug test", + StreamTcpReassembleTest32); + UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", + StreamTcpReassembleTest33); + UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", + StreamTcpReassembleTest34); + UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test", + StreamTcpReassembleTest35); + UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test", + StreamTcpReassembleTest36); + UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test", + StreamTcpReassembleTest37); + UtRegisterTest("StreamTcpReassembleTest38 -- app proto test", + StreamTcpReassembleTest38); + UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", + StreamTcpReassembleTest39); + UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", + StreamTcpReassembleTest40); + UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", + StreamTcpReassembleTest43); + UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", + StreamTcpReassembleTest44); + UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", + StreamTcpReassembleTest45); + UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", + StreamTcpReassembleTest46); + UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", + StreamTcpReassembleTest47); + + UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", + StreamTcpReassembleInlineTest01); + UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", + StreamTcpReassembleInlineTest02); + UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", + StreamTcpReassembleInlineTest03); + UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", + StreamTcpReassembleInlineTest04); + UtRegisterTest("StreamTcpReassembleInlineTest05 -- inline RAW ra 5 GAP", + StreamTcpReassembleInlineTest05); + UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", + StreamTcpReassembleInlineTest06); + UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", + StreamTcpReassembleInlineTest07); + UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", + StreamTcpReassembleInlineTest08); + UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", + StreamTcpReassembleInlineTest09); + + UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", + StreamTcpReassembleInlineTest10); + + UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", + StreamTcpReassembleInsertTest01); + UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", + StreamTcpReassembleInsertTest02); + UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", + StreamTcpReassembleInsertTest03); StreamTcpInlineRegisterTests(); StreamTcpUtilRegisterTests(); diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index 7eca5cf68389..b6e798ce0be6 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -57,15 +57,13 @@ typedef struct TcpReassemblyThreadCtx_ { uint16_t counter_tcp_segment_memcap; /** number of streams that stop reassembly because their depth is reached */ uint16_t counter_tcp_stream_depth; - /** account memory usage for the reassembly portion of the stream engine */ - uint16_t counter_tcp_reass_memuse; /** count number of streams with a unrecoverable stream gap (missing pkts) */ uint16_t counter_tcp_reass_gap; - /** account memory usage by suricata to handle HTTP protocol (not counting - * libhtp memory usage)*/ - uint16_t counter_htp_memuse; - /* number of allocation failed due to memcap when handling HTTP protocol */ - uint16_t counter_htp_memcap; +#ifdef DEBUG + uint64_t fp1; + uint64_t fp2; + uint64_t sp; +#endif } TcpReassemblyThreadCtx; #define OS_POLICY_DEFAULT OS_POLICY_BSD @@ -79,10 +77,6 @@ void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *); int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p); -int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); @@ -108,5 +102,9 @@ int StreamTcpReassembleDepthReached(Packet *p); void StreamTcpReassembleIncrMemuse(uint64_t size); void StreamTcpReassembleDecrMemuse(uint64_t size); int StreamTcpReassembleCheckMemcap(uint32_t size); + +void StreamTcpDisableAppLayer(Flow *f); +int StreamTcpAppLayerIsDisabled(Flow *f); + #endif /* __STREAM_TCP_REASSEMBLE_H__ */ diff --git a/src/stream-tcp-sack.c b/src/stream-tcp-sack.c index 9e5503f79834..ab0ad57faa82 100644 --- a/src/stream-tcp-sack.c +++ b/src/stream-tcp-sack.c @@ -254,8 +254,13 @@ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) { int records = TCP_GET_SACK_CNT(p); int record = 0; + const uint8_t *data = TCP_GET_SACK_PTR(p); - TCPOptSackRecord *sack_rec = (TCPOptSackRecord *)(TCP_GET_SACK_PTR(p)); + if (records == 0 || data == NULL) + return 0; + + TCPOptSackRecord rec[records], *sack_rec = rec; + memcpy(&rec, data, sizeof(TCPOptSackRecord) * records); for (record = 0; record < records; record++) { SCLogDebug("%p last_ack %u, left edge %u, right edge %u", sack_rec, @@ -266,13 +271,12 @@ int StreamTcpSackUpdatePacket(TcpStream *stream, Packet *p) goto next; } - /** \todo need a metric to a check for a right edge limit */ -/* - if (SEQ_GT(ntohl(sack_rec->re), stream->next_seq)) { - SCLogDebug("record beyond next_seq %u", stream->next_seq); + if (SEQ_GT(ntohl(sack_rec->re), stream->next_win)) { + SCLogDebug("record %u:%u beyond next_win %u", + ntohl(sack_rec->le), ntohl(sack_rec->re), stream->next_win); goto next; } -*/ + if (SEQ_GEQ(ntohl(sack_rec->le), ntohl(sack_rec->re))) { SCLogDebug("invalid record: le >= re"); goto next; @@ -391,6 +395,7 @@ static int StreamTcpSackTest01 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -427,6 +432,7 @@ static int StreamTcpSackTest02 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -465,6 +471,7 @@ static int StreamTcpSackTest03 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -500,6 +507,7 @@ static int StreamTcpSackTest04 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -535,6 +543,7 @@ static int StreamTcpSackTest05 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -572,6 +581,7 @@ static int StreamTcpSackTest06 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -618,6 +628,7 @@ static int StreamTcpSackTest07 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -664,6 +675,7 @@ static int StreamTcpSackTest08 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -711,6 +723,7 @@ static int StreamTcpSackTest09 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -757,6 +770,7 @@ static int StreamTcpSackTest10 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -803,6 +817,7 @@ static int StreamTcpSackTest11 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -856,6 +871,7 @@ static int StreamTcpSackTest12 (void) retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -888,6 +904,7 @@ static int StreamTcpSackTest13 (void) { retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -920,6 +937,7 @@ static int StreamTcpSackTest14 (void) { retval = 1; end: + StreamTcpSackFreeList(&stream); SCReturnInt(retval); } @@ -928,33 +946,23 @@ static int StreamTcpSackTest14 (void) { void StreamTcpSackRegisterTests (void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpSackTest01 -- Insertion", - StreamTcpSackTest01, 1); - UtRegisterTest("StreamTcpSackTest02 -- Insertion", - StreamTcpSackTest02, 1); - UtRegisterTest("StreamTcpSackTest03 -- Insertion", - StreamTcpSackTest03, 1); - UtRegisterTest("StreamTcpSackTest04 -- Insertion", - StreamTcpSackTest04, 1); - UtRegisterTest("StreamTcpSackTest05 -- Insertion", - StreamTcpSackTest05, 1); - UtRegisterTest("StreamTcpSackTest06 -- Insertion", - StreamTcpSackTest06, 1); - UtRegisterTest("StreamTcpSackTest07 -- Pruning", - StreamTcpSackTest07, 1); - UtRegisterTest("StreamTcpSackTest08 -- Pruning", - StreamTcpSackTest08, 1); - UtRegisterTest("StreamTcpSackTest09 -- Pruning", - StreamTcpSackTest09, 1); - UtRegisterTest("StreamTcpSackTest10 -- Pruning", - StreamTcpSackTest10, 1); + UtRegisterTest("StreamTcpSackTest01 -- Insertion", StreamTcpSackTest01); + UtRegisterTest("StreamTcpSackTest02 -- Insertion", StreamTcpSackTest02); + UtRegisterTest("StreamTcpSackTest03 -- Insertion", StreamTcpSackTest03); + UtRegisterTest("StreamTcpSackTest04 -- Insertion", StreamTcpSackTest04); + UtRegisterTest("StreamTcpSackTest05 -- Insertion", StreamTcpSackTest05); + UtRegisterTest("StreamTcpSackTest06 -- Insertion", StreamTcpSackTest06); + UtRegisterTest("StreamTcpSackTest07 -- Pruning", StreamTcpSackTest07); + UtRegisterTest("StreamTcpSackTest08 -- Pruning", StreamTcpSackTest08); + UtRegisterTest("StreamTcpSackTest09 -- Pruning", StreamTcpSackTest09); + UtRegisterTest("StreamTcpSackTest10 -- Pruning", StreamTcpSackTest10); UtRegisterTest("StreamTcpSackTest11 -- Insertion && Pruning", - StreamTcpSackTest11, 1); + StreamTcpSackTest11); UtRegisterTest("StreamTcpSackTest12 -- Insertion && Pruning", - StreamTcpSackTest12, 1); + StreamTcpSackTest12); UtRegisterTest("StreamTcpSackTest13 -- Insertion out of window", - StreamTcpSackTest13, 1); + StreamTcpSackTest13); UtRegisterTest("StreamTcpSackTest14 -- Insertion out of window", - StreamTcpSackTest14, 1); + StreamTcpSackTest14); #endif } diff --git a/src/stream-tcp-util.c b/src/stream-tcp-util.c index 83cccf4ae2cb..b58db5c2838f 100644 --- a/src/stream-tcp-util.c +++ b/src/stream-tcp-util.c @@ -40,6 +40,8 @@ /* unittest helper functions */ +extern int stream_inline; + void StreamTcpUTInit(TcpReassemblyThreadCtx **ra_ctx) { StreamTcpInitConfig(TRUE); @@ -50,6 +52,11 @@ void StreamTcpUTDeinit(TcpReassemblyThreadCtx *ra_ctx) { StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpFreeConfig(TRUE); + stream_inline = 0; +} + +void StreamTcpUTInitInline(void) { + stream_inline = 1; } void StreamTcpUTSetupSession(TcpSession *ssn) @@ -61,6 +68,7 @@ void StreamTcpUTClearSession(TcpSession *ssn) { StreamTcpUTClearStream(&ssn->client); StreamTcpUTClearStream(&ssn->server); + StreamTcpSessionCleanup(ssn); } void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn) @@ -73,7 +81,7 @@ void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn) void StreamTcpUTClearStream(TcpStream *s) { - StreamTcpReturnStreamSegments(s); + StreamTcpStreamCleanup(s); } int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len) @@ -249,9 +257,9 @@ int StreamTcpUtilStreamTest02(void) void StreamTcpUtilRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("StreamTcpUtilTest01", StreamTcpUtilTest01, 1); - UtRegisterTest("StreamTcpUtilStreamTest01", StreamTcpUtilStreamTest01, 1); - UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02, 1); + UtRegisterTest("StreamTcpUtilTest01", StreamTcpUtilTest01); + UtRegisterTest("StreamTcpUtilStreamTest01", StreamTcpUtilStreamTest01); + UtRegisterTest("StreamTcpUtilStreamTest02", StreamTcpUtilStreamTest02); #endif /* UNITTESTS */ } diff --git a/src/stream-tcp-util.h b/src/stream-tcp-util.h index 32dec5c79d24..72f2b4fcb97f 100644 --- a/src/stream-tcp-util.h +++ b/src/stream-tcp-util.h @@ -29,6 +29,8 @@ void StreamTcpUTInit(TcpReassemblyThreadCtx **); void StreamTcpUTDeinit(TcpReassemblyThreadCtx *); +void StreamTcpUTInitInline(void); + void StreamTcpUTSetupSession(TcpSession *); void StreamTcpUTClearSession(TcpSession *); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index d4ea8d909173..b3b861bdefb8 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -65,12 +65,14 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-protos.h" +#include "app-layer-htp-mem.h" #include "util-host-os-info.h" #include "util-privs.h" #include "util-profiling.h" #include "util-misc.h" #include "util-validate.h" +#include "util-runmodes.h" #include "source-pcap-file.h" @@ -91,12 +93,7 @@ #define STREAMTCP_EMERG_EST_TIMEOUT 300 #define STREAMTCP_EMERG_CLOSED_TIMEOUT 20 -TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); -TmEcode StreamTcpThreadDeinit(ThreadVars *, void *); -void StreamTcpExitPrintStats(ThreadVars *, void *); static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *, PacketQueue *); -void StreamTcpRegisterTests (void); void StreamTcpReturnStreamSegments (TcpStream *); void StreamTcpInitConfig(char); int StreamTcpGetFlowState(void *); @@ -114,23 +111,12 @@ static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect ini static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */ #endif +uint64_t StreamTcpReassembleMemuseGlobalCounter(void); SC_ATOMIC_DECLARE(uint64_t, st_memuse); /* stream engine running in "inline" mode. */ int stream_inline = 0; -void TmModuleStreamTcpRegister (void) -{ - tmm_modules[TMM_STREAMTCP].name = "StreamTcp"; - tmm_modules[TMM_STREAMTCP].ThreadInit = StreamTcpThreadInit; - tmm_modules[TMM_STREAMTCP].Func = StreamTcp; - tmm_modules[TMM_STREAMTCP].ThreadExitPrintStats = StreamTcpExitPrintStats; - tmm_modules[TMM_STREAMTCP].ThreadDeinit = StreamTcpThreadDeinit; - tmm_modules[TMM_STREAMTCP].RegisterTests = StreamTcpRegisterTests; - tmm_modules[TMM_STREAMTCP].cap_flags = 0; - tmm_modules[TMM_STREAMTCP].flags = TM_FLAG_STREAM_TM; -} - void StreamTcpIncrMemuse(uint64_t size) { (void) SC_ATOMIC_ADD(st_memuse, size); @@ -143,11 +129,10 @@ void StreamTcpDecrMemuse(uint64_t size) return; } -void StreamTcpMemuseCounter(ThreadVars *tv, StreamTcpThread *stt) +uint64_t StreamTcpMemuseCounter(void) { uint64_t memusecopy = SC_ATOMIC_GET(st_memuse); - SCPerfCounterSetUI64(stt->counter_tcp_memuse, tv->sc_perf_pca, memusecopy); - return; + return memusecopy; } /** @@ -163,33 +148,30 @@ int StreamTcpCheckMemcap(uint64_t size) return 0; } +void StreamTcpStreamCleanup(TcpStream *stream) +{ + if (stream != NULL) { + StreamTcpSackFreeList(stream); + StreamTcpReturnStreamSegments(stream); + } +} + /** - * \brief Function to return the stream back to the pool. It returns the - * segments in the stream to the segment pool. - * - * This function is called when the flow is destroyed, so it should free - * *everything* related to the tcp session. So including the app layer - * data. We are guaranteed to only get here when the flow's use_cnt is 0. - * - * \param ssn Void ptr to the ssn. + * \brief Session cleanup function. Does not free the ssn. + * \param ssn tcp session */ -void StreamTcpSessionClear(void *ssnptr) +void StreamTcpSessionCleanup(TcpSession *ssn) { SCEnter(); + StreamMsg *smsg = NULL; TcpStateQueue *q, *q_next; - TcpSession *ssn = (TcpSession *)ssnptr; if (ssn == NULL) - SCReturn; - - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); - - //AppLayerParserCleanupState(ssn); + return; - StreamTcpSackFreeList(&ssn->client); - StreamTcpSackFreeList(&ssn->server); + StreamTcpStreamCleanup(&ssn->client); + StreamTcpStreamCleanup(&ssn->server); /* if we have (a) smsg(s), return to the pool */ smsg = ssn->toserver_smsg_head; @@ -224,7 +206,33 @@ void StreamTcpSessionClear(void *ssnptr) ssn->queue = NULL; ssn->queue_len = 0; + SCReturn; +} + +/** + * \brief Function to return the stream back to the pool. It returns the + * segments in the stream to the segment pool. + * + * This function is called when the flow is destroyed, so it should free + * *everything* related to the tcp session. So including the app layer + * data. We are guaranteed to only get here when the flow's use_cnt is 0. + * + * \param ssn Void ptr to the ssn. + */ +void StreamTcpSessionClear(void *ssnptr) +{ + SCEnter(); + TcpSession *ssn = (TcpSession *)ssnptr; + if (ssn == NULL) + return; + + StreamTcpSessionCleanup(ssn); + + /* HACK: don't loose track of thread id */ + PoolThreadReserved a = ssn->res; memset(ssn, 0, sizeof(TcpSession)); + ssn->res = a; + PoolThreadReturn(ssn_pool, ssn); #ifdef DEBUG SCMutexLock(&ssn_pool_mutex); @@ -262,7 +270,7 @@ void StreamTcpSessionPktFree (Packet *p) /** \brief Stream alloc function for the Pool * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL */ -void *StreamTcpSessionPoolAlloc() +static void *StreamTcpSessionPoolAlloc() { void *ptr = NULL; @@ -276,7 +284,7 @@ void *StreamTcpSessionPoolAlloc() return ptr; } -int StreamTcpSessionPoolInit(void *data, void* initdata) +static int StreamTcpSessionPoolInit(void *data, void* initdata) { memset(data, 0, sizeof(TcpSession)); StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession)); @@ -284,55 +292,15 @@ int StreamTcpSessionPoolInit(void *data, void* initdata) return 1; } -/** \brief Pool free function +/** \brief Pool cleanup function * \param s Void ptr to TcpSession memory */ -void StreamTcpSessionPoolCleanup(void *s) +static void StreamTcpSessionPoolCleanup(void *s) { - StreamMsg *smsg = NULL; - TcpStateQueue *q, *q_next; - - if (s == NULL) - return; - - TcpSession *ssn = (TcpSession *)s; - - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); - - /* if we have (a) smsg(s), return to the pool */ - smsg = ssn->toserver_smsg_head; - while(smsg != NULL) { - StreamMsg *smsg_next = smsg->next; - SCLogDebug("returning smsg %p to pool", smsg); - smsg->next = NULL; - smsg->prev = NULL; - StreamMsgReturnToPool(smsg); - smsg = smsg_next; - } - ssn->toserver_smsg_head = NULL; - - smsg = ssn->toclient_smsg_head; - while(smsg != NULL) { - StreamMsg *smsg_next = smsg->next; - SCLogDebug("returning smsg %p to pool", smsg); - smsg->next = NULL; - smsg->prev = NULL; - StreamMsgReturnToPool(smsg); - smsg = smsg_next; + if (s != NULL) { + StreamTcpSessionCleanup(s); + /** \todo not very clean, as the memory is not freed here */ + StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession)); } - ssn->toclient_smsg_head = NULL; - - q = ssn->queue; - while (q != NULL) { - q_next = q->next; - SCFree(q); - q = q_next; - StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue)); - } - ssn->queue = NULL; - ssn->queue_len = 0; - - StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession)); } /** \brief To initialize the stream global configuration data @@ -371,7 +339,7 @@ void StreamTcpInitConfig(char quiet) } } if (!quiet) { - SCLogInfo("stream \"prealloc-sessions\": %"PRIu32" (per thread)", + SCLogConfig("stream \"prealloc-sessions\": %"PRIu32" (per thread)", stream_config.prealloc_sessions); } @@ -388,19 +356,19 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream \"memcap\": %"PRIu64, stream_config.memcap); + SCLogConfig("stream \"memcap\": %"PRIu64, stream_config.memcap); } ConfGetBool("stream.midstream", &stream_config.midstream); if (!quiet) { - SCLogInfo("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled"); + SCLogConfig("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled"); } ConfGetBool("stream.async-oneside", &stream_config.async_oneside); if (!quiet) { - SCLogInfo("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled"); + SCLogConfig("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled"); } int csum = 0; @@ -415,16 +383,15 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream \"checksum-validation\": %s", + SCLogConfig("stream \"checksum-validation\": %s", stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ? "enabled" : "disabled"); } - int inl = 0; - - char *temp_stream_inline_str; if (ConfGet("stream.inline", &temp_stream_inline_str) == 1) { + int inl = 0; + /* checking for "auto" and falling back to boolean to provide * backward compatibility */ if (strcmp(temp_stream_inline_str, "auto") == 0) { @@ -436,10 +403,32 @@ void StreamTcpInitConfig(char quiet) } else if (ConfGetBool("stream.inline", &inl) == 1) { stream_inline = inl; } + } else { + /* default to 'auto' */ + if (EngineModeIsIPS()) { + stream_inline = 1; + } else { + stream_inline = 0; + } } if (!quiet) { - SCLogInfo("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled"); + SCLogConfig("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled"); + } + + int bypass = 0; + if ((ConfGetBool("stream.bypass", &bypass)) == 1) { + if (bypass == 1) { + stream_config.bypass = 1; + } else { + stream_config.bypass = 0; + } + } else { + stream_config.bypass = 0; + } + + if (!quiet) { + SCLogConfig("stream \"bypass\": %s", bypass ? "enabled" : "disabled"); } if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) { @@ -452,7 +441,7 @@ void StreamTcpInitConfig(char quiet) stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED; } if (!quiet) { - SCLogInfo("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued); + SCLogConfig("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued); } char *temp_stream_reassembly_memcap_str; @@ -470,7 +459,7 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream.reassembly \"memcap\": %"PRIu64"", stream_config.reassembly_memcap); + SCLogConfig("stream.reassembly \"memcap\": %"PRIu64"", stream_config.reassembly_memcap); } char *temp_stream_reassembly_depth_str; @@ -488,7 +477,7 @@ void StreamTcpInitConfig(char quiet) } if (!quiet) { - SCLogInfo("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth); + SCLogConfig("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth); } int randomize = 0; @@ -570,9 +559,9 @@ void StreamTcpInitConfig(char quiet) stream_config.reassembly_toclient_chunk_size); if (!quiet) { - SCLogInfo("stream.reassembly \"toserver-chunk-size\": %"PRIu16, + SCLogConfig("stream.reassembly \"toserver-chunk-size\": %"PRIu16, stream_config.reassembly_toserver_chunk_size); - SCLogInfo("stream.reassembly \"toclient-chunk-size\": %"PRIu16, + SCLogConfig("stream.reassembly \"toclient-chunk-size\": %"PRIu16, stream_config.reassembly_toclient_chunk_size); } @@ -586,17 +575,17 @@ void StreamTcpInitConfig(char quiet) enable_raw = 1; } if (!quiet) - SCLogInfo("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled"); + SCLogConfig("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled"); /* init the memcap/use tracking */ SC_ATOMIC_INIT(st_memuse); + StatsRegisterGlobalCounter("tcp.memuse", StreamTcpMemuseCounter); StreamTcpReassembleInit(quiet); /* set the default free function and flow state function * values. */ FlowSetProtoFreeFunc(IPPROTO_TCP, StreamTcpSessionClear); - FlowSetFlowStateFunc(IPPROTO_TCP, StreamTcpGetFlowState); #ifdef UNITTESTS if (RunmodeIsUnittests()) { @@ -633,9 +622,10 @@ void StreamTcpFreeConfig(char quiet) /** \brief The function is used to to fetch a TCP session from the * ssn_pool, when a TCP SYN is received. * - * \param quiet Packet P, which has been recieved for the new TCP session. + * \param p packet starting the new TCP session. + * \param id thread pool id * - * \retval TcpSession A new TCP session with field initilaized to 0/NULL. + * \retval ssn new TCP session. */ TcpSession *StreamTcpNewSession (Packet *p, int id) { @@ -657,6 +647,7 @@ TcpSession *StreamTcpNewSession (Packet *p, int id) } ssn->state = TCP_NONE; + ssn->reassembly_depth = stream_config.reassembly_depth; ssn->flags = stream_config.ssn_init_flags; ssn->tcp_packet_flags = p->tcph ? p->tcph->th_flags : 0; @@ -679,6 +670,22 @@ static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn, return; ssn->state = state; + + /* update the flow state */ + switch(ssn->state) { + case TCP_ESTABLISHED: + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + case TCP_CLOSING: + case TCP_CLOSE_WAIT: + FlowUpdateState(p->flow, FLOW_STATE_ESTABLISHED); + break; + case TCP_LAST_ACK: + case TCP_TIME_WAIT: + case TCP_CLOSED: + FlowUpdateState(p->flow, FLOW_STATE_CLOSED); + break; + } } /** @@ -744,11 +751,20 @@ uint32_t StreamTcpGetStreamSize(TcpStream *stream) * \param ack ACK value to test and set */ #define StreamTcpUpdateLastAck(ssn, stream, ack) { \ - if (SEQ_GT((ack), (stream)->last_ack)) { \ + if (SEQ_GT((ack), (stream)->last_ack)) \ + { \ + SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \ + if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \ + SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \ + } else { \ + SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \ + }\ (stream)->last_ack = (ack); \ - SCLogDebug("ssn %p: last_ack set to %"PRIu32, (ssn), (stream)->last_ack); \ StreamTcpSackPruneList((stream)); \ - } \ + } else { \ + SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \ + (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \ + }\ } /** @@ -771,6 +787,13 @@ static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) if (p->payload_len == 0) SCReturnInt(0); + /* retransmission of already partially ack'd data */ + if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) + { + StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); + SCReturnInt(1); + } + /* retransmission of already ack'd data */ if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) { StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION); @@ -783,8 +806,8 @@ static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p) SCReturnInt(2); } - SCLogDebug("seq %u payload_len %u => %u, last_ack %u", TCP_GET_SEQ(p), - p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack); + SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", TCP_GET_SEQ(p), + p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack, stream->next_seq); SCReturnInt(0); } @@ -823,10 +846,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_sessions); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV); @@ -850,10 +873,12 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, ssn->client.last_ack = TCP_GET_ACK(p); ssn->server.last_ack = TCP_GET_SEQ(p); + ssn->server.next_win = ssn->server.last_ack + ssn->server.window; + /** If the client has a wscale option the server had it too, * so set the wscale for the server to max. Otherwise none * will have the wscale opt just like it should. */ - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { ssn->client.wscale = TCP_GET_WSCALE(p); ssn->server.wscale = TCP_WSCALE_MAX; } @@ -869,7 +894,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->server.last_ts = TCP_GET_TSVAL(p); ssn->client.last_ts = TCP_GET_TSECR(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " @@ -895,15 +920,18 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, "SACK permitted for both sides", ssn); } + /* packet thinks it is in the wrong direction, flip it */ + StreamTcpPacketSwitchDir(ssn, p); + } else if (p->tcph->th_flags & TH_SYN) { if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_sessions); } /* set the state */ @@ -917,10 +945,9 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, /* Set the stream timestamp value, if packet has timestamp option * enabled. */ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->client.last_ts = TCP_GET_TSVAL(p); - SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts, - ssn->client.last_ts); + SCLogDebug("ssn %p: %02x", ssn, ssn->client.last_ts); if (ssn->client.last_ts == 0) ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP; @@ -930,7 +957,7 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, } ssn->server.window = TCP_GET_WINDOW(p); - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = TCP_GET_WSCALE(p); } @@ -952,10 +979,10 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, if (ssn == NULL) { ssn = StreamTcpNewSession(p, stt->ssn_pool_id); if (ssn == NULL) { - SCPerfCounterIncr(stt->counter_tcp_ssn_memcap, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_ssn_memcap); return -1; } - SCPerfCounterIncr(stt->counter_tcp_sessions, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_sessions); } /* set the state */ StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); @@ -965,11 +992,16 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, ssn->flags = STREAMTCP_FLAG_MIDSTREAM; ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED; + /** window scaling for midstream pickups, we can't do much other + * than assume that it's set to the max value: 14 */ + ssn->client.wscale = TCP_WSCALE_MAX; + ssn->server.wscale = TCP_WSCALE_MAX; + /* set the sequence numbers and window */ ssn->client.isn = TCP_GET_SEQ(p) - 1; STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; - ssn->client.window = TCP_GET_WINDOW(p); + ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; ssn->client.last_ack = TCP_GET_SEQ(p); ssn->client.next_win = ssn->client.last_ack + ssn->client.window; SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u", @@ -988,14 +1020,9 @@ static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p, "ssn->server.last_ack %"PRIu32"", ssn, ssn->client.last_ack, ssn->server.last_ack); - /** window scaling for midstream pickups, we can't do much other - * than assume that it's set to the max value: 14 */ - ssn->client.wscale = TCP_WSCALE_MAX; - ssn->server.wscale = TCP_WSCALE_MAX; - /* Set the timestamp value for both streams, if packet has timestamp * option enabled.*/ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->client.last_ts = TCP_GET_TSVAL(p); ssn->server.last_ts = TCP_GET_TSECR(p); SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" " @@ -1043,11 +1070,11 @@ static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q) if (TCP_GET_SACKOK(p) == 1) q->flags |= STREAMTCP_QUEUE_FLAG_SACK; - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { q->flags |= STREAMTCP_QUEUE_FLAG_WS; q->wscale = TCP_GET_WSCALE(p); } - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { q->flags |= STREAMTCP_QUEUE_FLAG_TS; q->ts = TCP_GET_TSVAL(p); } @@ -1261,15 +1288,11 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1))) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); } @@ -1321,7 +1344,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Set the timestamp values used to validate the timestamp of * received packets. */ - if ((p->tcpvars.ts != NULL) && + if ((TCP_HAS_TS(p)) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) { ssn->client.last_ts = TCP_GET_TSVAL(p); @@ -1344,7 +1367,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /** check for the presense of the ws ptr to determine if we * support wscale at all */ if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) && - (p->tcpvars.ws != NULL)) + (TCP_HAS_WSCALE(p))) { ssn->server.wscale = TCP_GET_WSCALE(p); } else { @@ -1420,10 +1443,9 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, /* Set the stream timestamp value, if packet has timestamp * option enabled. */ - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { ssn->server.last_ts = TCP_GET_TSVAL(p); - SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, - p->tcpvars.ts, ssn->server.last_ts); + SCLogDebug("ssn %p: %02x", ssn, ssn->server.last_ts); if (ssn->server.last_ts == 0) ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP; @@ -1432,7 +1454,7 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, } ssn->server.window = TCP_GET_WINDOW(p); - if (p->tcpvars.ws != NULL) { + if (TCP_HAS_WSCALE(p)) { ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE; ssn->server.wscale = TCP_GET_WSCALE(p); } else { @@ -1501,12 +1523,15 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_seq); - ssn->client.wscale = TCP_WSCALE_MAX; - ssn->server.wscale = TCP_WSCALE_MAX; + /* if SYN had wscale, assume it to be supported. Otherwise + * we know it not to be supported. */ + if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) { + ssn->client.wscale = TCP_WSCALE_MAX; + } /* Set the timestamp values used to validate the timestamp of * received packets.*/ - if (p->tcpvars.ts != NULL && + if (TCP_HAS_TS(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP)) { ssn->flags |= STREAMTCP_FLAG_TIMESTAMP; @@ -1521,6 +1546,9 @@ static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p, ssn->flags |= STREAMTCP_FLAG_SACKOK; } + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->client, p, pq); + } else { SCLogDebug("ssn %p: default case", ssn); } @@ -1582,8 +1610,6 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, if (reset == TRUE) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -1762,14 +1788,17 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, ssn->server.next_win = ssn->server.last_ack + ssn->server.window; if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) { - ssn->client.window = TCP_GET_WINDOW(p); + ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; + ssn->client.next_win = ssn->client.last_ack + ssn->client.window; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; - /* window scaling for midstream pickups, we can't do much - * other than assume that it's set to the max value: 14 */ - ssn->server.wscale = TCP_WSCALE_MAX; - ssn->client.wscale = TCP_WSCALE_MAX; - ssn->flags |= STREAMTCP_FLAG_SACKOK; + if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) { + /* window scaling for midstream pickups, we can't do much + * other than assume that it's set to the max value: 14 */ + ssn->server.wscale = TCP_WSCALE_MAX; + ssn->client.wscale = TCP_WSCALE_MAX; + ssn->flags |= STREAMTCP_FLAG_SACKOK; + } } StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED); @@ -1845,6 +1874,7 @@ static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p, StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; ssn->server.next_win = ssn->server.last_ack + ssn->server.window; @@ -1962,6 +1992,19 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p)); ssn->flags |= STREAMTCP_FLAG_ASYNC; + /* if last ack is beyond next_seq, we have accepted ack's for missing data. + * In this case we do accept the data before last_ack if it is (partly) + * beyond next seq */ + } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->client.next_seq)) + { + SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 + " before last_ack %"PRIu32", after next_seq %"PRIu32":" + " acked data that we haven't seen before", + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack, ssn->client.next_seq); + if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) { + ssn->client.next_seq += p->payload_len; + } } else { SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ" " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), " @@ -1988,6 +2031,25 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack ssn->client.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn, ssn->client.next_seq); + /* not completely as expected, but valid */ + } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->client.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->client.next_seq)) + { + ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32 + " (started before next_seq, ended after)", + ssn, ssn->client.next_seq); + /* if next_seq has fallen behind last_ack, we got some catching up to do */ + } else if (SEQ_LT(ssn->client.next_seq, ssn->client.last_ack)) { + ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32 + " (next_seq had fallen behind last_ack)", + ssn, ssn->client.next_seq); + } else { + SCLogDebug("ssn %p: no update to ssn->client.next_seq %"PRIu32 + " SEQ %u SEQ+ %u last_ack %u", + ssn, ssn->client.next_seq, + TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->client.last_ack); } /* in window check */ @@ -2006,16 +2068,12 @@ static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Pack /* Check if the ACK value is sane and inside the window limit */ StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p)); + SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq); if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) { StreamTcpHandleTimestamp(ssn, p); } - /* Update the next_seq, in case if we have missed the server packet - and client has already received and acked it */ - if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p))) - ssn->server.next_seq = TCP_GET_ACK(p); - StreamTcpSackUpdatePacket(&ssn->server, p); /* update next_win */ @@ -2096,10 +2154,23 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.last_ack = TCP_GET_SEQ(p); + /* if last ack is beyond next_seq, we have accepted ack's for missing data. + * In this case we do accept the data before last_ack if it is (partly) + * beyond next seq */ + } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->server.next_seq)) + { + SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 + " before last_ack %"PRIu32", after next_seq %"PRIu32":" + " acked data that we haven't seen before", + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq); + if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) { + ssn->server.next_seq += p->payload_len; + } } else { SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16 - " before last_ack %"PRIu32, - ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack); + " before last_ack %"PRIu32". next_seq %"PRIu32, + ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq); StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK); return -1; } @@ -2116,6 +2187,25 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack ssn->server.next_seq += p->payload_len; SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn, ssn->server.next_seq); + /* not completely as expected, but valid */ + } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->server.next_seq) && + SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->server.next_seq)) + { + ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 + " (started before next_seq, ended after)", + ssn, ssn->server.next_seq); + /* if next_seq has fallen behind last_ack, we got some catching up to do */ + } else if (SEQ_LT(ssn->server.next_seq, ssn->server.last_ack)) { + ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len; + SCLogDebug("ssn %p: ssn->server.next_seq %"PRIu32 + " (next_seq had fallen behind last_ack)", + ssn, ssn->server.next_seq); + } else { + SCLogDebug("ssn %p: no update to ssn->server.next_seq %"PRIu32 + " SEQ %u SEQ+ %u last_ack %u", + ssn, ssn->server.next_seq, + TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->server.last_ack); } if (zerowindowprobe) { @@ -2135,11 +2225,6 @@ static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Pack StreamTcpHandleTimestamp(ssn, p); } - /* Update the next_seq, in case if we have missed the client packet - and server has already received and acked it */ - if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p))) - ssn->client.next_seq = TCP_GET_ACK(p); - StreamTcpSackUpdatePacket(&ssn->client, p); StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window)); @@ -2211,8 +2296,6 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, if (PKT_IS_TOSERVER(p)) { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2222,8 +2305,9 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->server.next_seq); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -2243,8 +2327,6 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, * cleanup. */ } else { StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received and state changed to " "TCP_CLOSED", ssn); @@ -2255,8 +2337,9 @@ static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p, ssn->server.next_seq); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -2442,7 +2525,6 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, } StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) @@ -2490,7 +2572,6 @@ static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt, } StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn); if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) @@ -2547,14 +2628,13 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -2566,8 +2646,9 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -2614,7 +2695,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -2671,7 +2751,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -2736,7 +2815,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_CLOSING); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -2794,7 +2872,6 @@ static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_CLOSING); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3007,14 +3084,13 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3026,8 +3102,9 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3078,7 +3155,6 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale; @@ -3133,7 +3209,6 @@ static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3317,14 +3392,13 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3336,8 +3410,9 @@ static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3499,14 +3574,13 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3518,8 +3592,9 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3619,7 +3694,6 @@ static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p, if (!retransmission) { StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn); ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale; @@ -3793,14 +3867,13 @@ static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3812,8 +3885,9 @@ static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -3920,14 +3994,13 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq); StreamTcpPacketSetState(p, ssn, TCP_CLOSED); - ssn->server.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; - ssn->client.flags |= STREAMTCP_STREAM_FLAG_CLOSE_INITIATED; SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED", ssn); if (PKT_IS_TOSERVER(p)) { - StreamTcpUpdateLastAck(ssn, &ssn->server, - StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->server, + StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->client, StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p))); @@ -3939,8 +4012,9 @@ static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p, StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq); } else { - StreamTcpUpdateLastAck(ssn, &ssn->client, - StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); + if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0) + StreamTcpUpdateLastAck(ssn, &ssn->client, + StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p))); StreamTcpUpdateLastAck(ssn, &ssn->server, StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p))); @@ -4251,7 +4325,7 @@ static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p) if (p->flags & PKT_PSEUDO_STREAM_END) return 0; - if (ssn->state != TCP_TIME_WAIT) + if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK)) return 0; if (p->tcph->th_flags != TH_ACK) return 0; @@ -4288,9 +4362,10 @@ static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p) * * The logic we use here is: * - packet seq > next_seq - * - packet acq > next_seq (packet acks unseen data) + * - packet ack > next_seq (packet acks unseen data) * - packet shrinks window more than it's own data size - * (in case of no data, any shrinking is rejected) + * - packet shrinks window more than the diff between it's ack and the + * last_ack value * * Packets coming in after packet loss can look quite a bit like this. */ @@ -4304,7 +4379,7 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) if (p->flags & PKT_PSEUDO_STREAM_END) return 0; - if (ssn->state < TCP_ESTABLISHED) + if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED) return 0; if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) @@ -4333,12 +4408,25 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len); SCLogDebug("%"PRIu64", pkt_win %u, stream win %u", p->pcap_cnt, pkt_win, ostream->window); - SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u stream->last_ack %u, diff %u (%u)", - p->pcap_cnt, seq, ack, ostream->next_seq, stream->last_ack, - ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack); - - StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE); - return 1; + SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)", + p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win, + ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack); + + /* get the expected window shrinking from looking at ack vs last_ack. + * Observed a lot of just a little overrunning that value. So added some + * margin that is still ok. To make sure this isn't a loophole to still + * close the window, this is limited to windows above 1024. Both values + * are rather arbitrary. */ + uint32_t adiff = ack - ostream->last_ack; + if (((pkt_win > 1024) && (diff > (adiff + 32))) || + ((pkt_win <= 1024) && (diff > adiff))) + { + SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u " + "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win); + SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state); + StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE); + return 1; + } } } @@ -4346,7 +4434,6 @@ static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p) return 0; } - /* flow is and stays locked */ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq) @@ -4357,6 +4444,15 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + /* assign the thread id to the flow */ + if (unlikely(p->flow->thread_id == 0)) { + p->flow->thread_id = (FlowThreadId)tv->id; +#ifdef DEBUG + } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id)) { + SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id, tv->id); +#endif + } + TcpSession *ssn = (TcpSession *)p->flow->protoctx; /* track TCP flags */ @@ -4370,12 +4466,12 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* update counters */ if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { - SCPerfCounterIncr(stt->counter_tcp_synack, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_synack); } else if (p->tcph->th_flags & (TH_SYN)) { - SCPerfCounterIncr(stt->counter_tcp_syn, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_syn); } if (p->tcph->th_flags & (TH_RST)) { - SCPerfCounterIncr(stt->counter_tcp_rst, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_rst); } /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */ @@ -4391,7 +4487,7 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, SCLogDebug("This flow/stream triggered a drop rule"); FlowSetNoPacketInspectionFlag(p->flow); DecodeSetNoPacketInspectionFlag(p); - FlowSetSessionNoApplayerInspectionFlag(p->flow); + StreamTcpDisableAppLayer(p->flow); PACKET_DROP(p); /* return the segments to the pool */ StreamTcpSessionPktFree(p); @@ -4406,6 +4502,23 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, if (ssn != NULL) SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto); } else { + /* special case for PKT_PSEUDO_STREAM_END packets: + * bypass the state handling and various packet checks, + * we care about reassembly here. */ + if (p->flags & PKT_PSEUDO_STREAM_END) { + if (PKT_IS_TOCLIENT(p)) { + ssn->client.last_ack = TCP_GET_ACK(p); + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->server, p, pq); + } else { + ssn->server.last_ack = TCP_GET_ACK(p); + StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, + &ssn->client, p, pq); + } + /* straight to 'skip' as we already handled reassembly */ + goto skip; + } + /* check if the packet is in right direction, when we missed the SYN packet and picked up midstream session. */ if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) @@ -4474,60 +4587,8 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, } break; case TCP_CLOSED: - /* TCP session memory is not returned to pool until timeout. - * If in the mean time we receive any other session from - * the same client reusing same port then we switch back to - * tcp state none, but only on a valid SYN that is not a - * resend from our previous session. - * - * We also check it's not a SYN/ACK, all other SYN pkt - * validation is done at StreamTcpPacketStateNone(); - */ - if (PKT_IS_TOSERVER(p) && (p->tcph->th_flags & TH_SYN) && - !(p->tcph->th_flags & TH_ACK) && - !(SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p)))) - { - SCLogDebug("reusing closed TCP session"); - - /* return segments */ - StreamTcpReturnStreamSegments(&ssn->client); - StreamTcpReturnStreamSegments(&ssn->server); - /* free SACK list */ - StreamTcpSackFreeList(&ssn->client); - StreamTcpSackFreeList(&ssn->server); - /* reset the app layer state */ - FlowCleanupAppLayer(p->flow); - - ssn->state = 0; - ssn->flags = 0; - ssn->client.flags = 0; - ssn->server.flags = 0; - - /* set state the NONE, also pulls flow out of closed queue */ - StreamTcpPacketSetState(p, ssn, TCP_NONE); - - p->flow->alproto_ts = p->flow->alproto_tc = p->flow->alproto = ALPROTO_UNKNOWN; - p->flow->data_al_so_far[0] = p->flow->data_al_so_far[1] = 0; - ssn->data_first_seen_dir = 0; - p->flow->flags &= (~FLOW_TS_PM_ALPROTO_DETECT_DONE & - ~FLOW_TS_PP_ALPROTO_DETECT_DONE & - ~FLOW_TC_PM_ALPROTO_DETECT_DONE & - ~FLOW_TC_PP_ALPROTO_DETECT_DONE); - p->flow->flags &= ~ FLOW_NO_APPLAYER_INSPECTION; - if (p->flow->de_state != NULL) { - SCMutexLock(&p->flow->de_state_m); - DetectEngineStateReset(p->flow->de_state, (STREAM_TOSERVER | STREAM_TOCLIENT)); - SCMutexUnlock(&p->flow->de_state_m); - } - - if (StreamTcpPacketStateNone(tv,p,stt,ssn, &stt->pseudo_queue)) { - goto error; - } - - SCPerfCounterIncr(stt->counter_tcp_reused_ssn, tv->sc_perf_pca); - } else { - SCLogDebug("packet received on closed state"); - } + /* TCP session memory is not returned to pool until timeout. */ + SCLogDebug("packet received on closed state"); break; default: SCLogDebug("packet received on default state"); @@ -4538,14 +4599,6 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, if (ssn->state >= TCP_ESTABLISHED) { p->flags |= PKT_STREAM_EST; } - - if (PKT_IS_TOSERVER(p)) { - if (ssn->client.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) - p->flags |= PKT_STREAM_EOF; - } else { - if (ssn->server.flags & STREAMTCP_STREAM_FLAG_CLOSE_INITIATED) - p->flags |= PKT_STREAM_EOF; - } } /* deal with a pseudo packet that is created upon receiving a RST @@ -4583,6 +4636,15 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, /* check for conditions that may make us not want to log this packet */ /* streams that hit depth */ + if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) && + (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) + { + /* we can call bypass callback, if enabled */ + if (StreamTcpBypassEnabled()) { + PacketBypassCallback(p); + } + } + if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) || (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED)) { @@ -4595,9 +4657,17 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, { p->flags |= PKT_STREAM_NOPCAPLOG; } + + if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) && + (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) + { + /* we can call bypass callback, if enabled */ + if (StreamTcpBypassEnabled()) { + PacketBypassCallback(p); + } + } } - StreamTcpMemuseCounter(tv, stt); SCReturnInt(0); error: @@ -4637,21 +4707,22 @@ static inline int StreamTcpValidateChecksum(Packet *p) if (p->level4_comp_csum == -1) { if (PKT_IS_IPV4(p)) { - p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p))); + p->level4_comp_csum = TCPChecksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); } else if (PKT_IS_IPV6(p)) { - p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, - (p->payload_len + - TCP_GET_HLEN(p))); + p->level4_comp_csum = TCPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->tcph, + (p->payload_len + + TCP_GET_HLEN(p)), + p->tcph->th_sum); } } - if (p->level4_comp_csum != p->tcph->th_sum) { + if (p->level4_comp_csum != 0) { ret = 0; - SCLogDebug("Checksum of received packet %p is invalid",p); if (p->livedev) { (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1); } else if (p->pcap_cnt) { @@ -4662,39 +4733,192 @@ static inline int StreamTcpValidateChecksum(Packet *p) return ret; } +/** \internal + * \brief check if a packet is a valid stream started + * \retval bool true/false */ +static int TcpSessionPacketIsStreamStarter(const Packet *p) +{ + if (p->tcph->th_flags == TH_SYN) { + SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + return 1; + } + + if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) { + if (p->tcph->th_flags == (TH_SYN|TH_ACK)) { + SCLogDebug("packet %"PRIu64" is a midstream stream starter: %02x", p->pcap_cnt, p->tcph->th_flags); + return 1; + } + } + return 0; +} + +/** \internal + * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused + * \retval bool true yes reuse, false no keep tracking old ssn */ +static int TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (FlowGetPacketDirection(f, p) == TOSERVER) { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); + return 0; + } + if (SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p))) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + return 0; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + + } else { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + return 1; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + } + + SCLogDebug("default: how did we get here?"); + return 0; +} + +/** \internal + * \brief check if ssn is done enough for reuse by syn/ack + * \note should only be called if midstream is enabled + */ +static int TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (FlowGetPacketDirection(f, p) == TOCLIENT) { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn); + return 0; + } + if (SEQ_EQ(ssn->server.isn, TCP_GET_SEQ(p))) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn); + return 0; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + + } else { + if (ssn == NULL) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn); + return 1; + } + if (ssn->state >= TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state == TCP_NONE) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state); + return 1; + } + if (ssn->state < TCP_LAST_ACK) { + SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state); + return 0; + } + } + + SCLogDebug("default: how did we get here?"); + return 0; +} + +/** \brief Check if SSN is done enough for reuse + * + * Reuse means a new TCP session reuses the tuple (flow in suri) + * + * \retval bool true if ssn can be reused, false if not */ +int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn) +{ + if (p->tcph->th_flags == TH_SYN) { + return TcpSessionReuseDoneEnoughSyn(p, f, ssn); + } + + if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) { + if (p->tcph->th_flags == (TH_SYN|TH_ACK)) { + return TcpSessionReuseDoneEnoughSynAck(p, f, ssn); + } + } + + return 0; +} + +int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn) +{ + if (p->proto == IPPROTO_TCP && p->tcph != NULL) { + if (TcpSessionPacketIsStreamStarter(p) == 1) { + if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) { + return 1; + } + } + } + return 0; +} + TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { StreamTcpThread *stt = (StreamTcpThread *)data; - TmEcode ret = TM_ECODE_OK; - if (!(PKT_IS_TCP(p))) + SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt); + + if (!(PKT_IS_TCP(p))) { return TM_ECODE_OK; + } if (p->flow == NULL) { - SCPerfCounterIncr(stt->counter_tcp_no_flow, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_no_flow); return TM_ECODE_OK; } - if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { - if (StreamTcpValidateChecksum(p) == 0) { - SCPerfCounterIncr(stt->counter_tcp_invalid_checksum, tv->sc_perf_pca); - return TM_ECODE_OK; + /* only TCP packets with a flow from here */ + + if (!(p->flags & PKT_PSEUDO_STREAM_END)) { + if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) { + if (StreamTcpValidateChecksum(p) == 0) { + StatsIncr(tv, stt->counter_tcp_invalid_checksum); + return TM_ECODE_OK; + } + } else { + p->flags |= PKT_IGNORE_CHECKSUM; } } else { - p->flags |= PKT_IGNORE_CHECKSUM; + p->flags |= PKT_IGNORE_CHECKSUM; //TODO check that this is set at creation } - AppLayerProfilingReset(stt->ra_ctx->app_tctx); - FLOWLOCK_WRLOCK(p->flow); - ret = StreamTcpPacket(tv, p, stt, pq); - FLOWLOCK_UNLOCK(p->flow); + (void)StreamTcpPacket(tv, p, stt, pq); - //if (ret) - // return TM_ECODE_FAILED; - - stt->pkts++; - return ret; + return TM_ECODE_OK; } TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) @@ -4708,64 +4932,24 @@ TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data) *data = (void *)stt; - stt->counter_tcp_sessions = SCPerfTVRegisterCounter("tcp.sessions", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_ssn_memcap = SCPerfTVRegisterCounter("tcp.ssn_memcap_drop", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_pseudo = SCPerfTVRegisterCounter("tcp.pseudo", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_pseudo_failed = SCPerfTVRegisterCounter("tcp.pseudo_failed", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_invalid_checksum = SCPerfTVRegisterCounter("tcp.invalid_checksum", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_no_flow = SCPerfTVRegisterCounter("tcp.no_flow", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_reused_ssn = SCPerfTVRegisterCounter("tcp.reused_ssn", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_memuse = SCPerfTVRegisterCounter("tcp.memuse", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_syn = SCPerfTVRegisterCounter("tcp.syn", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_synack = SCPerfTVRegisterCounter("tcp.synack", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->counter_tcp_rst = SCPerfTVRegisterCounter("tcp.rst", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv); + stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv); + stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv); + stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv); + stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv); + stt->counter_tcp_no_flow = StatsRegisterCounter("tcp.no_flow", tv); + stt->counter_tcp_syn = StatsRegisterCounter("tcp.syn", tv); + stt->counter_tcp_synack = StatsRegisterCounter("tcp.synack", tv); + stt->counter_tcp_rst = StatsRegisterCounter("tcp.rst", tv); /* init reassembly ctx */ stt->ra_ctx = StreamTcpReassembleInitThreadCtx(tv); if (stt->ra_ctx == NULL) SCReturnInt(TM_ECODE_FAILED); - stt->ra_ctx->counter_tcp_segment_memcap = SCPerfTVRegisterCounter("tcp.segment_memcap_drop", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->ra_ctx->counter_tcp_stream_depth = SCPerfTVRegisterCounter("tcp.stream_depth_reached", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->ra_ctx->counter_tcp_reass_memuse = SCPerfTVRegisterCounter("tcp.reassembly_memuse", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->ra_ctx->counter_tcp_reass_gap = SCPerfTVRegisterCounter("tcp.reassembly_gap", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - /** \fixme Find a better place in 2.1 as it is linked with app layer */ - stt->ra_ctx->counter_htp_memuse = SCPerfTVRegisterCounter("http.memuse", tv, - SC_PERF_TYPE_UINT64, - "NULL"); - stt->ra_ctx->counter_htp_memcap = SCPerfTVRegisterCounter("http.memcap", tv, - SC_PERF_TYPE_UINT64, - "NULL"); + stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv); + stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv); + stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv); SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p", stt, stt->ra_ctx); @@ -4819,16 +5003,6 @@ TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data) SCReturnInt(TM_ECODE_OK); } -void StreamTcpExitPrintStats(ThreadVars *tv, void *data) -{ - StreamTcpThread *stt = (StreamTcpThread *)data; - if (stt == NULL) { - return; - } - - SCLogInfo("Stream TCP processed %" PRIu64 " TCP packets", stt->pkts); -} - /** * \brief Function to check the validity of the RST packets based on the * target OS of the given packet. @@ -4987,45 +5161,6 @@ static int StreamTcpValidateRst(TcpSession *ssn, Packet *p) return 0; } -/** - * \brief Function to return the FLOW state depending upon the TCP session state. - * - * \param s TCP session of which the state has to be returned - * \retval state The FLOW_STATE_ depends upon the TCP sesison state, default is - * FLOW_STATE_CLOSED - */ - -int StreamTcpGetFlowState(void *s) -{ - SCEnter(); - - TcpSession *ssn = (TcpSession *)s; - if (unlikely(ssn == NULL)) { - SCReturnInt(FLOW_STATE_CLOSED); - } - - /* sorted most likely to least likely */ - switch(ssn->state) { - case TCP_ESTABLISHED: - case TCP_FIN_WAIT1: - case TCP_FIN_WAIT2: - case TCP_CLOSING: - case TCP_CLOSE_WAIT: - SCReturnInt(FLOW_STATE_ESTABLISHED); - case TCP_NONE: - case TCP_SYN_SENT: - case TCP_SYN_RECV: - case TCP_LISTEN: - SCReturnInt(FLOW_STATE_NEW); - case TCP_LAST_ACK: - case TCP_TIME_WAIT: - case TCP_CLOSED: - SCReturnInt(FLOW_STATE_CLOSED); - } - - SCReturnInt(FLOW_STATE_CLOSED); -} - /** * \brief Function to check the validity of the received timestamp based on * the target OS of the given stream. @@ -5063,7 +5198,7 @@ static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p) StreamTcpSetOSPolicy(receiver_stream, p); } - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { uint32_t ts = TCP_GET_TSVAL(p); uint32_t last_pkt_ts = sender_stream->last_pkt_ts; uint32_t last_ts = sender_stream->last_ts; @@ -5205,7 +5340,7 @@ static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p) StreamTcpSetOSPolicy(receiver_stream, p); } - if (p->tcpvars.ts != NULL) { + if (TCP_HAS_TS(p)) { uint32_t ts = TCP_GET_TSVAL(p); if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) { @@ -5569,7 +5704,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p)); if (np == NULL) { SCLogDebug("The packet received from packet allocation is NULL"); - SCPerfCounterIncr(stt->counter_tcp_pseudo_failed, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_pseudo_failed); SCReturn; } PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO); @@ -5577,6 +5712,8 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread /* Setup the IP and TCP headers */ StreamTcpPseudoPacketSetupHeader(np,p); + np->tenant_id = p->flow->tenant_id; + np->flowflags = p->flowflags; np->flags |= PKT_STREAM_EST; @@ -5584,6 +5721,13 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread np->flags |= PKT_HAS_FLOW; np->flags |= PKT_PSEUDO_STREAM_END; + if (p->flags & PKT_NOPACKET_INSPECTION) { + DecodeSetNoPacketInspectionFlag(np); + } + if (p->flags & PKT_NOPAYLOAD_INSPECTION) { + DecodeSetNoPayloadInspectionFlag(np); + } + if (PKT_IS_TOSERVER(p)) { SCLogDebug("original is to_server, so pseudo is to_client"); np->flowflags &= ~FLOW_PKT_TOSERVER; @@ -5604,15 +5748,17 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread PacketEnqueue(pq, np); - SCPerfCounterIncr(stt->counter_tcp_pseudo, tv->sc_perf_pca); + StatsIncr(tv, stt->counter_tcp_pseudo); SCReturn; } /** * \brief Run callback function on each TCP segment * - * This function is used by StreamMsgForEach() which - * should be used directly. + * \note when stream engine is running in inline mode all segments are used, + * in IDS/non-inline mode only ack'd segments are iterated. + * + * \note Must be called under flow lock. * * \return -1 in case of error, the number of segment in case of success * @@ -5627,11 +5773,9 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback if (p->flow == NULL) return 0; - FLOWLOCK_RDLOCK(p->flow); ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) { - FLOWLOCK_UNLOCK(p->flow); return 0; } @@ -5640,21 +5784,37 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback } else { stream = &(ssn->client); } + + /* for IDS, return ack'd segments. For IPS all. */ TcpSegment *seg = stream->seg_list; - for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) { + for (; seg != NULL && + (stream_inline || SEQ_LT(seg->seq, stream->last_ack));) + { ret = CallbackFunc(p, data, seg->payload, seg->payload_len); if (ret != 1) { SCLogDebug("Callback function has failed"); - FLOWLOCK_UNLOCK(p->flow); return -1; } seg = seg->next; cnt++; } - FLOWLOCK_UNLOCK(p->flow); return cnt; } +int StreamTcpBypassEnabled(void) +{ + return stream_config.bypass; +} + +void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size) +{ + if (size > ssn->reassembly_depth || size == 0) { + ssn->reassembly_depth = size; + } + + return; +} + #ifdef UNITTESTS /** @@ -5672,6 +5832,7 @@ static int StreamTcpTest01 (void) Flow f; memset(p, 0, SIZE_OF_PACKET); memset (&f, 0, sizeof(Flow)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -5699,6 +5860,7 @@ static int StreamTcpTest01 (void) end: StreamTcpFreeConfig(TRUE); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -5729,6 +5891,7 @@ static int StreamTcpTest02 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -5739,7 +5902,7 @@ static int StreamTcpTest02 (void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { goto end; } @@ -5796,8 +5959,9 @@ static int StreamTcpTest02 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -5825,6 +5989,7 @@ static int StreamTcpTest03 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -5836,7 +6001,7 @@ static int StreamTcpTest03 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -5872,8 +6037,9 @@ static int StreamTcpTest03 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -5901,6 +6067,7 @@ static int StreamTcpTest04 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -5913,7 +6080,7 @@ static int StreamTcpTest04 (void) int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -5941,8 +6108,9 @@ static int StreamTcpTest04 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -5971,6 +6139,7 @@ static int StreamTcpTest05 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -5990,7 +6159,7 @@ static int StreamTcpTest05 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6046,8 +6215,9 @@ static int StreamTcpTest05 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6077,6 +6247,7 @@ static int StreamTcpTest06 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6085,7 +6256,7 @@ static int StreamTcpTest06 (void) tcph.th_flags = TH_FIN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); /* StreamTcpPacket returns -1 on unsolicited FIN */ if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) { printf("StreamTcpPacket failed: "); @@ -6112,8 +6283,9 @@ static int StreamTcpTest06 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6127,16 +6299,12 @@ static int StreamTcpTest06 (void) static int StreamTcpTest07 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF(unlikely(p == NULL)); Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; - TCPVars tcpvars; - TCPOpt ts; - uint32_t data[2]; PacketQueue pq; memset(p, 0, SIZE_OF_PACKET); @@ -6145,11 +6313,9 @@ static int StreamTcpTest07 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); - memset(&tcpvars, 0, sizeof(TCPVars)); - memset(&ts, 0, sizeof(TCPOpt)); + FLOW_INITIALIZE(&f); p->flow = &f; - int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; @@ -6164,46 +6330,33 @@ static int StreamTcpTest07 (void) tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; - data[0] = htonl(10); - data[1] = htonl(11); - - ts.type = TCP_OPT_TS; - ts.len = 10; - ts.data = (uint8_t *)data; - tcpvars.ts = &ts; - p->tcpvars = tcpvars; + p->tcpvars.ts_set = TRUE; + p->tcpvars.ts_val = 10; + p->tcpvars.ts_ecr = 11; p->payload = payload; p->payload_len = 1; - SCMutexLock(&f.m); - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) - goto end; + FLOWLOCK_WRLOCK(&f); + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(23); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; - data[0] = htonl(2); - p->tcpvars.ts->data = (uint8_t *)data; + p->tcpvars.ts_val = 2; - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { - if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11) { - printf("the timestamp values are client %"PRIu32" server %" PRIu32"" - " seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p), - ((TcpSession *) (p->flow->protoctx))->client.next_seq); - goto end; - } + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) != -1); - StreamTcpSessionClear(p->flow->protoctx); - ret = 1; - } -end: + FAIL_IF (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11); + + StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); - return ret; + FLOW_DESTROY(&f); + PASS; } /** @@ -6215,18 +6368,13 @@ static int StreamTcpTest07 (void) static int StreamTcpTest08 (void) { - Packet *p = SCMalloc(SIZE_OF_PACKET); - if (unlikely(p == NULL)) - return 0; + FAIL_IF(unlikely(p == NULL)); Flow f; ThreadVars tv; StreamTcpThread stt; TCPHdr tcph; uint8_t payload[1] = {0x42}; - TCPVars tcpvars; - TCPOpt ts; - uint32_t data[2]; memset(p, 0, SIZE_OF_PACKET); PacketQueue pq; @@ -6235,11 +6383,9 @@ static int StreamTcpTest08 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); - memset(&tcpvars, 0, sizeof(TCPVars)); - memset(&ts, 0, sizeof(TCPOpt)); + FLOW_INITIALIZE(&f); p->flow = &f; - int ret = 0; StreamTcpInitConfig(TRUE); stream_config.midstream = TRUE; @@ -6254,48 +6400,34 @@ static int StreamTcpTest08 (void) tcph.th_flags = TH_ACK|TH_PUSH; p->tcph = &tcph; - data[0] = htonl(10); - data[1] = htonl(11); - - ts.type = TCP_OPT_TS; - ts.len = 10; - ts.data = (uint8_t *)data; - tcpvars.ts = &ts; - p->tcpvars = tcpvars; + p->tcpvars.ts_set = TRUE; + p->tcpvars.ts_val = 10; + p->tcpvars.ts_ecr = 11; p->payload = payload; p->payload_len = 1; - SCMutexLock(&f.m); - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) - goto end; + FLOWLOCK_WRLOCK(&f); + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); p->tcph->th_seq = htonl(11); p->tcph->th_ack = htonl(20); p->tcph->th_flags = TH_ACK|TH_PUSH; p->flowflags = FLOW_PKT_TOSERVER; - data[0] = htonl(12); - p->tcpvars.ts->data = (uint8_t *)data; + p->tcpvars.ts_val = 12; - if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) - goto end; + FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1); - if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 12) { - printf("the timestamp values are client %"PRIu32" server %" PRIu32 " " - "seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p), - ((TcpSession *) (p->flow->protoctx))->client.next_seq); - goto end; - } + FAIL_IF(((TcpSession *) (p->flow->protoctx))->client.next_seq != 12); StreamTcpSessionClear(p->flow->protoctx); - ret = 1; -end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); - return ret; + FLOW_DESTROY(&f); + PASS; } /** @@ -6325,6 +6457,7 @@ static int StreamTcpTest09 (void) memset(&stt, 0, sizeof(StreamTcpThread)); memset(&tcph, 0, sizeof(TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6344,7 +6477,7 @@ static int StreamTcpTest09 (void) p->payload = payload; p->payload_len = 1; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6372,8 +6505,9 @@ static int StreamTcpTest09 (void) StreamTcpSessionClear(p->flow->protoctx); end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6401,6 +6535,7 @@ static int StreamTcpTest10 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6412,7 +6547,7 @@ static int StreamTcpTest10 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6474,8 +6609,9 @@ static int StreamTcpTest10 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6503,6 +6639,7 @@ static int StreamTcpTest11 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6514,7 +6651,7 @@ static int StreamTcpTest11 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6577,8 +6714,9 @@ static int StreamTcpTest11 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6606,6 +6744,7 @@ static int StreamTcpTest12 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6617,7 +6756,7 @@ static int StreamTcpTest12 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6672,8 +6811,9 @@ static int StreamTcpTest12 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6702,6 +6842,7 @@ static int StreamTcpTest13 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -6713,7 +6854,7 @@ static int StreamTcpTest13 (void) p->tcph = &tcph; int ret = 0; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -6780,8 +6921,9 @@ static int StreamTcpTest13 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -6909,6 +7051,7 @@ static int StreamTcpTest14 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -6944,7 +7087,7 @@ static int StreamTcpTest14 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7033,9 +7176,9 @@ static int StreamTcpTest14 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_WINDOWS, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_LINUX); + (uint8_t)OS_POLICY_LINUX); goto end; } StreamTcpSessionClear(p->flow->protoctx); @@ -7045,8 +7188,9 @@ static int StreamTcpTest14 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7074,6 +7218,7 @@ static int StreamTcp4WHSTest01 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7084,7 +7229,7 @@ static int StreamTcp4WHSTest01 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7126,8 +7271,9 @@ static int StreamTcp4WHSTest01 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7156,6 +7302,7 @@ static int StreamTcp4WHSTest02 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7166,7 +7313,7 @@ static int StreamTcp4WHSTest02 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7197,8 +7344,9 @@ static int StreamTcp4WHSTest02 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7227,6 +7375,7 @@ static int StreamTcp4WHSTest03 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); p->flow = &f; StreamTcpInitConfig(TRUE); @@ -7237,7 +7386,7 @@ static int StreamTcp4WHSTest03 (void) tcph.th_flags = TH_SYN; p->tcph = &tcph; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7279,8 +7428,9 @@ static int StreamTcp4WHSTest03 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7315,6 +7465,7 @@ static int StreamTcpTest15 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -7350,7 +7501,7 @@ static int StreamTcpTest15 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7439,9 +7590,9 @@ static int StreamTcpTest15 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_WINDOWS, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_LINUX); + (uint8_t)OS_POLICY_LINUX); goto end; } StreamTcpSessionPktFree(p); @@ -7451,8 +7602,9 @@ static int StreamTcpTest15 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7487,6 +7639,7 @@ static int StreamTcpTest16 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -7522,7 +7675,7 @@ static int StreamTcpTest16 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7611,9 +7764,9 @@ static int StreamTcpTest16 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_LINUX, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_WINDOWS); + (uint8_t)OS_POLICY_WINDOWS); goto end; } StreamTcpSessionPktFree(p); @@ -7623,8 +7776,9 @@ static int StreamTcpTest16 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7660,6 +7814,7 @@ static int StreamTcpTest17 (void) memset(&tcph, 0, sizeof (TCPHdr)); memset(&addr, 0, sizeof(addr)); memset(&ipv4h, 0, sizeof(ipv4h)); + FLOW_INITIALIZE(&f); p->flow = &f; int ret = 0; @@ -7695,7 +7850,7 @@ static int StreamTcpTest17 (void) p->payload = payload; p->payload_len = 3; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -7784,9 +7939,9 @@ static int StreamTcpTest17 (void) printf("failed in setting up OS policy, client.os_policy: %"PRIu8"" " should be %"PRIu8" and server.os_policy: %"PRIu8"" " should be %"PRIu8"\n", ((TcpSession *) - (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX, + (p->flow->protoctx))->client.os_policy, (uint8_t)OS_POLICY_LINUX, ((TcpSession *)(p->flow->protoctx))->server.os_policy, - OS_POLICY_DEFAULT); + (uint8_t)OS_POLICY_DEFAULT); goto end; } StreamTcpSessionPktFree(p); @@ -7796,8 +7951,9 @@ static int StreamTcpTest17 (void) StreamTcpFreeConfig(TRUE); ConfDeInit(); ConfRestoreContextBackup(); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -7890,7 +8046,7 @@ static int StreamTcpTest19 (void) if (stream.os_policy != OS_POLICY_WINDOWS) { printf("expected os_policy: %"PRIu8" but received %"PRIu8": ", - OS_POLICY_WINDOWS, stream.os_policy); + (uint8_t)OS_POLICY_WINDOWS, stream.os_policy); goto end; } @@ -7942,7 +8098,7 @@ static int StreamTcpTest20 (void) if (stream.os_policy != OS_POLICY_LINUX) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", - OS_POLICY_LINUX, stream.os_policy); + (uint8_t)OS_POLICY_LINUX, stream.os_policy); goto end; } @@ -7994,7 +8150,7 @@ static int StreamTcpTest21 (void) if (stream.os_policy != OS_POLICY_LINUX) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", - OS_POLICY_LINUX, stream.os_policy); + (uint8_t)OS_POLICY_LINUX, stream.os_policy); goto end; } @@ -8046,7 +8202,7 @@ static int StreamTcpTest22 (void) if (stream.os_policy != OS_POLICY_DEFAULT) { printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n", - OS_POLICY_DEFAULT, stream.os_policy); + (uint8_t)OS_POLICY_DEFAULT, stream.os_policy); goto end; } @@ -8088,6 +8244,7 @@ static int StreamTcpTest23(void) StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); + FLOW_INITIALIZE(&f); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; @@ -8145,6 +8302,7 @@ static int StreamTcpTest23(void) printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse)); } SCFree(p); + FLOW_DESTROY(&f); return result; } @@ -8175,6 +8333,7 @@ static int StreamTcpTest24(void) memset(&f, 0, sizeof (Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); ssn.client.os_policy = OS_POLICY_BSD; f.protoctx = &ssn; p->src.family = AF_INET; @@ -8232,6 +8391,7 @@ static int StreamTcpTest24(void) printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse)); } SCFree(p); + FLOW_DESTROY(&f); return result; } @@ -8261,6 +8421,7 @@ static int StreamTcpTest25(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); @@ -8274,7 +8435,7 @@ static int StreamTcpTest25(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -8330,8 +8491,9 @@ static int StreamTcpTest25(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8361,6 +8523,7 @@ static int StreamTcpTest26(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); @@ -8370,7 +8533,7 @@ static int StreamTcpTest26(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -8426,8 +8589,9 @@ static int StreamTcpTest26(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8457,6 +8621,7 @@ static int StreamTcpTest27(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p->flow = &f; tcph.th_win = htons(5480); @@ -8466,7 +8631,7 @@ static int StreamTcpTest27(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -8522,8 +8687,9 @@ static int StreamTcpTest27(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -8611,6 +8777,7 @@ static int StreamTcpTest29(void) uint8_t packet[1460] = ""; int result = 1; + FLOW_INITIALIZE(&f); StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ @@ -8752,6 +8919,7 @@ static int StreamTcpTest30(void) 0x49, 0x4c }; int result = 1; + FLOW_INITIALIZE(&f); StreamTcpInitConfig(TRUE); /* prevent L7 from kicking in */ @@ -8893,6 +9061,7 @@ static int StreamTcpTest31(void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); /* prevent L7 from kicking in */ ssn.client.os_policy = OS_POLICY_LINUX; @@ -9033,6 +9202,7 @@ static int StreamTcpTest32(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p.flow = &f; tcph.th_win = htons(5480); @@ -9123,6 +9293,8 @@ static int StreamTcpTest33 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + + FLOW_INITIALIZE(&f); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; @@ -9225,6 +9397,8 @@ static int StreamTcpTest34 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + + FLOW_INITIALIZE(&f); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN|TH_PUSH; @@ -9291,6 +9465,8 @@ static int StreamTcpTest35 (void) memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + + FLOW_INITIALIZE(&f); p.flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN|TH_URG; @@ -9356,6 +9532,7 @@ static int StreamTcpTest36(void) memset(&stt, 0, sizeof (StreamTcpThread)); memset(&tcph, 0, sizeof (TCPHdr)); + FLOW_INITIALIZE(&f); stt.ra_ctx = ra_ctx; p.flow = &f; tcph.th_win = htons(5480); @@ -9460,7 +9637,7 @@ static int StreamTcpTest37(void) StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet\n"); goto end; @@ -9541,8 +9718,9 @@ static int StreamTcpTest37(void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -9559,12 +9737,11 @@ static int StreamTcpTest38 (void) Flow f; ThreadVars tv; StreamTcpThread stt; - uint8_t payload[4]; + uint8_t payload[128]; TCPHdr tcph; - TcpReassemblyThreadCtx ra_ctx; PacketQueue pq; - memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); @@ -9576,15 +9753,16 @@ static int StreamTcpTest38 (void) return 0; memset(p, 0, SIZE_OF_PACKET); + FLOW_INITIALIZE(&f); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; - stt.ra_ctx = &ra_ctx; + stt.ra_ctx = ra_ctx; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; @@ -9631,7 +9809,27 @@ static int StreamTcpTest38 (void) goto end; } - p->tcph->th_ack = htonl(2984); + p->tcph->th_ack = htonl(1); + p->tcph->th_seq = htonl(1); + p->tcph->th_flags = TH_PUSH | TH_ACK; + p->flowflags = FLOW_PKT_TOCLIENT; + + StreamTcpCreateTestPacket(payload, 0x41, 127, 128); /*AAA*/ + p->payload = payload; + p->payload_len = 127; + + if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { + printf("failed in processing packet in StreamTcpPacket\n"); + goto end; + } + + if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 128) { + printf("the server.next_seq should be 128, but it is %"PRIu32"\n", + ((TcpSession *)(p->flow->protoctx))->server.next_seq); + goto end; + } + + p->tcph->th_ack = htonl(256); // in window, but beyond next_seq p->tcph->th_seq = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; @@ -9645,10 +9843,32 @@ static int StreamTcpTest38 (void) goto end; } - /* last_ack value should be 2984 as the previous sent ACK value is inside + /* last_ack value should be 256, as the previous sent ACK value + is inside window */ + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) { + printf("the server.last_ack should be 1, but it is %"PRIu32"\n", + ((TcpSession *)(p->flow->protoctx))->server.last_ack); + goto end; + } + + p->tcph->th_ack = htonl(128); + p->tcph->th_seq = htonl(8); + p->tcph->th_flags = TH_PUSH | TH_ACK; + p->flowflags = FLOW_PKT_TOSERVER; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p->payload = payload; + p->payload_len = 3; + + if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { + printf("failed in processing packet in StreamTcpPacket\n"); + goto end; + } + + /* last_ack value should be 256 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2984) { - printf("the server.last_ack should be 2984, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) { + printf("the server.last_ack should be 256, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } @@ -9658,8 +9878,11 @@ static int StreamTcpTest38 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); + if (stt.ra_ctx != NULL) + StreamTcpReassembleFreeThreadCtx(stt.ra_ctx); return ret; } @@ -9677,10 +9900,9 @@ static int StreamTcpTest39 (void) StreamTcpThread stt; uint8_t payload[4]; TCPHdr tcph; - TcpReassemblyThreadCtx ra_ctx; PacketQueue pq; - memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx)); + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); memset (&f, 0, sizeof(Flow)); memset(&tv, 0, sizeof (ThreadVars)); memset(&stt, 0, sizeof (StreamTcpThread)); @@ -9692,17 +9914,18 @@ static int StreamTcpTest39 (void) return 0; memset(p, 0, SIZE_OF_PACKET); + FLOW_INITIALIZE(&f); p->flow = &f; tcph.th_win = htons(5480); tcph.th_flags = TH_SYN; p->tcph = &tcph; p->flowflags = FLOW_PKT_TOSERVER; int ret = 0; - stt.ra_ctx = &ra_ctx; + stt.ra_ctx = ra_ctx; StreamTcpInitConfig(TRUE); - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { printf("failed in processing packet in StreamTcpPacket\n"); goto end; @@ -9727,7 +9950,27 @@ static int StreamTcpTest39 (void) goto end; } - p->tcph->th_ack = htonl(2984); + p->tcph->th_ack = htonl(1); + p->tcph->th_seq = htonl(1); + p->tcph->th_flags = TH_PUSH | TH_ACK; + p->flowflags = FLOW_PKT_TOCLIENT; + + StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/ + p->payload = payload; + p->payload_len = 3; + + if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) { + printf("failed in processing packet in StreamTcpPacket\n"); + goto end; + } + + if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 4) { + printf("the server.next_seq should be 4, but it is %"PRIu32"\n", + ((TcpSession *)(p->flow->protoctx))->server.next_seq); + goto end; + } + + p->tcph->th_ack = htonl(4); p->tcph->th_seq = htonl(2); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOSERVER; @@ -9741,15 +9984,15 @@ static int StreamTcpTest39 (void) goto end; } - /* last_ack value should be 2984 as the previous sent ACK value is inside + /* last_ack value should be 4 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2984) { - printf("the server.last_ack should be 2984, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 4) { + printf("the server.last_ack should be 4, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.last_ack); goto end; } - p->tcph->th_seq = htonl(2984); + p->tcph->th_seq = htonl(4); p->tcph->th_ack = htonl(5); p->tcph->th_flags = TH_PUSH | TH_ACK; p->flowflags = FLOW_PKT_TOCLIENT; @@ -9765,8 +10008,8 @@ static int StreamTcpTest39 (void) /* next_seq value should be 2987 as the previous sent ACK value is inside window */ - if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 2987) { - printf("the server.next_seq should be 2987, but it is %"PRIu32"\n", + if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 7) { + printf("the server.next_seq should be 7, but it is %"PRIu32"\n", ((TcpSession *)(p->flow->protoctx))->server.next_seq); goto end; } @@ -9776,8 +10019,11 @@ static int StreamTcpTest39 (void) end: StreamTcpSessionClear(p->flow->protoctx); StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); + if (stt.ra_ctx != NULL) + StreamTcpReassembleFreeThreadCtx(stt.ra_ctx); return ret; } @@ -9810,7 +10056,7 @@ static int StreamTcpTest40(void) DecodeVLAN(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL); - if(p->vlanh == NULL) { + if(p->vlanh[0] == NULL) { SCFree(p); return 0; } @@ -9929,6 +10175,7 @@ static int StreamTcpTest42 (void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -9938,7 +10185,7 @@ static int StreamTcpTest42 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -9992,8 +10239,9 @@ static int StreamTcpTest42 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10021,6 +10269,7 @@ static int StreamTcpTest43 (void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -10030,7 +10279,7 @@ static int StreamTcpTest43 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10084,8 +10333,9 @@ static int StreamTcpTest43 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10113,6 +10363,7 @@ static int StreamTcpTest44 (void) StreamTcpInitConfig(TRUE); + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -10122,7 +10373,7 @@ static int StreamTcpTest44 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10171,8 +10422,9 @@ static int StreamTcpTest44 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); + FLOW_DESTROY(&f); return ret; } @@ -10201,6 +10453,7 @@ static int StreamTcpTest45 (void) StreamTcpInitConfig(TRUE); stream_config.max_synack_queued = 2; + FLOW_INITIALIZE(&f); p->tcph = &tcph; tcph.th_win = htons(5480); p->flow = &f; @@ -10210,7 +10463,7 @@ static int StreamTcpTest45 (void) tcph.th_seq = htonl(100); p->flowflags = FLOW_PKT_TOSERVER; - SCMutexLock(&f.m); + FLOWLOCK_WRLOCK(&f); if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) goto end; @@ -10282,7 +10535,7 @@ static int StreamTcpTest45 (void) ret = 1; end: StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); + FLOWLOCK_UNLOCK(&f); SCFree(p); return ret; } @@ -10293,52 +10546,50 @@ void StreamTcpRegisterTests (void) { #ifdef UNITTESTS UtRegisterTest("StreamTcpTest01 -- TCP session allocation", - StreamTcpTest01, 1); + StreamTcpTest01); UtRegisterTest("StreamTcpTest02 -- TCP session deallocation", - StreamTcpTest02, 1); + StreamTcpTest02); UtRegisterTest("StreamTcpTest03 -- SYN missed MidStream session", - StreamTcpTest03, 1); + StreamTcpTest03); UtRegisterTest("StreamTcpTest04 -- SYN/ACK missed MidStream session", - StreamTcpTest04, 1); + StreamTcpTest04); UtRegisterTest("StreamTcpTest05 -- 3WHS missed MidStream session", - StreamTcpTest05, 1); + StreamTcpTest05); UtRegisterTest("StreamTcpTest06 -- FIN, RST message MidStream session", - StreamTcpTest06, 1); + StreamTcpTest06); UtRegisterTest("StreamTcpTest07 -- PAWS invalid timestamp", - StreamTcpTest07, 1); - UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp", - StreamTcpTest08, 1); - UtRegisterTest("StreamTcpTest09 -- No Client Reassembly", - StreamTcpTest09, 1); + StreamTcpTest07); + UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp", StreamTcpTest08); + UtRegisterTest("StreamTcpTest09 -- No Client Reassembly", StreamTcpTest09); UtRegisterTest("StreamTcpTest10 -- No missed packet Async stream", - StreamTcpTest10, 1); + StreamTcpTest10); UtRegisterTest("StreamTcpTest11 -- SYN missed Async stream", - StreamTcpTest11, 1); + StreamTcpTest11); UtRegisterTest("StreamTcpTest12 -- SYN/ACK missed Async stream", - StreamTcpTest12, 1); - UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async " - "stream", StreamTcpTest13, 1); - UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01, 1); - UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02, 1); - UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03, 1); - UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14, 1); - UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15, 1); - UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16, 1); - UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17, 1); - UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18, 1); - UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19, 1); - UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20, 1); - UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21, 1); - UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22, 1); - UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23, 1); - UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24, 1); + StreamTcpTest12); + UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async " "stream", + StreamTcpTest13); + UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01); + UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02); + UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03); + UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14); + UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15); + UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16); + UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17); + UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18); + UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19); + UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20); + UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21); + UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22); + UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23); + UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24); UtRegisterTest("StreamTcpTest25 -- test ecn/cwr sessions", - StreamTcpTest25, 1); + StreamTcpTest25); UtRegisterTest("StreamTcpTest26 -- test ecn/cwr sessions", - StreamTcpTest26, 1); + StreamTcpTest26); UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions", - StreamTcpTest27, 1); - UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28, 1); + StreamTcpTest27); + UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28); #if 0 /* VJ 2010/09/01 disabled since they blow up on Fedora and Fedora is * right about blowing up. The checksum functions are not used properly @@ -10352,18 +10603,19 @@ void StreamTcpRegisterTests (void) UtRegisterTest("StreamTcpTest35 -- SYN-URG Test", StreamTcpTest35, 1); UtRegisterTest("StreamTcpTest36 -- PUSH-URG Test", StreamTcpTest36, 1); #endif - UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", StreamTcpTest37, 1); + UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", + StreamTcpTest37); - UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38, 1); - UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39, 1); + UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38); + UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39); - UtRegisterTest("StreamTcpTest40 -- pseudo setup", StreamTcpTest40, 1); - UtRegisterTest("StreamTcpTest41 -- pseudo setup", StreamTcpTest41, 1); + UtRegisterTest("StreamTcpTest40 -- pseudo setup", StreamTcpTest40); + UtRegisterTest("StreamTcpTest41 -- pseudo setup", StreamTcpTest41); - UtRegisterTest("StreamTcpTest42 -- SYN/ACK queue", StreamTcpTest42, 1); - UtRegisterTest("StreamTcpTest43 -- SYN/ACK queue", StreamTcpTest43, 1); - UtRegisterTest("StreamTcpTest44 -- SYN/ACK queue", StreamTcpTest44, 1); - UtRegisterTest("StreamTcpTest45 -- SYN/ACK queue", StreamTcpTest45, 1); + UtRegisterTest("StreamTcpTest42 -- SYN/ACK queue", StreamTcpTest42); + UtRegisterTest("StreamTcpTest43 -- SYN/ACK queue", StreamTcpTest43); + UtRegisterTest("StreamTcpTest44 -- SYN/ACK queue", StreamTcpTest44); + UtRegisterTest("StreamTcpTest45 -- SYN/ACK queue", StreamTcpTest45); /* set up the reassembly tests as well */ StreamTcpReassembleRegisterTests(); diff --git a/src/stream-tcp.h b/src/stream-tcp.h index b8a31855afad..e49ab9a8d3e8 100644 --- a/src/stream-tcp.h +++ b/src/stream-tcp.h @@ -51,6 +51,9 @@ typedef struct TcpStreamCnf_ { uint32_t ssn_init_flags; /**< new ssn flags will be initialized to this */ uint8_t segment_init_flags; /**< new seg flags will be initialized to this */ + uint16_t zero_copy_size; /**< use zero copy for app layer above segments + * of this size */ + uint32_t prealloc_sessions; /**< ssns to prealloc per stream thread */ int midstream; int async_oneside; @@ -60,12 +63,8 @@ typedef struct TcpStreamCnf_ { uint16_t reassembly_toclient_chunk_size; int check_overlap_different_data; + int bypass; - /** reassembly -- inline mode - * - * sliding window size for raw stream reassembly - */ - uint32_t reassembly_inline_window; uint8_t flags; uint8_t max_synack_queued; } TcpStreamCnf; @@ -73,8 +72,6 @@ typedef struct TcpStreamCnf_ { typedef struct StreamTcpThread_ { int ssn_pool_id; - uint64_t pkts; - /** queue for pseudo packet(s) that were created in the stream * process and need further handling. Currently only used when * receiving (valid) RST packets */ @@ -93,8 +90,6 @@ typedef struct StreamTcpThread_ { uint16_t counter_tcp_no_flow; /** sessions reused */ uint16_t counter_tcp_reused_ssn; - /** sessions reused */ - uint16_t counter_tcp_memuse; /** syn pkts */ uint16_t counter_tcp_syn; /** syn/ack pkts */ @@ -107,7 +102,6 @@ typedef struct StreamTcpThread_ { } StreamTcpThread; TcpStreamCnf stream_config; -void TmModuleStreamTcpRegister (void); void StreamTcpInitConfig (char); void StreamTcpFreeConfig(char); void StreamTcpRegisterTests (void); @@ -124,6 +118,7 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data); void StreamTcpReassembleConfigEnableOverlapCheck(void); +void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size); /** ------- Inline functions: ------ */ @@ -164,9 +159,19 @@ static inline void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p) if (PKT_IS_TOSERVER(p)) { p->flowflags &= ~FLOW_PKT_TOSERVER; p->flowflags |= FLOW_PKT_TOCLIENT; + + if (p->flowflags & FLOW_PKT_TOSERVER_FIRST) { + p->flowflags &= ~FLOW_PKT_TOSERVER_FIRST; + p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; + } } else { p->flowflags &= ~FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_TOSERVER; + + if (p->flowflags & FLOW_PKT_TOCLIENT_FIRST) { + p->flowflags &= ~FLOW_PKT_TOCLIENT_FIRST; + p->flowflags |= FLOW_PKT_TOSERVER_FIRST; + } } } @@ -206,11 +211,23 @@ static inline int StreamNeedsReassembly(TcpSession *ssn, int direction) } } +TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +void StreamTcpExitPrintStats(ThreadVars *, void *); TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **); TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data); +void StreamTcpRegisterTests (void); + int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueue *pq); +/* clear ssn and return to pool */ void StreamTcpSessionClear(void *ssnptr); +/* cleanup ssn, but don't free ssn */ +void StreamTcpSessionCleanup(TcpSession *ssn); +/* cleanup stream, but don't free the stream */ +void StreamTcpStreamCleanup(TcpStream *stream); +/* check if bypass is enabled */ +int StreamTcpBypassEnabled(void); + uint32_t StreamTcpGetStreamSize(TcpStream *stream); #endif /* __STREAM_TCP_H__ */ diff --git a/src/stream.c b/src/stream.c index 6d77890bbbde..6415420981a5 100644 --- a/src/stream.c +++ b/src/stream.c @@ -133,25 +133,31 @@ void StreamMsgPutInQueue(StreamMsgQueue *q, StreamMsg *s) SCLogDebug("q->len %" PRIu32 "", q->len); } +#define SIZE 4072 void *StreamMsgPoolAlloc(void) { - if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(StreamMsg)) == 0) + if (StreamTcpReassembleCheckMemcap((uint32_t)(sizeof(StreamMsg)+SIZE)) == 0) return NULL; - StreamMsg *m = SCMalloc(sizeof(StreamMsg)); - if (m != NULL) - StreamTcpReassembleIncrMemuse((uint32_t)sizeof(StreamMsg)); + StreamMsg *m = SCCalloc(1, (sizeof(StreamMsg) + SIZE)); + if (m != NULL) { + m->data = (uint8_t *)m + sizeof(StreamMsg); + m->data_size = SIZE; + + StreamTcpReassembleIncrMemuse((uint32_t)(sizeof(StreamMsg)+SIZE)); + } return m; } int StreamMsgInit(void *data, void *initdata) { - memset(data, 0, sizeof(StreamMsg)); + StreamMsg *s = data; + memset(s->data, 0, s->data_size); #ifdef DEBUG SCMutexLock(&stream_pool_memuse_mutex); - stream_pool_memuse += sizeof(StreamMsg); + stream_pool_memuse += (sizeof(StreamMsg) + SIZE); stream_pool_memcnt ++; SCMutexUnlock(&stream_pool_memuse_mutex); #endif @@ -162,7 +168,7 @@ void StreamMsgPoolFree(void *ptr) { if (ptr) { SCFree(ptr); - StreamTcpReassembleDecrMemuse((uint32_t)sizeof(StreamMsg)); + StreamTcpReassembleDecrMemuse((uint32_t)(sizeof(StreamMsg)+SIZE)); } } @@ -228,12 +234,6 @@ void StreamMsgQueueFree(StreamMsgQueue *q) StreamTcpReassembleDecrMemuse((uint32_t)sizeof(StreamMsgQueue)); } -StreamMsgQueue *StreamMsgQueueGetByPort(uint16_t port) -{ - /* XXX implement this */ - return NULL;//&stream_q; -} - void StreamMsgQueueSetMinChunkLen(uint8_t dir, uint16_t len) { if (dir == FLOW_PKT_TOSERVER) { @@ -268,6 +268,8 @@ void StreamMsgReturnListToPool(void *list) } /** \brief Run callback for all segments + * + * Must be called under flow lock. * * \return -1 in case of error, the number of segment in case of success */ diff --git a/src/stream.h b/src/stream.h index 6a5b75427543..72674f803d1f 100644 --- a/src/stream.h +++ b/src/stream.h @@ -30,11 +30,8 @@ #define STREAM_EOF 0x02 #define STREAM_TOSERVER 0x04 #define STREAM_TOCLIENT 0x08 -#define STREAM_GAP 0x10 /* data gap encountered */ -#define STREAM_DEPTH 0x20 /* depth reached */ - -/** size of the data chunks sent to the app layer parser. */ -#define MSG_DATA_SIZE 4072 /* 4096 - 24 (size of rest of the struct) */ +#define STREAM_GAP 0x10 /**< data gap encountered */ +#define STREAM_DEPTH 0x20 /**< depth reached */ typedef struct StreamMsg_ { struct StreamMsg_ *next; @@ -42,14 +39,15 @@ typedef struct StreamMsg_ { uint32_t seq; /**< sequence number */ uint32_t data_len; /**< length of the data */ - uint8_t data[MSG_DATA_SIZE]; /**< reassembled data */ + uint32_t data_size; + uint8_t *data; /**< reassembled data: ptr to after this + * struct */ } StreamMsg; typedef struct StreamMsgQueue_ { StreamMsg *top; StreamMsg *bot; uint16_t len; - //uint8_t flags; #ifdef DBG_PERF uint16_t dbg_maxlen; #endif /* DBG_PERF */ @@ -66,17 +64,16 @@ void StreamMsgPutInQueue(StreamMsgQueue *, StreamMsg *); StreamMsgQueue *StreamMsgQueueGetNew(void); void StreamMsgQueueFree(StreamMsgQueue *); -StreamMsgQueue *StreamMsgQueueGetByPort(uint16_t); void StreamMsgQueueSetMinChunkLen(uint8_t dir, uint16_t len); uint16_t StreamMsgQueueGetMinChunkLen(uint8_t); void StreamMsgReturnListToPool(void *); -typedef int (*StreamSegmentCallback)(const Packet *, void *, uint8_t *, uint32_t); +typedef int (*StreamSegmentCallback)(const Packet *, void *, const uint8_t *, uint32_t); int StreamSegmentForEach(const Packet *p, uint8_t flag, - StreamSegmentCallback CallbackFunc, - void *data); + StreamSegmentCallback CallbackFunc, + void *data); #endif /* __STREAM_H__ */ diff --git a/src/suricata-common.h b/src/suricata-common.h index 43c76c19f7c5..25afac2a9e28 100644 --- a/src/suricata-common.h +++ b/src/suricata-common.h @@ -49,10 +49,18 @@ #include #endif +#if HAVE_STDDEF_H +#include +#endif + #if HAVE_STDINT_h #include #endif +#if HAVE_STDBOOL_H +#include +#endif + #if HAVE_STDARG_H #include #endif @@ -85,6 +93,10 @@ #include #endif +#if HAVE_STRINGS_H +#include +#endif + #if HAVE_FCNTL_H #include #endif @@ -206,15 +218,19 @@ #endif #endif /* !__CYGWIN__ */ -#if CPPCHECK==1 -#define BUG_ON(x) if (((x))) exit(1) -#else -#ifdef HAVE_ASSERT_H -#include -#define BUG_ON(x) assert(!(x)) -#else -#define BUG_ON(x) +#ifdef HAVE_LIBJANSSON +#include +#ifndef JSON_ESCAPE_SLASH +#define JSON_ESCAPE_SLASH 0 #endif +/* Appears not all current distros have jansson that defines this. */ +#ifndef json_boolean +#define json_boolean(val) ((val) ? json_true() : json_false()) +#endif +#endif + +#ifdef HAVE_MAGIC +#include #endif /* we need this to stringify the defines which are supplied at compiletime see: @@ -222,15 +238,32 @@ #define xstr(s) str(s) #define str(s) #s +#if CPPCHECK==1 + #define BUG_ON(x) if (((x))) exit(1) +#else + #if defined HAVE_ASSERT_H && !defined NDEBUG + #include + #define BUG_ON(x) assert(!(x)) + #else + #define BUG_ON(x) do { \ + if (((x))) { \ + fprintf(stderr, "BUG at %s:%d(%s)\n", __FILE__, __LINE__, __func__); \ + fprintf(stderr, "Code: '%s'\n", xstr((x))); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + #endif +#endif + /** type for the internal signature id. Since it's used in the matching engine * extensively keeping this as small as possible reduces the overall memory * footprint of the engine. Set to uint32_t if the engine needs to support * more than 64k sigs. */ -#define SigIntId uint16_t -//#define SigIntId uint32_t +//#define SigIntId uint16_t +#define SigIntId uint32_t /** same for pattern id's */ -#define PatIntId uint16_t +#define PatIntId uint32_t /** FreeBSD does not define __WORDSIZE, but it uses __LONG_BIT */ #ifndef __WORDSIZE @@ -245,73 +278,136 @@ /** Windows does not define __WORDSIZE, but it uses __X86__ */ #ifndef __WORDSIZE - #if defined(__X86__) || defined(_X86_) - #define __WORDSIZE 32 - #else - #if defined(__X86_64__) || defined(_X86_64_) - #define __WORDSIZE 64 - #endif - #endif - - #ifndef __WORDSIZE - #warning Defaulting to __WORDSIZE 32 + #if defined(__X86__) || defined(_X86_) || defined(_M_IX86) #define __WORDSIZE 32 + #else + #if defined(__X86_64__) || defined(_X86_64_) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(__amd64) || defined(__amd64__) + #define __WORDSIZE 64 + #endif #endif #endif +/** if not succesful yet try the data models */ +#ifndef __WORDSIZE + #if defined(_ILP32) || defined(__ILP32__) + #define __WORDSIZE 32 + #endif + #if defined(_LP64) || defined(__LP64__) + #define __WORDSIZE 64 + #endif +#endif + +#ifndef __WORDSIZE + #warning Defaulting to __WORDSIZE 32 + #define __WORDSIZE 32 +#endif + /** darwin doesn't defined __BYTE_ORDER and friends, but BYTE_ORDER */ #ifndef __BYTE_ORDER -#ifdef BYTE_ORDER -#define __BYTE_ORDER BYTE_ORDER -#endif + #if defined(BYTE_ORDER) + #define __BYTE_ORDER BYTE_ORDER + #elif defined(__BYTE_ORDER__) + #define __BYTE_ORDER __BYTE_ORDER__ + #else + #error "byte order not detected" + #endif #endif #ifndef __LITTLE_ENDIAN -#ifdef LITTLE_ENDIAN -#define __LITTLE_ENDIAN LITTLE_ENDIAN -#endif + #if defined(LITTLE_ENDIAN) + #define __LITTLE_ENDIAN LITTLE_ENDIAN + #elif defined(__ORDER_LITTLE_ENDIAN__) + #define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ + #endif #endif #ifndef __BIG_ENDIAN -#ifdef BIG_ENDIAN -#define __BIG_ENDIAN BIG_ENDIAN + #if defined(BIG_ENDIAN) + #define __BIG_ENDIAN BIG_ENDIAN + #elif defined(__ORDER_BIG_ENDIAN__) + #define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ + #endif #endif + +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) + #error "byte order: can't figure out big or little" #endif #ifndef HAVE_PCRE_FREE_STUDY #define pcre_free_study pcre_free #endif +#ifndef MIN +#define MIN(x, y) (((x)<(y))?(x):(y)) +#endif + +#ifndef MAX +#define MAX(x, y) (((x)<(y))?(y):(x)) +#endif + +#define BIT_U8(n) ((uint8_t)(1 << (n))) +#define BIT_U16(n) ((uint16_t)(1 << (n))) +#define BIT_U32(n) (1UL << (n)) +#define BIT_U64(n) (1ULL << (n)) + +#define WARN_UNUSED __attribute__((warn_unused_result)) + typedef enum PacketProfileDetectId_ { - PROF_DETECT_MPM, - PROF_DETECT_MPM_PACKET, /* PKT MPM */ - PROF_DETECT_MPM_PKT_STREAM, /* PKT inspected with stream MPM */ - PROF_DETECT_MPM_STREAM, /* STREAM MPM */ - PROF_DETECT_MPM_URI, - PROF_DETECT_MPM_HCBD, - PROF_DETECT_MPM_HSBD, - PROF_DETECT_MPM_HHD, - PROF_DETECT_MPM_HRHD, - PROF_DETECT_MPM_HMD, - PROF_DETECT_MPM_HCD, - PROF_DETECT_MPM_HRUD, - PROF_DETECT_MPM_HSMD, - PROF_DETECT_MPM_HSCD, - PROF_DETECT_MPM_HUAD, - PROF_DETECT_MPM_HHHD, - PROF_DETECT_MPM_HRHHD, - PROF_DETECT_MPM_DNSQUERY, PROF_DETECT_IPONLY, PROF_DETECT_RULES, PROF_DETECT_STATEFUL, PROF_DETECT_PREFILTER, + PROF_DETECT_PF_PKT, + PROF_DETECT_PF_PAYLOAD, + PROF_DETECT_PF_TX, + PROF_DETECT_PF_SORT1, + PROF_DETECT_PF_SORT2, + PROF_DETECT_NONMPMLIST, PROF_DETECT_ALERT, PROF_DETECT_CLEANUP, PROF_DETECT_GETSGH, + PROF_DETECT_MPM_FD_SMTP, PROF_DETECT_SIZE, } PacketProfileDetectId; +typedef enum { + LOGGER_UNDEFINED, + LOGGER_ALERT_DEBUG, + LOGGER_ALERT_FAST, + LOGGER_UNIFIED2, + LOGGER_ALERT_SYSLOG, + LOGGER_DROP, + LOGGER_JSON_ALERT, + LOGGER_JSON_DROP, + LOGGER_JSON_SSH, + LOGGER_DNS, + LOGGER_HPFEEDS, + LOGGER_HTTP, + LOGGER_JSON_DNS, + LOGGER_JSON_HTTP, + LOGGER_JSON_SMTP, + LOGGER_JSON_TLS, + LOGGER_JSON_TEMPLATE, + LOGGER_TLS_STORE, + LOGGER_TLS, + LOGGER_FILE, + LOGGER_FILE_STORE, + LOGGER_JSON_FILE, + LOGGER_TCP_DATA, + LOGGER_JSON_FLOW, + LOGGER_JSON_NETFLOW, + LOGGER_STATS, + LOGGER_JSON_STATS, + LOGGER_PRELUDE, + LOGGER_PCAP, + LOGGER_JSON_DNP3, + LOGGER_JSON_VARS, + LOGGER_SIZE, +} LoggerId; + #include #include "threads.h" #include "tm-threads-common.h" @@ -323,8 +419,18 @@ typedef enum PacketProfileDetectId_ { #include "util-path.h" #include "util-conf.h" +#ifdef HAVE_LUA +#include +#include +#include +#endif + +#ifndef HAVE_STRLCAT size_t strlcat(char *, const char *src, size_t siz); +#endif +#ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); +#endif extern int coverage_unittests; extern int g_ut_modules; diff --git a/src/suricata.c b/src/suricata.c index 954982793956..6cd05f2c8a70 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -43,6 +43,7 @@ #include "packet-queue.h" #include "threads.h" #include "threadvars.h" +#include "flow-worker.h" #include "util-atomic.h" #include "util-spm.h" @@ -72,32 +73,6 @@ #include "conf.h" #include "conf-yaml-loader.h" -#include "alert-fastlog.h" -#include "alert-unified2-alert.h" -#include "alert-debuglog.h" -#include "alert-prelude.h" -#include "alert-syslog.h" -#include "output-json-alert.h" - -#include "output-json-flow.h" -#include "output-json-netflow.h" -#include "log-droplog.h" -#include "output-json-drop.h" -#include "log-httplog.h" -#include "output-json-http.h" -#include "log-dnslog.h" -#include "output-json-dns.h" -#include "log-tlslog.h" -#include "output-json-tls.h" -#include "output-json-ssh.h" -#include "log-pcap.h" -#include "log-file.h" -#include "output-json-file.h" -#include "log-filestore.h" -#include "log-tcp-data.h" - -#include "output-json.h" - #include "stream-tcp.h" #include "source-nfq.h" @@ -117,6 +92,7 @@ #include "source-napatech.h" #include "source-af-packet.h" +#include "source-netmap.h" #include "source-mpipe.h" #include "respond-reject.h" @@ -127,6 +103,10 @@ #include "flow-var.h" #include "flow-bit.h" #include "pkt-var.h" +#include "host-bit.h" + +#include "ippair.h" +#include "ippair-bit.h" #include "host.h" #include "unix-manager.h" @@ -134,7 +114,18 @@ #include "app-layer.h" #include "app-layer-parser.h" #include "app-layer-htp.h" - +#include "app-layer-ssl.h" +#include "app-layer-dns-tcp.h" +#include "app-layer-dns-udp.h" +#include "app-layer-ssh.h" +#include "app-layer-ftp.h" +#include "app-layer-smtp.h" +#include "app-layer-smb.h" +#include "app-layer-modbus.h" +#include "app-layer-enip.h" +#include "app-layer-dnp3.h" + +#include "util-decode-der.h" #include "util-radix-tree.h" #include "util-host-os-info.h" #include "util-cidr.h" @@ -151,6 +142,8 @@ #include "util-coredump-config.h" +#include "util-decode-mime.h" + #include "defrag.h" #include "runmodes.h" @@ -164,13 +157,6 @@ #include "reputation.h" #include "output.h" -#include "output-lua.h" - -#include "output-packet.h" -#include "output-tx.h" -#include "output-file.h" -#include "output-filedata.h" -#include "output-streaming.h" #include "util-privs.h" @@ -181,15 +167,19 @@ #include "util-cuda-buffer.h" #include "util-mpm-ac.h" #endif +#include "util-mpm-hs.h" #include "util-storage.h" #include "host-storage.h" +#include "util-lua.h" + /* * we put this here, because we only use it here in main. */ volatile sig_atomic_t sigint_count = 0; volatile sig_atomic_t sighup_count = 0; volatile sig_atomic_t sigterm_count = 0; +volatile sig_atomic_t sigusr2_count = 0; /* * Flag to indicate if the engine is at the initialization @@ -202,11 +192,14 @@ SC_ATOMIC_DECLARE(unsigned int, engine_stage); #define DEFAULT_MAX_PENDING_PACKETS 1024 /** suricata engine control flags */ -uint8_t suricata_ctl_flags = 0; +volatile uint8_t suricata_ctl_flags = 0; /** Run mode selected */ int run_mode = RUNMODE_UNKNOWN; +/** Is this an offline run mode. */ +int run_mode_offline = 0; + /** Engine mode: inline (ENGINE_MODE_IPS) or just * detection mode (ENGINE_MODE_IDS by default) */ static enum EngineMode g_engine_mode = ENGINE_MODE_IDS; @@ -222,9 +215,10 @@ intmax_t max_pending_packets; int g_detect_disabled = 0; /** set caps or not */ -int sc_set_caps; +int sc_set_caps = FALSE; -char *conf_filename = NULL; +/** highest mtu of the interfaces we monitor */ +int g_default_mtu = 0; int EngineModeIsIPS(void) { @@ -259,73 +253,33 @@ int RunmodeGetCurrent(void) return run_mode; } +/** signal handlers + * + * WARNING: don't use the SCLog* API in the handlers. The API is complex + * with memory allocation possibly happening, calls to syslog, json message + * construction, etc. + */ + static void SignalHandlerSigint(/*@unused@*/ int sig) { sigint_count = 1; - suricata_ctl_flags |= SURICATA_STOP; } static void SignalHandlerSigterm(/*@unused@*/ int sig) { sigterm_count = 1; - suricata_ctl_flags |= SURICATA_KILL; -} - -void SignalHandlerSigusr2Disabled(int sig) -{ - SCLogInfo("Live rule reload not enabled in config."); - - return; -} - -void SignalHandlerSigusr2StartingUp(int sig) -{ - SCLogInfo("Live rule reload only possible after engine completely started."); - - return; -} - -void SignalHandlerSigusr2DelayedDetect(int sig) -{ - SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload blocked while delayed detect is still loading."); -} - -void SignalHandlerSigusr2SigFileStartup(int sig) -{ - SCLogInfo("Live rule reload not possible if -s or -S option used at runtime."); - - return; -} - -void SignalHandlerSigusr2Idle(int sig) -{ - if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { - SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); - return; - } - - SCLogInfo("Ruleset load in progress. New ruleset load " - "allowed after current is done"); - - return; } -void SignalHandlerSigusr2(int sig) +/** + * SIGUSR2 handler. Just set sigusr2_count. The main loop will act on + * it. + */ +static void SignalHandlerSigusr2(int sig) { - if (run_mode == RUNMODE_UNKNOWN || run_mode == RUNMODE_UNITTEST) { - SCLogInfo("Ruleset load signal USR2 triggered for wrong runmode"); - return; - } - - if (suricata_ctl_flags != 0) { - SCLogInfo("Live rule swap no longer possible. Engine in shutdown mode."); - return; + if (sigusr2_count < 16) { + sigusr2_count++; + } else { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Too many USR2 signals pending, ignoring new ones!"); } - - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle); - - DetectEngineSpawnLiveRuleSwapMgmtThread(); - - return; } /** @@ -365,8 +319,14 @@ void CreateLowercaseTable() } } -void GlobalInits() +void GlobalsInitPreConfig() { +#ifdef __SC_CUDA_SUPPORT__ + /* Init the CUDA environment */ + SCCudaInitCudaEnvironment(); + CudaBufferInit(); +#endif + memset(trans_q, 0, sizeof(trans_q)); memset(data_queues, 0, sizeof(data_queues)); @@ -387,19 +347,88 @@ void GlobalInits() } CreateLowercaseTable(); + + TimeInit(); + SupportFastPatternForSigMatchTypes(); } -/* XXX hack: make sure threads can stop the engine by calling this - function. Purpose: pcap file mode needs to be able to tell the - engine the file eof is reached. */ -void EngineStop(void) +void GlobalsDestroy(SCInstance *suri) { - suricata_ctl_flags |= SURICATA_STOP; + HostShutdown(); + HTPFreeConfig(); + HTPAtExitPrintStats(); + +#ifdef DBG_MEM_ALLOC + SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); +#ifdef DBG_MEM_ALLOC_SKIP_STARTUP + print_mem_flag = 0; +#endif +#endif + + AppLayerHtpPrintStats(); + + /* TODO this can do into it's own func */ + DetectEngineCtx *de_ctx = DetectEngineGetCurrent(); + if (de_ctx) { + DetectEngineMoveToFreeList(de_ctx); + DetectEngineDeReference(&de_ctx); + } + DetectEnginePruneFreeList(); + + AppLayerDeSetup(); + + TagDestroyCtx(); + + LiveDeviceListClean(); + OutputDeregisterAll(); + TimeDeinit(); + SCProtoNameDeInit(); + if (!suri->disabled_detect) { + SCReferenceConfDeinit(); + SCClassConfDeinit(); + } +#ifdef HAVE_MAGIC + MagicDeinit(); +#endif + TmqhCleanup(); + TmModuleRunDeInit(); + ParseSizeDeinit(); +#ifdef HAVE_NSS + NSS_Shutdown(); + PR_Cleanup(); +#endif + +#ifdef HAVE_AF_PACKET + AFPPeersListClean(); +#endif + + SC_ATOMIC_DESTROY(engine_stage); + +#ifdef BUILD_HYPERSCAN + MpmHSGlobalCleanup(); +#endif + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) + MpmCudaBufferDeSetup(); + CudaHandlerFreeProfiles(); +#endif + ConfDeInit(); +#ifdef HAVE_LUAJIT + LuajitFreeStatesPool(); +#endif + SCLogDeInitLogModule(); + DetectParseFreeRegexes(); + + SCPidfileRemove(suri->pid_filename); } -void EngineKill(void) +/** \brief make sure threads can stop the engine by calling this + * function. Purpose: pcap file mode needs to be able to tell the + * engine the file eof is reached. */ +void EngineStop(void) { - suricata_ctl_flags |= SURICATA_KILL; + suricata_ctl_flags |= SURICATA_STOP; } /** @@ -413,14 +442,14 @@ void EngineDone(void) suricata_ctl_flags |= SURICATA_DONE; } -static int SetBpfString(int optind, char *argv[]) +static int SetBpfString(int argc, char *argv[]) { char *bpf_filter = NULL; uint32_t bpf_len = 0; int tmpindex = 0; /* attempt to parse remaining args as bpf filter */ - tmpindex = optind; + tmpindex = argc; while(argv[tmpindex] != NULL) { bpf_len+=strlen(argv[tmpindex]) + 1; tmpindex++; @@ -453,6 +482,7 @@ static int SetBpfString(int optind, char *argv[]) if(strlen(bpf_filter) > 0) { if (ConfSetFinal("bpf-filter", bpf_filter) != 1) { SCLogError(SC_ERR_FATAL, "Failed to set bpf filter."); + SCFree(bpf_filter); return TM_ECODE_FAILED; } } @@ -505,11 +535,15 @@ static void SetBpfStringFromFile(char *filename) } memset(bpf_filter, 0x00, bpf_len); - nm = fread(bpf_filter, bpf_len - 1, 1, fp); - if((ferror(fp) != 0)||( nm != 1)) { - *bpf_filter='\0'; + nm = fread(bpf_filter, 1, bpf_len - 1, fp); + if ((ferror(fp) != 0) || (nm != (bpf_len - 1))) { + SCLogError(SC_ERR_BPF, "Failed to read complete BPF file %s", filename); + SCFree(bpf_filter); + fclose(fp); + exit(EXIT_FAILURE); } fclose(fp); + bpf_filter[nm] = '\0'; if(strlen(bpf_filter) > 0) { /*replace comments with space*/ @@ -529,10 +563,18 @@ static void SetBpfStringFromFile(char *filename) while((bpf_comment_tmp = strchr(bpf_filter, '\n')) != NULL) { *bpf_comment_tmp = ' '; } - if(ConfSetFinal("bpf-filter", bpf_filter) != 1) { - SCLogError(SC_ERR_FOPEN, "ERROR: Failed to set bpf filter!"); - SCFree(bpf_filter); - exit(EXIT_FAILURE); + /* cut trailing spaces */ + while (strlen(bpf_filter) > 0 && + bpf_filter[strlen(bpf_filter)-1] == ' ') + { + bpf_filter[strlen(bpf_filter)-1] = '\0'; + } + if (strlen(bpf_filter) > 0) { + if(ConfSetFinal("bpf-filter", bpf_filter) != 1) { + SCLogError(SC_ERR_FOPEN, "ERROR: Failed to set bpf filter!"); + SCFree(bpf_filter); + exit(EXIT_FAILURE); + } } } SCFree(bpf_filter); @@ -601,12 +643,16 @@ void usage(const char *progname) #ifdef HAVE_AF_PACKET printf("\t--af-packet[=] : run in af-packet mode, no value select interfaces from suricata.yaml\n"); #endif +#ifdef HAVE_NETMAP + printf("\t--netmap[=] : run in netmap mode, no value select interfaces from suricata.yaml\n"); +#endif #ifdef HAVE_PFRING printf("\t--pfring[=] : run in pfring mode, use interfaces from suricata.yaml\n"); printf("\t--pfring-int : run in pfring mode, use interface \n"); printf("\t--pfring-cluster-id : pfring cluster id \n"); printf("\t--pfring-cluster-type : pfring cluster type for PF_RING 4.1.2 and later cluster_round_robin|cluster_flow\n"); #endif /* HAVE_PFRING */ + printf("\t--simulate-ips : force engine into IPS mode. Useful for QA\n"); #ifdef HAVE_LIBCAP_NG printf("\t--user : run suricata as this user after init\n"); printf("\t--group : run suricata as this group after init\n"); @@ -637,6 +683,7 @@ void SCPrintBuildInfo(void) char *bits = "-bits"; char *endian = "-endian"; char features[2048] = ""; + char *tls = "pthread key"; #ifdef REVISION printf("This is %s version %s (rev %s)\n", PROG_NAME, PROG_VER, xstr(REVISION)); @@ -678,6 +725,9 @@ void SCPrintBuildInfo(void) #ifdef HAVE_AF_PACKET strlcat(features, "AF_PACKET ", sizeof(features)); #endif +#ifdef HAVE_NETMAP + strlcat(features, "NETMAP ", sizeof(features)); +#endif #ifdef HAVE_PACKET_FANOUT strlcat(features, "HAVE_PACKET_FANOUT ", sizeof(features)); #endif @@ -713,6 +763,12 @@ void SCPrintBuildInfo(void) #endif #ifdef PROFILE_LOCKING strlcat(features, "PROFILE_LOCKING ", sizeof(features)); +#endif +#ifdef TLS + strlcat(features, "TLS ", sizeof(features)); +#endif +#ifdef HAVE_MAGIC + strlcat(features, "MAGIC ", sizeof(features)); #endif if (strlen(features) == 0) { strlcat(features, "none", sizeof(features)); @@ -788,16 +844,31 @@ void SCPrintBuildInfo(void) #if __SSP_ALL__ == 2 printf("compiled with -fstack-protector-all\n"); #endif -#ifdef _FORTIFY_SOURCE - printf("compiled with _FORTIFY_SOURCE=%d\n", _FORTIFY_SOURCE); +/* + * Workaround for special defines of _FORTIFY_SOURCE like + * FORTIFY_SOURCE=((defined __OPTIMIZE && OPTIMIZE > 0) ? 2 : 0) + * which is used by Gentoo for example and would result in the error + * 'defined' undeclared when _FORTIFY_SOURCE used via %d in printf func + * + */ +#if _FORTIFY_SOURCE == 2 + printf("compiled with _FORTIFY_SOURCE=2\n"); +#elif _FORTIFY_SOURCE == 1 + printf("compiled with _FORTIFY_SOURCE=1\n"); +#elif _FORTIFY_SOURCE == 0 + printf("compiled with _FORTIFY_SOURCE=0\n"); #endif #ifdef CLS printf("L1 cache line size (CLS)=%d\n", CLS); #endif +#ifdef TLS + tls = "__thread"; +#endif + printf("thread local storage method: %s\n", tls); printf("compiled with %s, linked against %s\n", HTP_VERSION_STRING_FULL, htp_get_version()); - + printf("\n"); #include "build-info.h" } @@ -807,6 +878,8 @@ int g_ut_covered; void RegisterAllModules() { + /* commanders */ + TmModuleUnixManagerRegister(); /* managers */ TmModuleFlowManagerRegister(); TmModuleFlowRecyclerRegister(); @@ -832,6 +905,9 @@ void RegisterAllModules() /* af-packet */ TmModuleReceiveAFPRegister(); TmModuleDecodeAFPRegister(); + /* netmap */ + TmModuleReceiveNetmapRegister(); + TmModuleDecodeNetmapRegister(); /* pfring */ TmModuleReceivePfringRegister(); TmModuleDecodePfringRegister(); @@ -845,75 +921,29 @@ void RegisterAllModules() TmModuleNapatechStreamRegister(); TmModuleNapatechDecodeRegister(); - /* stream engine */ - TmModuleStreamTcpRegister(); - /* detection */ - TmModuleDetectRegister(); + /* flow worker */ + TmModuleFlowWorkerRegister(); /* respond-reject */ TmModuleRespondRejectRegister(); - TmModuleLuaLogRegister(); - /* fast log */ - TmModuleAlertFastLogRegister(); - /* debug log */ - TmModuleAlertDebugLogRegister(); - /* prelue log */ - TmModuleAlertPreludeRegister(); - /* syslog log */ - TmModuleAlertSyslogRegister(); - /* unified2 log */ - TmModuleUnified2AlertRegister(); - /* drop log */ - TmModuleLogDropLogRegister(); - TmModuleJsonDropLogRegister(); - /* json log */ - TmModuleOutputJsonRegister(); - /* http log */ - TmModuleLogHttpLogRegister(); - TmModuleJsonHttpLogRegister(); - /* tls log */ - TmModuleLogTlsLogRegister(); - TmModuleJsonTlsLogRegister(); - /* ssh */ - TmModuleJsonSshLogRegister(); - /* pcap log */ - TmModulePcapLogRegister(); - /* file log */ - TmModuleLogFileLogRegister(); - TmModuleJsonFileLogRegister(); - TmModuleLogFilestoreRegister(); - /* dns log */ - TmModuleLogDnsLogRegister(); - TmModuleJsonDnsLogRegister(); - /* tcp streaming data */ - TmModuleLogTcpDataLogRegister(); - - TmModuleJsonAlertLogRegister(); - /* flow/netflow */ - TmModuleJsonFlowLogRegister(); - TmModuleJsonNetFlowLogRegister(); - /* log api */ - TmModulePacketLoggerRegister(); - TmModuleTxLoggerRegister(); - TmModuleFileLoggerRegister(); - TmModuleFiledataLoggerRegister(); - TmModuleStreamingLoggerRegister(); + TmModuleLoggerRegister(); + TmModuleStatsLoggerRegister(); + TmModuleDebugList(); /* nflog */ TmModuleReceiveNFLOGRegister(); TmModuleDecodeNFLOGRegister(); - } -TmEcode LoadYamlConfig(char *conf_filename) +static TmEcode LoadYamlConfig(SCInstance *suri) { SCEnter(); - if (conf_filename == NULL) - SCReturnInt(TM_ECODE_OK); + if (suri->conf_filename == NULL) + suri->conf_filename = DEFAULT_CONF_FILE; - if (ConfYamlLoadFile(conf_filename) != 0) { + if (ConfYamlLoadFile(suri->conf_filename) != 0) { /* Error already displayed. */ SCReturnInt(TM_ECODE_FAILED); } @@ -921,31 +951,12 @@ TmEcode LoadYamlConfig(char *conf_filename) SCReturnInt(TM_ECODE_OK); } -int IsRuleReloadSet(int quiet) -{ - int rule_reload = 0; - - ConfNode *denode = NULL; - ConfNode *decnf = ConfGetNode("detect-engine"); - if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { - if (strcmp(denode->val, "rule-reload") == 0) { - (void)ConfGetChildValueBool(denode, "rule-reload", &rule_reload); - if (!quiet) - SCLogInfo("Live rule reloads %s", - rule_reload ? "enabled" : "disabled"); - } - } - } - return rule_reload; -} - -static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) +static TmEcode ParseInterfacesList(int runmode, char *pcap_dev) { SCEnter(); /* run the selected runmode */ - if (run_mode == RUNMODE_PCAP_DEV) { + if (runmode == RUNMODE_PCAP_DEV) { if (strlen(pcap_dev) == 0) { int ret = LiveBuildDeviceList("pcap"); if (ret == 0) { @@ -954,7 +965,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) } } #ifdef HAVE_MPIPE - } else if (run_mode == RUNMODE_TILERA_MPIPE) { + } else if (runmode == RUNMODE_TILERA_MPIPE) { if (strlen(pcap_dev)) { if (ConfSetFinal("mpipe.single_mpipe_dev", pcap_dev) != 1) { fprintf(stderr, "ERROR: Failed to set mpipe.single_mpipe_dev\n"); @@ -968,7 +979,7 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) } } #endif - } else if (run_mode == RUNMODE_PFRING) { + } else if (runmode == RUNMODE_PFRING) { /* FIXME add backward compat support */ /* iface has been set on command line */ if (strlen(pcap_dev)) { @@ -980,7 +991,8 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) /* not an error condition if we have a 1.0 config */ LiveBuildDeviceList("pfring"); } - } else if (run_mode == RUNMODE_AFP_DEV) { +#ifdef HAVE_AF_PACKET + } else if (runmode == RUNMODE_AFP_DEV) { /* iface has been set on command line */ if (strlen(pcap_dev)) { if (ConfSetFinal("af-packet.live-interface", pcap_dev) != 1) { @@ -998,8 +1010,29 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) EngineModeSetIPS(); } } +#endif +#ifdef HAVE_NETMAP + } else if (runmode == RUNMODE_NETMAP) { + /* iface has been set on command line */ + if (strlen(pcap_dev)) { + if (ConfSetFinal("netmap.live-interface", pcap_dev) != 1) { + SCLogError(SC_ERR_INITIALIZATION, "Failed to set netmap.live-interface"); + SCReturnInt(TM_ECODE_FAILED); + } + } else { + int ret = LiveBuildDeviceList("netmap"); + if (ret == 0) { + SCLogError(SC_ERR_INITIALIZATION, "No interface found in config for netmap"); + SCReturnInt(TM_ECODE_FAILED); + } + if (NetmapRunModeIsIPS()) { + SCLogInfo("Netmap: Setting IPS mode"); + EngineModeSetIPS(); + } + } +#endif #ifdef HAVE_NFLOG - } else if (run_mode == RUNMODE_NFLOG) { + } else if (runmode == RUNMODE_NFLOG) { int ret = LiveBuildDeviceListCustom("nflog", "group"); if (ret == 0) { SCLogError(SC_ERR_INITIALIZATION, "No group found in config for nflog"); @@ -1011,8 +1044,11 @@ static TmEcode ParseInterfacesList(int run_mode, char *pcap_dev) SCReturnInt(TM_ECODE_OK); } -static void SCInstanceInit(SCInstance *suri) +static void SCInstanceInit(SCInstance *suri, const char *progname) { + memset(suri, 0x00, sizeof(*suri)); + + suri->progname = progname; suri->run_mode = RUNMODE_UNKNOWN; memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); @@ -1074,16 +1110,322 @@ static void SCSetStartTime(SCInstance *suri) gettimeofday(&suri->start_time, NULL); } -static void SCPrintElapsedTime(SCInstance *suri) +static void SCPrintElapsedTime(struct timeval *start_time) { + if (start_time == NULL) + return; struct timeval end_time; memset(&end_time, 0, sizeof(end_time)); gettimeofday(&end_time, NULL); - uint64_t milliseconds = ((end_time.tv_sec - suri->start_time.tv_sec) * 1000) + - (((1000000 + end_time.tv_usec - suri->start_time.tv_usec) / 1000) - 1000); + uint64_t milliseconds = ((end_time.tv_sec - start_time->tv_sec) * 1000) + + (((1000000 + end_time.tv_usec - start_time->tv_usec) / 1000) - 1000); SCLogInfo("time elapsed %.3fs", (float)milliseconds/(float)1000); } +static int ParseCommandLineAfpacket(SCInstance *suri, const char *in_arg) +{ +#ifdef HAVE_AF_PACKET + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_AFP_DEV; + if (in_arg) { + LiveRegisterDevice(in_arg); + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + strlcpy(suri->pcap_dev, in_arg, sizeof(suri->pcap_dev)); + } + } else if (suri->run_mode == RUNMODE_AFP_DEV) { + SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " + "multiple devices to get packets is experimental."); + if (in_arg) { + LiveRegisterDevice(in_arg); + } else { + SCLogInfo("Multiple af-packet option without interface on each is useless"); + } + } else { + SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " + "has been specified"); + usage(suri->progname); + return TM_ECODE_FAILED; + } + return TM_ECODE_OK; +#else + SCLogError(SC_ERR_NO_AF_PACKET,"AF_PACKET not enabled. On Linux " + "host, make sure to pass --enable-af-packet to " + "configure when building."); + return TM_ECODE_FAILED; +#endif +} + +static int ParseCommandLinePcapLive(SCInstance *suri, const char *in_arg) +{ + memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); + + if (in_arg != NULL) { + /* some windows shells require escaping of the \ in \Device. Otherwise + * the backslashes are stripped. We put them back here. */ + if (strlen(in_arg) > 9 && strncmp(in_arg, "DeviceNPF", 9) == 0) { + snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", in_arg+9); + } else { + strlcpy(suri->pcap_dev, in_arg, sizeof(suri->pcap_dev)); + PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); + } + + if (strcmp(suri->pcap_dev, in_arg) != 0) { + SCLogInfo("translated %s to pcap device %s", in_arg, suri->pcap_dev); + } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { + SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", in_arg); + return TM_ECODE_FAILED; + } + } + + if (suri->run_mode == RUNMODE_UNKNOWN) { + suri->run_mode = RUNMODE_PCAP_DEV; + if (in_arg) { + LiveRegisterDevice(suri->pcap_dev); + } + } else if (suri->run_mode == RUNMODE_PCAP_DEV) { +#ifdef OS_WIN32 + SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " + "support is not (yet) supported on Windows."); + return TM_ECODE_FAILED; +#else + SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " + "multiple pcap devices to get packets is experimental."); + LiveRegisterDevice(suri->pcap_dev); +#endif + } else { + SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " + "has been specified"); + usage(suri->progname); + return TM_ECODE_FAILED; + } + return TM_ECODE_OK; +} + +static void ParseCommandLineAFL(const char *opt_name, char *opt_arg) +{ +#ifdef AFLFUZZ_RULES + if(strcmp(opt_name, "afl-rules") == 0) { + MpmTableSetup(); + SpmTableSetup(); + exit(RuleParseDataFromFile(opt_arg)); + } else +#endif +#ifdef AFLFUZZ_APPLAYER + if(strcmp(opt_name, "afl-http-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterHTPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_HTTP, opt_arg)); + } else if(strcmp(opt_name, "afl-http") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterHTPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_HTTP, opt_arg)); + + } else if(strcmp(opt_name, "afl-tls-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSSLParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_TLS, opt_arg)); + } else if(strcmp(opt_name, "afl-tls") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSSLParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_TLS, opt_arg)); + + } else if(strcmp(opt_name, "afl-dns-request") == 0) { + //printf("arg: //%s\n", opt_arg); + RegisterDNSUDPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_UDP, ALPROTO_DNS, opt_arg)); + } else if(strcmp(opt_name, "afl-dns") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterDNSUDPParsers(); + exit(AppLayerParserFromFile(IPPROTO_UDP, ALPROTO_DNS, opt_arg)); + + } else if(strcmp(opt_name, "afl-dnstcp-request") == 0) { + //printf("arg: //%s\n", opt_arg); + RegisterDNSTCPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNS, opt_arg)); + } else if(strcmp(opt_name, "afl-dnstcp") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterDNSTCPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNS, opt_arg)); + + } else if(strcmp(opt_name, "afl-ssh-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + RegisterSSHParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SSH, opt_arg)); + } else if(strcmp(opt_name, "afl-ssh") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSSHParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SSH, opt_arg)); + + } else if(strcmp(opt_name, "afl-ftp-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterFTPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_FTP, opt_arg)); + } else if(strcmp(opt_name, "afl-ftp") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterFTPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_FTP, opt_arg)); + + } else if(strcmp(opt_name, "afl-smtp-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSMTPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMTP, opt_arg)); + } else if(strcmp(opt_name, "afl-smtp") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSMTPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMTP, opt_arg)); + + } else if(strcmp(opt_name, "afl-smb-request") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + RegisterSMBParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_SMB, opt_arg)); + } else if(strcmp(opt_name, "afl-smb") == 0) { + //printf("arg: //%s\n", opt_arg); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + AppLayerParserSetup(); + RegisterSMBParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_SMB, opt_arg)); + + } else if(strcmp(opt_name, "afl-modbus-request") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterModbusParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_MODBUS, opt_arg)); + } else if(strcmp(opt_name, "afl-modbus") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterModbusParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_MODBUS, opt_arg)); + } else if(strcmp(opt_name, "afl-enip-request") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterENIPTCPParsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_ENIP, opt_arg)); + } else if(strcmp(opt_name, "afl-enip") == 0) { + //printf("arg: //%s\n", opt_arg); + AppLayerParserSetup(); + RegisterENIPTCPParsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_ENIP, opt_arg)); + } else if(strcmp(opt_name, "afl-dnp3-request") == 0) { + AppLayerParserSetup(); + RegisterDNP3Parsers(); + exit(AppLayerParserRequestFromFile(IPPROTO_TCP, ALPROTO_DNP3, opt_arg)); + } else if(strcmp(opt_name, "afl-dnp3") == 0) { + AppLayerParserSetup(); + RegisterDNP3Parsers(); + exit(AppLayerParserFromFile(IPPROTO_TCP, ALPROTO_DNP3, opt_arg)); + } else +#endif +#ifdef AFLFUZZ_MIME + if(strcmp(opt_name, "afl-mime") == 0) { + //printf("arg: //%s\n", opt_arg); + exit(MimeParserDataFromFile(opt_arg)); + } else +#endif +#ifdef AFLFUZZ_DECODER + if(strstr(opt_name, "afl-decoder-ppp") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ppp") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodePPP)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodePPP)); + } else if(strstr(opt_name, "afl-decoder-ipv4") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ipv4") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeIPV4)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeIPV4)); + } else if(strstr(opt_name, "afl-decoder-ipv6") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ipv6") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeIPV6)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeIPV6)); + } else if(strstr(opt_name, "afl-decoder-ethernet") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-ethernet") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeEthernet)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeEthernet)); + } else if(strstr(opt_name, "afl-decoder-erspan") != NULL) { + StatsInit(); + MpmTableSetup(); + SpmTableSetup(); + AppLayerProtoDetectSetup(); + if (strcmp(opt_name, "afl-decoder-erspan") == 0) + exit(DecoderParseDataFromFile(opt_arg, DecodeERSPAN)); + else + exit(DecoderParseDataFromFileSerie(opt_arg, DecodeERSPAN)); + } else +#endif +#ifdef AFLFUZZ_DER + if(strcmp(opt_name, "afl-der") == 0) { + //printf("arg: //%s\n", opt_arg); + exit(DerParseDataFromFile(opt_arg)); + } else +#endif + { + abort(); + } +} + static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) { int opt; @@ -1096,7 +1438,11 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) int list_keywords = 0; int build_info = 0; int conf_test = 0; +#ifdef AFLFUZZ_CONF_TEST + int conf_test_force_success = 0; +#endif int engine_analysis = 0; + int set_log_directory = 0; int ret = TM_ECODE_OK; #ifdef UNITTESTS @@ -1112,7 +1458,48 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"pfring-cluster-id", required_argument, 0, 0}, {"pfring-cluster-type", required_argument, 0, 0}, {"af-packet", optional_argument, 0, 0}, + {"netmap", optional_argument, 0, 0}, {"pcap", optional_argument, 0, 0}, + {"simulate-ips", 0, 0 , 0}, + + /* AFL app-layer options. */ + {"afl-http-request", required_argument, 0 , 0}, + {"afl-http", required_argument, 0 , 0}, + {"afl-tls-request", required_argument, 0 , 0}, + {"afl-tls", required_argument, 0 , 0}, + {"afl-dns-request", required_argument, 0 , 0}, + {"afl-dns", required_argument, 0 , 0}, + {"afl-ssh-request", required_argument, 0 , 0}, + {"afl-ssh", required_argument, 0 , 0}, + {"afl-ftp-request", required_argument, 0 , 0}, + {"afl-ftp", required_argument, 0 , 0}, + {"afl-smtp-request", required_argument, 0 , 0}, + {"afl-smtp", required_argument, 0 , 0}, + {"afl-smb-request", required_argument, 0 , 0}, + {"afl-smb", required_argument, 0 , 0}, + {"afl-modbus-request", required_argument, 0 , 0}, + {"afl-modbus", required_argument, 0 , 0}, + {"afl-enip-request", required_argument, 0 , 0}, + {"afl-enip", required_argument, 0 , 0}, + {"afl-mime", required_argument, 0 , 0}, + {"afl-dnp3-request", required_argument, 0, 0}, + {"afl-dnp3", required_argument, 0, 0}, + + /* Other AFL options. */ + {"afl-rules", required_argument, 0 , 0}, + {"afl-mime", required_argument, 0 , 0}, + {"afl-decoder-ppp", required_argument, 0 , 0}, + {"afl-decoder-ppp-serie", required_argument, 0 , 0}, + {"afl-decoder-ethernet", required_argument, 0 , 0}, + {"afl-decoder-ethernet-serie", required_argument, 0 , 0}, + {"afl-decoder-erspan", required_argument, 0 , 0}, + {"afl-decoder-erspan-serie", required_argument, 0 , 0}, + {"afl-decoder-ipv4", required_argument, 0 , 0}, + {"afl-decoder-ipv4-serie", required_argument, 0 , 0}, + {"afl-decoder-ipv6", required_argument, 0 , 0}, + {"afl-decoder-ipv6-serie", required_argument, 0 , 0}, + {"afl-der", required_argument, 0, 0}, + #ifdef BUILD_UNIX_SOCKET {"unix-socket", optional_argument, 0, 0}, #endif @@ -1147,6 +1534,9 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) {"set", required_argument, 0, 0}, #ifdef HAVE_NFLOG {"nflog", optional_argument, 0, 0}, +#endif +#ifdef AFLFUZZ_CONF_TEST + {"afl-parse-rules", 0, &conf_test_force_success, 1}, #endif {NULL, 0, NULL, 0} }; @@ -1200,10 +1590,15 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; #endif /* HAVE_PFRING */ } - else if (strcmp((long_opts[option_index]).name , "af-packet") == 0){ -#ifdef HAVE_AF_PACKET + else if (strcmp((long_opts[option_index]).name , "af-packet") == 0) + { + if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { + return TM_ECODE_FAILED; + } + } else if (strcmp((long_opts[option_index]).name , "netmap") == 0){ +#ifdef HAVE_NETMAP if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_AFP_DEV; + suri->run_mode = RUNMODE_NETMAP; if (optarg) { LiveRegisterDevice(optarg); memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); @@ -1211,13 +1606,13 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); } - } else if (suri->run_mode == RUNMODE_AFP_DEV) { + } else if (suri->run_mode == RUNMODE_NETMAP) { SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " "multiple devices to get packets is experimental."); if (optarg) { LiveRegisterDevice(optarg); } else { - SCLogInfo("Multiple af-packet option without interface on each is useless"); + SCLogInfo("Multiple netmap option without interface on each is useless"); break; } } else { @@ -1227,10 +1622,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; } #else - SCLogError(SC_ERR_NO_AF_PACKET,"AF_PACKET not enabled. On Linux " - "host, make sure to pass --enable-af-packet to " - "configure when building."); - return TM_ECODE_FAILED; + SCLogError(SC_ERR_NO_NETMAP, "NETMAP not enabled."); + return TM_ECODE_FAILED; #endif } else if (strcmp((long_opts[option_index]).name, "nflog") == 0) { #ifdef HAVE_NFLOG @@ -1243,31 +1636,14 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) return TM_ECODE_FAILED; #endif /* HAVE_NFLOG */ } else if (strcmp((long_opts[option_index]).name , "pcap") == 0) { - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_PCAP_DEV; - if (optarg) { - LiveRegisterDevice(optarg); - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - strlcpy(suri->pcap_dev, optarg, - ((strlen(optarg) < sizeof(suri->pcap_dev)) ? - (strlen(optarg) + 1) : sizeof(suri->pcap_dev))); - } - } else if (suri->run_mode == RUNMODE_PCAP_DEV) { -#ifdef OS_WIN32 - SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " - "support is not (yet) supported on Windows."); - return TM_ECODE_FAILED; -#else - SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " - "multiple pcap devices to get packets is experimental."); - LiveRegisterDevice(optarg); -#endif - } else { - SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " - "has been specified"); - usage(argv[0]); + if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } + } else if(strncmp((long_opts[option_index]).name, "afl-", 4) == 0) { + ParseCommandLineAFL((long_opts[option_index]).name, optarg); + } else if(strcmp((long_opts[option_index]).name, "simulate-ips") == 0) { + SCLogInfo("Setting IPS mode"); + EngineModeSetIPS(); } else if(strcmp((long_opts[option_index]).name, "init-errors-fatal") == 0) { if (ConfSetFinal("engine.init-failure-fatal", "1") != 1) { fprintf(stderr, "ERROR: Failed to set engine init-failure-fatal.\n"); @@ -1345,10 +1721,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } else if(strcmp((long_opts[option_index]).name, "fatal-unittests") == 0) { #ifdef UNITTESTS - if (ConfSetFinal("unittests.failure-fatal", "1") != 1) { - fprintf(stderr, "ERROR: Failed to set unittests failure-fatal.\n"); - return TM_ECODE_FAILED; - } + unittests_fatal = 1; #else fprintf(stderr, "ERROR: Unit tests not enabled. Make sure to pass --enable-unittests to configure when building.\n"); return TM_ECODE_FAILED; @@ -1395,7 +1768,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) LiveRegisterDevice(optarg); #else SCLogError(SC_ERR_DAG_REQUIRED, "libdag and a DAG card are required" - " to receieve packets using --dag."); + " to receive packets using --dag."); return TM_ECODE_FAILED; #endif /* HAVE_DAG */ } @@ -1444,14 +1817,14 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) #endif else if (strcmp((long_opts[option_index]).name, "set") == 0) { if (optarg != NULL) { + /* Quick validation. */ char *val = strchr(optarg, '='); if (val == NULL) { SCLogError(SC_ERR_CMD_LINE, "Invalid argument for --set, must be key=val."); exit(EXIT_FAILURE); } - *val++ = '\0'; - if (ConfSetFinal(optarg, val) != 1) { + if (!ConfSetFromString(optarg, 1)) { fprintf(stderr, "Failed to set configuration value %s.", optarg); exit(EXIT_FAILURE); @@ -1460,7 +1833,7 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) } break; case 'c': - conf_filename = optarg; + suri->conf_filename = optarg; break; case 'T': SCLogInfo("Running suricata under test mode"); @@ -1479,48 +1852,47 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) suri->run_mode = RUNMODE_PRINT_USAGE; return TM_ECODE_OK; case 'i': - memset(suri->pcap_dev, 0, sizeof(suri->pcap_dev)); - if (optarg == NULL) { SCLogError(SC_ERR_INITIALIZATION, "no option argument (optarg) for -i"); return TM_ECODE_FAILED; } - - /* some windows shells require escaping of the \ in \Device. Otherwise - * the backslashes are stripped. We put them back here. */ - if (strlen(optarg) > 9 && strncmp(optarg, "DeviceNPF", 9) == 0) { - snprintf(suri->pcap_dev, sizeof(suri->pcap_dev), "\\Device\\NPF%s", optarg+9); - } else { - strlcpy(suri->pcap_dev, optarg, ((strlen(optarg) < sizeof(suri->pcap_dev)) ? (strlen(optarg)+1) : (sizeof(suri->pcap_dev)))); - PcapTranslateIPToDevice(suri->pcap_dev, sizeof(suri->pcap_dev)); - } - - if (strcmp(suri->pcap_dev, optarg) != 0) { - SCLogInfo("translated %s to pcap device %s", optarg, suri->pcap_dev); - } else if (strlen(suri->pcap_dev) > 0 && isdigit((unsigned char)suri->pcap_dev[0])) { - SCLogError(SC_ERR_PCAP_TRANSLATE, "failed to find a pcap device for IP %s", optarg); +#ifdef HAVE_AF_PACKET + if (ParseCommandLineAfpacket(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } - - if (suri->run_mode == RUNMODE_UNKNOWN) { - suri->run_mode = RUNMODE_PCAP_DEV; - LiveRegisterDevice(suri->pcap_dev); - } else if (suri->run_mode == RUNMODE_PCAP_DEV) { -#ifdef OS_WIN32 - SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " - "support is not (yet) supported on Windows."); - return TM_ECODE_FAILED; -#else - SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " - "multiple pcap devices to get packets is experimental."); - LiveRegisterDevice(suri->pcap_dev); +#else /* not afpacket */ + /* warn user if netmap or pf-ring are available */ +#if defined HAVE_PFRING || HAVE_NETMAP + int i = 0; +#ifdef HAVE_PFRING + i++; #endif - } else { - SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " - "has been specified"); - usage(argv[0]); +#ifdef HAVE_NETMAP + i++; +#endif + SCLogWarning(SC_WARN_FASTER_CAPTURE_AVAILABLE, "faster capture " + "option%s %s available:" +#ifdef HAVE_PFRING + " PF_RING (--pfring-int=%s)" +#endif +#ifdef HAVE_NETMAP + " NETMAP (--netmap=%s)" +#endif + ". Use --pcap=%s to suppress this warning", + i == 1 ? "" : "s", i == 1 ? "is" : "are" +#ifdef HAVE_PFRING + , optarg +#endif +#ifdef HAVE_NETMAP + , optarg +#endif + , optarg + ); +#endif /* have faster methods */ + if (ParseCommandLinePcapLive(suri, optarg) != TM_ECODE_OK) { return TM_ECODE_FAILED; } +#endif break; case 'l': if (optarg == NULL) { @@ -1538,6 +1910,8 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) "exist. Shutting down the engine.", optarg, optarg); return TM_ECODE_FAILED; } + set_log_directory = 1; + break; case 'q': #ifdef NFQ @@ -1671,9 +2045,19 @@ static TmEcode ParseCommandLine(int argc, char** argv, SCInstance *suri) SCLogError(SC_ERR_INITIALIZATION, "can't use -s/-S when detection is disabled"); return TM_ECODE_FAILED; } +#ifdef AFLFUZZ_CONF_TEST + if (conf_test && conf_test_force_success) { + (void)ConfSetFinal("engine.init-failure-fatal", "0"); + } +#endif - if (list_app_layer_protocols) - suri->run_mode = RUNMODE_LIST_APP_LAYERS; + if ((suri->run_mode == RUNMODE_UNIX_SOCKET) && set_log_directory) { + SCLogError(SC_ERR_INITIALIZATION, "can't use -l and unix socket runmode at the same time"); + return TM_ECODE_FAILED; + } + + if (list_app_layer_protocols) + suri->run_mode = RUNMODE_LIST_APP_LAYERS; if (list_cuda_cards) suri->run_mode = RUNMODE_LIST_CUDA_CARDS; if (list_keywords) @@ -1762,6 +2146,7 @@ static int InitSignalHandler(SCInstance *suri) { /* registering signals we use */ UtilSignalHandlerSetup(SIGINT, SignalHandlerSigint); + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); UtilSignalHandlerSetup(SIGTERM, SignalHandlerSigterm); UtilSignalHandlerSetup(SIGPIPE, SIG_IGN); UtilSignalHandlerSetup(SIGSYS, SIG_IGN); @@ -1806,6 +2191,89 @@ static int InitSignalHandler(SCInstance *suri) return TM_ECODE_OK; } +/* initialization code for both the main modes and for + * unix socket mode. + * + * Will be run once per pcap in unix-socket mode */ +void PreRunInit(const int runmode) +{ + if (runmode == RUNMODE_UNIX_SOCKET) + return; + + StatsInit(); +#ifdef PROFILING + SCProfilingRulesGlobalInit(); + SCProfilingKeywordsGlobalInit(); + SCProfilingSghsGlobalInit(); + SCProfilingInit(); +#endif /* PROFILING */ + DefragInit(); + FlowInitConfig(FLOW_QUIET); + IPPairInitConfig(FLOW_QUIET); + StreamTcpInitConfig(STREAM_VERBOSE); + AppLayerRegisterGlobalCounters(); +} + +/* tasks we need to run before packets start flowing, + * but after we dropped privs */ +void PreRunPostPrivsDropInit(const int runmode) +{ + if (runmode == RUNMODE_UNIX_SOCKET) + return; + + RunModeInitializeOutputs(); + StatsSetupPostConfig(); +} + +/* clean up / shutdown code for both the main modes and for + * unix socket mode. + * + * Will be run once per pcap in unix-socket mode */ +void PostRunDeinit(const int runmode, struct timeval *start_time) +{ + if (runmode == RUNMODE_UNIX_SOCKET) + return; + + /* needed by FlowForceReassembly */ + PacketPoolInit(); + + /* handle graceful shutdown of the flow engine, it's helper + * threads and the packet threads */ + FlowDisableFlowManagerThread(); + TmThreadDisableReceiveThreads(); + FlowForceReassembly(); + TmThreadDisablePacketThreads(); + SCPrintElapsedTime(start_time); + FlowDisableFlowRecyclerThread(); + + /* kill the stats threads */ + TmThreadKillThreadsFamily(TVT_MGMT); + TmThreadClearThreadsFamily(TVT_MGMT); + + /* kill packet threads -- already in 'disabled' state */ + TmThreadKillThreadsFamily(TVT_PPT); + TmThreadClearThreadsFamily(TVT_PPT); + + PacketPoolDestroy(); + + /* mgt and ppt threads killed, we can run non thread-safe + * shutdown functions */ + StatsReleaseResources(); + RunModeShutDown(); + FlowShutdown(); + IPPairShutdown(); + HostCleanup(); + StreamTcpFreeConfig(STREAM_VERBOSE); + DefragDestroy(); + TmqResetQueues(); +#ifdef PROFILING + if (profiling_rules_enabled) + SCProfilingDump(); + SCProfilingDestroy(); +#endif +} + + int StartInternalRunMode(SCInstance *suri, int argc, char **argv) { /* Treat internal running mode */ @@ -1834,6 +2302,8 @@ int StartInternalRunMode(SCInstance *suri, int argc, char **argv) return TM_ECODE_DONE; case RUNMODE_LIST_UNITTEST: RunUnittests(1, suri->regex_arg); + case RUNMODE_UNITTEST: + RunUnittests(0, suri->regex_arg); #ifdef OS_WIN32 case RUNMODE_INSTALL_SERVICE: if (SCServiceInstall(argc, argv)) { @@ -1872,33 +2342,40 @@ static int FinalizeRunMode(SCInstance *suri, char **argv) case RUNMODE_UNKNOWN: usage(argv[0]); return TM_ECODE_FAILED; + default: + break; } - /* Set the global run mode */ + /* Set the global run mode and offline flag. */ run_mode = suri->run_mode; + run_mode_offline = suri->offline; + if (!CheckValidDaemonModes(suri->daemon, suri->run_mode)) { + return TM_ECODE_FAILED; + } return TM_ECODE_OK; } -static void SetupDelayedDetect(DetectEngineCtx *de_ctx, SCInstance *suri) +static void SetupDelayedDetect(SCInstance *suri) { /* In offline mode delayed init of detect is a bad idea */ if (suri->offline) { suri->delayed_detect = 0; } else { - ConfNode *denode = NULL; - ConfNode *decnf = ConfGetNode("detect-engine"); - if (decnf != NULL) { - TAILQ_FOREACH(denode, &decnf->head, next) { - if (strcmp(denode->val, "delayed-detect") == 0) { - (void)ConfGetChildValueBool(denode, "delayed-detect", &suri->delayed_detect); + if (ConfGetBool("detect.delayed-detect", &suri->delayed_detect) != 1) { + ConfNode *denode = NULL; + ConfNode *decnf = ConfGetNode("detect-engine"); + if (decnf != NULL) { + TAILQ_FOREACH(denode, &decnf->head, next) { + if (strcmp(denode->val, "delayed-detect") == 0) { + (void)ConfGetChildValueBool(denode, "delayed-detect", &suri->delayed_detect); + } } } } } - de_ctx->delayed_detect = suri->delayed_detect; - SCLogInfo("Delayed detect %s", suri->delayed_detect ? "enabled" : "disabled"); + SCLogConfig("Delayed detect %s", suri->delayed_detect ? "enabled" : "disabled"); if (suri->delayed_detect) { SCLogInfo("Packets will start being processed before signatures are active."); } @@ -1908,16 +2385,11 @@ static void SetupDelayedDetect(DetectEngineCtx *de_ctx, SCInstance *suri) static int LoadSignatures(DetectEngineCtx *de_ctx, SCInstance *suri) { if (SigLoadSignatures(de_ctx, suri->sig_file, suri->sig_file_exclusive) < 0) { - if (suri->sig_file == NULL) { - SCLogError(SC_ERR_OPENING_FILE, "Signature file has not been provided"); - } else { - SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); - } + SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed."); if (de_ctx->failure_fatal) return TM_ECODE_FAILED; } - SCThresholdConfInitContext(de_ctx, NULL); return TM_ECODE_OK; } @@ -1930,7 +2402,7 @@ static int ConfigGetCaptureValue(SCInstance *suri) if (max_pending_packets >= 65535) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Maximum max-pending-packets setting is 65534. " - "Please check %s for errors", conf_filename); + "Please check %s for errors", suri->conf_filename); return TM_ECODE_FAILED; } @@ -1940,17 +2412,42 @@ static int ConfigGetCaptureValue(SCInstance *suri) * back on a sane default. */ char *temp_default_packet_size; if ((ConfGet("default-packet-size", &temp_default_packet_size)) != 1) { + int lthread; + int nlive; + int strip_trailing_plus = 0; switch (suri->run_mode) { case RUNMODE_PCAP_DEV: case RUNMODE_AFP_DEV: + case RUNMODE_NETMAP: + /* in netmap igb0+ has a special meaning, however the + * interface really is igb0 */ + strip_trailing_plus = 1; + /* fall through */ case RUNMODE_PFRING: - /* FIXME this don't work effficiently in multiinterface */ - /* find payload for interface and use it */ - default_packet_size = GetIfaceMaxPacketSize(suri->pcap_dev); + nlive = LiveGetDeviceCount(); + for (lthread = 0; lthread < nlive; lthread++) { + const char *live_dev = LiveGetDeviceName(lthread); + char dev[32]; + (void)strlcpy(dev, live_dev, sizeof(dev)); + + if (strip_trailing_plus) { + size_t len = strlen(dev); + if (len && dev[len-1] == '+') { + dev[len-1] = '\0'; + } + } + int mtu = GetIfaceMTU(dev); + g_default_mtu = MAX(mtu, g_default_mtu); + + unsigned int iface_max_packet_size = GetIfaceMaxPacketSize(dev); + if (iface_max_packet_size > default_packet_size) + default_packet_size = iface_max_packet_size; + } if (default_packet_size) break; /* fall through */ default: + g_default_mtu = DEFAULT_MTU; default_packet_size = DEFAULT_PACKET_SIZE; } } else { @@ -1966,6 +2463,73 @@ static int ConfigGetCaptureValue(SCInstance *suri) return TM_ECODE_OK; } + +static void PostRunStartedDetectSetup(SCInstance *suri) +{ + /* registering signal handlers we use. We register usr2 here, so that one + * can't call it during the first sig load phase or while threads are still + * starting up. */ + if (DetectEngineEnabled() && suri->sig_file == NULL && + suri->delayed_detect == 0) + UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); + + if (suri->delayed_detect) { + /* force 'reload', this will load the rules and swap engines */ + DetectEngineReload(suri); + SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); + } +} + +static void PostConfLoadedDetectSetup(SCInstance *suri) +{ + DetectEngineCtx *de_ctx = NULL; + if (!suri->disabled_detect) { + SCClassConfInit(); + SCReferenceConfInit(); + SetupDelayedDetect(suri); + int mt_enabled = 0; + (void)ConfGetBool("multi-detect.enabled", &mt_enabled); + int default_tenant = 0; + if (mt_enabled) + (void)ConfGetBool("multi-detect.default", &default_tenant); + if (DetectEngineMultiTenantSetup() == -1) { + SCLogError(SC_ERR_INITIALIZATION, "initializing multi-detect " + "detection engine contexts failed."); + exit(EXIT_FAILURE); + } + if ((suri->delayed_detect || (mt_enabled && !default_tenant)) && + (suri->run_mode != RUNMODE_CONF_TEST)) { + de_ctx = DetectEngineCtxInitMinimal(); + } else { + de_ctx = DetectEngineCtxInit(); + } + if (de_ctx == NULL) { + SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " + "context failed."); + exit(EXIT_FAILURE); + } + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) + CudaVarsSetDeCtx(de_ctx); +#endif /* __SC_CUDA_SUPPORT__ */ + + if (!de_ctx->minimal) { + if (LoadSignatures(de_ctx, suri) != TM_ECODE_OK) + exit(EXIT_FAILURE); + if (suri->run_mode == RUNMODE_ENGINE_ANALYSIS) { + exit(EXIT_SUCCESS); + } + } + + DetectEngineAddToMaster(de_ctx); + DetectEngineBumpVersion(); + } else { + /* tell the app layer to consider only the log id */ + RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); + } +} + /** * This function is meant to contain code that needs * to be run once the configuration has been loaded. @@ -1974,14 +2538,39 @@ static int PostConfLoadedSetup(SCInstance *suri) { char *hostmode = NULL; + /* do this as early as possible #1577 #1955 */ +#ifdef HAVE_LUAJIT + if (LuajitSetupStatesPool() != 0) { + SCReturnInt(TM_ECODE_FAILED); + } +#endif + /* load the pattern matchers */ MpmTableSetup(); #ifdef __SC_CUDA_SUPPORT__ MpmCudaEnvironmentSetup(); #endif + SpmTableSetup(); - suri->rule_reload = IsRuleReloadSet(FALSE); + int disable_offloading; + if (ConfGetBool("capture.disable-offloading", &disable_offloading) == 0) + disable_offloading = 1; + if (disable_offloading) { + LiveSetOffloadDisable(); + } else { + LiveSetOffloadWarn(); + } + if (suri->checksum_validation == -1) { + char *cv = NULL; + if (ConfGet("capture.checksum-validation", &cv) == 1) { + if (strcmp(cv, "none") == 0) { + suri->checksum_validation = 0; + } else if (strcmp(cv, "all") == 0) { + suri->checksum_validation = 1; + } + } + } switch (suri->checksum_validation) { case 0: ConfSet("stream.checksum-validation", "0"); @@ -2000,7 +2589,7 @@ static int PostConfLoadedSetup(SCInstance *suri) if (ConfigCheckLogDirectory(suri->log_dir) != TM_ECODE_OK) { SCLogError(SC_ERR_LOGDIR_CONFIG, "The logging directory \"%s\" " "supplied by %s (default-log-dir) doesn't exist. " - "Shutting down the engine", suri->log_dir, conf_filename); + "Shutting down the engine", suri->log_dir, suri->conf_filename); SCReturnInt(TM_ECODE_FAILED); } @@ -2042,9 +2631,6 @@ static int PostConfLoadedSetup(SCInstance *suri) /* Load the Host-OS lookup. */ SCHInfoLoadFromConfig(); - if (suri->run_mode != RUNMODE_UNIX_SOCKET) { - DefragInit(); - } if (suri->run_mode == RUNMODE_ENGINE_ANALYSIS) { SCLogInfo("== Carrying out Engine Analysis =="); @@ -2064,29 +2650,25 @@ static int PostConfLoadedSetup(SCInstance *suri) StorageInit(); CIDRInit(); SigParsePrepare(); - //PatternMatchPrepare(mpm_ctx, MPM_B2G); - if (suri->run_mode != RUNMODE_UNIX_SOCKET) { - SCPerfInitCounterApi(); - } -#ifdef PROFILING - SCProfilingRulesGlobalInit(); - SCProfilingKeywordsGlobalInit(); - SCProfilingInit(); -#endif /* PROFILING */ SCReputationInitCtx(); SCProtoNameInit(); TagInitCtx(); + PacketAlertTagInit(); ThresholdInit(); + HostBitInitCtx(); + IPPairBitInitCtx(); if (DetectAddressTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, - "basic address vars test failed. Please check %s for errors", conf_filename); + "basic address vars test failed. Please check %s for errors", + suri->conf_filename); SCReturnInt(TM_ECODE_FAILED); } if (DetectPortTestConfVars() < 0) { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, - "basic port vars test failed. Please check %s for errors", conf_filename); + "basic port vars test failed. Please check %s for errors", + suri->conf_filename); SCReturnInt(TM_ECODE_FAILED); } @@ -2094,51 +2676,107 @@ static int PostConfLoadedSetup(SCInstance *suri) AppLayerHtpNeedFileInspection(); - DetectEngineRegisterAppInspectionEngines(); + StorageFinalize(); + + TmModuleRunInit(); - if (suri->rule_reload) { - if (suri->sig_file != NULL) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); - else - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2StartingUp); - } else { - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Disabled); + if (MayDaemonize(suri) != TM_ECODE_OK) + SCReturnInt(TM_ECODE_FAILED); + + if (InitSignalHandler(suri) != TM_ECODE_OK) + SCReturnInt(TM_ECODE_FAILED); + + +#ifdef HAVE_NSS + if (suri->run_mode != RUNMODE_CONF_TEST) { + /* init NSS for hashing */ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + NSS_NoDB_Init(NULL); } +#endif - StorageFinalize(); + if (suri->disabled_detect) { + /* disable raw reassembly */ + (void)ConfSetFinal("stream.reassembly.raw", "false"); + } - TmModuleRunInit(); + HostInitConfig(HOST_VERBOSE); +#ifdef HAVE_MAGIC + if (MagicInit() != 0) + SCReturnInt(TM_ECODE_FAILED); +#endif + SCAsn1LoadConfig(); + + CoredumpLoadConfig(); + + PreRunInit(suri->run_mode); - PcapLogProfileSetup(); SCReturnInt(TM_ECODE_OK); } -int main(int argc, char **argv) +static void SuricataMainLoop(SCInstance *suri) { - SCInstance suri; + while(1) { + if (sigterm_count || sigint_count) { + suricata_ctl_flags |= SURICATA_STOP; + } - SCInstanceInit(&suri); + if (suricata_ctl_flags & SURICATA_STOP) { + SCLogNotice("Signal Received. Stopping engine."); + break; + } + + TmThreadCheckThreadState(); + + if (sighup_count > 0) { + OutputNotifyFileRotation(); + sighup_count--; + } + + if (sigusr2_count > 0) { + if (suri->sig_file != NULL) { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " + "possible if -s or -S option used at runtime."); + sigusr2_count--; + } else { + if (!(DetectEngineReloadIsStart())) { + DetectEngineReloadStart(); + DetectEngineReload(suri); + DetectEngineReloadSetDone(); + sigusr2_count--; + } + } + + } else if (DetectEngineReloadIsStart()) { + if (suri->sig_file != NULL) { + SCLogWarning(SC_ERR_LIVE_RULE_SWAP, "Live rule reload not " + "possible if -s or -S option used at runtime."); + DetectEngineReloadSetDone(); + } else { + DetectEngineReload(suri); + DetectEngineReloadSetDone(); + } + } + + usleep(10* 1000); + } +} - sc_set_caps = FALSE; +int main(int argc, char **argv) +{ + SCInstance suri; + SCInstanceInit(&suri, argv[0]); SC_ATOMIC_INIT(engine_stage); /* initialize the logging subsys */ SCLogInitLogModule(NULL); - if (SCSetThreadName("Suricata-Main") < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } + (void)SCSetThreadName("Suricata-Main"); ParseSizeInit(); - RunModeRegisterRunModes(); - /* By default use IDS mode, but if nfq or ipfw - * are specified, IPS mode will overwrite this */ - EngineModeSetIDS(); - - #ifdef OS_WIN32 /* service initialization */ if (WindowsInit(argc, argv) != 0) { @@ -2153,6 +2791,10 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (FinalizeRunMode(&suri, argv) != TM_ECODE_OK) { + exit(EXIT_FAILURE); + } + switch (StartInternalRunMode(&suri, argc, argv)) { case TM_ECODE_DONE: exit(EXIT_SUCCESS); @@ -2160,167 +2802,52 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if (FinalizeRunMode(&suri, argv) != TM_ECODE_OK) { - exit(EXIT_FAILURE); - } - - if (suri.run_mode == RUNMODE_UNITTEST) - RunUnittests(0, suri.regex_arg); - -#ifdef __SC_CUDA_SUPPORT__ - /* Init the CUDA environment */ - SCCudaInitCudaEnvironment(); - CudaBufferInit(); -#endif - - if (!CheckValidDaemonModes(suri.daemon, suri.run_mode)) { - exit(EXIT_FAILURE); - } - /* Initializations for global vars, queues, etc (memsets, mutex init..) */ - GlobalInits(); - TimeInit(); - SupportFastPatternForSigMatchTypes(); - - if (conf_filename == NULL) - conf_filename = DEFAULT_CONF_FILE; + GlobalsInitPreConfig(); - /** \todo we need an api for these */ /* Load yaml configuration file if provided. */ - if (LoadYamlConfig(conf_filename) != TM_ECODE_OK) { + if (LoadYamlConfig(&suri) != TM_ECODE_OK) { exit(EXIT_FAILURE); } + if (suri.run_mode == RUNMODE_DUMP_CONFIG) { + ConfDump(); + exit(EXIT_SUCCESS); + } + /* Since our config is now loaded we can finish configurating the * logging module. */ SCLogLoadConfig(suri.daemon, suri.verbose); SCPrintVersion(); - UtilCpuPrintSummary(); - if (suri.run_mode == RUNMODE_DUMP_CONFIG) { - ConfDump(); - exit(EXIT_SUCCESS); - } - - if (PostConfLoadedSetup(&suri) != TM_ECODE_OK) { + if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { exit(EXIT_FAILURE); } - if (MayDaemonize(&suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - - if (InitSignalHandler(&suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - -#ifdef HAVE_NSS - /* init NSS for md5 */ - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); - NSS_NoDB_Init(NULL); -#endif - - HostInitConfig(HOST_VERBOSE); - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - FlowInitConfig(FLOW_VERBOSE); - } - - DetectEngineCtx *de_ctx = NULL; - if (!suri.disabled_detect) { - de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine " - "context failed."); - exit(EXIT_FAILURE); - } -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) - CudaVarsSetDeCtx(de_ctx); -#endif /* __SC_CUDA_SUPPORT__ */ - - SCClassConfLoadClassficationConfigFile(de_ctx); - SCRConfLoadReferenceConfigFile(de_ctx); - - if (ActionInitConfig() < 0) { - exit(EXIT_FAILURE); - } - } else { - /* disable raw reassembly */ - (void)ConfSetFinal("stream.reassembly.raw", "false"); - - /* tell the app layer to consider only the log id */ - RegisterAppLayerGetActiveTxIdFunc(AppLayerTransactionGetActiveLogOnly); - } - - if (MagicInit() != 0) + if (PostConfLoadedSetup(&suri) != TM_ECODE_OK) { exit(EXIT_FAILURE); - - - if (de_ctx != NULL) { - SetupDelayedDetect(de_ctx, &suri); - - if (!suri.delayed_detect) { - if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - if (suri.run_mode == RUNMODE_ENGINE_ANALYSIS) { - exit(EXIT_SUCCESS); - } - } } - - SCAsn1LoadConfig(); - - CoredumpLoadConfig(); - - SCSetStartTime(&suri); + PostConfLoadedDetectSetup(&suri); SCDropMainThreadCaps(suri.userid, suri.groupid); + PreRunPostPrivsDropInit(suri.run_mode); - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - RunModeInitializeOutputs(); - } - - if (ParseInterfacesList(suri.run_mode, suri.pcap_dev) != TM_ECODE_OK) { - exit(EXIT_FAILURE); - } - - if(suri.run_mode == RUNMODE_CONF_TEST){ - SCLogInfo("Configuration provided was successfully loaded. Exiting."); + if (suri.run_mode == RUNMODE_CONF_TEST){ + SCLogNotice("Configuration provided was successfully loaded. Exiting."); +#ifdef HAVE_MAGIC + MagicDeinit(); +#endif exit(EXIT_SUCCESS); } - RunModeDispatch(suri.run_mode, suri.runmode_custom_mode, de_ctx); - - /* In Unix socket runmode, Flow manager is started on demand */ + SCSetStartTime(&suri); + RunModeDispatch(suri.run_mode, suri.runmode_custom_mode); if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* Spawn the unix socket manager thread */ - int unix_socket = 0; - if (ConfGetBool("unix-command.enabled", &unix_socket) != 1) - unix_socket = 0; - if (unix_socket == 1) { - UnixManagerThreadSpawn(de_ctx, 0); -#ifdef BUILD_UNIX_SOCKET - UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, - UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0); -#endif - } - /* Spawn the flow manager thread */ - FlowManagerThreadSpawn(); - FlowRecyclerThreadSpawn(); - StreamTcpInitConfig(STREAM_VERBOSE); - - SCPerfSpawnThreads(); + UnixManagerThreadSpawnNonRunmode(); } -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) - SCACCudaStartDispatcher(); -#endif - - /* Check if the alloted queues have at least 1 reader and writer */ - TmValidateQueueState(); - /* Wait till all the threads have been initialized */ if (TmThreadWaitOnThreadInit() == TM_ECODE_FAILED) { SCLogError(SC_ERR_INITIALIZATION, "Engine initialization failed, " @@ -2329,31 +2856,12 @@ int main(int argc, char **argv) } (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_INIT, SURICATA_RUNTIME); + PacketPoolPostRunmodes(); /* Un-pause all the paused threads */ TmThreadContinueThreads(); - /* registering singal handlers we use. We register usr2 here, so that one - * can't call it during the first sig load phase or while threads are still - * starting up. */ - if (de_ctx != NULL && suri.sig_file == NULL && suri.rule_reload == 1 && - suri.delayed_detect == 0) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - - if (de_ctx != NULL && suri.delayed_detect) { - if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK) - exit(EXIT_FAILURE); - de_ctx->delayed_detect_initialized = 1; - TmThreadActivateDummySlot(); - - if (suri.rule_reload) { - if (suri.sig_file != NULL) - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2SigFileStartup); - else - UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2); - } - SCLogNotice("Signature(s) loaded, Detect thread(s) activated."); - } + PostRunStartedDetectSetup(&suri); #ifdef DBG_MEM_ALLOC SCLogInfo("Memory used at startup: %"PRIdMAX, (intmax_t)global_mem); @@ -2362,143 +2870,17 @@ int main(int argc, char **argv) #endif #endif - int engine_retval = EXIT_SUCCESS; - while(1) { - if (suricata_ctl_flags & (SURICATA_KILL | SURICATA_STOP)) { - SCLogNotice("Signal Received. Stopping engine."); - - break; - } - - TmThreadCheckThreadState(); - - if (sighup_count > 0) { - OutputNotifyFileRotation(); - sighup_count--; - } - - usleep(10* 1000); - } + SuricataMainLoop(&suri); /* Update the engine stage/status flag */ (void) SC_ATOMIC_CAS(&engine_stage, SURICATA_RUNTIME, SURICATA_DEINIT); UnixSocketKillSocketThread(); - - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - /* First we need to kill the flow manager thread */ - FlowKillFlowManagerThread(); - } - - /* Disable packet acquire thread first */ - TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM); - - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - FlowForceReassembly(); - } - - SCPrintElapsedTime(&suri); - - if (suri.rule_reload == 1) { - /* Disable detect threads first. This is required by live rule swap */ - TmThreadDisableThreadsWithTMS(TM_FLAG_RECEIVE_TM | TM_FLAG_DECODE_TM | - TM_FLAG_STREAM_TM | TM_FLAG_DETECT_TM); - - /* wait if live rule swap is in progress */ - if (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { - SCLogInfo("Live rule swap in progress. Waiting for it to end " - "before we shut the engine/threads down"); - while (UtilSignalIsHandler(SIGUSR2, SignalHandlerSigusr2Idle)) { - /* sleep for 0.5 seconds */ - usleep(500000); - } - SCLogInfo("Received notification that live rule swap is done. " - "Continuing with engine/threads shutdown"); - } - } - - DetectEngineCtx *global_de_ctx = DetectEngineGetGlobalDeCtx(); - if (suri.run_mode != RUNMODE_UNIX_SOCKET && de_ctx != NULL) { - BUG_ON(global_de_ctx == NULL); - } - - /* before TmThreadKillThreads, as otherwise that kills it - * but more slowly */ - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - FlowKillFlowRecyclerThread(); - } - + PostRunDeinit(suri.run_mode, &suri.start_time); + /* kill remaining threads */ TmThreadKillThreads(); - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - SCPerfReleaseResources(); - FlowShutdown(); - StreamTcpFreeConfig(STREAM_VERBOSE); - } - HostShutdown(); - - HTPFreeConfig(); - HTPAtExitPrintStats(); - -#ifdef DBG_MEM_ALLOC - SCLogInfo("Total memory used (without SCFree()): %"PRIdMAX, (intmax_t)global_mem); -#ifdef DBG_MEM_ALLOC_SKIP_STARTUP - print_mem_flag = 0; -#endif -#endif - - SCPidfileRemove(suri.pid_filename); - - AppLayerHtpPrintStats(); - - if (global_de_ctx) { - DetectEngineCtxFree(global_de_ctx); - } - AppLayerDeSetup(); - - TagDestroyCtx(); - - LiveDeviceListClean(); - RunModeShutDown(); - OutputDeregisterAll(); - TimeDeinit(); - SCProtoNameDeInit(); - if (suri.run_mode != RUNMODE_UNIX_SOCKET) { - DefragDestroy(); - } - PacketPoolDestroy(); - MagicDeinit(); - TmqhCleanup(); - TmModuleRunDeInit(); - ParseSizeDeinit(); -#ifdef HAVE_NSS - NSS_Shutdown(); - PR_Cleanup(); -#endif - -#ifdef HAVE_AF_PACKET - AFPPeersListClean(); -#endif - -#ifdef PROFILING - if (profiling_rules_enabled) - SCProfilingDump(); - SCProfilingDestroy(); -#endif - -#ifdef OS_WIN32 - if (daemon) { - return 0; - } -#endif /* OS_WIN32 */ - - SC_ATOMIC_DESTROY(engine_stage); - -#ifdef __SC_CUDA_SUPPORT__ - if (PatternMatchDefaultMatcher() == MPM_AC_CUDA) - MpmCudaBufferDeSetup(); - CudaHandlerFreeProfiles(); -#endif + GlobalsDestroy(&suri); - exit(engine_retval); + exit(EXIT_SUCCESS); } diff --git a/src/suricata.h b/src/suricata.h index de0fb02f1122..aaee9fe535e2 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -71,7 +71,7 @@ /* the name of our binary */ #define PROG_NAME "Suricata" -#define PROG_VER "2.1dev" +#define PROG_VER "4.0dev" /* workaround SPlint error (don't know __gnuc_va_list) */ #ifdef S_SPLINT_S @@ -85,11 +85,17 @@ #define DEFAULT_PID_BASENAME "suricata.pid" #define DEFAULT_PID_FILENAME DEFAULT_PID_DIR DEFAULT_PID_BASENAME +#define DOC_URL "http://suricata.readthedocs.io/en/" + +#if defined RELEASE +#define DOC_VERSION PROG_VER +#else +#define DOC_VERSION "latest" +#endif + /* runtime engine control flags */ #define SURICATA_STOP (1 << 0) /**< gracefully stop the engine: process all outstanding packets first */ -#define SURICATA_KILL (1 << 1) /**< shut down asap, discarding outstanding - packets. */ #define SURICATA_DONE (1 << 2) /**< packets capture ended */ /* Engine stage/status*/ @@ -119,6 +125,8 @@ enum { #define IS_SURI_HOST_MODE_SNIFFER_ONLY(host_mode) ((host_mode) == SURI_HOST_IS_SNIFFER_ONLY) #define IS_SURI_HOST_MODE_ROUTER(host_mode) ((host_mode) == SURI_HOST_IS_ROUTER) +#include "runmodes.h" + /* queue's between various other threads * XXX move to the TmQueue structure later */ @@ -127,7 +135,7 @@ PacketQueue trans_q[256]; SCDQDataQueue data_queues[256]; typedef struct SCInstance_ { - int run_mode; + enum RunModes run_mode; char pcap_dev[128]; char *sig_file; @@ -146,7 +154,6 @@ typedef struct SCInstance_ { uint32_t groupid; #endif /* OS_WIN32 */ int delayed_detect; - int rule_reload; int disabled_detect; int daemon; int offline; @@ -156,19 +163,19 @@ typedef struct SCInstance_ { struct timeval start_time; char *log_dir; + const char *progname; /**< pointer to argv[0] */ + const char *conf_filename; } SCInstance; /* memset to zeros, and mutex init! */ -void GlobalInits(); +void GlobalsInitPreConfig(); -extern uint8_t suricata_ctl_flags; +extern volatile uint8_t suricata_ctl_flags; /* uppercase to lowercase conversion lookup table */ uint8_t g_u8_lowercasetable[256]; -extern char *conf_filename; - /* marco to do the actual lookup */ //#define u8_tolower(c) g_u8_lowercasetable[(c)] // these 2 are slower: @@ -180,19 +187,18 @@ extern char *conf_filename; #define u8_tolower(c) tolower((uint8_t)(c)) void EngineStop(void); -void EngineKill(void); void EngineDone(void); -/* live rule swap required this to be made static */ -void SignalHandlerSigusr2(int); -void SignalHandlerSigusr2EngineShutdown(int); -void SignalHandlerSigusr2Idle(int sig); - int RunmodeIsUnittests(void); int RunmodeGetCurrent(void); int IsRuleReloadSet(int quiet); extern int run_mode; +extern int run_mode_offline; + +void PreRunInit(const int runmode); +void PreRunPostPrivsDropInit(const int runmode); +void PostRunDeinit(const int runmode, struct timeval *start_time); #endif /* __SURICATA_H__ */ diff --git a/src/threads-arch-tile.h b/src/threads-arch-tile.h index a0e2fc501d0b..d022d90e339f 100644 --- a/src/threads-arch-tile.h +++ b/src/threads-arch-tile.h @@ -47,6 +47,7 @@ #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy /* mutex */ diff --git a/src/threads-debug.h b/src/threads-debug.h index 5a8b30fa6317..050e305643eb 100644 --- a/src/threads-debug.h +++ b/src/threads-debug.h @@ -383,6 +383,7 @@ #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy #endif diff --git a/src/threads-profile.h b/src/threads-profile.h index 4adde85889b8..6e19673b1048 100644 --- a/src/threads-profile.h +++ b/src/threads-profile.h @@ -212,6 +212,7 @@ extern __thread uint64_t rwr_lock_cnt; #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy #endif diff --git a/src/threads.c b/src/threads.c index 329890157391..29b924f4a74c 100644 --- a/src/threads.c +++ b/src/threads.c @@ -89,7 +89,13 @@ int ThreadMacrosTest03RWLocks(void) int r = 0; r |= SCRWLockInit(&rwl_write, NULL); r |= SCRWLockWRLock(&rwl_write); +/* OS X/macOS 10.10 (Yosemite) and newer return EDEADLK. Older versions + * and other tested OS's return EBUSY. */ +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__>=101000 + r |= (SCRWLockTryWRLock(&rwl_write) == EDEADLK)? 0 : 1; +#else r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1; +#endif r |= SCRWLockUnlock(&rwl_write); r |= SCRWLockDestroy(&rwl_write); @@ -136,9 +142,9 @@ int ThreadMacrosTest05RWLocks(void) void ThreadMacrosRegisterTests(void) { #ifdef UNITTESTS /* UNIT TESTS */ - UtRegisterTest("ThreadMacrosTest01Mutex", ThreadMacrosTest01Mutex, 1); - UtRegisterTest("ThreadMacrosTest02Spinlocks", ThreadMacrosTest02Spinlocks, 1); - UtRegisterTest("ThreadMacrosTest03RWLocks", ThreadMacrosTest03RWLocks, 1); - UtRegisterTest("ThreadMacrosTest04RWLocks", ThreadMacrosTest04RWLocks, 1); + UtRegisterTest("ThreadMacrosTest01Mutex", ThreadMacrosTest01Mutex); + UtRegisterTest("ThreadMacrosTest02Spinlocks", ThreadMacrosTest02Spinlocks); + UtRegisterTest("ThreadMacrosTest03RWLocks", ThreadMacrosTest03RWLocks); + UtRegisterTest("ThreadMacrosTest04RWLocks", ThreadMacrosTest04RWLocks); #endif /* UNIT TESTS */ } diff --git a/src/threads.h b/src/threads.h index 18f1eaae9e97..6a1329dea2b5 100644 --- a/src/threads.h +++ b/src/threads.h @@ -153,6 +153,7 @@ enum { #define SCCtrlCondInit pthread_cond_init #define SCCtrlCondSignal pthread_cond_signal #define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondWait pthread_cond_wait #define SCCtrlCondDestroy pthread_cond_destroy /* spinlocks */ @@ -215,39 +216,47 @@ enum { #define SCGetThreadIdLong(...) ({ \ long tmpthid; \ thr_self(&tmpthid); \ - u_long tid = (u_long)tmpthid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tmpthid; \ + _scgetthread_tid; \ }) #elif __OpenBSD__ #define SCGetThreadIdLong(...) ({ \ pid_t tpid; \ tpid = getpid(); \ - u_long tid = (u_long)tpid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tpid; \ + _scgetthread_tid; \ }) #elif __CYGWIN__ #define SCGetThreadIdLong(...) ({ \ - u_long tid = (u_long)GetCurrentThreadId(); \ - tid; \ + u_long _scgetthread_tid = (u_long)GetCurrentThreadId(); \ + _scgetthread_tid; \ }) #elif OS_WIN32 #define SCGetThreadIdLong(...) ({ \ - u_long tid = (u_long)GetCurrentThreadId(); \ - tid; \ + u_long _scgetthread_tid = (u_long)GetCurrentThreadId(); \ + _scgetthread_tid; \ }) #elif OS_DARWIN #define SCGetThreadIdLong(...) ({ \ thread_port_t tpid; \ tpid = mach_thread_self(); \ - u_long tid = (u_long)tpid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tpid; \ + _scgetthread_tid; \ }) +#elif defined(sun) +#include +#define SCGetThreadIdLong(...) ({ \ + thread_t tmpthid = thr_self(); \ + u_long _scgetthread_tid = (u_long)tmpthid; \ + _scgetthread_tid; \ +}) + #else #define SCGetThreadIdLong(...) ({ \ pid_t tmpthid; \ tmpthid = syscall(SYS_gettid); \ - u_long tid = (u_long)tmpthid; \ - tid; \ + u_long _scgetthread_tid = (u_long)tmpthid; \ + _scgetthread_tid; \ }) #endif /* OS FREEBSD */ diff --git a/src/threadvars.h b/src/threadvars.h index 0e04af2ca93c..82de83bcd820 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -24,7 +24,6 @@ #ifndef __THREADVARS_H__ #define __THREADVARS_H__ -#include "util-mpm.h" #include "util-affinity.h" #include "tm-queues.h" #include "counters.h" @@ -45,29 +44,25 @@ struct TmSlot_; #define THV_DEINIT (1 << 7) #define THV_RUNNING_DONE (1 << 8) /** thread has completed running and is entering * the de-init phase */ +#define THV_KILL_PKTACQ (1 << 9) /**< flag thread to stop packet acq */ +#define THV_FLOW_LOOP (1 << 10) /**< thread is in flow shutdown loop */ -/** Thread flags set and read by threads, to control the threads, when they - * encounter certain conditions like failure */ -#define THV_RESTART_THREAD 0x01 /** restart the thread */ -#define THV_ENGINE_EXIT 0x02 /** shut the engine down gracefully */ - -/** Maximum no of times a thread can be restarted */ -#define THV_MAX_RESTARTS 50 +/** signal thread's capture method to create a fake packet to force through + * the engine. This is to force timely handling of maintenance taks like + * rule reloads even if no packets are read by the capture method. */ +#define THV_CAPTURE_INJECT_PKT (1<<11) +#define THV_DEAD (1 << 12) /**< thread has been joined with pthread_join() */ /** \brief Per thread variable structure */ typedef struct ThreadVars_ { pthread_t t; - char *name; + char name[16]; char *thread_group_name; SC_ATOMIC_DECLARE(unsigned int, flags); - /** aof(action on failure) determines what should be done with the thread - when it encounters certain conditions like failures */ - uint8_t aof; - - /** no of times the thread has been restarted on failure */ - uint8_t restarted; + /** TmModule::flags for each module part of this thread */ + uint8_t tmm_flags; /** local id */ int id; @@ -87,6 +82,9 @@ typedef struct ThreadVars_ { void *(*tm_func)(void *); struct TmSlot_ *tm_slots; + /** stream packet queue for flow time out injection */ + struct PacketQueue_ *stream_pq; + uint8_t thread_setup_flags; /** the type of thread as defined in tm-threads.h (TVT_PPT, TVT_MGMT) */ @@ -96,9 +94,13 @@ typedef struct ThreadVars_ { uint16_t rank; int thread_priority; /** priority (real time) for this thread. Look at threads.h */ - /* the perf counter context and the perf counter array */ - SCPerfContext sc_perf_pctx; - SCPerfCounterArray *sc_perf_pca; + /* counters */ + + /** public counter store: counter syncs update this */ + StatsPublicThreadContext perf_public_ctx; + + /** private counter store: counter updates modify this */ + StatsPrivateThreadContext perf_private_ctx; SCCtrlMutex *ctrl_mutex; SCCtrlCondT *ctrl_cond; diff --git a/src/tm-modules.c b/src/tm-modules.c index 791938e6b10f..061b2838bfa9 100644 --- a/src/tm-modules.c +++ b/src/tm-modules.c @@ -199,6 +199,7 @@ void TmModuleRegisterTests(void) const char * TmModuleTmmIdToString(TmmId id) { switch (id) { + CASE_CODE (TMM_FLOWWORKER); CASE_CODE (TMM_RECEIVENFLOG); CASE_CODE (TMM_DECODENFLOG); CASE_CODE (TMM_DECODENFQ); @@ -210,30 +211,7 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_DECODEPCAPFILE); CASE_CODE (TMM_RECEIVEPFRING); CASE_CODE (TMM_DECODEPFRING); - CASE_CODE (TMM_DETECT); - CASE_CODE (TMM_ALERTFASTLOG); - CASE_CODE (TMM_ALERTFASTLOG4); - CASE_CODE (TMM_ALERTFASTLOG6); - CASE_CODE (TMM_ALERTUNIFIED2ALERT); - CASE_CODE (TMM_ALERTPRELUDE); - CASE_CODE (TMM_ALERTDEBUGLOG); - CASE_CODE (TMM_ALERTSYSLOG); - CASE_CODE (TMM_LOGDROPLOG); - CASE_CODE (TMM_ALERTSYSLOG4); - CASE_CODE (TMM_ALERTSYSLOG6); CASE_CODE (TMM_RESPONDREJECT); - CASE_CODE (TMM_LOGDNSLOG); - CASE_CODE (TMM_LOGHTTPLOG); - CASE_CODE (TMM_LOGHTTPLOG4); - CASE_CODE (TMM_LOGHTTPLOG6); - CASE_CODE (TMM_LOGTLSLOG); - CASE_CODE (TMM_LOGTLSLOG4); - CASE_CODE (TMM_LOGTLSLOG6); - CASE_CODE (TMM_LOGTCPDATALOG); - CASE_CODE (TMM_PCAPLOG); - CASE_CODE (TMM_FILELOG); - CASE_CODE (TMM_FILESTORE); - CASE_CODE (TMM_STREAMTCP); CASE_CODE (TMM_DECODEIPFW); CASE_CODE (TMM_VERDICTIPFW); CASE_CODE (TMM_RECEIVEIPFW); @@ -248,24 +226,14 @@ const char * TmModuleTmmIdToString(TmmId id) CASE_CODE (TMM_RECEIVEAFP); CASE_CODE (TMM_ALERTPCAPINFO); CASE_CODE (TMM_DECODEAFP); - CASE_CODE (TMM_PACKETLOGGER); - CASE_CODE (TMM_TXLOGGER); - CASE_CODE (TMM_FILELOGGER); - CASE_CODE (TMM_FILEDATALOGGER); - CASE_CODE (TMM_STREAMINGLOGGER); - CASE_CODE (TMM_JSONALERTLOG); - CASE_CODE (TMM_JSONDROPLOG); - CASE_CODE (TMM_JSONDNSLOG); - CASE_CODE (TMM_JSONHTTPLOG); - CASE_CODE (TMM_JSONFILELOG); - CASE_CODE (TMM_JSONFLOWLOG); - CASE_CODE (TMM_JSONNETFLOWLOG); - CASE_CODE (TMM_JSONSSHLOG); - CASE_CODE (TMM_JSONTLSLOG); - CASE_CODE (TMM_OUTPUTJSON); + CASE_CODE (TMM_STATSLOGGER); CASE_CODE (TMM_FLOWMANAGER); CASE_CODE (TMM_FLOWRECYCLER); - CASE_CODE (TMM_LUALOG); + CASE_CODE (TMM_ALERTHPFEEDS); + CASE_CODE (TMM_UNIXMANAGER); + CASE_CODE (TMM_DETECTLOADER); + CASE_CODE (TMM_RECEIVENETMAP); + CASE_CODE (TMM_DECODENETMAP); CASE_CODE (TMM_SIZE); } diff --git a/src/tm-modules.h b/src/tm-modules.h index a606306c5590..4e29aa35563b 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -34,6 +34,11 @@ #define TM_FLAG_DETECT_TM 0x08 #define TM_FLAG_LOGAPI_TM 0x10 /**< TM is run by Log API */ #define TM_FLAG_MANAGEMENT_TM 0x20 +#define TM_FLAG_COMMAND_TM 0x40 + +typedef TmEcode (*ThreadInitFunc)(ThreadVars *, void *, void **); +typedef TmEcode (*ThreadDeinitFunc)(ThreadVars *, void *); +typedef void (*ThreadExitPrintStatsFunc)(ThreadVars *, void *); typedef struct TmModule_ { char *name; @@ -48,6 +53,9 @@ typedef struct TmModule_ { TmEcode (*PktAcqLoop)(ThreadVars *, void *, void *); + /** terminates the capture loop in PktAcqLoop */ + TmEcode (*PktAcqBreakLoop)(ThreadVars *, void *); + TmEcode (*Management)(ThreadVars *, void *); /** global Init/DeInit */ diff --git a/src/tm-queues.c b/src/tm-queues.c index e549a975c7b0..b956c714984c 100644 --- a/src/tm-queues.c +++ b/src/tm-queues.c @@ -52,7 +52,10 @@ Tmq* TmqCreateQueue(char *name) goto error; Tmq *q = &tmqs[tmq_id]; - q->name = name; + q->name = SCStrdup(name); + if (q->name == NULL) + goto error; + q->id = tmq_id++; /* for cuda purposes */ q->q_type = 0; @@ -90,6 +93,12 @@ void TmqDebugList(void) void TmqResetQueues(void) { + uint16_t i; + for (i = 0; i < TMQ_MAX_QUEUES; i++) { + if (tmqs[i].name) { + SCFree(tmqs[i].name); + } + } memset(&tmqs, 0x00, sizeof(tmqs)); tmq_id = 0; } diff --git a/src/tm-threads-common.h b/src/tm-threads-common.h index 867190d745d3..9669a0e2ea5c 100644 --- a/src/tm-threads-common.h +++ b/src/tm-threads-common.h @@ -31,6 +31,7 @@ * in tm-modules.c */ typedef enum { + TMM_FLOWWORKER, TMM_DECODENFQ, TMM_VERDICTNFQ, TMM_RECEIVENFQ, @@ -40,31 +41,7 @@ typedef enum { TMM_DECODEPCAPFILE, TMM_RECEIVEPFRING, TMM_DECODEPFRING, - TMM_DETECT, - TMM_ALERTFASTLOG, - TMM_ALERTFASTLOG4, - TMM_ALERTFASTLOG6, - TMM_ALERTUNIFIED2ALERT, - TMM_ALERTPRELUDE, - TMM_ALERTDEBUGLOG, - TMM_ALERTSYSLOG, - TMM_LOGDROPLOG, - TMM_ALERTSYSLOG4, - TMM_ALERTSYSLOG6, TMM_RESPONDREJECT, - TMM_LOGDNSLOG, - TMM_LOGHTTPLOG, - TMM_LOGHTTPLOG4, - TMM_LOGHTTPLOG6, - TMM_LOGTLSLOG, - TMM_LOGTLSLOG4, - TMM_LOGTLSLOG6, - TMM_LOGTCPDATALOG, - TMM_OUTPUTJSON, - TMM_PCAPLOG, - TMM_FILELOG, - TMM_FILESTORE, - TMM_STREAMTCP, TMM_DECODEIPFW, TMM_VERDICTIPFW, TMM_RECEIVEIPFW, @@ -74,32 +51,24 @@ typedef enum { TMM_DECODEERFDAG, TMM_RECEIVEAFP, TMM_DECODEAFP, + TMM_RECEIVENETMAP, + TMM_DECODENETMAP, TMM_ALERTPCAPINFO, TMM_RECEIVEMPIPE, TMM_DECODEMPIPE, TMM_RECEIVENAPATECH, TMM_DECODENAPATECH, - TMM_PACKETLOGGER, - TMM_TXLOGGER, - TMM_FILELOGGER, - TMM_FILEDATALOGGER, - TMM_STREAMINGLOGGER, - TMM_JSONALERTLOG, - TMM_JSONDROPLOG, - TMM_JSONHTTPLOG, - TMM_JSONDNSLOG, - TMM_JSONSSHLOG, - TMM_JSONTLSLOG, - TMM_JSONFILELOG, + TMM_STATSLOGGER, TMM_RECEIVENFLOG, TMM_DECODENFLOG, - TMM_JSONFLOWLOG, - TMM_JSONNETFLOWLOG, TMM_FLOWMANAGER, TMM_FLOWRECYCLER, + TMM_ALERTHPFEEDS, + TMM_DETECTLOADER, + + TMM_UNIXMANAGER, - TMM_LUALOG, TMM_SIZE, } TmmId; diff --git a/src/tm-threads.c b/src/tm-threads.c index 7cd06e9ea5b3..bede1e05a661 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -73,16 +73,14 @@ __thread uint64_t rwr_lock_cnt; /* prototypes */ static int SetCPUAffinity(uint16_t cpu); +static void TmThreadDeinitMC(ThreadVars *tv); + /* root of the threadvars list */ ThreadVars *tv_root[TVT_MAX] = { NULL }; /* lock to protect tv_root */ SCMutex tv_root_lock = SCMUTEX_INITIALIZER; -/* Action On Failure(AOF). Determines how the engine should behave when a - * thread encounters a failure. Defaults to restart the failed thread */ -uint8_t tv_aof = THV_RESTART_THREAD; - /** * \brief Check if a thread flag is set. * @@ -92,465 +90,22 @@ uint8_t tv_aof = THV_RESTART_THREAD; int TmThreadsCheckFlag(ThreadVars *tv, uint16_t flag) { return (SC_ATOMIC_GET(tv->flags) & flag) ? 1 : 0; -} - -/** - * \brief Set a thread flag. - */ -void TmThreadsSetFlag(ThreadVars *tv, uint16_t flag) -{ - SC_ATOMIC_OR(tv->flags, flag); -} - -/** - * \brief Unset a thread flag. - */ -void TmThreadsUnsetFlag(ThreadVars *tv, uint16_t flag) -{ - SC_ATOMIC_AND(tv->flags, ~flag); -} - -/** - * \brief Function to use as dummy stack function - * - * \retval TM_ECODE_OK - */ -TmEcode TmDummyFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - return TM_ECODE_OK; -} - -/* 1 slot functions */ -void *TmThreadsSlot1NoIn(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - - r = SlotFunc(tv, NULL, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); - - SCMutexLock(&s->slot_post_pq.mutex_q); - TmqhReleasePacketsToPacketPool(&s->slot_post_pq); - SCMutexUnlock(&s->slot_post_pq.mutex_q); - - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - /* handle pre queue */ - while (s->slot_pre_pq.top != NULL) { - Packet *extra_p = PacketDequeue(&s->slot_pre_pq); - if (extra_p != NULL) - tv->tmqh_out(tv, extra_p); - } - - /* handle post queue */ - if (s->slot_post_pq.top != NULL) { - SCMutexLock(&s->slot_post_pq.mutex_q); - while (s->slot_post_pq.top != NULL) { - Packet *extra_p = PacketDequeue(&s->slot_post_pq); - if (extra_p != NULL) - tv->tmqh_out(tv, extra_p); - } - SCMutexUnlock(&s->slot_post_pq.mutex_q); - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - -void *TmThreadsSlot1NoOut(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - Packet *p = NULL; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - - p = tv->tmqh_in(tv); - - PACKET_PROFILING_TMM_START(p, s->tm_id); - r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), /* no outqh no pq */ NULL, - /* no outqh no pq */ NULL); - PACKET_PROFILING_TMM_END(p, s->tm_id); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmqhOutputPacketpool(tv, p); - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - -void *TmThreadsSlot1NoInOut(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - SCLogDebug("%s starting", tv->name); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - - r = SlotFunc(tv, NULL, SC_ATOMIC_GET(s->slot_data), /* no outqh, no pq */NULL, NULL); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } - - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; -} - -void *TmThreadsSlot1(void *td) -{ - /* block usr2. usr2 to be handled by the main thread only */ - UtilSignalBlock(SIGUSR2); - - ThreadVars *tv = (ThreadVars *)td; - TmSlot *s = (TmSlot *)tv->tm_slots; - Packet *p = NULL; - char run = 1; - TmEcode r = TM_ECODE_OK; - - /* Set the thread name */ - if (SCSetThreadName(tv->name) < 0) { - SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); - } - - if (tv->thread_setup_flags != 0) - TmThreadSetupOptions(tv); - - /* Drop the capabilities for this thread */ - SCDropCaps(tv); - - PacketPoolInit(); - - SCLogDebug("%s starting", tv->name); - - if (s->SlotThreadInit != NULL) { - void *slot_data = NULL; - r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); - SCMutexInit(&s->slot_pre_pq.mutex_q, NULL); - memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - SCMutexInit(&s->slot_post_pq.mutex_q, NULL); - - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); - - TmThreadsSetFlag(tv, THV_INIT_DONE); - - while (run) { - if (TmThreadsCheckFlag(tv, THV_PAUSE)) { - TmThreadsSetFlag(tv, THV_PAUSED); - TmThreadTestThreadUnPaused(tv); - TmThreadsUnsetFlag(tv, THV_PAUSED); - } - - /* input a packet */ - p = tv->tmqh_in(tv); - - if (p != NULL) { - TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); - PACKET_PROFILING_TMM_START(p, s->tm_id); - r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, - &s->slot_post_pq); - PACKET_PROFILING_TMM_END(p, s->tm_id); - - /* handle error */ - if (r == TM_ECODE_FAILED) { - TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); - - SCMutexLock(&s->slot_post_pq.mutex_q); - TmqhReleasePacketsToPacketPool(&s->slot_post_pq); - SCMutexUnlock(&s->slot_post_pq.mutex_q); - - TmqhOutputPacketpool(tv, p); - TmThreadsSetFlag(tv, THV_FAILED); - break; - } - - while (s->slot_pre_pq.top != NULL) { - /* handle new packets from this func */ - Packet *extra_p = PacketDequeue(&s->slot_pre_pq); - if (extra_p != NULL) { - tv->tmqh_out(tv, extra_p); - } - } - - /* output the packet */ - tv->tmqh_out(tv, p); - } - if (s->slot_post_pq.top != NULL) { - SCMutexLock(&s->slot_post_pq.mutex_q); - while (s->slot_post_pq.top != NULL) { - /* handle new packets from this func */ - Packet *extra_p = PacketDequeue(&s->slot_post_pq); - if (extra_p != NULL) { - tv->tmqh_out(tv, extra_p); - } - } - SCMutexUnlock(&s->slot_post_pq.mutex_q); - } - - if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); - run = 0; - } - } /* while (run) */ - - PacketPoolDestroy(); - - TmThreadsSetFlag(tv, THV_RUNNING_DONE); - TmThreadWaitForFlag(tv, THV_DEINIT); - - if (s->SlotThreadExitPrintStats != NULL) { - s->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(s->slot_data)); - } - - if (s->SlotThreadDeinit != NULL) { - r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); - if (r != TM_ECODE_OK) { - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; - } - } +} - SCLogDebug("%s ending", tv->name); - TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) 0); - return NULL; +/** + * \brief Set a thread flag. + */ +void TmThreadsSetFlag(ThreadVars *tv, uint16_t flag) +{ + SC_ATOMIC_OR(tv->flags, flag); +} + +/** + * \brief Unset a thread flag. + */ +void TmThreadsUnsetFlag(ThreadVars *tv, uint16_t flag) +{ + SC_ATOMIC_AND(tv->flags, ~flag); } /** @@ -618,6 +173,59 @@ TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p, return TM_ECODE_OK; } +/** \internal + * + * \brief Process flow timeout packets + * + * Process flow timeout pseudo packets. During shutdown this loop + * is run until the flow engine kills the thread and the queue is + * empty. + */ +static int TmThreadTimeoutLoop(ThreadVars *tv, TmSlot *s) +{ + TmSlot *stream_slot = NULL, *slot = NULL; + int run = 1; + int r = TM_ECODE_OK; + + for (slot = s; slot != NULL; slot = slot->slot_next) { + if (slot->tm_id == TMM_FLOWWORKER) + { + stream_slot = slot; + break; + } + } + + if (tv->stream_pq == NULL || stream_slot == NULL) { + SCLogDebug("not running TmThreadTimeoutLoop %p/%p", tv->stream_pq, stream_slot); + return r; + } + + SCLogDebug("flow end loop starting"); + while(run) { + Packet *p; + if (tv->stream_pq->len != 0) { + SCMutexLock(&tv->stream_pq->mutex_q); + p = PacketDequeue(tv->stream_pq); + SCMutexUnlock(&tv->stream_pq->mutex_q); + BUG_ON(p == NULL); + + if ((r = TmThreadsSlotProcessPkt(tv, stream_slot, p) != TM_ECODE_OK)) { + if (r == TM_ECODE_FAILED) + run = 0; + } + } else { + usleep(1); + } + + if (tv->stream_pq->len == 0 && TmThreadsCheckFlag(tv, THV_KILL)) { + run = 0; + } + } + SCLogDebug("flow end loop complete"); + + return r; +} + /* pcap/nfq @@ -675,8 +283,6 @@ void *TmThreadsSlotPktAcqLoop(void *td) " PktAcqLoop=%p, tmqh_in=%p," " tmqh_out=%p", s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; @@ -690,12 +296,10 @@ void *TmThreadsSlotPktAcqLoop(void *td) if (r == TM_ECODE_DONE) { EngineDone(); TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); - pthread_exit((void *) -1); + goto error; } else { - EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; + goto error; } } (void)SC_ATOMIC_SET(slot->slot_data, slot_data); @@ -704,11 +308,19 @@ void *TmThreadsSlotPktAcqLoop(void *td) SCMutexInit(&slot->slot_pre_pq.mutex_q, NULL); memset(&slot->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); + + /* get the 'pre qeueue' from module before the stream module */ + if (slot->slot_next != NULL && (slot->slot_next->tm_id == TMM_FLOWWORKER)) { + SCLogDebug("pre-stream packetqueue %p (postq)", &s->slot_post_pq); + tv->stream_pq = &slot->slot_post_pq; + /* if the stream module is the first, get the threads input queue */ + } else if (slot == (TmSlot *)tv->tm_slots && (slot->tm_id == TMM_FLOWWORKER)) { + tv->stream_pq = &trans_q[tv->inq->id]; + SCLogDebug("pre-stream packetqueue %p (inq)", &slot->slot_pre_pq); + } } - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); + StatsSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -721,21 +333,29 @@ void *TmThreadsSlotPktAcqLoop(void *td) r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); - if (r == TM_ECODE_FAILED || TmThreadsCheckFlag(tv, THV_KILL) - || suricata_ctl_flags) { + if (r == TM_ECODE_FAILED) { + TmThreadsSetFlag(tv, THV_FAILED); + run = 0; + } + if (TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) || suricata_ctl_flags) { run = 0; } if (r == TM_ECODE_DONE) { run = 0; } } - SCPerfSyncCounters(tv); + StatsSyncCounters(tv); - PacketPoolDestroy(); + TmThreadsSetFlag(tv, THV_FLOW_LOOP); + + /* process all pseudo packets the flow timeout may throw at us */ + TmThreadTimeoutLoop(tv, s); TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); + PacketPoolDestroy(); + for (slot = s; slot != NULL; slot = slot->slot_next) { if (slot->SlotThreadExitPrintStats != NULL) { slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data)); @@ -745,18 +365,140 @@ void *TmThreadsSlotPktAcqLoop(void *td) r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; + goto error; } } + + BUG_ON(slot->slot_pre_pq.len); + BUG_ON(slot->slot_post_pq.len); } + tv->stream_pq = NULL; SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; + +error: + tv->stream_pq = NULL; + pthread_exit((void *) -1); + return NULL; } +#ifdef AFLFUZZ_PCAP_RUNMODE +/** \brief simplified loop to speed up AFL + * + * The loop runs in the caller's thread. No separate thread. + */ +void *TmThreadsSlotPktAcqLoopAFL(void *td) +{ + SCLogNotice("AFL mode starting"); + + ThreadVars *tv = (ThreadVars *)td; + TmSlot *s = tv->tm_slots; + char run = 1; + TmEcode r = TM_ECODE_OK; + TmSlot *slot = NULL; + + PacketPoolInit(); + + /* check if we are setup properly */ + if (s == NULL || s->PktAcqLoop == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { + SCLogError(SC_ERR_FATAL, "TmSlot or ThreadVars badly setup: s=%p," + " PktAcqLoop=%p, tmqh_in=%p," + " tmqh_out=%p", + s, s ? s->PktAcqLoop : NULL, tv->tmqh_in, tv->tmqh_out); + TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); + return NULL; + } + + for (slot = s; slot != NULL; slot = slot->slot_next) { + if (slot->SlotThreadInit != NULL) { + void *slot_data = NULL; + r = slot->SlotThreadInit(tv, slot->slot_initdata, &slot_data); + if (r != TM_ECODE_OK) { + if (r == TM_ECODE_DONE) { + EngineDone(); + TmThreadsSetFlag(tv, THV_CLOSED | THV_INIT_DONE | THV_RUNNING_DONE); + goto error; + } else { + TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); + goto error; + } + } + (void)SC_ATOMIC_SET(slot->slot_data, slot_data); + } + memset(&slot->slot_pre_pq, 0, sizeof(PacketQueue)); + SCMutexInit(&slot->slot_pre_pq.mutex_q, NULL); + memset(&slot->slot_post_pq, 0, sizeof(PacketQueue)); + SCMutexInit(&slot->slot_post_pq.mutex_q, NULL); + + /* get the 'pre qeueue' from module before the stream module */ + if (slot->slot_next != NULL && (slot->slot_next->tm_id == TMM_FLOWWORKER)) { + SCLogDebug("pre-stream packetqueue %p (postq)", &s->slot_post_pq); + tv->stream_pq = &slot->slot_post_pq; + /* if the stream module is the first, get the threads input queue */ + } else if (slot == (TmSlot *)tv->tm_slots && (slot->tm_id == TMM_FLOWWORKER)) { + tv->stream_pq = &trans_q[tv->inq->id]; + SCLogDebug("pre-stream packetqueue %p (inq)", &slot->slot_pre_pq); + } + } + + StatsSetupPrivate(tv); + + TmThreadsSetFlag(tv, THV_INIT_DONE); + + while(run) { + /* run right away */ + + r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s); + + if (r == TM_ECODE_FAILED) { + TmThreadsSetFlag(tv, THV_FAILED); + run = 0; + } + if (TmThreadsCheckFlag(tv, THV_KILL_PKTACQ) || suricata_ctl_flags) { + run = 0; + } + if (r == TM_ECODE_DONE) { + run = 0; + } + } + StatsSyncCounters(tv); + + TmThreadsSetFlag(tv, THV_FLOW_LOOP); + + TmThreadsSetFlag(tv, THV_RUNNING_DONE); + + PacketPoolDestroy(); + + for (slot = s; slot != NULL; slot = slot->slot_next) { + if (slot->SlotThreadExitPrintStats != NULL) { + slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data)); + } + + if (slot->SlotThreadDeinit != NULL) { + r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data)); + if (r != TM_ECODE_OK) { + TmThreadsSetFlag(tv, THV_CLOSED); + goto error; + } + } + + BUG_ON(slot->slot_pre_pq.len); + BUG_ON(slot->slot_post_pq.len); + } + + tv->stream_pq = NULL; + SCLogDebug("%s ending", tv->name); + TmThreadsSetFlag(tv, THV_CLOSED); + return NULL; + +error: + tv->stream_pq = NULL; + return NULL; +} +#endif /** * \todo Only the first "slot" currently makes the "post_pq" available @@ -773,6 +515,8 @@ void *TmThreadsSlotVar(void *td) char run = 1; TmEcode r = TM_ECODE_OK; + PacketPoolInitEmpty(); + /* Set the thread name */ if (SCSetThreadName(tv->name) < 0) { SCLogWarning(SC_ERR_THREAD_INIT, "Unable to set thread name"); @@ -786,8 +530,6 @@ void *TmThreadsSlotVar(void *td) /* check if we are setup properly */ if (s == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; @@ -798,11 +540,8 @@ void *TmThreadsSlotVar(void *td) void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); - pthread_exit((void *) -1); - return NULL; + goto error; } (void)SC_ATOMIC_SET(s->slot_data, slot_data); } @@ -810,11 +549,22 @@ void *TmThreadsSlotVar(void *td) SCMutexInit(&s->slot_pre_pq.mutex_q, NULL); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); SCMutexInit(&s->slot_post_pq.mutex_q, NULL); + + /* special case: we need to access the stream queue + * from the flow timeout code */ + + /* get the 'pre qeueue' from module before the stream module */ + if (s->slot_next != NULL && (s->slot_next->tm_id == TMM_FLOWWORKER)) { + SCLogDebug("pre-stream packetqueue %p (preq)", &s->slot_pre_pq); + tv->stream_pq = &s->slot_pre_pq; + /* if the stream module is the first, get the threads input queue */ + } else if (s == (TmSlot *)tv->tm_slots && (s->tm_id == TMM_FLOWWORKER)) { + tv->stream_pq = &trans_q[tv->inq->id]; + SCLogDebug("pre-stream packetqueue %p (inq)", &s->slot_pre_pq); + } } - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); + StatsSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -878,11 +628,13 @@ void *TmThreadsSlotVar(void *td) run = 0; } } /* while (run) */ - SCPerfSyncCounters(tv); + StatsSyncCounters(tv); TmThreadsSetFlag(tv, THV_RUNNING_DONE); TmThreadWaitForFlag(tv, THV_DEINIT); + PacketPoolDestroy(); + s = (TmSlot *)tv->tm_slots; for ( ; s != NULL; s = s->slot_next) { @@ -894,16 +646,23 @@ void *TmThreadsSlotVar(void *td) r = s->SlotThreadDeinit(tv, SC_ATOMIC_GET(s->slot_data)); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); - pthread_exit((void *) -1); - return NULL; + goto error; } } + BUG_ON(s->slot_pre_pq.len); + BUG_ON(s->slot_post_pq.len); } SCLogDebug("%s ending", tv->name); + tv->stream_pq = NULL; TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); return NULL; + +error: + tv->stream_pq = NULL; + pthread_exit((void *) -1); + return NULL; } static void *TmThreadsManagement(void *td) @@ -934,8 +693,6 @@ static void *TmThreadsManagement(void *td) void *slot_data = NULL; r = s->SlotThreadInit(tv, s->slot_initdata, &slot_data); if (r != TM_ECODE_OK) { - EngineKill(); - TmThreadsSetFlag(tv, THV_CLOSED | THV_RUNNING_DONE); pthread_exit((void *) -1); return NULL; @@ -945,9 +702,7 @@ static void *TmThreadsManagement(void *td) memset(&s->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->slot_post_pq, 0, sizeof(PacketQueue)); - tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); - SCPerfAddToClubbedTMTable((tv->thread_group_name != NULL) ? - tv->thread_group_name : tv->name, &tv->sc_perf_pctx); + StatsSetupPrivate(tv); TmThreadsSetFlag(tv, THV_INIT_DONE); @@ -958,7 +713,7 @@ static void *TmThreadsManagement(void *td) } if (TmThreadsCheckFlag(tv, THV_KILL)) { - SCPerfSyncCounters(tv); + StatsSyncCounters(tv); } TmThreadsSetFlag(tv, THV_RUNNING_DONE); @@ -1004,20 +759,18 @@ TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *)) } } - if (strcmp(name, "1slot") == 0) { - tv->tm_func = TmThreadsSlot1; - } else if (strcmp(name, "1slot_noout") == 0) { - tv->tm_func = TmThreadsSlot1NoOut; - } else if (strcmp(name, "1slot_noin") == 0) { - tv->tm_func = TmThreadsSlot1NoIn; - } else if (strcmp(name, "1slot_noinout") == 0) { - tv->tm_func = TmThreadsSlot1NoInOut; - } else if (strcmp(name, "varslot") == 0) { + if (strcmp(name, "varslot") == 0) { tv->tm_func = TmThreadsSlotVar; } else if (strcmp(name, "pktacqloop") == 0) { +#ifndef AFLFUZZ_PCAP_RUNMODE tv->tm_func = TmThreadsSlotPktAcqLoop; +#else + tv->tm_func = TmThreadsSlotPktAcqLoopAFL; +#endif } else if (strcmp(name, "management") == 0) { tv->tm_func = TmThreadsManagement; + } else if (strcmp(name, "command") == 0) { + tv->tm_func = TmThreadsManagement; } else if (strcmp(name, "custom") == 0) { if (fn_p == NULL) goto error; @@ -1090,6 +843,7 @@ static inline TmSlot * _TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void * * received a TM as arg, if it didn't exist */ slot->tm_id = TmModuleGetIDForTM(tm); + tv->tmm_flags |= tm->flags; tv->cap_flags |= tm->cap_flags; if (tv->tm_slots == NULL) { @@ -1130,90 +884,6 @@ void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) _TmSlotSetFuncAppend(tv, tm, data); } -typedef struct TmDummySlot_ { - TmSlot *slot; - TmEcode (*SlotFunc)(ThreadVars *, Packet *, void *, PacketQueue *, - PacketQueue *); - TmEcode (*SlotThreadInit)(ThreadVars *, void *, void **); - TAILQ_ENTRY(TmDummySlot_) next; -} TmDummySlot; - -static TAILQ_HEAD(, TmDummySlot_) dummy_slots = - TAILQ_HEAD_INITIALIZER(dummy_slots); - -/** - * \brief Appends a new entry to the slots with a delayed option. - * - * \param tv TV the slot is attached to. - * \param tm TM to append. - * \param data Data to be passed on to the slot init function. - * \param delayed Delayed start of slot if equal to 1 - */ -void TmSlotSetFuncAppendDelayed(ThreadVars *tv, TmModule *tm, void *data, - int delayed) -{ - TmSlot *slot = _TmSlotSetFuncAppend(tv, tm, data); - TmDummySlot *dslot = NULL; - - if ((slot == NULL) || (delayed == 0)) { - return; - } - - dslot = SCMalloc(sizeof(TmDummySlot)); - if (unlikely(dslot == NULL)) { - TmSlotFree(slot); - return; - } - memset(dslot, 0, sizeof(*dslot)); - - dslot->SlotFunc = SC_ATOMIC_GET(slot->SlotFunc); - (void)SC_ATOMIC_SET(slot->SlotFunc, TmDummyFunc); - dslot->SlotThreadInit = slot->SlotThreadInit; - dslot->slot = slot; - - TAILQ_INSERT_TAIL(&dummy_slots, dslot, next); - - return; -} - -/** - * \brief Activate slots that have been started in delayed mode - */ -void TmThreadActivateDummySlot() -{ - TmDummySlot *dslot; - TmSlot *s; - TmEcode r = TM_ECODE_OK; - - TAILQ_FOREACH(dslot, &dummy_slots, next) { - void *slot_data = NULL; - s = dslot->slot; - if (dslot->SlotThreadInit != NULL) { - s->SlotThreadInit = dslot->SlotThreadInit; - r = s->SlotThreadInit(s->tv, s->slot_initdata, &slot_data); - if (r != TM_ECODE_OK) { - EngineKill(); - TmThreadsSetFlag(s->tv, THV_CLOSED | THV_RUNNING_DONE); - } - (void)SC_ATOMIC_SET(s->slot_data, slot_data); - } - (void)SC_ATOMIC_CAS(&s->SlotFunc, TmDummyFunc, dslot->SlotFunc); - } -} - -/** - * \brief Deactivate slots that have been started in delayed mode. - */ -void TmThreadDeActivateDummySlot() -{ - TmDummySlot *dslot; - - TAILQ_FOREACH(dslot, &dummy_slots, next) { - (void)SC_ATOMIC_CAS(&dslot->slot->SlotFunc, dslot->SlotFunc, TmDummyFunc); - dslot->slot->SlotThreadInit = NULL; - } -} - /** * \brief Returns the slot holding a TM with the particular tm_id. * @@ -1249,7 +919,7 @@ TmSlot *TmSlotGetSlotForTM(int tm_id) return NULL; } -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun static int SetCPUAffinitySet(cpu_set_t *cs) { #if defined OS_FREEBSD @@ -1283,7 +953,7 @@ static int SetCPUAffinitySet(cpu_set_t *cs) */ static int SetCPUAffinity(uint16_t cpuid) { -#if defined __OpenBSD__ +#if defined __OpenBSD__ || defined sun return 0; #else int cpu = (int)cpuid; @@ -1346,8 +1016,9 @@ void TmThreadSetPrio(ThreadVars *tv) #else int ret = nice(tv->thread_priority); if (ret == -1) { - SCLogError(SC_ERR_THREAD_NICE_PRIO, "Error setting nice value " - "for thread %s: %s", tv->name, strerror(errno)); + SCLogError(SC_ERR_THREAD_NICE_PRIO, "Error setting nice value %d " + "for thread %s: %s", tv->thread_priority, tv->name, + strerror(errno)); } else { SCLogDebug("Nice value set to %"PRId32" for thread %s", tv->thread_priority, tv->name); @@ -1410,13 +1081,13 @@ int TmThreadGetNbThreads(uint8_t type) TmEcode TmThreadSetupOptions(ThreadVars *tv) { if (tv->thread_setup_flags & THREAD_SET_AFFINITY) { - SCLogInfo("Setting affinity for \"%s\" Module to cpu/core " + SCLogPerf("Setting affinity for thread \"%s\"to cpu/core " "%"PRIu16", thread id %lu", tv->name, tv->cpu_affinity, SCGetThreadIdLong()); SetCPUAffinity(tv->cpu_affinity); } -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun if (tv->thread_setup_flags & THREAD_SET_PRIORITY) TmThreadSetPrio(tv); if (tv->thread_setup_flags & THREAD_SET_AFFTYPE) { @@ -1434,14 +1105,14 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) } else { tv->thread_priority = taf->prio; } - SCLogInfo("Setting prio %d for \"%s\" Module to cpu/core " - "%"PRIu16", thread id %lu", tv->thread_priority, + SCLogPerf("Setting prio %d for thread \"%s\" to cpu/core " + "%d, thread id %lu", tv->thread_priority, tv->name, cpu, SCGetThreadIdLong()); } else { SetCPUAffinitySet(&taf->cpu_set); tv->thread_priority = taf->prio; - SCLogInfo("Setting prio %d for \"%s\" thread " - ", thread id %lu", tv->thread_priority, + SCLogPerf("Setting prio %d for thread \"%s\", " + "thread id %lu", tv->thread_priority, tv->name, SCGetThreadIdLong()); } TmThreadSetPrio(tv); @@ -1466,7 +1137,7 @@ TmEcode TmThreadSetupOptions(ThreadVars *tv) * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, +ThreadVars *TmThreadCreate(const char *name, char *inq_name, char *inqh_name, char *outq_name, char *outqh_name, char *slots, void * (*fn_p)(void *), int mucond) { @@ -1483,14 +1154,13 @@ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, memset(tv, 0, sizeof(ThreadVars)); SC_ATOMIC_INIT(tv->flags); - SCMutexInit(&tv->sc_perf_pctx.m, NULL); + SCMutexInit(&tv->perf_public_ctx.m, NULL); + + strlcpy(tv->name, name, sizeof(tv->name)); - tv->name = name; /* default state for every newly created thread */ TmThreadsSetFlag(tv, THV_PAUSE); TmThreadsSetFlag(tv, THV_USE); - /* default aof for every newly created thread */ - tv->aof = THV_RESTART_THREAD; /* set the incoming queue */ if (inq_name != NULL && strcmp(inq_name, "packetpool") != 0) { @@ -1588,7 +1258,7 @@ ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, +ThreadVars *TmThreadCreatePacketHandler(const char *name, char *inq_name, char *inqh_name, char *outq_name, char *outqh_name, char *slots) { @@ -1597,8 +1267,11 @@ ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name, slots, NULL, 0); - if (tv != NULL) + if (tv != NULL) { tv->type = TVT_PPT; + tv->id = TmThreadsRegisterThread(tv, tv->type); + } + return tv; } @@ -1615,7 +1288,7 @@ ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name, * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), +ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int mucond) { ThreadVars *tv = NULL; @@ -1624,6 +1297,7 @@ ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), if (tv != NULL) { tv->type = TVT_MGMT; + tv->id = TmThreadsRegisterThread(tv, tv->type); TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); } @@ -1642,7 +1316,7 @@ ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, +ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, char *module, int mucond) { ThreadVars *tv = NULL; @@ -1651,6 +1325,7 @@ ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, if (tv != NULL) { tv->type = TVT_MGMT; + tv->id = TmThreadsRegisterThread(tv, tv->type); TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); TmModule *m = TmModuleGetByName(module); @@ -1663,27 +1338,33 @@ ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, } /** - * \brief Creates and returns the TV instance for a CMD thread. + * \brief Creates and returns the TV instance for a Command thread (CMD). * This function supports only custom slot functions and hence a * function pointer should be sent as an argument. * * \param name Name of this TV instance - * \param fn_p Pointer to function when \"slots\" is of type \"custom\" + * \param module Name of TmModule with COMMAND flag set. * \param mucond Flag to indicate whether to initialize the condition * and the mutex variables for this newly created TV. * * \retval the newly created TV instance, or NULL on error */ -ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), +ThreadVars *TmThreadCreateCmdThreadByName(const char *name, char *module, int mucond) { ThreadVars *tv = NULL; - tv = TmThreadCreate(name, NULL, NULL, NULL, NULL, "custom", fn_p, mucond); + tv = TmThreadCreate(name, NULL, NULL, NULL, NULL, "command", NULL, mucond); if (tv != NULL) { tv->type = TVT_CMD; + tv->id = TmThreadsRegisterThread(tv, tv->type); TmThreadSetCPU(tv, MANAGEMENT_CPU_SET); + + TmModule *m = TmModuleGetByName(module); + if (m) { + TmSlotSetFuncAppend(tv, m, NULL); + } } return tv; @@ -1767,13 +1448,20 @@ void TmThreadRemove(ThreadVars *tv, int type) * * \param tv A ThreadVars instance corresponding to the thread that has to be * killed. + * + * \retval r 1 killed succesfully + * 0 not yet ready, needs another look */ -void TmThreadKillThread(ThreadVars *tv) +static int TmThreadKillThread(ThreadVars *tv) { int i = 0; - if (tv == NULL) - return; + BUG_ON(tv == NULL); + + /* kill only once :) */ + if (TmThreadsCheckFlag(tv, THV_DEAD)) { + return 1; + } if (tv->inq != NULL) { /* we wait till we dry out all the inq packets, before we @@ -1782,8 +1470,8 @@ void TmThreadKillThread(ThreadVars *tv) if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { - usleep(1000); + if (q->len != 0) { + return 0; } } } @@ -1794,15 +1482,7 @@ void TmThreadKillThread(ThreadVars *tv) TmThreadsSetFlag(tv, THV_DEINIT); /* to be sure, signal more */ - int cnt = 0; - while (1) { - if (TmThreadsCheckFlag(tv, THV_CLOSED)) { - SCLogDebug("signalled the thread %" PRId32 " times", cnt); - break; - } - - cnt++; - + if (!(TmThreadsCheckFlag(tv, THV_CLOSED))) { if (tv->InShutdownHandler != NULL) { tv->InShutdownHandler(tv); } @@ -1819,31 +1499,93 @@ void TmThreadKillThread(ThreadVars *tv) if (tv->ctrl_cond != NULL ) { pthread_cond_broadcast(tv->ctrl_cond); } + return 0; + } + + if (tv->outctx != NULL) { + Tmqh *tmqh = TmqhGetQueueHandlerByName(tv->outqh_name); + if (tmqh == NULL) + BUG_ON(1); + + if (tmqh->OutHandlerCtxFree != NULL) { + tmqh->OutHandlerCtxFree(tv->outctx); + tv->outctx = NULL; + } + } + + /* join it and flag it as dead */ + pthread_join(tv->t, NULL); + SCLogDebug("thread %s stopped", tv->name); + TmThreadsSetFlag(tv, THV_DEAD); + return 1; +} + +/** \internal + * + * \brief make sure that all packet threads are done processing their + * in-flight packets + */ +static void TmThreadDrainPacketThreads(void) +{ + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 1000 + + uint64_t total_wait_time = 0; - usleep(100); + ThreadVars *tv = NULL; + +again: + if (total_wait_time > (THREAD_KILL_MAX_WAIT_TIME * 1000000)) { + SCLogWarning(SC_ERR_SHUTDOWN, "unable to get all packet threads " + "to process their packets in time"); + return; } - if (tv->outctx != NULL) { - Tmqh *tmqh = TmqhGetQueueHandlerByName(tv->outqh_name); - if (tmqh == NULL) - BUG_ON(1); + SCMutexLock(&tv_root_lock); - if (tmqh->OutHandlerCtxFree != NULL) { - tmqh->OutHandlerCtxFree(tv->outctx); + /* all receive threads are part of packet processing threads */ + tv = tv_root[TVT_PPT]; + + while (tv) { + if (tv->inq != NULL) { + /* we wait till we dry out all the inq packets, before we + * kill this thread. Do note that you should have disabled + * packet acquire by now using TmThreadDisableReceiveThreads()*/ + if (!(strlen(tv->inq->name) == strlen("packetpool") && + strcasecmp(tv->inq->name, "packetpool") == 0)) { + PacketQueue *q = &trans_q[tv->inq->id]; + if (q->len != 0) { + SCMutexUnlock(&tv_root_lock); + + total_wait_time += WAIT_TIME; + + /* don't sleep while holding a lock */ + usleep(WAIT_TIME); + goto again; + } + } } - } - /* join it */ - pthread_join(tv->t, NULL); - SCLogDebug("thread %s stopped", tv->name); + tv = tv->next; + } + SCMutexUnlock(&tv_root_lock); return; + +#undef THREAD_KILL_MAX_WAIT_TIME +#undef WAIT_TIME } /** - * \brief Disable all threads having the specified TMs. + * \brief Disable all threads having the specified TMs. + * + * Breaks out of the packet acquisition loop, and bumps + * into the 'flow loop', where it will process packets + * from the flow engine's shutdown handling. */ -void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) +void TmThreadDisableReceiveThreads(void) { /* value in seconds */ #define THREAD_KILL_MAX_WAIT_TIME 60 @@ -1854,6 +1596,7 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) ThreadVars *tv = NULL; +again: SCMutexLock(&tv_root_lock); /* all receive threads are part of packet processing threads */ @@ -1865,12 +1608,13 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) * with all receive threads */ while (tv) { int disable = 0; + TmModule *tm = NULL; /* obtain the slots for this TV */ TmSlot *slots = tv->tm_slots; while (slots != NULL) { - TmModule *tm = TmModuleGetById(slots->tm_id); + tm = TmModuleGetById(slots->tm_id); - if (tm->flags & tm_flags) { + if (tm->flags & TM_FLAG_RECEIVE_TM) { disable = 1; break; } @@ -1887,15 +1631,20 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) if (!(strlen(tv->inq->name) == strlen("packetpool") && strcasecmp(tv->inq->name, "packetpool") == 0)) { PacketQueue *q = &trans_q[tv->inq->id]; - while (q->len != 0) { + if (q->len != 0) { + SCMutexUnlock(&tv_root_lock); + /* don't sleep while holding a lock */ usleep(1000); + goto again; } } } - /* we found our receive TV. Send it a KILL signal. This is all - * we need to do to kill receive threads */ - TmThreadsSetFlag(tv, THV_KILL); + /* we found a receive TV. Send it a KILL_PKTACQ signal. */ + if (tm && tm->PktAcqBreakLoop != NULL) { + tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(slots->slot_data)); + } + TmThreadsSetFlag(tv, THV_KILL_PKTACQ); if (tv->inq != NULL) { int i; @@ -1908,7 +1657,10 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); } - while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + /* wait for it to enter the 'flow loop' stage */ + while (!TmThreadsCheckFlag(tv, THV_FLOW_LOOP)) { + SCMutexUnlock(&tv_root_lock); + usleep(WAIT_TIME); total_wait_time += WAIT_TIME / 1000000.0; if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { @@ -1917,7 +1669,93 @@ void TmThreadDisableThreadsWithTMS(uint8_t tm_flags) "Killing engine", tv->name); exit(EXIT_FAILURE); } + goto again; + } + } + + tv = tv->next; + } + + SCMutexUnlock(&tv_root_lock); + + /* finally wait for all packet threads to have + * processed all of their 'live' packets so we + * don't process the last live packets together + * with FFR packets */ + TmThreadDrainPacketThreads(); + return; +} + +/** + * \brief Disable all threads having the specified TMs. + */ +void TmThreadDisablePacketThreads(void) +{ + /* value in seconds */ +#define THREAD_KILL_MAX_WAIT_TIME 60 + /* value in microseconds */ +#define WAIT_TIME 100 + + double total_wait_time = 0; + + ThreadVars *tv = NULL; + + /* first drain all packet threads of their packets */ + TmThreadDrainPacketThreads(); +again: + SCMutexLock(&tv_root_lock); + + /* all receive threads are part of packet processing threads */ + tv = tv_root[TVT_PPT]; + + /* we do have to keep in mind that TVs are arranged in the order + * right from receive to log. The moment we fail to find a + * receive TM amongst the slots in a tv, it indicates we are done + * with all receive threads */ + while (tv) { + if (tv->inq != NULL) { + /* we wait till we dry out all the inq packets, before we + * kill this thread. Do note that you should have disabled + * packet acquire by now using TmThreadDisableReceiveThreads()*/ + if (!(strlen(tv->inq->name) == strlen("packetpool") && + strcasecmp(tv->inq->name, "packetpool") == 0)) { + PacketQueue *q = &trans_q[tv->inq->id]; + if (q->len != 0) { + SCMutexUnlock(&tv_root_lock); + /* don't sleep while holding a lock */ + usleep(1000); + goto again; + } + } + } + + /* we found our receive TV. Send it a KILL signal. This is all + * we need to do to kill receive threads */ + TmThreadsSetFlag(tv, THV_KILL); + + if (tv->inq != NULL) { + int i; + for (i = 0; i < (tv->inq->reader_cnt + tv->inq->writer_cnt); i++) { + if (tv->inq->q_type == 0) + SCCondSignal(&trans_q[tv->inq->id].cond_q); + else + SCCondSignal(&data_queues[tv->inq->id].cond_q); + } + SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); + } + + while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) { + SCMutexUnlock(&tv_root_lock); + + usleep(WAIT_TIME); + total_wait_time += WAIT_TIME / 1000000.0; + if (total_wait_time > THREAD_KILL_MAX_WAIT_TIME) { + SCLogError(SC_ERR_FATAL, "Engine unable to " + "disable detect thread - \"%s\". " + "Killing engine", tv->name); + exit(EXIT_FAILURE); } + goto again; } tv = tv->next; @@ -1959,20 +1797,31 @@ TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *tm_name) return slots; } +#define MIN_WAIT_TIME 100 void TmThreadKillThreadsFamily(int family) { ThreadVars *tv = NULL; + unsigned int sleep = MIN_WAIT_TIME; - if ((family < 0) || (family >= TVT_MAX)) - return; + BUG_ON((family < 0) || (family >= TVT_MAX)); +again: + SCMutexLock(&tv_root_lock); tv = tv_root[family]; while (tv) { - TmThreadKillThread(tv); + int r = TmThreadKillThread(tv); + if (r == 0) { + SCMutexUnlock(&tv_root_lock); + usleep(sleep); + sleep += MIN_WAIT_TIME; /* slowly back off */ + goto again; + } + sleep = MIN_WAIT_TIME; /* reset */ tv = tv->next; } + SCMutexUnlock(&tv_root_lock); } void TmThreadKillThreads(void) @@ -1995,7 +1844,13 @@ void TmThreadFree(ThreadVars *tv) SCLogDebug("Freeing thread '%s'.", tv->name); - SCMutexDestroy(&tv->sc_perf_pctx.m); + StatsThreadCleanup(tv); + + TmThreadDeinitMC(tv); + + if (tv->thread_group_name) { + SCFree(tv->thread_group_name); + } s = (TmSlot *)tv->tm_slots; while (s) { @@ -2003,9 +1858,29 @@ void TmThreadFree(ThreadVars *tv) s = s->slot_next; SCFree(ps); } + + TmThreadsUnregisterThread(tv->id); SCFree(tv); } +void TmThreadSetGroupName(ThreadVars *tv, const char *name) +{ + char *thread_group_name = NULL; + + if (name == NULL) + return; + + if (tv == NULL) + return; + + thread_group_name = SCStrdup(name); + if (unlikely(thread_group_name == NULL)) { + SCLogError(SC_ERR_RUNMODE, "error allocating memory"); + return; + } + tv->thread_group_name = thread_group_name; +} + void TmThreadClearThreadsFamily(int family) { ThreadVars *tv = NULL; @@ -2014,6 +1889,7 @@ void TmThreadClearThreadsFamily(int family) if ((family < 0) || (family >= TVT_MAX)) return; + SCMutexLock(&tv_root_lock); tv = tv_root[family]; while (tv) { @@ -2022,6 +1898,7 @@ void TmThreadClearThreadsFamily(int family) TmThreadFree(ptv); } tv_root[family] = NULL; + SCMutexUnlock(&tv_root_lock); } /** @@ -2069,23 +1946,13 @@ void TmThreadSetFlags(ThreadVars *tv, uint8_t flags) return; } #endif -/** - * \brief Sets the aof(Action on failure) for a thread instance(tv) - * - * \param tv Pointer to the thread instance for which the aof has to be set - * \param aof Holds the aof this thread instance has to be set to - */ -void TmThreadSetAOF(ThreadVars *tv, uint8_t aof) -{ - if (tv != NULL) - tv->aof = aof; - - return; -} /** * \brief Initializes the mutex and condition variables for this TV * + * It can be used by a thread to control a wait loop that can also be + * influenced by other threads. + * * \param tv Pointer to a TV instance */ void TmThreadInitMC(ThreadVars *tv) @@ -2098,24 +1965,37 @@ void TmThreadInitMC(ThreadVars *tv) if (SCCtrlMutexInit(tv->ctrl_mutex, NULL) != 0) { printf("Error initializing the tv->m mutex\n"); - exit(0); + exit(EXIT_FAILURE); } if ( (tv->ctrl_cond = SCMalloc(sizeof(*tv->ctrl_cond))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in TmThreadInitMC. " "Exiting..."); - exit(0); + exit(EXIT_FAILURE); } if (SCCtrlCondInit(tv->ctrl_cond, NULL) != 0) { SCLogError(SC_ERR_FATAL, "Error initializing the tv->cond condition " "variable"); - exit(0); + exit(EXIT_FAILURE); } return; } +static void TmThreadDeinitMC(ThreadVars *tv) +{ + if (tv->ctrl_mutex) { + SCCtrlMutexDestroy(tv->ctrl_mutex); + SCFree(tv->ctrl_mutex); + } + if (tv->ctrl_cond) { + SCCtrlCondDestroy(tv->ctrl_cond); + SCFree(tv->ctrl_cond); + } + return; +} + /** * \brief Tests if the thread represented in the arg has been unpaused or not. * @@ -2171,6 +2051,7 @@ void TmThreadContinueThreads() ThreadVars *tv = NULL; int i = 0; + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { @@ -2178,6 +2059,7 @@ void TmThreadContinueThreads() tv = tv->next; } } + SCMutexUnlock(&tv_root_lock); return; } @@ -2202,6 +2084,9 @@ void TmThreadPauseThreads() ThreadVars *tv = NULL; int i = 0; + TmThreadsListThreads(); + + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { @@ -2209,73 +2094,31 @@ void TmThreadPauseThreads() tv = tv->next; } } + SCMutexUnlock(&tv_root_lock); return; } /** - * \brief Restarts the thread sent as the argument - * - * \param tv Pointer to the thread instance(tv) to be restarted - */ -static void TmThreadRestartThread(ThreadVars *tv) -{ - if (tv->restarted >= THV_MAX_RESTARTS) { - SCLogError(SC_ERR_TM_THREADS_ERROR,"thread restarts exceeded " - "threshold limit for thread \"%s\"", tv->name); - exit(EXIT_FAILURE); - } - - TmThreadsUnsetFlag(tv, THV_CLOSED); - TmThreadsUnsetFlag(tv, THV_FAILED); - - if (TmThreadSpawn(tv) != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_SPAWN, "thread \"%s\" failed to spawn", tv->name); - exit(EXIT_FAILURE); - } - - tv->restarted++; - SCLogInfo("thread \"%s\" restarted", tv->name); - - return; -} - -/** - * \brief Used to check the thread for certain conditions of failure. If the - * thread has been specified to restart on failure, the thread is - * restarted. If the thread has been specified to gracefully shutdown - * the engine on failure, it does so. The global aof flag, tv_aof - * overrides the thread aof flag, if it holds a THV_ENGINE_EXIT; + * \brief Used to check the thread for certain conditions of failure. */ void TmThreadCheckThreadState(void) { ThreadVars *tv = NULL; int i = 0; + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv) { if (TmThreadsCheckFlag(tv, THV_FAILED)) { - TmThreadsSetFlag(tv, THV_DEINIT); - pthread_join(tv->t, NULL); - if ((tv_aof & THV_ENGINE_EXIT) || (tv->aof & THV_ENGINE_EXIT)) { - EngineKill(); - return; - } else { - /* if the engine kill-stop has been received by now, chuck - * restarting and return to kill the engine */ - if ((suricata_ctl_flags & SURICATA_KILL) || - (suricata_ctl_flags & SURICATA_STOP)) { - return; - } - TmThreadRestartThread(tv); - } + FatalError(SC_ERR_FATAL, "thread %s failed", tv->name); } tv = tv->next; } } - + SCMutexUnlock(&tv_root_lock); return; } @@ -2294,37 +2137,61 @@ TmEcode TmThreadWaitOnThreadInit(void) uint16_t mgt_num = 0; uint16_t ppt_num = 0; + uint64_t slept = 0; + +again: + SCMutexLock(&tv_root_lock); for (i = 0; i < TVT_MAX; i++) { tv = tv_root[i]; while (tv != NULL) { - char started = FALSE; - while (started == FALSE) { - if (TmThreadsCheckFlag(tv, THV_INIT_DONE)) { - started = TRUE; - } else { - /* sleep a little to give the thread some - * time to finish initialization */ - usleep(100); - } + if (TmThreadsCheckFlag(tv, (THV_CLOSED|THV_DEAD))) { + SCMutexUnlock(&tv_root_lock); + + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " + "initialize: flags %04x", tv->name, + SC_ATOMIC_GET(tv->flags)); + return TM_ECODE_FAILED; + } + + if (!(TmThreadsCheckFlag(tv, THV_INIT_DONE))) { + SCMutexUnlock(&tv_root_lock); - if (TmThreadsCheckFlag(tv, THV_FAILED)) { + if (slept > (120*1000000)) { SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " - "initialize.", tv->name); - return TM_ECODE_FAILED; - } - if (TmThreadsCheckFlag(tv, THV_CLOSED)) { - SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" closed on " - "initialization.", tv->name); + "initialize in time: flags %04x", tv->name, + SC_ATOMIC_GET(tv->flags)); return TM_ECODE_FAILED; } + + /* sleep a little to give the thread some + * time to finish initialization */ + usleep(100); + slept += 100; + goto again; + } + + if (TmThreadsCheckFlag(tv, THV_FAILED)) { + SCMutexUnlock(&tv_root_lock); + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" failed to " + "initialize.", tv->name); + return TM_ECODE_FAILED; + } + if (TmThreadsCheckFlag(tv, THV_CLOSED)) { + SCMutexUnlock(&tv_root_lock); + SCLogError(SC_ERR_THREAD_INIT, "thread \"%s\" closed on " + "initialization.", tv->name); + return TM_ECODE_FAILED; } - if (i == TVT_MGMT) mgt_num++; - else if (i == TVT_PPT) ppt_num++; + if (i == TVT_MGMT) + mgt_num++; + else if (i == TVT_PPT) + ppt_num++; tv = tv->next; } } + SCMutexUnlock(&tv_root_lock); SCLogNotice("all %"PRIu16" packet processing threads, %"PRIu16" management " "threads initialized, engine started.", ppt_num, mgt_num); @@ -2361,3 +2228,220 @@ ThreadVars *TmThreadsGetCallingThread(void) return NULL; } + +/** + * \brief returns a count of all the threads that match the flag + */ +uint32_t TmThreadCountThreadsByTmmFlags(uint8_t flags) +{ + ThreadVars *tv = NULL; + int i = 0; + uint32_t cnt = 0; + + SCMutexLock(&tv_root_lock); + for (i = 0; i < TVT_MAX; i++) { + tv = tv_root[i]; + while (tv != NULL) { + if ((tv->tmm_flags & flags) == flags) + cnt++; + + tv = tv->next; + } + } + SCMutexUnlock(&tv_root_lock); + return cnt; +} + +typedef struct Thread_ { + ThreadVars *tv; /**< threadvars structure */ + const char *name; + int type; + int in_use; /**< bool to indicate this is in use */ + + struct timeval ts; /**< current time of this thread (offline mode) */ +} Thread; + +typedef struct Threads_ { + Thread *threads; + size_t threads_size; + int threads_cnt; +} Threads; + +static Threads thread_store = { NULL, 0, 0 }; +static SCMutex thread_store_lock = SCMUTEX_INITIALIZER; + +void TmThreadsListThreads(void) +{ + Thread *t; + size_t s; + + SCMutexLock(&thread_store_lock); + + for (s = 0; s < thread_store.threads_size; s++) { + t = &thread_store.threads[s]; + if (t == NULL || t->in_use == 0) + continue; + SCLogInfo("Thread %"PRIuMAX", %s type %d, tv %p", (uintmax_t)s+1, t->name, t->type, t->tv); + } + + SCMutexUnlock(&thread_store_lock); +} + +#define STEP 32 +/** + * \retval id thread id, or 0 if not found + */ +int TmThreadsRegisterThread(ThreadVars *tv, const int type) +{ + SCMutexLock(&thread_store_lock); + if (thread_store.threads == NULL) { + thread_store.threads = SCCalloc(STEP, sizeof(Thread)); + BUG_ON(thread_store.threads == NULL); + thread_store.threads_size = STEP; + } + + size_t s; + for (s = 0; s < thread_store.threads_size; s++) { + if (thread_store.threads[s].in_use == 0) { + Thread *t = &thread_store.threads[s]; + t->name = tv->name; + t->type = type; + t->tv = tv; + t->in_use = 1; + + SCMutexUnlock(&thread_store_lock); + return (int)(s+1); + } + } + + /* if we get here the array is completely filled */ + void *newmem = SCRealloc(thread_store.threads, ((thread_store.threads_size + STEP) * sizeof(Thread))); + BUG_ON(newmem == NULL); + thread_store.threads = newmem; + memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, STEP * sizeof(Thread)); + + Thread *t = &thread_store.threads[thread_store.threads_size]; + t->name = tv->name; + t->type = type; + t->tv = tv; + t->in_use = 1; + + s = thread_store.threads_size; + thread_store.threads_size += STEP; + + SCMutexUnlock(&thread_store_lock); + return (int)(s+1); +} +#undef STEP + +void TmThreadsUnregisterThread(const int id) +{ + SCMutexLock(&thread_store_lock); + if (id <= 0 || id > (int)thread_store.threads_size) { + SCMutexUnlock(&thread_store_lock); + return; + } + + /* id is one higher than index */ + int idx = id - 1; + + /* reset thread_id, which serves as clearing the record */ + thread_store.threads[idx].in_use = 0; + + /* check if we have at least one registered thread left */ + size_t s; + for (s = 0; s < thread_store.threads_size; s++) { + Thread *t = &thread_store.threads[s]; + if (t->in_use == 1) { + goto end; + } + } + + /* if we get here no threads are registered */ + SCFree(thread_store.threads); + thread_store.threads = NULL; + thread_store.threads_size = 0; + thread_store.threads_cnt = 0; + +end: + SCMutexUnlock(&thread_store_lock); +} + +void TmThreadsSetThreadTimestamp(const int id, const struct timeval *ts) +{ + SCMutexLock(&thread_store_lock); + if (unlikely(id <= 0 || id > (int)thread_store.threads_size)) { + SCMutexUnlock(&thread_store_lock); + return; + } + + int idx = id - 1; + Thread *t = &thread_store.threads[idx]; + t->ts.tv_sec = ts->tv_sec; + t->ts.tv_usec = ts->tv_usec; + SCMutexUnlock(&thread_store_lock); +} + +#define COPY_TIMESTAMP(src,dst) ((dst)->tv_sec = (src)->tv_sec, (dst)->tv_usec = (src)->tv_usec) // XXX unify with flow-util.h +void TmreadsGetMinimalTimestamp(struct timeval *ts) +{ + struct timeval local, nullts; + memset(&local, 0, sizeof(local)); + memset(&nullts, 0, sizeof(nullts)); + int set = 0; + size_t s; + + SCMutexLock(&thread_store_lock); + for (s = 0; s < thread_store.threads_size; s++) { + Thread *t = &thread_store.threads[s]; + if (t == NULL || t->in_use == 0) + continue; + if (!(timercmp(&t->ts, &nullts, ==))) { + if (!set) { + local.tv_sec = t->ts.tv_sec; + local.tv_usec = t->ts.tv_usec; + set = 1; + } else { + if (timercmp(&t->ts, &local, <)) { + COPY_TIMESTAMP(&t->ts, &local); + } + } + } + } + SCMutexUnlock(&thread_store_lock); + COPY_TIMESTAMP(&local, ts); + SCLogDebug("ts->tv_sec %u", (uint)ts->tv_sec); +} +#undef COPY_TIMESTAMP + +/** + * \retval r 1 if packet was accepted, 0 otherwise + * \note if packet was not accepted, it's still the responsibility + * of the caller. + */ +int TmThreadsInjectPacketsById(Packet **packets, const int id) +{ + if (id <= 0 || id > (int)thread_store.threads_size) + return 0; + + int idx = id - 1; + + Thread *t = &thread_store.threads[idx]; + ThreadVars *tv = t->tv; + + if (tv == NULL || tv->stream_pq == NULL) + return 0; + + SCMutexLock(&tv->stream_pq->mutex_q); + while (*packets != NULL) { + PacketEnqueue(tv->stream_pq, *packets); + packets++; + } + SCMutexUnlock(&tv->stream_pq->mutex_q); + + /* wake up listening thread(s) if necessary */ + if (tv->inq != NULL) { + SCCondSignal(&trans_q[tv->inq->id].cond_q); + } + return 1; +} diff --git a/src/tm-threads.h b/src/tm-threads.h index 37c773553317..ff6fd35fd8bb 100644 --- a/src/tm-threads.h +++ b/src/tm-threads.h @@ -84,23 +84,23 @@ void TmSlotSetFuncAppend(ThreadVars *, TmModule *, void *); void TmSlotSetFuncAppendDelayed(ThreadVars *, TmModule *, void *, int delayed); TmSlot *TmSlotGetSlotForTM(int); -ThreadVars *TmThreadCreate(char *, char *, char *, char *, char *, char *, +ThreadVars *TmThreadCreate(const char *, char *, char *, char *, char *, char *, void *(fn_p)(void *), int); -ThreadVars *TmThreadCreatePacketHandler(char *, char *, char *, char *, char *, +ThreadVars *TmThreadCreatePacketHandler(const char *, char *, char *, char *, char *, char *); -ThreadVars *TmThreadCreateMgmtThread(char *name, void *(fn_p)(void *), int); -ThreadVars *TmThreadCreateMgmtThreadByName(char *name, char *module, +ThreadVars *TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int); +ThreadVars *TmThreadCreateMgmtThreadByName(const char *name, char *module, + int mucond); +ThreadVars *TmThreadCreateCmdThreadByName(const char *name, char *module, int mucond); -ThreadVars *TmThreadCreateCmdThread(char *name, void *(fn_p)(void *), int); TmEcode TmThreadSpawn(ThreadVars *); void TmThreadSetFlags(ThreadVars *, uint8_t); -void TmThreadSetAOF(ThreadVars *, uint8_t); -void TmThreadKillThread(ThreadVars *); void TmThreadKillThreadsFamily(int family); void TmThreadKillThreads(void); void TmThreadClearThreadsFamily(int family); void TmThreadAppend(ThreadVars *, int); void TmThreadRemove(ThreadVars *, int); +void TmThreadSetGroupName(ThreadVars *tv, const char *name); TmEcode TmThreadSetCPUAffinity(ThreadVars *, uint16_t); TmEcode TmThreadSetThreadPriority(ThreadVars *, int); @@ -119,9 +119,6 @@ void TmThreadCheckThreadState(void); TmEcode TmThreadWaitOnThreadInit(void); ThreadVars *TmThreadsGetCallingThread(void); -void TmThreadActivateDummySlot(void); -void TmThreadDeActivateDummySlot(void); - int TmThreadsCheckFlag(ThreadVars *, uint16_t); void TmThreadsSetFlag(ThreadVars *, uint16_t); void TmThreadsUnsetFlag(ThreadVars *, uint16_t); @@ -130,9 +127,12 @@ void TmThreadWaitForFlag(ThreadVars *, uint16_t); TmEcode TmThreadsSlotVarRun (ThreadVars *tv, Packet *p, TmSlot *slot); ThreadVars *TmThreadsGetTVContainingSlot(TmSlot *); -void TmThreadDisableThreadsWithTMS(uint8_t tm_flags); +void TmThreadDisablePacketThreads(void); +void TmThreadDisableReceiveThreads(void); TmSlot *TmThreadGetFirstTmSlotForPartialPattern(const char *); +uint32_t TmThreadCountThreadsByTmmFlags(uint8_t flags); + /** * \brief Process the rest of the functions (if any) and queue. */ @@ -195,4 +195,32 @@ static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet return r; } +/** \brief inject packet if THV_CAPTURE_INJECT_PKT is set + * Allow caller to supply their own packet + * + * Meant for detect reload process that interupts an sleeping capture thread + * to force a packet through the engine to complete a reload */ +static inline void TmThreadsCaptureInjectPacket(ThreadVars *tv, TmSlot *slot, Packet *p) +{ + if (TmThreadsCheckFlag(tv, THV_CAPTURE_INJECT_PKT)) { + TmThreadsUnsetFlag(tv, THV_CAPTURE_INJECT_PKT); + if (p == NULL) + p = PacketGetFromQueueOrAlloc(); + if (p != NULL) { + p->flags |= PKT_PSEUDO_STREAM_END; + if (TmThreadsSlotProcessPkt(tv, slot, p) != TM_ECODE_OK) { + TmqhOutputPacketpool(tv, p); + } + } + } +} + +void TmThreadsListThreads(void); +int TmThreadsRegisterThread(ThreadVars *tv, const int type); +void TmThreadsUnregisterThread(const int id); +int TmThreadsInjectPacketsById(Packet **, int id); + +void TmThreadsSetThreadTimestamp(const int id, const struct timeval *ts); +void TmreadsGetMinimalTimestamp(struct timeval *ts); + #endif /* __TM_THREADS_H__ */ diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index cebd34429f4c..cdcfd670a3e4 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -41,8 +41,7 @@ Packet *TmqhInputFlow(ThreadVars *t); void TmqhOutputFlowHash(ThreadVars *t, Packet *p); -void TmqhOutputFlowActivePackets(ThreadVars *t, Packet *p); -void TmqhOutputFlowRoundRobin(ThreadVars *t, Packet *p); +void TmqhOutputFlowIPPair(ThreadVars *t, Packet *p); void *TmqhOutputFlowSetupCtx(char *queue_str); void TmqhOutputFlowFreeCtx(void *ctx); void TmqhFlowRegisterTests(void); @@ -58,14 +57,15 @@ void TmqhFlowRegister(void) char *scheduler = NULL; if (ConfGet("autofp-scheduler", &scheduler) == 1) { if (strcasecmp(scheduler, "round-robin") == 0) { - SCLogInfo("AutoFP mode using \"Round Robin\" flow load balancer"); - tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowRoundRobin; + SCLogNotice("using flow hash instead of round robin"); + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "active-packets") == 0) { - SCLogInfo("AutoFP mode using \"Active Packets\" flow load balancer"); - tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; + SCLogNotice("using flow hash instead of active packets"); + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } else if (strcasecmp(scheduler, "hash") == 0) { - SCLogInfo("AutoFP mode using \"Hash\" flow load balancer"); tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; + } else if (strcasecmp(scheduler, "ippair") == 0) { + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowIPPair; } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry \"%s\" " "for autofp-scheduler in conf. Killing engine.", @@ -73,19 +73,30 @@ void TmqhFlowRegister(void) exit(EXIT_FAILURE); } } else { - SCLogInfo("AutoFP mode using default \"Active Packets\" flow load balancer"); - tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowActivePackets; + tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash; } return; } +void TmqhFlowPrintAutofpHandler(void) +{ +#define PRINT_IF_FUNC(f, msg) \ + if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \ + SCLogConfig("AutoFP mode using \"%s\" flow load balancer", (msg)) + + PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash"); + PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair"); + +#undef PRINT_IF_FUNC +} + /* same as 'simple' */ Packet *TmqhInputFlow(ThreadVars *tv) { PacketQueue *q = &trans_q[tv->inq->id]; - SCPerfSyncCountersIfSignalled(tv); + StatsSyncCountersIfSignalled(tv); SCMutexLock(&q->mutex_q); if (q->len == 0) { @@ -109,7 +120,7 @@ static int StoreQueueId(TmqhFlowCtx *ctx, char *name) void *ptmp; Tmq *tmq = TmqGetQueueByName(name); if (tmq == NULL) { - tmq = TmqCreateQueue(SCStrdup(name)); + tmq = TmqCreateQueue(name); if (tmq == NULL) return -1; } @@ -137,8 +148,6 @@ static int StoreQueueId(TmqhFlowCtx *ctx, char *name) memset(ctx->queues + (ctx->size - 1), 0, sizeof(TmqhFlowMode)); } ctx->queues[ctx->size - 1].q = &trans_q[id]; - SC_ATOMIC_INIT(ctx->queues[ctx->size - 1].total_packets); - SC_ATOMIC_INIT(ctx->queues[ctx->size - 1].total_flows); return 0; } @@ -189,8 +198,6 @@ void *TmqhOutputFlowSetupCtx(char *queue_str) tstr = comma ? (comma + 1) : comma; } while (tstr != NULL); - SC_ATOMIC_INIT(ctx->round_robin_idx); - SCFree(str); return (void *)ctx; @@ -203,104 +210,31 @@ void *TmqhOutputFlowSetupCtx(char *queue_str) void TmqhOutputFlowFreeCtx(void *ctx) { - int i; TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx; - SCLogInfo("AutoFP - Total flow handler queues - %" PRIu16, + SCLogPerf("AutoFP - Total flow handler queues - %" PRIu16, fctx->size); - for (i = 0; i < fctx->size; i++) { - SCLogInfo("AutoFP - Queue %-2"PRIu32 " - pkts: %-12"PRIu64" flows: %-12"PRIu64, i, - SC_ATOMIC_GET(fctx->queues[i].total_packets), - SC_ATOMIC_GET(fctx->queues[i].total_flows)); - SC_ATOMIC_DESTROY(fctx->queues[i].total_packets); - SC_ATOMIC_DESTROY(fctx->queues[i].total_flows); - } - SCFree(fctx->queues); + SCFree(fctx); return; } -/** - * \brief select the queue to output in a round robin fashion. - * - * \param tv thread vars - * \param p packet - */ -void TmqhOutputFlowRoundRobin(ThreadVars *tv, Packet *p) -{ - int32_t qid = 0; - - TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - - /* if no flow we use the first queue, - * should be rare */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { - qid = SC_ATOMIC_ADD(ctx->round_robin_idx, 1); - if (qid >= ctx->size) { - SC_ATOMIC_RESET(ctx->round_robin_idx); - qid = 0; - } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); - } - } else { - qid = ctx->last++; - - if (ctx->last == ctx->size) - ctx->last = 0; - } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); - - PacketQueue *q = ctx->queues[qid].q; - SCMutexLock(&q->mutex_q); - PacketEnqueue(q, p); - SCCondSignal(&q->cond_q); - SCMutexUnlock(&q->mutex_q); - - return; -} - -/** - * \brief select the queue to output to based on queue lengths. - * - * \param tv thread vars - * \param p packet - */ -void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) +void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) { - int32_t qid = 0; + int16_t qid = 0; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - /* if no flow we use the first queue, - * should be rare */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { - uint16_t i = 0; - int lowest_id = 0; - TmqhFlowMode *queues = ctx->queues; - uint32_t lowest = queues[i].q->len; - for (i = 1; i < ctx->size; i++) { - if (queues[i].q->len < lowest) { - lowest = queues[i].q->len; - lowest_id = i; - } - } - qid = lowest_id; - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, lowest_id); - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); - } + if (p->flags & PKT_WANTS_FLOW) { + uint32_t hash = p->flow_hash; + qid = hash % ctx->size; } else { qid = ctx->last++; if (ctx->last == ctx->size) ctx->last = 0; } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); @@ -312,42 +246,30 @@ void TmqhOutputFlowActivePackets(ThreadVars *tv, Packet *p) } /** - * \brief select the queue to output based on address hash. + * \brief select the queue to output based on IP address pair. * * \param tv thread vars. * \param p packet. */ -void TmqhOutputFlowHash(ThreadVars *tv, Packet *p) +void TmqhOutputFlowIPPair(ThreadVars *tv, Packet *p) { - int32_t qid = 0; + int16_t qid = 0; + uint32_t addr_hash = 0; + int i; TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx; - /* if no flow we use the first queue, - * should be rare */ - if (p->flow != NULL) { - qid = SC_ATOMIC_GET(p->flow->autofp_tmqh_flow_qid); - if (qid == -1) { -#if __WORDSIZE == 64 - uint64_t addr = (uint64_t)p->flow; -#else - uint32_t addr = (uint32_t)p->flow; -#endif - addr >>= 7; - - /* we don't have to worry about possible overflow, since - * ctx->size will be lesser than 2 ** 31 for sure */ - qid = addr % ctx->size; - (void) SC_ATOMIC_SET(p->flow->autofp_tmqh_flow_qid, qid); - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_flows, 1); + if (p->src.family == AF_INET6) { + for (i = 0; i < 4; i++) { + addr_hash += p->src.addr_data32[i] + p->dst.addr_data32[i]; } } else { - qid = ctx->last++; - - if (ctx->last == ctx->size) - ctx->last = 0; + addr_hash = p->src.addr_data32[0] + p->dst.addr_data32[0]; } - (void) SC_ATOMIC_ADD(ctx->queues[qid].total_packets, 1); + + /* we don't have to worry about possible overflow, since + * ctx->size will be lesser than 2 ** 31 for sure */ + qid = addr_hash % ctx->size; PacketQueue *q = ctx->queues[qid].q; SCMutexLock(&q->mutex_q); @@ -501,9 +423,12 @@ static int TmqhOutputFlowSetupCtxTest03(void) void TmqhFlowRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("TmqhOutputFlowSetupCtxTest01", TmqhOutputFlowSetupCtxTest01, 1); - UtRegisterTest("TmqhOutputFlowSetupCtxTest02", TmqhOutputFlowSetupCtxTest02, 1); - UtRegisterTest("TmqhOutputFlowSetupCtxTest03", TmqhOutputFlowSetupCtxTest03, 1); + UtRegisterTest("TmqhOutputFlowSetupCtxTest01", + TmqhOutputFlowSetupCtxTest01); + UtRegisterTest("TmqhOutputFlowSetupCtxTest02", + TmqhOutputFlowSetupCtxTest02); + UtRegisterTest("TmqhOutputFlowSetupCtxTest03", + TmqhOutputFlowSetupCtxTest03); #endif return; diff --git a/src/tmqh-flow.h b/src/tmqh-flow.h index ccf926333710..3cec7a165f5b 100644 --- a/src/tmqh-flow.h +++ b/src/tmqh-flow.h @@ -26,8 +26,6 @@ typedef struct TmqhFlowMode_ { PacketQueue *q; - SC_ATOMIC_DECLARE(uint64_t, total_packets); - SC_ATOMIC_DECLARE(uint64_t, total_flows); } TmqhFlowMode; /** \brief Ctx for the flow queue handler @@ -38,11 +36,11 @@ typedef struct TmqhFlowCtx_ { uint16_t last; TmqhFlowMode *queues; - - SC_ATOMIC_DECLARE(uint16_t, round_robin_idx); } TmqhFlowCtx; void TmqhFlowRegister (void); void TmqhFlowRegisterTests(void); +void TmqhFlowPrintAutofpHandler(void); + #endif /* __TMQH_FLOW_H__ */ diff --git a/src/tmqh-packetpool.c b/src/tmqh-packetpool.c index 38ca297c7054..913cb3e78c93 100644 --- a/src/tmqh-packetpool.c +++ b/src/tmqh-packetpool.c @@ -38,6 +38,8 @@ #include "stream-tcp-reassemble.h" #include "tm-queuehandlers.h" +#include "tm-threads.h" +#include "tm-modules.h" #include "pkt-var.h" @@ -50,6 +52,7 @@ /* Number of freed packet to save for one pool before freeing them. */ #define MAX_PENDING_RETURN_PACKETS 32 +static uint32_t max_pending_return_packets = MAX_PENDING_RETURN_PACKETS; #ifdef TLS __thread PktPool thread_pkt_pool; @@ -66,7 +69,7 @@ static int pkt_pool_thread_key_initialized = 0; static void PktPoolThreadDestroy(void * buf) { - free(buf); + SCFreeAligned(buf); } static void TmqhPacketPoolInit(void) @@ -101,6 +104,8 @@ static PktPool *ThreadPacketPoolCreate(void) SCLogError(SC_ERR_MEM_ALLOC, "malloc failed"); exit(EXIT_FAILURE); } + memset(pool,0x0,sizeof(*pool)); + int r = pthread_setspecific(pkt_pool_thread_key, pool); if (r != 0) { SCLogError(SC_ERR_MEM_ALLOC, "pthread_setspecific failed with %d", r); @@ -144,10 +149,68 @@ void PacketPoolWait(void) { PktPool *my_pool = GetThreadPacketPool(); + if (PacketPoolIsEmpty(my_pool)) { + SCMutexLock(&my_pool->return_stack.mutex); + SC_ATOMIC_ADD(my_pool->return_stack.sync_now, 1); + SCCondWait(&my_pool->return_stack.cond, &my_pool->return_stack.mutex); + SCMutexUnlock(&my_pool->return_stack.mutex); + } + while(PacketPoolIsEmpty(my_pool)) cc_barrier(); } +/** \brief Wait until we have the requested ammount of packets in the pool + * + * In some cases waiting for packets is undesirable. Especially when + * a wait would happen under a lock of some kind, other parts of the + * engine could have to wait. + * + * This function only returns when at least N packets are in our pool. + * + * \param n number of packets needed + */ +void PacketPoolWaitForN(int n) +{ + PktPool *my_pool = GetThreadPacketPool(); + Packet *p = NULL; + + while (1) { + int i = 0; + PacketPoolWait(); + + /* count packets in our stack */ + p = my_pool->head; + while (p != NULL) { + if (++i == n) + return; + + p = p->next; + } + + /* continue counting in the return stack */ + if (my_pool->return_stack.head != NULL) { + SCMutexLock(&my_pool->return_stack.mutex); + p = my_pool->return_stack.head; + while (p != NULL) { + if (++i == n) { + SCMutexUnlock(&my_pool->return_stack.mutex); + return; + } + p = p->next; + } + SCMutexUnlock(&my_pool->return_stack.mutex); + + /* or signal that we need packets and wait */ + } else { + SCMutexLock(&my_pool->return_stack.mutex); + SC_ATOMIC_ADD(my_pool->return_stack.sync_now, 1); + SCCondWait(&my_pool->return_stack.cond, &my_pool->return_stack.mutex); + SCMutexUnlock(&my_pool->return_stack.mutex); + } + } +} + /** \brief a initialized packet * * \warning Use *only* at init, not at packet runtime @@ -181,7 +244,10 @@ static void PacketPoolGetReturnedPackets(PktPool *pool) Packet *PacketPoolGetPacket(void) { PktPool *pool = GetThreadPacketPool(); - +#ifdef DEBUG_VALIDATION + BUG_ON(pool->initialized == 0); + BUG_ON(pool->destroyed == 1); +#endif /* DEBUG_VALIDATION */ if (pool->head) { /* Stack is not empty. */ Packet *p = pool->head; @@ -223,9 +289,15 @@ void PacketPoolReturnPacket(Packet *p) PktPool *pool = p->pool; if (pool == NULL) { - free(p); + PacketFree(p); return; } +#ifdef DEBUG_VALIDATION + BUG_ON(pool->initialized == 0); + BUG_ON(pool->destroyed == 1); + BUG_ON(my_pool->initialized == 0); + BUG_ON(my_pool->destroyed == 1); +#endif /* DEBUG_VALIDATION */ if (pool == my_pool) { /* Push back onto this thread's own stack, so no locking. */ @@ -235,6 +307,7 @@ void PacketPoolReturnPacket(Packet *p) PktPool *pending_pool = my_pool->pending_pool; if (pending_pool == NULL) { /* No pending packet, so store the current packet. */ + p->next = NULL; my_pool->pending_pool = pool; my_pool->pending_head = p; my_pool->pending_tail = p; @@ -244,25 +317,51 @@ void PacketPoolReturnPacket(Packet *p) p->next = my_pool->pending_head; my_pool->pending_head = p; my_pool->pending_count++; - if (my_pool->pending_count > MAX_PENDING_RETURN_PACKETS) { + if (SC_ATOMIC_GET(pool->return_stack.sync_now) || my_pool->pending_count > max_pending_return_packets) { /* Return the entire list of pending packets. */ SCMutexLock(&pool->return_stack.mutex); my_pool->pending_tail->next = pool->return_stack.head; pool->return_stack.head = my_pool->pending_head; + SC_ATOMIC_RESET(pool->return_stack.sync_now); SCMutexUnlock(&pool->return_stack.mutex); + SCCondSignal(&pool->return_stack.cond); /* Clear the list of pending packets to return. */ my_pool->pending_pool = NULL; + my_pool->pending_head = NULL; + my_pool->pending_tail = NULL; + my_pool->pending_count = 0; } } else { /* Push onto return stack for this pool */ SCMutexLock(&pool->return_stack.mutex); p->next = pool->return_stack.head; pool->return_stack.head = p; + SC_ATOMIC_RESET(pool->return_stack.sync_now); SCMutexUnlock(&pool->return_stack.mutex); + SCCondSignal(&pool->return_stack.cond); } } } +void PacketPoolInitEmpty(void) +{ +#ifndef TLS + TmqhPacketPoolInit(); +#endif + + PktPool *my_pool = GetThreadPacketPool(); + +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->initialized); + my_pool->initialized = 1; + my_pool->destroyed = 0; +#endif /* DEBUG_VALIDATION */ + + SCMutexInit(&my_pool->return_stack.mutex, NULL); + SCCondInit(&my_pool->return_stack.cond, NULL); + SC_ATOMIC_INIT(my_pool->return_stack.sync_now); +} + void PacketPoolInit(void) { extern intmax_t max_pending_packets; @@ -273,7 +372,15 @@ void PacketPoolInit(void) PktPool *my_pool = GetThreadPacketPool(); +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->initialized); + my_pool->initialized = 1; + my_pool->destroyed = 0; +#endif /* DEBUG_VALIDATION */ + SCMutexInit(&my_pool->return_stack.mutex, NULL); + SCCondInit(&my_pool->return_stack.cond, NULL); + SC_ATOMIC_INIT(my_pool->return_stack.sync_now); /* pre allocate packets */ SCLogDebug("preallocating packets... packet size %" PRIuMAX "", @@ -287,16 +394,46 @@ void PacketPoolInit(void) } PacketPoolStorePacket(p); } - SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", - max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); + + //SCLogInfo("preallocated %"PRIiMAX" packets. Total memory %"PRIuMAX"", + // max_pending_packets, (uintmax_t)(max_pending_packets*SIZE_OF_PACKET)); } void PacketPoolDestroy(void) { Packet *p = NULL; + PktPool *my_pool = GetThreadPacketPool(); + +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->destroyed); +#endif /* DEBUG_VALIDATION */ + + if (my_pool && my_pool->pending_pool != NULL) { + p = my_pool->pending_head; + while (p) { + Packet *next_p = p->next; + PacketFree(p); + p = next_p; + my_pool->pending_count--; + } +#ifdef DEBUG_VALIDATION + BUG_ON(my_pool->pending_count); +#endif /* DEBUG_VALIDATION */ + my_pool->pending_pool = NULL; + my_pool->pending_head = NULL; + my_pool->pending_tail = NULL; + } + while ((p = PacketPoolGetPacket()) != NULL) { PacketFree(p); } + + SC_ATOMIC_DESTROY(my_pool->return_stack.sync_now); + +#ifdef DEBUG_VALIDATION + my_pool->initialized = 0; + my_pool->destroyed = 1; +#endif /* DEBUG_VALIDATION */ } Packet *TmqhInputPacketpool(ThreadVars *tv) @@ -311,15 +448,6 @@ void TmqhOutputPacketpool(ThreadVars *t, Packet *p) SCEnter(); SCLogDebug("Packet %p, p->root %p, alloced %s", p, p->root, p->flags & PKT_ALLOC ? "true" : "false"); - /** \todo make this a callback - * Release tcp segments. Done here after alerting can use them. */ - if (p->flow != NULL && p->proto == IPPROTO_TCP) { - SCMutexLock(&p->flow->m); - StreamTcpPruneSession(p->flow, p->flowflags & FLOW_PKT_TOSERVER ? - STREAM_TOSERVER : STREAM_TOCLIENT); - SCMutexUnlock(&p->flow->m); - } - if (IS_TUNNEL_PKT(p)) { SCLogDebug("Packet %p is a tunnel packet: %s", p,p->root ? "upper layer" : "tunnel root"); @@ -430,3 +558,34 @@ void TmqhReleasePacketsToPacketPool(PacketQueue *pq) return; } + +/** + * \brief Set the max_pending_return_packets value + * + * Set it to the max pending packets value, devided by the number + * of lister threads. Normally, in autofp these are the stream/detect/log + * worker threads. + * + * The max_pending_return_packets value needs to stay below the packet + * pool size of the 'producers' (normally pkt capture threads but also + * flow timeout injection ) to avoid a deadlock where all the 'workers' + * keep packets in their return pools, while the capture thread can't + * continue because its pool is empty. + */ +void PacketPoolPostRunmodes(void) +{ + extern intmax_t max_pending_packets; + + uint32_t threads = TmThreadCountThreadsByTmmFlags(TM_FLAG_DETECT_TM); + if (threads == 0) + return; + if (threads > max_pending_packets) + return; + + uint32_t packets = (max_pending_packets / threads) - 1; + if (packets < max_pending_return_packets) + max_pending_return_packets = packets; + + SCLogDebug("detect threads %u, max packets %u, max_pending_return_packets %u", + threads, (uint)threads, max_pending_return_packets); +} diff --git a/src/tmqh-packetpool.h b/src/tmqh-packetpool.h index 729883cd31fe..2b6b90b04e95 100644 --- a/src/tmqh-packetpool.h +++ b/src/tmqh-packetpool.h @@ -26,16 +26,19 @@ #include "decode.h" #include "threads.h" +#include "util-atomic.h" /* Return stack, onto which other threads free packets. */ typedef struct PktPoolLockedStack_{ /* linked list of free packets. */ SCMutex mutex; + SCCondT cond; + SC_ATOMIC_DECLARE(int, sync_now); Packet *head; } __attribute__((aligned(CLS))) PktPoolLockedStack; typedef struct PktPool_ { - /* link listed of free packets local to this thread. + /* link listed of free packets local to this thread. * No mutex is needed. */ Packet *head; @@ -48,8 +51,13 @@ typedef struct PktPool_ { Packet *pending_head; Packet *pending_tail; uint32_t pending_count; - - /* All members above this point are accessed locally by only one thread, so + +#ifdef DEBUG_VALIDATION + int initialized; + int destroyed; +#endif /* DEBUG_VALIDATION */ + + /* All members above this point are accessed locally by only one thread, so * these should live on their own cache line. */ @@ -57,7 +65,6 @@ typedef struct PktPool_ { * to this thread. */ PktPoolLockedStack return_stack; - } PktPool; Packet *TmqhInputPacketpool(ThreadVars *); @@ -66,8 +73,11 @@ void TmqhReleasePacketsToPacketPool(PacketQueue *); void TmqhPacketpoolRegister(void); Packet *PacketPoolGetPacket(void); void PacketPoolWait(void); +void PacketPoolWaitForN(int n); void PacketPoolReturnPacket(Packet *p); void PacketPoolInit(void); +void PacketPoolInitEmpty(void); void PacketPoolDestroy(void); +void PacketPoolPostRunmodes(void); #endif /* __TMQH_PACKETPOOL_H__ */ diff --git a/src/tmqh-ringbuffer.c b/src/tmqh-ringbuffer.c index 95c8c08b1edf..29228e1a7430 100644 --- a/src/tmqh-ringbuffer.c +++ b/src/tmqh-ringbuffer.c @@ -104,7 +104,7 @@ Packet *TmqhInputRingBufferMrSw(ThreadVars *t) Packet *p = (Packet *)RingBufferMrSw8Get(rb); - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); return p; } @@ -121,7 +121,7 @@ Packet *TmqhInputRingBufferSrSw(ThreadVars *t) Packet *p = (Packet *)RingBufferSrSw8Get(rb); - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); return p; } @@ -138,7 +138,7 @@ Packet *TmqhInputRingBufferSrMw(ThreadVars *t) Packet *p = (Packet *)RingBufferSrMw8Get(rb); - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); return p; } diff --git a/src/tmqh-simple.c b/src/tmqh-simple.c index 26aea2adc248..bc09dff340bf 100644 --- a/src/tmqh-simple.c +++ b/src/tmqh-simple.c @@ -47,7 +47,7 @@ Packet *TmqhInputSimple(ThreadVars *t) { PacketQueue *q = &trans_q[t->inq->id]; - SCPerfSyncCountersIfSignalled(t); + StatsSyncCountersIfSignalled(t); SCMutexLock(&q->mutex_q); diff --git a/src/unix-manager.c b/src/unix-manager.c index 2d0a90641aa5..5f9a0e49fb09 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -31,7 +31,9 @@ #include "util-privs.h" #include "util-debug.h" +#include "util-device.h" #include "util-signal.h" +#include "util-buffer.h" #include #include @@ -40,6 +42,8 @@ #ifdef BUILD_UNIX_SOCKET #include +#include "output-json.h" + // MSG_NOSIGNAL does not exists on OS X #ifdef OS_DARWIN # ifndef MSG_NOSIGNAL @@ -65,8 +69,10 @@ typedef struct Task_ { TAILQ_ENTRY(Task_) next; } Task; +#define CLIENT_BUFFER_SIZE 4096 typedef struct UnixClient_ { int fd; + MemBuffer *mbuf; /**< buffer for response construction */ TAILQ_ENTRY(UnixClient_) next; } UnixClient; @@ -91,7 +97,7 @@ int UnixNew(UnixCommand * this) int len; int ret; int on = 1; - char *sockettarget = NULL; + char sockettarget[PATH_MAX]; char *socketname; this->start_timestamp = time(NULL); @@ -102,32 +108,39 @@ int UnixNew(UnixCommand * this) TAILQ_INIT(&this->tasks); TAILQ_INIT(&this->clients); - /* Create socket dir */ - ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); - if ( ret != 0 ) { - int err = errno; - if (err != EEXIST) { - SCLogError(SC_ERR_OPENING_FILE, - "Cannot create socket directory %s: %s", SOCKET_PATH, strerror(err)); - return 0; - } - } - + int check_dir = 0; if (ConfGet("unix-command.filename", &socketname) == 1) { - int socketlen = strlen(SOCKET_PATH) + strlen(socketname) + 2; - sockettarget = SCMalloc(socketlen); - if (unlikely(sockettarget == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); - return 0; + if (PathIsAbsolute(socketname)) { + strlcpy(sockettarget, socketname, sizeof(sockettarget)); + } else { + snprintf(sockettarget, sizeof(sockettarget), "%s/%s", + SOCKET_PATH, socketname); + check_dir = 1; } - snprintf(sockettarget, socketlen, "%s/%s", SOCKET_PATH, socketname); - SCLogInfo("Use unix socket file '%s'.", sockettarget); - } - if (sockettarget == NULL) { - sockettarget = SCStrdup(SOCKET_TARGET); - if (unlikely(sockettarget == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name"); - return 0; + } else { + strlcpy(sockettarget, SOCKET_TARGET, sizeof(sockettarget)); + check_dir = 1; + } + SCLogInfo("Using unix socket file '%s'", sockettarget); + + if (check_dir) { + struct stat stat_buf; + /* coverity[toctou] */ + if (stat(SOCKET_PATH, &stat_buf) != 0) { + /* coverity[toctou] */ + ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP); + if (ret != 0) { + int err = errno; + if (err != EEXIST) { + SCLogError(SC_ERR_INITIALIZATION, + "Cannot create socket directory %s: %s", + SOCKET_PATH, strerror(err)); + return 0; + } + } else { + SCLogInfo("Created socket directory %s", + SOCKET_PATH); + } } } @@ -138,7 +151,7 @@ int UnixNew(UnixCommand * this) addr.sun_family = AF_UNIX; strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path)); addr.sun_path[sizeof(addr.sun_path) - 1] = 0; - len = strlen(addr.sun_path) + sizeof(addr.sun_family); + len = strlen(addr.sun_path) + sizeof(addr.sun_family) + 1; /* create socket */ this->socket = socket(AF_UNIX, SOCK_STREAM, 0); @@ -146,14 +159,14 @@ int UnixNew(UnixCommand * this) SCLogWarning(SC_ERR_OPENING_FILE, "Unix Socket: unable to create UNIX socket %s: %s", addr.sun_path, strerror(errno)); - SCFree(sockettarget); return 0; } this->select_max = this->socket + 1; +#if !(defined OS_FREEBSD || defined __OpenBSD__) /* Set file mode: will not fully work on most system, the group - * permission is not changed on some Linux and *BSD won't do the - * chmod. */ + * permission is not changed on some Linux. *BSD won't do the + * chmod: it returns EINVAL when calling fchmod on sockets. */ ret = fchmod(this->socket, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (ret == -1) { int err = errno; @@ -162,6 +175,7 @@ int UnixNew(UnixCommand * this) strerror(err), err); } +#endif /* set reuse option */ ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); @@ -176,7 +190,6 @@ int UnixNew(UnixCommand * this) SCLogWarning(SC_ERR_INITIALIZATION, "Unix socket: UNIX socket bind(%s) error: %s", sockettarget, strerror(errno)); - SCFree(sockettarget); return 0; } @@ -185,10 +198,8 @@ int UnixNew(UnixCommand * this) SCLogWarning(SC_ERR_INITIALIZATION, "Command server: UNIX socket listen() error: %s", strerror(errno)); - SCFree(sockettarget); return 0; } - SCFree(sockettarget); return 1; } @@ -209,6 +220,30 @@ void UnixCommandSetMaxFD(UnixCommand *this) } } +static UnixClient *UnixClientAlloc(void) +{ + UnixClient *uclient = SCMalloc(sizeof(UnixClient)); + if (unlikely(uclient == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client"); + return NULL; + } + uclient->mbuf = MemBufferCreateNew(CLIENT_BUFFER_SIZE); + if (uclient->mbuf == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client send buffer"); + SCFree(uclient); + return NULL; + } + return uclient; +} + +static void UnixClientFree(UnixClient *c) +{ + if (c != NULL) { + MemBufferFree(c->mbuf); + SCFree(c); + } +} + /** * \brief Close the unix socket */ @@ -233,27 +268,43 @@ void UnixCommandClose(UnixCommand *this, int fd) close(item->fd); UnixCommandSetMaxFD(this); - SCFree(item); + UnixClientFree(item); } -/** - * \brief Callback function used to send message to socket - */ -int UnixCommandSendCallback(const char *buffer, size_t size, void *data) +#define UNIX_PROTO_VERSION_LENGTH 200 +#define UNIX_PROTO_VERSION "0.1" + +int UnixCommandSendJSONToClient(UnixClient *client, json_t *js) { - int fd = *(int *) data; + MemBufferReset(client->mbuf); + + OutputJSONMemBufferWrapper wrapper = { + .buffer = &client->mbuf, + .expand_by = CLIENT_BUFFER_SIZE + }; + + int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + if (r != 0) { + SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object"); + return -1; + } - if (send(fd, buffer, size, MSG_NOSIGNAL) == -1) { - SCLogInfo("Unable to send block: %s", strerror(errno)); + if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf), + MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1) + { + SCLogWarning(SC_ERR_SOCKET, "unable to send block of size " + "%"PRIuMAX": %s", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), + strerror(errno)); return -1; } + SCLogDebug("sent message of size %"PRIuMAX" to client socket %d", + (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), client->fd); return 0; } -#define UNIX_PROTO_VERSION_LENGTH 200 -#define UNIX_PROTO_VERSION "0.1" - /** * \brief Accept a new client on unix socket * @@ -297,6 +348,7 @@ int UnixCommandAccept(UnixCommand *this) SCLogInfo("Command server: client message is too long, " "disconnect him."); close(client); + return 0; } buffer[ret] = 0; @@ -323,7 +375,7 @@ int UnixCommandAccept(UnixCommand *this) close(client); return 0; } else { - SCLogInfo("Unix socket: client version: \"%s\"", + SCLogDebug("Unix socket: client version: \"%s\"", json_string_value(version)); } @@ -336,23 +388,29 @@ int UnixCommandAccept(UnixCommand *this) } json_object_set_new(server_msg, "return", json_string("OK")); - if (json_dump_callback(server_msg, UnixCommandSendCallback, &client, 0) == -1) { + uclient = UnixClientAlloc(); + if (unlikely(uclient == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client"); + json_decref(server_msg); + close(client); + return 0; + } + uclient->fd = client; + + if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) { SCLogWarning(SC_ERR_SOCKET, "Unable to send command"); + + UnixClientFree(uclient); json_decref(server_msg); close(client); return 0; } + json_decref(server_msg); /* client connected */ - SCLogInfo("Unix socket: client connected"); + SCLogDebug("Unix socket: client connected"); - uclient = SCMalloc(sizeof(UnixClient)); - if (unlikely(uclient == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new cient"); - return 0; - } - uclient->fd = client; TAILQ_INSERT_TAIL(&this->clients, uclient, next); UnixCommandSetMaxFD(this); return 1; @@ -442,10 +500,8 @@ int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client) break; } - /* send answer */ - if (json_dump_callback(server_msg, UnixCommandSendCallback, &client->fd, 0) == -1) { - SCLogWarning(SC_ERR_SOCKET, "Unable to send command"); - goto error_cmd; + if (UnixCommandSendJSONToClient(client, server_msg) != 0) { + goto error; } json_decref(jsoncmd); @@ -467,9 +523,9 @@ void UnixCommandRun(UnixCommand * this, UnixClient *client) ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0); if (ret <= 0) { if (ret == 0) { - SCLogInfo("Unix socket: lost connection with client"); + SCLogDebug("Unix socket: lost connection with client"); } else { - SCLogInfo("Unix socket: error on recv() from client: %s", + SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s", strerror(errno)); } UnixCommandClose(this, client->fd); @@ -514,11 +570,14 @@ int UnixMain(UnixCommand * this) if (errno == EINTR) { return 1; } - SCLogInfo("Command server: select() fatal error: %s", strerror(errno)); + SCLogError(SC_ERR_SOCKET, "Command server: select() fatal error: %s", strerror(errno)); return 0; } - if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { + if (suricata_ctl_flags & SURICATA_STOP) { + TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) { + UnixCommandClose(this, uclient->fd); + } return 1; } @@ -551,8 +610,8 @@ void UnixKillUnixManagerThread(void) ThreadVars *tv = NULL; int cnt = 0; +again: SCCtrlCondSignal(&unix_manager_ctrl_cond); - SCMutexLock(&tv_root_lock); /* flow manager thread(s) is/are a part of mgmt threads */ @@ -564,8 +623,10 @@ void UnixKillUnixManagerThread(void) TmThreadsSetFlag(tv, THV_DEINIT); /* be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { + if(!(TmThreadsCheckFlag(tv, THV_CLOSED))) { + SCMutexUnlock(&tv_root_lock); usleep(100); + goto again; } cnt++; } @@ -598,7 +659,7 @@ TmEcode UnixManagerVersionCommand(json_t *cmd, SCEnter(); json_object_set_new(server_msg, "message", json_string( #ifdef REVISION - PROG_VER xstr(REVISION) + PROG_VER " (rev " xstr(REVISION) ")" #elif defined RELEASE PROG_VER " RELEASE" #else @@ -636,6 +697,18 @@ TmEcode UnixManagerCaptureModeCommand(json_t *cmd, SCReturnInt(TM_ECODE_OK); } +TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data) +{ + SCEnter(); + DetectEngineReloadStart(); + + while (DetectEngineReloadIsDone() == 0) + usleep(100); + + json_object_set_new(server_msg, "message", json_string("done")); + SCReturnInt(TM_ECODE_OK); +} + TmEcode UnixManagerConfGetCommand(json_t *cmd, json_t *server_msg, void *data) { @@ -690,7 +763,7 @@ TmEcode UnixManagerListCommand(json_t *cmd, } TAILQ_FOREACH(lcmd, &gcmd->commands, next) { - json_array_append(jarray, json_string(lcmd->name)); + json_array_append_new(jarray, json_string(lcmd->name)); i++; } @@ -759,7 +832,7 @@ TmEcode UnixManagerRegisterCommand(const char * keyword, TAILQ_FOREACH(lcmd, &command.commands, next) { if (!strcmp(keyword, lcmd->name)) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "%s already registered", keyword); SCReturnInt(TM_ECODE_FAILED); } } @@ -818,37 +891,33 @@ TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *), SCReturnInt(TM_ECODE_OK); } -void *UnixManagerThread(void *td) -{ - ThreadVars *th_v = (ThreadVars *)td; - int ret; - - /* set the thread name */ - (void) SCSetThreadName(th_v->name); - SCLogDebug("%s started...", th_v->name); +typedef struct UnixManagerThreadData_ { + int padding; +} UnixManagerThreadData; - th_v->sc_perf_pca = SCPerfGetAllCountersArray(&th_v->sc_perf_pctx); - SCPerfAddToClubbedTMTable(th_v->name, &th_v->sc_perf_pctx); +static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data) +{ + UnixManagerThreadData *utd = SCCalloc(1, sizeof(*utd)); + if (utd == NULL) + return TM_ECODE_FAILED; if (UnixNew(&command) == 0) { int failure_fatal = 0; - SCLogError(SC_ERR_INITIALIZATION, - "Unable to create unix command socket"); if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) { SCLogDebug("ConfGetBool could not load the value."); } + SCFree(utd); if (failure_fatal) { + SCLogError(SC_ERR_INITIALIZATION, + "Unable to create unix command socket"); exit(EXIT_FAILURE); } else { - TmThreadsSetFlag(th_v, THV_INIT_DONE|THV_RUNNING_DONE); - pthread_exit((void *) 0); + SCLogWarning(SC_ERR_INITIALIZATION, + "Unable to create unix command socket"); + return TM_ECODE_FAILED; } } - /* Set the threads capability */ - th_v->cap_flags = 0; - SCDropCaps(th_v); - /* Init Unix socket */ UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0); UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0); @@ -858,10 +927,39 @@ void *UnixManagerThread(void *td) UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0); UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0); UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS); - UnixManagerRegisterCommand("dump-counters", SCPerfOutputCounterSocket, NULL, 0); -#if 0 + UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0); UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0); -#endif + UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS); + + *data = utd; + return TM_ECODE_OK; +} + +static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data) +{ + SCFree(data); + return TM_ECODE_OK; +} + +static TmEcode UnixManager(ThreadVars *th_v, void *thread_data) +{ + int ret; + + /* set the thread name */ + SCLogDebug("%s started...", th_v->name); + + StatsSetupPrivate(th_v); + + /* Set the threads capability */ + th_v->cap_flags = 0; + SCDropCaps(th_v); TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { @@ -877,33 +975,29 @@ void *UnixManagerThread(void *td) close(item->fd); SCFree(item); } - SCPerfSyncCounters(th_v); + StatsSyncCounters(th_v); break; } UnixCommandBackgroundTasks(&command); } - TmThreadWaitForFlag(th_v, THV_DEINIT); - - TmThreadsSetFlag(th_v, THV_CLOSED); - pthread_exit((void *) 0); + return TM_ECODE_OK; } /** \brief Spawn the unix socket manager thread * - * \param de_ctx context for detection engine * \param mode if set to 1, init failure cause suricata exit * */ -void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) +void UnixManagerThreadSpawn(int mode) { ThreadVars *tv_unixmgr = NULL; SCCtrlCondInit(&unix_manager_ctrl_cond, NULL); SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL); - tv_unixmgr = TmThreadCreateCmdThread("UnixManagerThread", - UnixManagerThread, 0); + tv_unixmgr = TmThreadCreateCmdThreadByName(thread_name_unix_socket, + "UnixManager", 0); if (tv_unixmgr == NULL) { SCLogError(SC_ERR_INITIALIZATION, "TmThreadsCreate failed"); @@ -922,6 +1016,19 @@ void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) return; } +// TODO can't think of a good name +void UnixManagerThreadSpawnNonRunmode(void) +{ + /* Spawn the unix socket manager thread */ + int unix_socket = ConfUnixSocketIsEnable(); + if (unix_socket == 1) { + UnixManagerThreadSpawn(0); + UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL, + UNIX_CMD_TAKE_ARGS); + UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0); + } +} + /** * \brief Used to kill unix manager thread(s). * @@ -932,6 +1039,7 @@ void UnixSocketKillSocketThread(void) { ThreadVars *tv = NULL; +again: SCMutexLock(&tv_root_lock); /* unix manager thread(s) is/are a part of command threads */ @@ -952,8 +1060,10 @@ void UnixSocketKillSocketThread(void) TmThreadsSetFlag(tv, THV_KILL); TmThreadsSetFlag(tv, THV_DEINIT); /* Be sure it has shut down */ - while (!TmThreadsCheckFlag(tv, THV_CLOSED)) { + if (!TmThreadsCheckFlag(tv, THV_CLOSED)) { + SCMutexUnlock(&tv_root_lock); usleep(100); + goto again; } } tv = tv->next; @@ -965,7 +1075,7 @@ void UnixSocketKillSocketThread(void) #else /* BUILD_UNIX_SOCKET */ -void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) +void UnixManagerThreadSpawn(int mode) { SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled"); return; @@ -976,4 +1086,21 @@ void UnixSocketKillSocketThread(void) return; } +void UnixManagerThreadSpawnNonRunmode(void) +{ + return; +} + +#endif /* BUILD_UNIX_SOCKET */ + +void TmModuleUnixManagerRegister (void) +{ +#ifdef BUILD_UNIX_SOCKET + tmm_modules[TMM_UNIXMANAGER].name = "UnixManager"; + tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit; + tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit; + tmm_modules[TMM_UNIXMANAGER].Management = UnixManager; + tmm_modules[TMM_UNIXMANAGER].cap_flags = 0; + tmm_modules[TMM_UNIXMANAGER].flags = TM_FLAG_COMMAND_TM; #endif /* BUILD_UNIX_SOCKET */ +} diff --git a/src/unix-manager.h b/src/unix-manager.h index 937737ef110a..5ec3c889e348 100644 --- a/src/unix-manager.h +++ b/src/unix-manager.h @@ -33,10 +33,9 @@ SCCtrlCondT unix_manager_ctrl_cond; SCCtrlMutex unix_manager_ctrl_mutex; -void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode); +void UnixManagerThreadSpawn(int mode); void UnixSocketKillSocketThread(void); - #ifdef BUILD_UNIX_SOCKET TmEcode UnixManagerRegisterCommand(const char * keyword, TmEcode (*Func)(json_t *, json_t *, void *), @@ -46,4 +45,7 @@ TmEcode UnixManagerRegisterBackgroundTask( void *data); #endif +void TmModuleUnixManagerRegister(void); +void UnixManagerThreadSpawnNonRunmode(void); + #endif /* UNIX_MANAGER_H */ diff --git a/src/util-action.c b/src/util-action.c index 2b3497489891..a47e79dfcad6 100644 --- a/src/util-action.c +++ b/src/util-action.c @@ -163,7 +163,6 @@ int ActionInitConfig() } #ifdef UNITTESTS -#include "util-unittest.h" /** * \test Check that we invalidate duplicated actions @@ -1598,30 +1597,30 @@ void UtilActionRegisterTests(void) { #ifdef UNITTESTS /* Generic tests */ - UtRegisterTest("UtilActionTest01", UtilActionTest01, 1); - UtRegisterTest("UtilActionTest02", UtilActionTest02, 1); - UtRegisterTest("UtilActionTest02", UtilActionTest02, 1); - UtRegisterTest("UtilActionTest03", UtilActionTest03, 1); - UtRegisterTest("UtilActionTest04", UtilActionTest04, 1); - UtRegisterTest("UtilActionTest05", UtilActionTest05, 1); - UtRegisterTest("UtilActionTest06", UtilActionTest06, 1); - UtRegisterTest("UtilActionTest07", UtilActionTest07, 1); - UtRegisterTest("UtilActionTest08", UtilActionTest08, 1); - UtRegisterTest("UtilActionTest09", UtilActionTest09, 1); - UtRegisterTest("UtilActionTest10", UtilActionTest10, 1); - UtRegisterTest("UtilActionTest11", UtilActionTest11, 1); - UtRegisterTest("UtilActionTest12", UtilActionTest12, 1); - UtRegisterTest("UtilActionTest13", UtilActionTest13, 1); - UtRegisterTest("UtilActionTest14", UtilActionTest14, 1); - UtRegisterTest("UtilActionTest15", UtilActionTest15, 1); - UtRegisterTest("UtilActionTest16", UtilActionTest16, 1); - UtRegisterTest("UtilActionTest17", UtilActionTest17, 1); - UtRegisterTest("UtilActionTest18", UtilActionTest18, 1); - UtRegisterTest("UtilActionTest19", UtilActionTest19, 1); - UtRegisterTest("UtilActionTest20", UtilActionTest20, 1); - UtRegisterTest("UtilActionTest21", UtilActionTest21, 1); - UtRegisterTest("UtilActionTest22", UtilActionTest22, 1); - UtRegisterTest("UtilActionTest23", UtilActionTest23, 1); - UtRegisterTest("UtilActionTest24", UtilActionTest24, 1); + UtRegisterTest("UtilActionTest01", UtilActionTest01); + UtRegisterTest("UtilActionTest02", UtilActionTest02); + UtRegisterTest("UtilActionTest02", UtilActionTest02); + UtRegisterTest("UtilActionTest03", UtilActionTest03); + UtRegisterTest("UtilActionTest04", UtilActionTest04); + UtRegisterTest("UtilActionTest05", UtilActionTest05); + UtRegisterTest("UtilActionTest06", UtilActionTest06); + UtRegisterTest("UtilActionTest07", UtilActionTest07); + UtRegisterTest("UtilActionTest08", UtilActionTest08); + UtRegisterTest("UtilActionTest09", UtilActionTest09); + UtRegisterTest("UtilActionTest10", UtilActionTest10); + UtRegisterTest("UtilActionTest11", UtilActionTest11); + UtRegisterTest("UtilActionTest12", UtilActionTest12); + UtRegisterTest("UtilActionTest13", UtilActionTest13); + UtRegisterTest("UtilActionTest14", UtilActionTest14); + UtRegisterTest("UtilActionTest15", UtilActionTest15); + UtRegisterTest("UtilActionTest16", UtilActionTest16); + UtRegisterTest("UtilActionTest17", UtilActionTest17); + UtRegisterTest("UtilActionTest18", UtilActionTest18); + UtRegisterTest("UtilActionTest19", UtilActionTest19); + UtRegisterTest("UtilActionTest20", UtilActionTest20); + UtRegisterTest("UtilActionTest21", UtilActionTest21); + UtRegisterTest("UtilActionTest22", UtilActionTest22); + UtRegisterTest("UtilActionTest23", UtilActionTest23); + UtRegisterTest("UtilActionTest24", UtilActionTest24); #endif } diff --git a/src/util-affinity.c b/src/util-affinity.c index 82456c20cd11..37539aef66b5 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Open Information Security Foundation +/* Copyright (C) 2010-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -39,19 +39,7 @@ ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { .lcpu = 0, }, { - .name = "decode-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "stream-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "detect-cpu-set", + .name = "worker-cpu-set", .mode_flag = EXCLUSIVE_AFFINITY, .prio = PRIO_MEDIUM, .lcpu = 0, @@ -62,18 +50,6 @@ ThreadsAffinityType thread_affinity[MAX_CPU_SET] = { .prio = PRIO_MEDIUM, .lcpu = 0, }, - { - .name = "reject-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, - { - .name = "output-cpu-set", - .mode_flag = BALANCED_AFFINITY, - .prio = PRIO_MEDIUM, - .lcpu = 0, - }, { .name = "management-cpu-set", .mode_flag = BALANCED_AFFINITY, @@ -100,7 +76,7 @@ ThreadsAffinityType * GetAffinityTypeFromName(const char *name) return NULL; } -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun static void AffinitySetupInit() { int i, j; @@ -119,7 +95,7 @@ static void AffinitySetupInit() return; } -static void build_cpuset(char *name, ConfNode *node, cpu_set_t *cpu) +static void BuildCpuset(const char *name, ConfNode *node, cpu_set_t *cpu) { ConfNode *lnode; TAILQ_FOREACH(lnode, &node->head, next) { @@ -190,7 +166,7 @@ static void build_cpuset(char *name, ConfNode *node, cpu_set_t *cpu) void AffinitySetupLoadFromConfig() { -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun ConfNode *root = ConfGetNode("threading.cpu-affinity"); ConfNode *affinity; @@ -206,7 +182,18 @@ void AffinitySetupLoadFromConfig() } TAILQ_FOREACH(affinity, &root->head, next) { - ThreadsAffinityType *taf = GetAffinityTypeFromName(affinity->val); + if (strcmp(affinity->val, "decode-cpu-set") == 0 || + strcmp(affinity->val, "stream-cpu-set") == 0 || + strcmp(affinity->val, "reject-cpu-set") == 0 || + strcmp(affinity->val, "output-cpu-set") == 0) { + continue; + } + + const char *setname = affinity->val; + if (strcmp(affinity->val, "detect-cpu-set") == 0) + setname = "worker-cpu-set"; + + ThreadsAffinityType *taf = GetAffinityTypeFromName(setname); ConfNode *node = NULL; ConfNode *nprio = NULL; @@ -214,8 +201,7 @@ void AffinitySetupLoadFromConfig() SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu-affinity type"); exit(EXIT_FAILURE); } else { - SCLogInfo("Found affinity definition for \"%s\"", - affinity->val); + SCLogConfig("Found affinity definition for \"%s\"", setname); } CPU_ZERO(&taf->cpu_set); @@ -223,7 +209,7 @@ void AffinitySetupLoadFromConfig() if (node == NULL) { SCLogInfo("unable to find 'cpu'"); } else { - build_cpuset(affinity->val, node, &taf->cpu_set); + BuildCpuset(setname, node, &taf->cpu_set); } CPU_ZERO(&taf->lowprio_cpu); @@ -235,21 +221,21 @@ void AffinitySetupLoadFromConfig() if (node == NULL) { SCLogDebug("unable to find 'low' prio using default value"); } else { - build_cpuset(affinity->val, node, &taf->lowprio_cpu); + BuildCpuset(setname, node, &taf->lowprio_cpu); } node = ConfNodeLookupChild(nprio, "medium"); if (node == NULL) { SCLogDebug("unable to find 'medium' prio using default value"); } else { - build_cpuset(affinity->val, node, &taf->medprio_cpu); + BuildCpuset(setname, node, &taf->medprio_cpu); } node = ConfNodeLookupChild(nprio, "high"); if (node == NULL) { SCLogDebug("unable to find 'high' prio using default value"); } else { - build_cpuset(affinity->val, node, &taf->hiprio_cpu); + BuildCpuset(setname, node, &taf->hiprio_cpu); } node = ConfNodeLookupChild(nprio, "default"); if (node != NULL) { @@ -263,7 +249,8 @@ void AffinitySetupLoadFromConfig() SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu_affinity prio"); exit(EXIT_FAILURE); } - SCLogInfo("Using default prio '%s'", node->val); + SCLogConfig("Using default prio '%s' for set '%s'", + node->val, setname); } } @@ -298,8 +285,7 @@ void AffinitySetupLoadFromConfig() int AffinityGetNextCPU(ThreadsAffinityType *taf) { int ncpu = 0; - -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun int iter = 0; SCMutexLock(&taf->taf_mutex); ncpu = taf->lcpu; @@ -311,13 +297,14 @@ int AffinityGetNextCPU(ThreadsAffinityType *taf) } } if (iter == 2) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contains available cpus, cpu afinity conf is invalid"); + SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contain " + "available cpus, cpu affinity conf is invalid"); } taf->lcpu = ncpu + 1; if (taf->lcpu >= UtilCpuGetNumProcessorsOnline()) taf->lcpu = 0; SCMutexUnlock(&taf->taf_mutex); - SCLogInfo("Setting affinity on CPU %d", ncpu); + SCLogDebug("Setting affinity on CPU %d", ncpu); #endif /* OS_WIN32 and __OpenBSD__ */ return ncpu; } diff --git a/src/util-affinity.h b/src/util-affinity.h index 9ca30fcfe2d7..bd9e1626ea0b 100644 --- a/src/util-affinity.h +++ b/src/util-affinity.h @@ -48,12 +48,8 @@ enum { RECEIVE_CPU_SET, - DECODE_CPU_SET, - STREAM_CPU_SET, - DETECT_CPU_SET, + WORKER_CPU_SET, VERDICT_CPU_SET, - REJECT_CPU_SET, - OUTPUT_CPU_SET, MANAGEMENT_CPU_SET, MAX_CPU_SET }; @@ -65,20 +61,19 @@ enum { }; typedef struct ThreadsAffinityType_ { - char *name; -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ - cpu_set_t cpu_set; -#endif + const char *name; uint8_t mode_flag; int prio; int nb_threads; -#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ + SCMutex taf_mutex; + uint16_t lcpu; /* use by exclusive mode */ + +#if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun + cpu_set_t cpu_set; cpu_set_t lowprio_cpu; cpu_set_t medprio_cpu; cpu_set_t hiprio_cpu; #endif - SCMutex taf_mutex; - uint16_t lcpu; /* use by exclusive mode */ } ThreadsAffinityType; /** store thread affinity mode for all type of threads */ diff --git a/src/util-atomic.c b/src/util-atomic.c index 9ad448e693d4..569f4c0a344f 100644 --- a/src/util-atomic.c +++ b/src/util-atomic.c @@ -66,7 +66,7 @@ static int SCAtomicTest01(void) void SCAtomicRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCAtomicTest01", SCAtomicTest01, 1); + UtRegisterTest("SCAtomicTest01", SCAtomicTest01); #endif return; diff --git a/src/util-base64.c b/src/util-base64.c new file mode 100644 index 000000000000..bea92d52bb4b --- /dev/null +++ b/src/util-base64.c @@ -0,0 +1,151 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#include "util-base64.h" + +/* Constants */ +#define BASE64_TABLE_MAX 122 + +/* Base64 character to index conversion table */ +/* Characters are mapped as "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */ +static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51 }; + +/** + * \brief Gets a base64-decoded value from an encoded character + * + * \param c The encoded character + * + * \return The decoded value (0 or above), or -1 if the parameter is invalid + */ +static inline int GetBase64Value(uint8_t c) +{ + int val = -1; + + /* Pull from conversion table */ + if (c <= BASE64_TABLE_MAX) { + val = b64table[(int) c]; + } + + return val; +} + +/** + * \brief Decodes a 4-byte base64-encoded block into a 3-byte ascii-encoded block + * + * \param ascii the 3-byte ascii output block + * \param b64 the 4-byte base64 input block + * + * \return none + */ +static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) +{ + ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4); + ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2); + ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]); +} + +/** + * \brief Decodes a base64-encoded string buffer into an ascii-encoded byte buffer + * + * \param dest The destination byte buffer + * \param src The source string + * \param len The length of the source string + * \param strict If set file on invalid byte, otherwise return what has been + * decoded. + * + * \return Number of bytes decoded, or 0 if no data is decoded or it fails + */ +uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, + int strict) +{ + int val; + uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; + uint8_t *dptr = dest; + uint8_t b64[B64_BLOCK] = { 0,0,0,0 }; + + /* Traverse through each alpha-numeric letter in the source array */ + for(i = 0; i < len && src[i] != 0; i++) { + + /* Get decimal representation */ + val = GetBase64Value(src[i]); + if (val < 0) { + + /* Invalid character found, so decoding fails */ + if (src[i] != '=') { + valid = 0; + if (strict) { + numDecoded = 0; + } + break; + } + padding++; + } + + /* For each alpha-numeric letter in the source array, find the numeric + * value */ + b64[bbidx++] = (val > 0 ? val : 0); + + /* Decode every 4 base64 bytes into 3 ascii bytes */ + if (bbidx == B64_BLOCK) { + + /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */ + numDecoded += ASCII_BLOCK - (padding < B64_BLOCK ? + padding : ASCII_BLOCK); + + /* Decode base-64 block into ascii block and move pointer */ + DecodeBase64Block(dptr, b64); + dptr += ASCII_BLOCK; + + /* Reset base-64 block and index */ + bbidx = 0; + padding = 0; + } + } + + /* Finish remaining b64 bytes by padding */ + if (valid && bbidx > 0) { + + /* Decode remaining */ + numDecoded += ASCII_BLOCK - (B64_BLOCK - bbidx); + DecodeBase64Block(dptr, b64); + } + + if (numDecoded == 0) { + SCLogDebug("base64 decoding failed"); + } + + return numDecoded; +} diff --git a/src/util-base64.h b/src/util-base64.h new file mode 100644 index 000000000000..7c8bed626261 --- /dev/null +++ b/src/util-base64.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2007-2012 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#ifndef __UTIL_BASE64_H_ +#define __UTIL_BASE64_H_ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" + +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-engine-state.h" + +#include "flow.h" +#include "flow-var.h" +#include "flow-util.h" + +#include "util-debug.h" +#include "util-spm-bm.h" + +/* Constants */ +#define ASCII_BLOCK 3 +#define B64_BLOCK 4 + +/* Function prototypes */ +uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, + int strict); + +#endif diff --git a/src/util-bloomfilter-counting.c b/src/util-bloomfilter-counting.c index 443b8d79e9ad..66dac54d77f7 100644 --- a/src/util-bloomfilter-counting.c +++ b/src/util-bloomfilter-counting.c @@ -393,18 +393,28 @@ static int BloomFilterCountingTestFull02 (void) void BloomFilterCountingRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("BloomFilterCountingTestInit01", BloomFilterCountingTestInit01, 1); - UtRegisterTest("BloomFilterCountingTestInit02", BloomFilterCountingTestInit02, 1); - UtRegisterTest("BloomFilterCountingTestInit03", BloomFilterCountingTestInit03, 1); - UtRegisterTest("BloomFilterCountingTestInit04", BloomFilterCountingTestInit04, 1); - UtRegisterTest("BloomFilterCountingTestInit05", BloomFilterCountingTestInit05, 1); - UtRegisterTest("BloomFilterCountingTestInit06", BloomFilterCountingTestInit06, 1); - - UtRegisterTest("BloomFilterCountingTestAdd01", BloomFilterCountingTestAdd01, 1); - UtRegisterTest("BloomFilterCountingTestAdd02", BloomFilterCountingTestAdd02, 1); - - UtRegisterTest("BloomFilterCountingTestFull01", BloomFilterCountingTestFull01, 1); - UtRegisterTest("BloomFilterCountingTestFull02", BloomFilterCountingTestFull02, 1); + UtRegisterTest("BloomFilterCountingTestInit01", + BloomFilterCountingTestInit01); + UtRegisterTest("BloomFilterCountingTestInit02", + BloomFilterCountingTestInit02); + UtRegisterTest("BloomFilterCountingTestInit03", + BloomFilterCountingTestInit03); + UtRegisterTest("BloomFilterCountingTestInit04", + BloomFilterCountingTestInit04); + UtRegisterTest("BloomFilterCountingTestInit05", + BloomFilterCountingTestInit05); + UtRegisterTest("BloomFilterCountingTestInit06", + BloomFilterCountingTestInit06); + + UtRegisterTest("BloomFilterCountingTestAdd01", + BloomFilterCountingTestAdd01); + UtRegisterTest("BloomFilterCountingTestAdd02", + BloomFilterCountingTestAdd02); + + UtRegisterTest("BloomFilterCountingTestFull01", + BloomFilterCountingTestFull01); + UtRegisterTest("BloomFilterCountingTestFull02", + BloomFilterCountingTestFull02); #endif } diff --git a/src/util-bloomfilter.c b/src/util-bloomfilter.c index 5718fb1002c6..7403f5f7629f 100644 --- a/src/util-bloomfilter.c +++ b/src/util-bloomfilter.c @@ -27,7 +27,8 @@ #include "util-bloomfilter.h" #include "util-unittest.h" -BloomFilter *BloomFilterInit(uint32_t size, uint8_t iter, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)) { +BloomFilter *BloomFilterInit(uint32_t size, uint8_t iter, + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)) { BloomFilter *bf = NULL; if (size == 0 || iter == 0) @@ -122,7 +123,7 @@ uint32_t BloomFilterMemorySize(BloomFilter *bf) */ #ifdef UNITTESTS -static uint32_t BloomFilterTestHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) +static uint32_t BloomFilterTestHash(const void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { uint8_t *d = (uint8_t *)data; uint32_t i; @@ -274,17 +275,17 @@ static int BloomFilterTestFull02 (void) void BloomFilterRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01, 1); - UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02, 1); - UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03, 1); - UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04, 1); - UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05, 1); + UtRegisterTest("BloomFilterTestInit01", BloomFilterTestInit01); + UtRegisterTest("BloomFilterTestInit02", BloomFilterTestInit02); + UtRegisterTest("BloomFilterTestInit03", BloomFilterTestInit03); + UtRegisterTest("BloomFilterTestInit04", BloomFilterTestInit04); + UtRegisterTest("BloomFilterTestInit05", BloomFilterTestInit05); - UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01, 1); - UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02, 1); + UtRegisterTest("BloomFilterTestAdd01", BloomFilterTestAdd01); + UtRegisterTest("BloomFilterTestAdd02", BloomFilterTestAdd02); - UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01, 1); - UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02, 1); + UtRegisterTest("BloomFilterTestFull01", BloomFilterTestFull01); + UtRegisterTest("BloomFilterTestFull02", BloomFilterTestFull02); #endif /* UNITTESTS */ } diff --git a/src/util-bloomfilter.h b/src/util-bloomfilter.h index e7a5874f612d..59b5dcdca5ab 100644 --- a/src/util-bloomfilter.h +++ b/src/util-bloomfilter.h @@ -27,13 +27,13 @@ /* Bloom Filter structure */ typedef struct BloomFilter_ { uint8_t hash_iterations; - uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t); + uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t); uint32_t bitarray_size; uint8_t *bitarray; } BloomFilter; /* prototypes */ -BloomFilter *BloomFilterInit(uint32_t, uint8_t, uint32_t (*Hash)(void *, uint16_t, uint8_t, uint32_t)); +BloomFilter *BloomFilterInit(uint32_t, uint8_t, uint32_t (*Hash)(const void *, uint16_t, uint8_t, uint32_t)); void BloomFilterFree(BloomFilter *); void BloomFilterPrint(BloomFilter *); int BloomFilterAdd(BloomFilter *, void *, uint16_t); @@ -44,9 +44,9 @@ void BloomFilterRegisterTests(void); /** ----- Inline functions ---- */ -static inline int BloomFilterTest(BloomFilter *, void *, uint16_t); +static inline int BloomFilterTest(const BloomFilter *, const void *, uint16_t); -static inline int BloomFilterTest(BloomFilter *bf, void *data, uint16_t datalen) +static inline int BloomFilterTest(const BloomFilter *bf, const void *data, uint16_t datalen) { uint8_t iter = 0; uint32_t hash = 0; diff --git a/src/util-buffer.c b/src/util-buffer.c index 8dd108e8ef37..d4f50b06a41b 100644 --- a/src/util-buffer.c +++ b/src/util-buffer.c @@ -51,6 +51,34 @@ MemBuffer *MemBufferCreateNew(uint32_t size) return buffer; } +/** \brief expand membuffer by size of 'expand_by' + * + * If expansion failed, buffer will still be valid. + * + * \retval result 0 ok, -1 expansion failed + */ +int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by) { + if (((*buffer)->size + expand_by) > MAX_LIMIT) { + SCLogWarning(SC_ERR_MEM_BUFFER_API, "Mem buffer asked to create " + "buffer with size greater than API limit - %d", MAX_LIMIT); + return -1; + } + + uint32_t total_size = (*buffer)->size + sizeof(MemBuffer) + expand_by; + + MemBuffer *tbuffer = SCRealloc(*buffer, total_size); + if (unlikely(tbuffer == NULL)) { + return -1; + } + + *buffer = tbuffer; + (*buffer)->size += expand_by; + (*buffer)->buffer = (uint8_t *)tbuffer + sizeof(MemBuffer); + + SCLogDebug("expanded buffer by %u, size is now %u", expand_by, (*buffer)->size); + return 0; +} + void MemBufferFree(MemBuffer *buffer) { SCFree(buffer); diff --git a/src/util-buffer.h b/src/util-buffer.h index 5c592ae43a32..cc7616ccfb6d 100644 --- a/src/util-buffer.h +++ b/src/util-buffer.h @@ -31,6 +31,7 @@ typedef struct MemBuffer_ { } MemBuffer; MemBuffer *MemBufferCreateNew(uint32_t size); +int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by); void MemBufferFree(MemBuffer *buffer); /** @@ -53,6 +54,11 @@ void MemBufferFree(MemBuffer *buffer); */ #define MEMBUFFER_OFFSET(mem_buffer) (mem_buffer)->offset +/** + * \brief Get the MemBuffers current size. + */ +#define MEMBUFFER_SIZE(mem_buffer) (mem_buffer)->size + /** * \brief Write a buffer to the file pointer. * @@ -129,7 +135,7 @@ void MemBufferFree(MemBuffer *buffer); \ if (((raw_buffer_len) >= (dst)->size - (dst)->offset)) { \ SCLogDebug("Truncating data write since it exceeded buffer limit of " \ - "- %"PRIu32"\n", (dst)->size); \ + "- %"PRIu32, (dst)->size); \ write_len = ((dst)->size - (dst)->offset) - 1; \ } else { \ write_len = (raw_buffer_len); \ @@ -138,8 +144,6 @@ void MemBufferFree(MemBuffer *buffer); memcpy((dst)->buffer + (dst)->offset, (raw_buffer), write_len); \ (dst)->offset += write_len; \ dst->buffer[dst->offset] = '\0'; \ - \ - return; \ } while (0) /** diff --git a/src/util-byte.c b/src/util-byte.c index 6f0cd132314c..f0d0a1332cef 100644 --- a/src/util-byte.c +++ b/src/util-byte.c @@ -207,7 +207,7 @@ int ByteExtractStringUint32(uint32_t *res, int base, uint16_t len, const char *s if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIu64 " > %" PRIu32 ")", i64, UINT_MAX); + "(%" PRIu64 " > %" PRIuMAX ")", i64, (uintmax_t)UINT_MAX); return -1; } @@ -228,7 +228,7 @@ int ByteExtractStringUint16(uint16_t *res, int base, uint16_t len, const char *s if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIu64 " > %" PRIu16 ")", i64, USHRT_MAX); + "(%" PRIu64 " > %" PRIuMAX ")", i64, (uintmax_t)USHRT_MAX); return -1; } @@ -249,7 +249,7 @@ int ByteExtractStringUint8(uint8_t *res, int base, uint16_t len, const char *str if ((uint64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIu64 " > %" PRIu8 ")", i64, UCHAR_MAX); + "(%" PRIu64 " > %" PRIuMAX ")", i64, (uintmax_t)UCHAR_MAX); return -1; } @@ -326,7 +326,7 @@ int ByteExtractStringInt32(int32_t *res, int base, uint16_t len, const char *str if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIi64 " > %" PRIi32 ")\n", i64, INT_MAX); + "(%" PRIi64 " > %" PRIiMAX ")\n", i64, (intmax_t)INT_MAX); return -1; } @@ -347,7 +347,7 @@ int ByteExtractStringInt16(int16_t *res, int base, uint16_t len, const char *str if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIi64 " > %" PRIi16 ")\n", i64, SHRT_MAX); + "(%" PRIi64 " > %" PRIiMAX ")\n", i64, (intmax_t)SHRT_MAX); return -1; } @@ -368,7 +368,7 @@ int ByteExtractStringInt8(int8_t *res, int base, uint16_t len, const char *str) if ((int64_t)(*res) != i64) { SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range " - "(%" PRIi64 " > %" PRIi8 ")\n", i64, CHAR_MAX); + "(%" PRIi64 " > %" PRIiMAX ")\n", i64, (intmax_t)CHAR_MAX); return -1; } @@ -607,22 +607,22 @@ static int ByteTest16 (void) void ByteRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ByteTest01", ByteTest01, 1); - UtRegisterTest("ByteTest02", ByteTest02, 1); - UtRegisterTest("ByteTest03", ByteTest03, 1); - UtRegisterTest("ByteTest04", ByteTest04, 1); - UtRegisterTest("ByteTest05", ByteTest05, 1); - UtRegisterTest("ByteTest06", ByteTest06, 1); - UtRegisterTest("ByteTest07", ByteTest07, 1); - UtRegisterTest("ByteTest08", ByteTest08, 1); - UtRegisterTest("ByteTest09", ByteTest09, 1); - UtRegisterTest("ByteTest10", ByteTest10, 1); - UtRegisterTest("ByteTest11", ByteTest11, 1); - UtRegisterTest("ByteTest12", ByteTest12, 1); - UtRegisterTest("ByteTest13", ByteTest13, 1); - UtRegisterTest("ByteTest14", ByteTest14, 1); - UtRegisterTest("ByteTest15", ByteTest15, 1); - UtRegisterTest("ByteTest16", ByteTest16, 1); + UtRegisterTest("ByteTest01", ByteTest01); + UtRegisterTest("ByteTest02", ByteTest02); + UtRegisterTest("ByteTest03", ByteTest03); + UtRegisterTest("ByteTest04", ByteTest04); + UtRegisterTest("ByteTest05", ByteTest05); + UtRegisterTest("ByteTest06", ByteTest06); + UtRegisterTest("ByteTest07", ByteTest07); + UtRegisterTest("ByteTest08", ByteTest08); + UtRegisterTest("ByteTest09", ByteTest09); + UtRegisterTest("ByteTest10", ByteTest10); + UtRegisterTest("ByteTest11", ByteTest11); + UtRegisterTest("ByteTest12", ByteTest12); + UtRegisterTest("ByteTest13", ByteTest13); + UtRegisterTest("ByteTest14", ByteTest14); + UtRegisterTest("ByteTest15", ByteTest15); + UtRegisterTest("ByteTest16", ByteTest16); #endif /* UNITTESTS */ } diff --git a/src/util-byte.h b/src/util-byte.h index 82c16a4d1c50..aca846ac2bfe 100644 --- a/src/util-byte.h +++ b/src/util-byte.h @@ -45,7 +45,7 @@ #define SCByteSwap16(x) OSSwapInt16(x) #define SCByteSwap32(x) OSSwapInt32(x) #define SCByteSwap64(x) OSSwapInt64(x) -#elif defined(__WIN32) || defined(_WIN32) +#elif defined(__WIN32) || defined(_WIN32) || defined(sun) /* Quick & dirty solution, nothing seems to exist for this in Win32 API */ #define SCByteSwap16(x) \ ((((x) & 0xff00) >> 8) \ diff --git a/src/util-checksum.c b/src/util-checksum.c index 455e2f52aa77..245f3b6908ca 100644 --- a/src/util-checksum.c +++ b/src/util-checksum.c @@ -33,27 +33,27 @@ int ReCalculateChecksum(Packet *p) if (PKT_IS_TCP(p)) { /* TCP */ p->tcph->th_sum = 0; - p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); + p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; - p->udph->uh_sum = UDPV4CalculateChecksum(p->ip4h->s_ip_addrs, - (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN)); + p->udph->uh_sum = UDPV4Checksum(p->ip4h->s_ip_addrs, + (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } /* IPV4 */ p->ip4h->ip_csum = 0; - p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, - IPV4_GET_RAW_HLEN(p->ip4h)); + p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, + IPV4_GET_RAW_HLEN(p->ip4h), 0); } else if (PKT_IS_IPV6(p)) { /* just TCP for IPV6 */ if (PKT_IS_TCP(p)) { p->tcph->th_sum = 0; - p->tcph->th_sum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p))); + p->tcph->th_sum = TCPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; - p->udph->uh_sum = UDPV6CalculateChecksum(p->ip6h->s_ip6_addrs, - (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN)); + p->udph->uh_sum = UDPV6Checksum(p->ip6h->s_ip6_addrs, + (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } } diff --git a/src/util-classification-config.c b/src/util-classification-config.c index 3a0d62a8cb4a..a5d4bdbe99a8 100644 --- a/src/util-classification-config.c +++ b/src/util-classification-config.c @@ -47,9 +47,6 @@ #define SC_CLASS_CONF_DEF_CONF_FILEPATH CONFIG_DIR "/classification.config" #endif -/* Holds a pointer to the default path for the classification.config file */ -static const char *default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; -static FILE *fd = NULL; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -57,7 +54,43 @@ uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datale char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2); void SCClassConfClasstypeHashFree(void *ch); -static char *SCClassConfGetConfFilename(void); +static char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx); + +void SCClassConfInit(void) +{ + const char *eb = NULL; + int eo; + int opts = 0; + + regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL); + if (regex == NULL) { + SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", + DETECT_CLASSCONFIG_REGEX, eo, eb); + return; + } + + regex_study = pcre_study(regex, 0, &eb); + if (eb != NULL) { + pcre_free(regex); + regex = NULL; + SCLogDebug("pcre study failed: %s", eb); + return; + } + return; +} + +void SCClassConfDeinit(void) +{ + if (regex != NULL) { + pcre_free(regex); + regex = NULL; + } + if (regex_study != NULL) { + pcre_free(regex_study); + regex_study = NULL; + } +} + /** * \brief Inits the context to be used by the Classification Config parsing API. @@ -70,18 +103,14 @@ static char *SCClassConfGetConfFilename(void); * * \param de_ctx Pointer to the Detection Engine Context. * - * \retval 0 On success. - * \retval -1 On failure. + * \retval fp NULL on error */ -int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) +FILE *SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { char *filename = NULL; - const char *eb = NULL; - int eo; - int opts = 0; /* init the hash table to be used by the classification config Classtypes */ - de_ctx->class_conf_ht = HashTableInit(4096, SCClassConfClasstypeHashFunc, + de_ctx->class_conf_ht = HashTableInit(128, SCClassConfClasstypeHashFunc, SCClassConfClasstypeHashCompareFunc, SCClassConfClasstypeHashFree); if (de_ctx->class_conf_ht == NULL) { @@ -95,27 +124,18 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) * instead use an input stream against a buffer containing the * classification strings */ if (fd == NULL) { - filename = SCClassConfGetConfFilename(); + filename = SCClassConfGetConfFilename(de_ctx); if ( (fd = fopen(filename, "r")) == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) + goto error; // silently fail +#endif SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } } - regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", - DETECT_CLASSCONFIG_REGEX, eo, eb); - goto error; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - - return 0; + return fd; error: if (de_ctx->class_conf_ht != NULL) { @@ -127,16 +147,7 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) fd = NULL; } - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; - } - - return -1; + return NULL; } @@ -149,12 +160,26 @@ int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) * \retval log_filename Pointer to a string containing the path for the * Classification Config file. */ -static char *SCClassConfGetConfFilename(void) +static char *SCClassConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *log_filename = NULL; - if (ConfGet("classification-file", &log_filename) != 1) { - log_filename = (char *)default_file_path; + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; + snprintf(config_value, sizeof(config_value), + "%s.classification-file", de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &log_filename) != 1) { + if (ConfGet("classification-file", &log_filename) != 1) { + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + } + } + } else { + if (ConfGet("classification-file", &log_filename) != 1) { + log_filename = (char *)SC_CLASS_CONF_DEF_CONF_FILEPATH; + } } return log_filename; @@ -163,22 +188,12 @@ static char *SCClassConfGetConfFilename(void) /** * \brief Releases resources used by the Classification Config API. */ -static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx) +static void SCClassConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { - - fclose(fd); - default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH; - fd = NULL; - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; + if (fd != NULL) { + fclose(fd); + fd = NULL; } - - return; } /** @@ -206,7 +221,7 @@ static char *SCClassConfStringToLowercase(const char *str) if ( (new_str = SCStrdup(str)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + return NULL; } temp_str = new_str; @@ -231,9 +246,9 @@ static char *SCClassConfStringToLowercase(const char *str) */ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx) { - const char *ct_name = NULL; - const char *ct_desc = NULL; - const char *ct_priority_str = NULL; + char ct_name[64]; + char ct_desc[512]; + char ct_priority_str[16]; int ct_priority = 0; uint8_t ct_id = index; @@ -252,26 +267,26 @@ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx } /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, ct_name, sizeof(ct_name)); if (ret < 0) { - SCLogInfo("pcre_get_substring() failed"); + SCLogInfo("pcre_copy_substring() failed"); goto error; } /* retrieve the classtype description */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, ct_desc, sizeof(ct_desc)); if (ret < 0) { - SCLogInfo("pcre_get_substring() failed"); + SCLogInfo("pcre_copy_substring() failed"); goto error; } /* retrieve the classtype priority */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 3, ct_priority_str, sizeof(ct_priority_str)); if (ret < 0) { - SCLogInfo("pcre_get_substring() failed"); + SCLogInfo("pcre_copy_substring() failed"); goto error; } - if (ct_priority_str == NULL) { + if (strlen(ct_priority_str) == 0) { goto error; } @@ -295,16 +310,9 @@ int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx SCFree(ct_new); } - if (ct_name) SCFree((char *)ct_name); - if (ct_desc) SCFree((char *)ct_desc); - if (ct_priority_str) SCFree((char *)ct_priority_str); return 0; error: - if (ct_name) SCFree((char *)ct_name); - if (ct_desc) SCFree((char *)ct_desc); - if (ct_priority_str) SCFree((char *)ct_priority_str); - return -1; } @@ -344,7 +352,7 @@ static int SCClassConfIsLineBlankOrComment(char *line) * * \param de_ctx Pointer to the Detection Engine Context. */ -void SCClassConfParseFile(DetectEngineCtx *de_ctx) +void SCClassConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) { char line[1024]; uint8_t i = 1; @@ -392,13 +400,17 @@ SCClassConfClasstype *SCClassConfAllocClasstype(uint8_t classtype_id, if ( (ct->classtype = SCClassConfStringToLowercase(classtype)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + + SCClassConfDeAllocClasstype(ct); + return NULL; } if (classtype_desc != NULL && (ct->classtype_desc = SCStrdup(classtype_desc)) == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); + + SCClassConfDeAllocClasstype(ct); + return NULL; } ct->classtype_id = classtype_id; @@ -516,15 +528,22 @@ void SCClassConfClasstypeHashFree(void *ch) * \param de_ctx Pointer to the Detection Engine Context that should be updated * with Classtype information. */ -void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx) +void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx, FILE *fd) { - if (SCClassConfInitContextAndLocalResources(de_ctx) == -1) { - SCLogInfo("Please check the \"classification-file\" option in your suricata.yaml file"); - exit(EXIT_FAILURE); + fd = SCClassConfInitContextAndLocalResources(de_ctx, fd); + if (fd == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests() && fd == NULL) { + return; + } +#endif + SCLogError(SC_ERR_OPENING_FILE, "please check the \"classification-file\" " + "option in your suricata.yaml file"); + return; } - SCClassConfParseFile(de_ctx); - SCClassConfDeInitLocalResources(de_ctx); + SCClassConfParseFile(de_ctx, fd); + SCClassConfDeInitLocalResources(de_ctx, fd); return; } @@ -566,18 +585,18 @@ SCClassConfClasstype *SCClassConfGetClasstype(const char *ct_name, * * \file_path Pointer to the file_path for the dummy classification file. */ -void SCClassConfGenerateValidDummyClassConfigFD01(void) +FILE *SCClassConfGenerateValidDummyClassConfigFD01(void) { const char *buffer = "config classification: nothing-wrong,Nothing Wrong With Us,3\n" "config classification: unknown,Unknown are we,3\n" "config classification: bad-unknown,We think it's bad, 2\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); - return; + return fd; } /** @@ -586,7 +605,7 @@ void SCClassConfGenerateValidDummyClassConfigFD01(void) * * \file_path Pointer to the file_path for the dummy classification file. */ -void SCClassConfGenerateInValidDummyClassConfigFD02(void) +FILE *SCClassConfGenerateInValidDummyClassConfigFD02(void) { const char *buffer = "config classification: not-suspicious,Not Suspicious Traffic,3\n" @@ -597,11 +616,11 @@ void SCClassConfGenerateInValidDummyClassConfigFD02(void) "config classification: policy-violation,Potential Corporate " "config classification: bamboola,Unknown Traffic,3\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); - return; + return fd; } /** @@ -610,7 +629,7 @@ void SCClassConfGenerateInValidDummyClassConfigFD02(void) * * \file_path Pointer to the file_path for the dummy classification file. */ -void SCClassConfGenerateInValidDummyClassConfigFD03(void) +FILE *SCClassConfGenerateInValidDummyClassConfigFD03(void) { const char *buffer = "conig classification: not-suspicious,Not Suspicious Traffic,3\n" @@ -618,26 +637,11 @@ void SCClassConfGenerateInValidDummyClassConfigFD03(void) "config classification: _badunknown,Potentially Bad Traffic, 2\n" "config classification: misc-activity,Misc activity,-1\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Classifiation Config test code"); - return; -} - -/** - * \brief Deletes a file, whose path is specified as the argument. - * - * \file_path Pointer to the file_path that has to be deleted. - */ -void SCClassConfDeleteDummyClassificationConfigFD(void) -{ - if (fd != NULL) { - fclose(fd); - fd = NULL; - } - - return; + return fd; } /** @@ -652,9 +656,8 @@ int SCClassConfTest01(void) if (de_ctx == NULL) return result; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return result; @@ -679,9 +682,8 @@ int SCClassConfTest02(void) if (de_ctx == NULL) return result; - SCClassConfGenerateInValidDummyClassConfigFD03(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD03(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return result; @@ -705,9 +707,8 @@ int SCClassConfTest03(void) if (de_ctx == NULL) return result; - SCClassConfGenerateInValidDummyClassConfigFD02(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD02(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return result; @@ -731,9 +732,8 @@ int SCClassConfTest04(void) if (de_ctx == NULL) return 0; - SCClassConfGenerateValidDummyClassConfigFD01(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return 0; @@ -765,9 +765,8 @@ int SCClassConfTest05(void) if (de_ctx == NULL) return 0; - SCClassConfGenerateInValidDummyClassConfigFD03(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD03(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return 0; @@ -798,9 +797,8 @@ int SCClassConfTest06(void) if (de_ctx == NULL) return 0; - SCClassConfGenerateInValidDummyClassConfigFD02(); - SCClassConfLoadClassficationConfigFile(de_ctx); - SCClassConfDeleteDummyClassificationConfigFD(); + FILE *fd = SCClassConfGenerateInValidDummyClassConfigFD02(); + SCClassConfLoadClassficationConfigFile(de_ctx, fd); if (de_ctx->class_conf_ht == NULL) return 0; @@ -829,12 +827,12 @@ void SCClassConfRegisterTests(void) #ifdef UNITTESTS - UtRegisterTest("SCClassConfTest01", SCClassConfTest01, 1); - UtRegisterTest("SCClassConfTest02", SCClassConfTest02, 1); - UtRegisterTest("SCClassConfTest03", SCClassConfTest03, 1); - UtRegisterTest("SCClassConfTest04", SCClassConfTest04, 1); - UtRegisterTest("SCClassConfTest05", SCClassConfTest05, 1); - UtRegisterTest("SCClassConfTest06", SCClassConfTest06, 1); + UtRegisterTest("SCClassConfTest01", SCClassConfTest01); + UtRegisterTest("SCClassConfTest02", SCClassConfTest02); + UtRegisterTest("SCClassConfTest03", SCClassConfTest03); + UtRegisterTest("SCClassConfTest04", SCClassConfTest04); + UtRegisterTest("SCClassConfTest05", SCClassConfTest05); + UtRegisterTest("SCClassConfTest06", SCClassConfTest06); #endif /* UNITTESTS */ diff --git a/src/util-classification-config.h b/src/util-classification-config.h index 4d0c80a2675c..7e916c2cd2ef 100644 --- a/src/util-classification-config.h +++ b/src/util-classification-config.h @@ -45,16 +45,18 @@ typedef struct SCClassConfClasstype_ { SCClassConfClasstype *SCClassConfAllocClasstype(uint8_t, const char *, const char *, int); void SCClassConfDeAllocClasstype(SCClassConfClasstype *); -void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *); +void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *, FILE *fd); SCClassConfClasstype *SCClassConfGetClasstype(const char *, DetectEngineCtx *); void SCClassConfDeInitContext(DetectEngineCtx *); void SCClassConfRegisterTests(void); /* for unittests */ -void SCClassConfGenerateValidDummyClassConfigFD01(void); -void SCClassConfGenerateInValidDummyClassConfigFD02(void); -void SCClassConfGenerateInValidDummyClassConfigFD03(void); -void SCClassConfDeleteDummyClassificationConfigFD(void); +FILE *SCClassConfGenerateValidDummyClassConfigFD01(void); +FILE *SCClassConfGenerateInValidDummyClassConfigFD02(void); +FILE *SCClassConfGenerateInValidDummyClassConfigFD03(void); + +void SCClassConfInit(void); +void SCClassConfDeinit(void); #endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */ diff --git a/src/util-conf.c b/src/util-conf.c index e0f25d1d6395..0c81178ec5c8 100644 --- a/src/util-conf.c +++ b/src/util-conf.c @@ -25,6 +25,7 @@ #include "suricata-common.h" #include "config.h" #include "conf.h" +#include "util-conf.h" TmEcode ConfigSetLogDirectory(char *name) { @@ -63,3 +64,58 @@ TmEcode ConfigCheckLogDirectory(char *log_dir) } SCReturnInt(TM_ECODE_OK); } + +/** + * \brief Find the configuration node for a specific device. + + * Basically hunts through the list of maps for the first one with a + * key of "interface", and a value of the provided interface. + * + * \param node The node to start looking for the device + * configuration. Typically this would be something like the af-packet + * or pf-ring node. + * + * \param iface The name of the interface to find the config for. + */ +ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface) +{ + ConfNode *if_node, *item; + TAILQ_FOREACH(if_node, &node->head, next) { + TAILQ_FOREACH(item, &if_node->head, next) { + if (strcmp(item->name, "interface") == 0 && + strcmp(item->val, iface) == 0) { + return if_node; + } + } + } + + return NULL; +} + +int ConfUnixSocketIsEnable(void) +{ + char *value; + + if (ConfGet("unix-command.enabled", &value) != 1) { + return 0; + } + + if (!strcmp(value, "auto")) { +#ifdef HAVE_LIBJANSSON +#ifdef OS_WIN32 + return 0; +#else + if (TimeModeIsLive()) { + SCLogInfo("Running in live mode, activating unix socket"); + return 1; + } else { + return 0; + } +#endif +#else + return 0; +#endif + } + + return ConfValIsTrue(value); +} diff --git a/src/util-conf.h b/src/util-conf.h index 74d87e305a78..08727567f507 100644 --- a/src/util-conf.h +++ b/src/util-conf.h @@ -25,8 +25,14 @@ #ifndef __UTIL_UTIL_CONF_H__ #define __UTIL_UTIL_CONF_H__ +#include "conf.h" + TmEcode ConfigSetLogDirectory(char *name); char *ConfigGetLogDirectory(); TmEcode ConfigCheckLogDirectory(char *log_dir); +ConfNode *ConfFindDeviceConfig(ConfNode *node, const char *iface); + +int ConfUnixSocketIsEnable(void); + #endif /* __UTIL_UTIL_CONF_H__ */ diff --git a/src/util-coredump-config.c b/src/util-coredump-config.c index 2115f930fbbe..8677211b6064 100644 --- a/src/util-coredump-config.c +++ b/src/util-coredump-config.c @@ -26,7 +26,9 @@ #define _FILE_OFFSET_BITS 64 #include "util-coredump-config.h" #include "conf.h" +#ifdef HAVE_SYS_RESOURCE_H #include +#endif /** * \brief Configures the core dump size. @@ -36,6 +38,7 @@ */ int32_t CoredumpLoadConfig (void) { +#ifdef HAVE_SYS_RESOURCE_H /* get core dump configuration settings for suricata */ char* dump_size_config = NULL; rlim_t max_dump = 0; @@ -71,7 +74,7 @@ int32_t CoredumpLoadConfig (void) SCLogInfo ("Illegal core dump size: %s.", dump_size_config); return 0; } - SCLogInfo ("Max dump is %llu", (unsigned long long) max_dump); + SCLogInfo ("Max dump is %"PRIu64, (uint64_t) max_dump); } #if defined OS_WIN32 @@ -112,14 +115,14 @@ int32_t CoredumpLoadConfig (void) if (unlimited) { /* we want no limit on coredump size */ if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) { - SCLogInfo ("Core dump size is unlimited."); + SCLogConfig ("Core dump size is unlimited."); return 1; } else { new_lim.rlim_max = RLIM_INFINITY; new_lim.rlim_cur = RLIM_INFINITY; if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogInfo ("Core dump size set to unlimited."); + SCLogConfig ("Core dump size set to unlimited."); return 1; } if (errno == EPERM) { @@ -165,11 +168,11 @@ int32_t CoredumpLoadConfig (void) new_lim.rlim_max = lim.rlim_max; } if (setrlimit (RLIMIT_CORE, &new_lim) == 0) { - SCLogInfo ("Core dump setting attempted is %llu", (unsigned long long) new_lim.rlim_cur); + SCLogInfo ("Core dump setting attempted is %"PRIu64, (uint64_t) new_lim.rlim_cur); struct rlimit actual_lim; if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) { if (actual_lim.rlim_cur == RLIM_INFINITY) { - SCLogInfo ("Core dump size set to unlimited."); + SCLogConfig ("Core dump size set to unlimited."); } #ifdef RLIM_SAVED_CUR else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) { @@ -177,7 +180,7 @@ int32_t CoredumpLoadConfig (void) } #endif else { - SCLogInfo ("Core dump size set to %llu", (unsigned long long) actual_lim.rlim_cur); + SCLogInfo ("Core dump size set to %"PRIu64, (uint64_t) actual_lim.rlim_cur); } } return 1; @@ -202,5 +205,6 @@ int32_t CoredumpLoadConfig (void) } /* failed to set the coredump limit */ SCLogInfo ("Could't set coredump size to %s.", dump_size_config); +#endif /* HAVE_SYS_RESOURCE_H */ return 0; } diff --git a/src/util-cpu.c b/src/util-cpu.c index f8f748bc7060..655bffbd55c0 100644 --- a/src/util-cpu.c +++ b/src/util-cpu.c @@ -23,9 +23,9 @@ * Retrieve CPU information (configured CPUs, online CPUs) */ +#include "suricata-common.h" #include "util-error.h" #include "util-debug.h" -#include "suricata-common.h" /** * Ok, if they should use sysconf, check that they have the macro's @@ -221,7 +221,7 @@ uint64_t UtilCpuGetTicks(void) #endif #else /* #if defined(__GNU__) */ -#warning Using inferior version of UtilCpuGetTicks +//#warning Using inferior version of UtilCpuGetTicks struct timeval now; gettimeofday(&now, NULL); val = (now.tv_sec * 1000000) + now.tv_usec; diff --git a/src/util-cuda-buffer.c b/src/util-cuda-buffer.c index efaef9ffa964..54ae272a524a 100644 --- a/src/util-cuda-buffer.c +++ b/src/util-cuda-buffer.c @@ -45,9 +45,9 @@ * to be reallocated to other writers. */ -#ifdef __SC_CUDA_SUPPORT__ #include "suricata-common.h" +#ifdef __SC_CUDA_SUPPORT__ #include "suricata.h" #include "util-atomic.h" @@ -1344,12 +1344,12 @@ int CudaBufferTest06(void) void CudaBufferRegisterUnittests(void) { #ifdef UNITTESTS - UtRegisterTest("CudaBufferTest01", CudaBufferTest01, 1); - UtRegisterTest("CudaBufferTest02", CudaBufferTest02, 1); - UtRegisterTest("CudaBufferTest03", CudaBufferTest03, 1); - UtRegisterTest("CudaBufferTest04", CudaBufferTest04, 1); - UtRegisterTest("CudaBufferTest05", CudaBufferTest05, 1); - UtRegisterTest("CudaBufferTest06", CudaBufferTest06, 1); + UtRegisterTest("CudaBufferTest01", CudaBufferTest01); + UtRegisterTest("CudaBufferTest02", CudaBufferTest02); + UtRegisterTest("CudaBufferTest03", CudaBufferTest03); + UtRegisterTest("CudaBufferTest04", CudaBufferTest04); + UtRegisterTest("CudaBufferTest05", CudaBufferTest05); + UtRegisterTest("CudaBufferTest06", CudaBufferTest06); #endif return; diff --git a/src/util-cuda-handlers.c b/src/util-cuda-handlers.c index a6cbeec9fb52..198c6f73b92d 100644 --- a/src/util-cuda-handlers.c +++ b/src/util-cuda-handlers.c @@ -23,10 +23,11 @@ /* compile in, only if we have a CUDA enabled device on the machine, with the * toolkit and the driver installed */ -#ifdef __SC_CUDA_SUPPORT__ #include "suricata-common.h" +#ifdef __SC_CUDA_SUPPORT__ + #include "util-error.h" #include "util-debug.h" #include "conf.h" diff --git a/src/util-cuda-vars.c b/src/util-cuda-vars.c index 624c09f8511b..596be8582667 100644 --- a/src/util-cuda-vars.c +++ b/src/util-cuda-vars.c @@ -21,8 +21,8 @@ * \author Anoop Saldanha */ +#include "suricata-common.h" #ifdef __SC_CUDA_SUPPORT__ - #include "suricata.h" #include "util-mpm.h" #include "util-cuda-handlers.h" diff --git a/src/util-cuda.c b/src/util-cuda.c index 3ada56b26c6d..288631176be7 100644 --- a/src/util-cuda.c +++ b/src/util-cuda.c @@ -25,12 +25,12 @@ /* compile in, only if we have a CUDA enabled device on the machine, with the * toolkit and the driver installed */ + +#include "suricata-common.h" #ifdef __SC_CUDA_SUPPORT__ #include #include "util-cuda.h" -#include "suricata-common.h" - #include "util-error.h" #include "util-debug.h" #include "util-unittest.h" @@ -5445,8 +5445,8 @@ int SCCudaTest02(void) void SCCudaRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCCudaTest01", SCCudaTest01, 1); - UtRegisterTest("SCCudaTest02", SCCudaTest02, 1); + UtRegisterTest("SCCudaTest01", SCCudaTest01); + UtRegisterTest("SCCudaTest02", SCCudaTest02); #endif return; diff --git a/src/util-daemon.c b/src/util-daemon.c index 2eec7af13b54..5aab8509e22a 100644 --- a/src/util-daemon.c +++ b/src/util-daemon.c @@ -89,12 +89,9 @@ static void SetupLogging (void) int fd = open("/dev/null", O_RDWR); if (fd < 0) return; - if (dup2(fd, 0) < 0) - return; - if (dup2(fd, 1) < 0) - return; - if (dup2(fd, 2) < 0) - return; + (void)dup2(fd, 0); + (void)dup2(fd, 1); + (void)dup2(fd, 2); close(fd); } diff --git a/src/util-debug.c b/src/util-debug.c index 8283c99c5f37..1a0f19341e1b 100644 --- a/src/util-debug.c +++ b/src/util-debug.c @@ -34,6 +34,7 @@ #include "detect.h" #include "packet-queue.h" #include "threadvars.h" +#include "output.h" #include "tm-queuehandlers.h" #include "tm-queues.h" @@ -55,6 +56,8 @@ SCEnumCharMap sc_log_level_map[ ] = { { "Warning", SC_LOG_WARNING }, { "Notice", SC_LOG_NOTICE }, { "Info", SC_LOG_INFO }, + { "Perf", SC_LOG_PERF }, + { "Config", SC_LOG_CONFIG }, { "Debug", SC_LOG_DEBUG }, { NULL, -1 } }; @@ -152,11 +155,16 @@ static inline int SCLogMapLogLevelToSyslogLevel(int log_level) */ static inline void SCLogPrintToStream(FILE *fd, char *msg) { + /* Would only happen if the log file failed to re-open during rotation. */ + if (fd == NULL) { + return; + } + #if defined (OS_WIN32) SCMutexLock(&sc_log_stream_lock); #endif /* OS_WIN32 */ - if (fprintf(fd, "%s", msg) < 0) + if (fprintf(fd, "%s\n", msg) < 0) printf("Error writing to stream using fprintf\n"); fflush(fd); @@ -188,70 +196,64 @@ static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg) return; } +#ifdef HAVE_LIBJANSSON +#include /** - * \brief Outputs the message sent as the argument - * - * \param msg Pointer to the message that has to be logged - * \param log_level The log_level of the message that has to be logged */ -void SCLogOutputBuffer(SCLogLevel log_level, char *msg) +int SCLogMessageJSON(struct timeval *tval, char *buffer, size_t buffer_size, + SCLogLevel log_level, const char *file, + unsigned line, const char *function, SCError error_code, + const char *message) { - char *temp = msg; - int len = strlen(msg); - SCLogOPIfaceCtx *op_iface_ctx = NULL; + json_t *js = json_object(); + if (unlikely(js == NULL)) + goto error; + json_t *ejs = json_object(); + if (unlikely(ejs == NULL)) + goto error; -#define MAX_SUBSTRINGS 30 - int ov[MAX_SUBSTRINGS]; + char timebuf[64]; + CreateIsoTimeString(tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); - if (sc_log_module_initialized != 1) { - printf("Logging module not initialized. Call SCLogInitLogModule() " - "first before using the debug API\n"); - return; + json_object_set_new(js, "event_type", json_string("engine")); + + if (error_code > 0) { + json_object_set_new(ejs, "error_code", json_integer(error_code)); + json_object_set_new(ejs, "error", json_string(SCErrorToString(error_code))); } - /* We need to add a \n for our messages, before logging them. If the - * messages have hit the 1023 length limit, strip the message to - * accomodate the \n */ - if (len == SC_LOG_MAX_LOG_MSG_LEN - 1) - len = SC_LOG_MAX_LOG_MSG_LEN - 2; + if (message) + json_object_set_new(ejs, "message", json_string(message)); - temp[len] = '\n'; - temp[len + 1] = '\0'; + if (log_level >= SC_LOG_DEBUG) { + if (function) + json_object_set_new(ejs, "function", json_string(function)); - if (sc_log_config->op_filter_regex != NULL) { - if (pcre_exec(sc_log_config->op_filter_regex, - sc_log_config->op_filter_regex_study, - msg, strlen(msg), 0, 0, ov, MAX_SUBSTRINGS) < 0) - return; + if (file) + json_object_set_new(ejs, "file", json_string(file)); + + if (line > 0) + json_object_set_new(ejs, "line", json_integer(line)); } - op_iface_ctx = sc_log_config->op_ifaces; - while (op_iface_ctx != NULL) { - if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { - op_iface_ctx = op_iface_ctx->next; - continue; - } + json_object_set_new(js, "engine", ejs); - switch (op_iface_ctx->iface) { - case SC_LOG_OP_IFACE_CONSOLE: - SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, - msg); - break; - case SC_LOG_OP_IFACE_FILE: - SCLogPrintToStream(op_iface_ctx->file_d, msg); - break; - case SC_LOG_OP_IFACE_SYSLOG: - SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), - msg); - break; - default: - break; - } - op_iface_ctx = op_iface_ctx->next; - } + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + snprintf(buffer, buffer_size, "%s", js_s); + free(js_s); - return; + json_object_del(js, "engine"); + json_object_clear(js); + json_decref(js); + + return 0; +error: + return -1; } +#endif /* HAVE_LIBJANSSON */ /** * \brief Adds the global log_format to the outgoing buffer @@ -264,71 +266,69 @@ void SCLogOutputBuffer(SCLogLevel log_level, char *msg) * * \retval SC_OK on success; else an error code */ -SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, - unsigned line, const char *function) +static SCError SCLogMessageGetBuffer( + struct timeval *tval, int color, SCLogOPType type, + char *buffer, size_t buffer_size, + const char *log_format, + + const SCLogLevel log_level, const char *file, + const unsigned int line, const char *function, + const SCError error_code, const char *message) { - char *temp = *msg; - const char *s = NULL; +#ifdef HAVE_LIBJANSSON + if (type == SC_LOG_OP_TYPE_JSON) + return SCLogMessageJSON(tval, buffer, buffer_size, log_level, file, line, function, error_code, message); +#endif - struct timeval tval; + char *temp = buffer; + const char *s = NULL; struct tm *tms = NULL; + char *redb = ""; + char *red = ""; + char *yellowb = ""; + char *yellow = ""; + char *green = ""; + char *blue = ""; + char *reset = ""; + if (color) { + redb = "\x1b[1;31m"; + red = "\x1b[31m"; + yellowb = "\x1b[1;33m"; + yellow = "\x1b[33m"; + green = "\x1b[32m"; + blue = "\x1b[34m"; + reset = "\x1b[0m"; + } /* no of characters_written(cw) by snprintf */ int cw = 0; - if (sc_log_module_initialized != 1) { -#ifdef DEBUG - printf("Logging module not initialized. Call SCLogInitLogModule(), " - "before using the logging API\n"); -#endif - return SC_ERR_LOG_MODULE_NOT_INIT; - } + BUG_ON(sc_log_module_initialized != 1); - if (sc_log_fg_filters_present == 1) { - if (SCLogMatchFGFilterWL(file, function, line) != 1) { - return SC_ERR_LOG_FG_FILTER_MATCH; - } - - if (SCLogMatchFGFilterBL(file, function, line) != 1) { - return SC_ERR_LOG_FG_FILTER_MATCH; - } - } - - if (sc_log_fd_filters_present == 1 && SCLogMatchFDFilter(function) != 1) { - return SC_ERR_LOG_FG_FILTER_MATCH; - } - - char *temp_fmt = strdup(sc_log_config->log_format); - if (unlikely(temp_fmt == NULL)) { - return SC_ERR_MEM_ALLOC; - } - char *temp_fmt_h = temp_fmt; + /* make a copy of the format string as it will be modified below */ + char local_format[strlen(log_format) + 1]; + strlcpy(local_format, log_format, sizeof(local_format)); + char *temp_fmt = local_format; char *substr = temp_fmt; while ( (temp_fmt = index(temp_fmt, SC_LOG_FMT_PREFIX)) ) { - if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { - printf("Warning: Log message exceeded message length limit of %d\n", - SC_LOG_MAX_LOG_MSG_LEN); - *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { return SC_OK; } switch(temp_fmt[1]) { case SC_LOG_FMT_TIME: temp_fmt[0] = '\0'; - gettimeofday(&tval, NULL); struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); + tms = SCLocalTime(tval->tv_sec, &local_tm); - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%d/%d/%04d -- %02d:%02d:%02d", - substr, tms->tm_mday, tms->tm_mon + 1, + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%d/%d/%04d -- %02d:%02d:%02d%s", + substr, green, tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, - tms->tm_sec); + tms->tm_sec, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -337,10 +337,10 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_PID: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%u", substr, getpid()); + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%u%s", substr, yellow, getpid(), reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -349,10 +349,10 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_TID: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%lu", substr, SCGetThreadIdLong()); + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -361,11 +361,19 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_TM: temp_fmt[0] = '\0'; +/* disabled to prevent dead lock: + * log or alloc (which calls log on error) can call TmThreadsGetCallingThread + * which will lock tv_root_lock. This can happen while we already hold this + * lock. */ +#if 0 ThreadVars *tv = TmThreadsGetCallingThread(); cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s%s", substr, ((tv != NULL)? tv->name: "UNKNOWN TM")); +#endif + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s", substr, "N/A"); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -375,14 +383,25 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_LOG_LEVEL: temp_fmt[0] = '\0'; s = SCMapEnumValueToName(log_level, sc_log_level_map); - if (s != NULL) - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%s", substr, s); - else - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), + if (s != NULL) { + if (log_level <= SC_LOG_ERROR) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, redb, s, reset); + else if (log_level == SC_LOG_WARNING) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, red, s, reset); + else if (log_level == SC_LOG_NOTICE) + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, yellowb, s, reset); + else + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, yellow, s, reset); + } else { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s", substr, "INVALID"); + } if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -391,10 +410,10 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_FILE_NAME: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%s", substr, file); + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, blue, file, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -403,10 +422,10 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_LINE: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%u", substr, line); + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%u%s", substr, green, line, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -415,10 +434,10 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, case SC_LOG_FMT_FUNCTION: temp_fmt[0] = '\0'; - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), - "%s%s", substr, function); + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "%s%s%s%s", substr, green, function, reset); if (cw < 0) - goto error; + return SC_ERR_SPRINTF; temp += cw; temp_fmt++; substr = temp_fmt; @@ -428,37 +447,155 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file, } temp_fmt++; } - if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { - printf("Warning: Log message exceeded message length limit of %d\n", - SC_LOG_MAX_LOG_MSG_LEN); - *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { return SC_OK; } - cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg), "%s", substr); - if (cw < 0) - goto error; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr); + if (cw < 0) { + return SC_ERR_SPRINTF; + } + temp += cw; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + return SC_OK; + } + + if (error_code != SC_OK) { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), + "[%sERRCODE%s: %s%s%s(%s%d%s)] - ", yellow, reset, red, SCErrorToString(error_code), reset, yellow, error_code, reset); + if (cw < 0) { + return SC_ERR_SPRINTF; + } + temp += cw; + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { + return SC_OK; + } + } + + char *hi = ""; + if (error_code > SC_OK) + hi = red; + else if (log_level <= SC_LOG_NOTICE) + hi = yellow; + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message, reset); + if (cw < 0) { + return SC_ERR_SPRINTF; + } temp += cw; - if ((temp - *msg) > SC_LOG_MAX_LOG_MSG_LEN) { - printf("Warning: Log message exceeded message length limit of %d\n", - SC_LOG_MAX_LOG_MSG_LEN); - *msg = *msg + SC_LOG_MAX_LOG_MSG_LEN; - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); + if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) { return SC_OK; } - *msg = temp; + if (sc_log_config->op_filter_regex != NULL) { +#define MAX_SUBSTRINGS 30 + int ov[MAX_SUBSTRINGS]; - SCFree(temp_fmt_h); + if (pcre_exec(sc_log_config->op_filter_regex, + sc_log_config->op_filter_regex_study, + buffer, strlen(buffer), 0, 0, ov, MAX_SUBSTRINGS) < 0) + { + return SC_ERR_LOG_FG_FILTER_MATCH; // bit hacky, but just return !0 + } +#undef MAX_SUBSTRINGS + } return SC_OK; +} + +static void SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx) +{ + if (op_iface_ctx->file_d == NULL) { + return; + } - error: - if (temp_fmt_h != NULL) - SCFree(temp_fmt_h); - return SC_ERR_SPRINTF; + if (op_iface_ctx->file == NULL) { + return; + } + + fclose(op_iface_ctx->file_d); + op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a"); + if (op_iface_ctx->file_d == NULL) { + SCLogError(SC_ERR_FOPEN, "Erroring re-opening file \"%s\": %s", + op_iface_ctx->file, strerror(errno)); + } +} + +/** + * \brief Adds the global log_format to the outgoing buffer + * + * \param log_level log_level of the message that has to be logged + * \param msg Buffer containing the outgoing message + * \param file File_name from where the message originated + * \param function Function_name from where the message originated + * \param line Line_no from where the messaged originated + * + * \retval SC_OK on success; else an error code + */ +SCError SCLogMessage(const SCLogLevel log_level, const char *file, + const unsigned int line, const char *function, + const SCError error_code, const char *message) +{ + char buffer[SC_LOG_MAX_LOG_MSG_LEN] = ""; + SCLogOPIfaceCtx *op_iface_ctx = NULL; + + if (sc_log_module_initialized != 1) { + printf("Logging module not initialized. Call SCLogInitLogModule() " + "first before using the debug API\n"); + return SC_OK; + } + + /* get ts here so we log the same ts to each output */ + struct timeval tval; + gettimeofday(&tval, NULL); + + op_iface_ctx = sc_log_config->op_ifaces; + while (op_iface_ctx != NULL) { + if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) { + op_iface_ctx = op_iface_ctx->next; + continue; + } + + switch (op_iface_ctx->iface) { + case SC_LOG_OP_IFACE_CONSOLE: + if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, op_iface_ctx->type, + buffer, sizeof(buffer), + op_iface_ctx->log_format ? + op_iface_ctx->log_format : sc_log_config->log_format, + log_level, file, line, function, + error_code, message) == 0) + { + SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer); + } + break; + case SC_LOG_OP_IFACE_FILE: + if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer), + op_iface_ctx->log_format ? + op_iface_ctx->log_format : sc_log_config->log_format, + log_level, file, line, function, + error_code, message) == 0) + { + if (op_iface_ctx->rotation_flag) { + SCLogReopen(op_iface_ctx); + op_iface_ctx->rotation_flag = 0; + } + SCLogPrintToStream(op_iface_ctx->file_d, buffer); + } + break; + case SC_LOG_OP_IFACE_SYSLOG: + if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer), + op_iface_ctx->log_format ? + op_iface_ctx->log_format : sc_log_config->log_format, + log_level, file, line, function, + error_code, message) == 0) + { + SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer); + } + break; + default: + break; + } + op_iface_ctx = op_iface_ctx->next; + } + return SC_OK; } /** @@ -543,7 +680,8 @@ static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx() */ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, const char *log_format, - int log_level) + int log_level, + SCLogOPType type) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); @@ -557,8 +695,9 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, } iface_ctx->iface = SC_LOG_OP_IFACE_FILE; + iface_ctx->type = type; - if ( (iface_ctx->file_d = fopen(file, "w+")) == NULL) { + if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) { printf("Error opening file %s\n", file); goto error; } @@ -571,6 +710,8 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, goto error; } + OutputRegisterFileRotationFlag(&iface_ctx->rotation_flag); + iface_ctx->log_level = log_level; return iface_ctx; @@ -588,6 +729,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, fclose(iface_ctx->file_d); iface_ctx->file_d = NULL; } + SCFree(iface_ctx); return NULL; } @@ -603,7 +745,7 @@ static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file, * \initonly */ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, - SCLogLevel log_level) + SCLogLevel log_level, SCLogOPType type) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); @@ -613,6 +755,7 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, } iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE; + iface_ctx->type = type; /* console log format is overridden by envvars */ const char *tmp_log_format = log_format; @@ -646,6 +789,10 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, } iface_ctx->log_level = tmp_log_level; + if (isatty(fileno(stdout)) && isatty(fileno(stderr))) { + iface_ctx->use_color = TRUE; + } + return iface_ctx; } @@ -661,7 +808,8 @@ static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format, */ static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility, const char *log_format, - SCLogLevel log_level) + SCLogLevel log_level, + SCLogOPType type) { SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx(); @@ -671,6 +819,7 @@ static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility, } iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG; + iface_ctx->type = type; if (facility == -1) facility = SC_LOG_DEF_SYSLOG_FACILITY; @@ -846,18 +995,18 @@ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) switch (op_iface) { case SC_LOG_OP_IFACE_CONSOLE: - op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX); + op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0); break; case SC_LOG_OP_IFACE_FILE: s = getenv(SC_LOG_ENV_LOG_FILE); if (s == NULL) { char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); if (str != NULL) { - op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX); + op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX,0); SCFree(str); } } else { - op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX); + op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX,0); } break; case SC_LOG_OP_IFACE_SYSLOG: @@ -865,13 +1014,12 @@ static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc) if (s == NULL) s = SC_LOG_DEF_SYSLOG_FACILITY_STR; - op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1); + op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0); break; } sc_lc->op_ifaces = op_ifaces_ctx; sc_lc->op_ifaces_cnt++; } - return; } @@ -1053,11 +1201,12 @@ SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(const char *iface_name, switch (iface) { case SC_LOG_OP_IFACE_CONSOLE: - return SCLogInitConsoleOPIface(log_format, log_level); + return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR); case SC_LOG_OP_IFACE_FILE: - return SCLogInitFileOPIface(arg, log_format, log_level); + return SCLogInitFileOPIface(arg, log_format, log_level, SC_LOG_OP_TYPE_REGULAR); case SC_LOG_OP_IFACE_SYSLOG: - return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), log_format, log_level); + return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()), + log_format, log_level, SC_LOG_OP_TYPE_REGULAR); default: #ifdef DEBUG printf("Output Interface \"%s\" not supported by the logging module", @@ -1170,6 +1319,22 @@ void SCLogLoadConfig(int daemon, int verbose) if (enabled != NULL && ConfValIsFalse(enabled)) continue; + SCLogOPType type = SC_LOG_OP_TYPE_REGULAR; + const char *type_s = ConfNodeLookupChildValue(output, "type"); + if (type_s != NULL) { + if (strcmp(type_s, "regular") == 0) + type = SC_LOG_OP_TYPE_REGULAR; + else if (strcmp(type_s, "json") == 0) { +#ifdef HAVE_LIBJANSSON + type = SC_LOG_OP_TYPE_JSON; +#else + SCLogError(SC_ERR_INVALID_ARGUMENT, "libjansson support not " + "compiled in, can't use 'json' logging"); + exit(EXIT_FAILURE); +#endif /* HAVE_LIBJANSSON */ + } + } + /* if available use the log format setting for this output, * otherwise fall back to the global setting. */ format = ConfNodeLookupChildValue(output, "format"); @@ -1187,7 +1352,7 @@ void SCLogLoadConfig(int daemon, int verbose) } if (strcmp(output->name, "console") == 0) { - op_iface_ctx = SCLogInitConsoleOPIface(format, level); + op_iface_ctx = SCLogInitConsoleOPIface(format, level, type); } else if (strcmp(output->name, "file") == 0) { const char *filename = ConfNodeLookupChildValue(output, "filename"); @@ -1197,7 +1362,7 @@ void SCLogLoadConfig(int daemon, int verbose) exit(EXIT_FAILURE); } have_logging = 1; - op_iface_ctx = SCLogInitFileOPIface(filename, format, level); + op_iface_ctx = SCLogInitFileOPIface(filename, format, level, type); } else if (strcmp(output->name, "syslog") == 0) { int facility = SC_LOG_DEF_SYSLOG_FACILITY; @@ -1215,7 +1380,7 @@ void SCLogLoadConfig(int daemon, int verbose) printf("Initialization syslog logging with format \"%s\".\n", format); have_logging = 1; - op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level); + op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type); } else { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid logging method: %s, " @@ -1239,144 +1404,10 @@ void SCLogLoadConfig(int daemon, int verbose) SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format); SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter); - //exit(1); - /* \todo Can we free sc_lid now? */ if (sc_lid != NULL) SCFree(sc_lid); } -/** - * \brief Initializes the logging module if the environment variables are set. - * Used at the start of the engine, for cases, where there is an error - * in the yaml parsing code, and we want to enable the logging module. - */ -void SCLogInitLogModuleIfEnvSet(void) -{ - SCLogConfig *sc_lc = NULL; - const char *s = NULL; - const char *filter = NULL; - int opts = 0; - const char *ep; - int eo = 0; - SCLogOPIfaceCtx *op_ifaces_ctx = NULL; - int op_iface = 0; - char *format = NULL; - SCLogLevel log_level = SC_LOG_NOTSET; - - /* sc_log_config is a global variable */ - if ( (sc_log_config = SCMalloc(sizeof(SCLogConfig))) == NULL) - return; - memset(sc_log_config, 0, sizeof(SCLogConfig)); - sc_lc = sc_log_config; - - /* Check if the user has set the op_iface env var. Only if it is set, - * we proceed with the initialization */ - s = getenv(SC_LOG_ENV_LOG_OP_IFACE); - if (s != NULL) { - op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map); - - if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) { - op_iface = SC_LOG_DEF_LOG_OP_IFACE; -#ifndef UNITTESTS - printf("Warning: Invalid output interface supplied by user. " - "Falling back on default_output_interface \"%s\"\n", - SCMapEnumValueToName(op_iface, sc_log_op_iface_map)); -#endif - } - } else { - SCLogFreeLogConfig(sc_lc); - sc_log_config = NULL; - return; - } - - switch (op_iface) { - case SC_LOG_OP_IFACE_CONSOLE: - op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, -1); - break; - case SC_LOG_OP_IFACE_FILE: - s = getenv(SC_LOG_ENV_LOG_FILE); - if (s == NULL) { - char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE); - if (str != NULL) { - op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX); - SCFree(str); - } - } else { - op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, -1); - } - break; - case SC_LOG_OP_IFACE_SYSLOG: - s = getenv(SC_LOG_ENV_LOG_FACILITY); - if (s == NULL) - s = SC_LOG_DEF_SYSLOG_FACILITY_STR; - - op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1); - break; - } - sc_lc->op_ifaces = op_ifaces_ctx; - - - /* Set the filter */ - filter = getenv(SC_LOG_ENV_LOG_OP_FILTER); - if (filter != NULL && strcmp(filter, "") != 0) { - sc_lc->op_filter_regex = pcre_compile(filter, opts, &ep, &eo, NULL); - if (sc_lc->op_filter_regex == NULL) { - printf("pcre compile of \"%s\" failed at offset %d : %s\n", filter, - eo, ep); - return; - } - - sc_lc->op_filter_regex_study = pcre_study(sc_lc->op_filter_regex, 0, - &ep); - if (ep != NULL) { - printf("pcre study failed: %s\n", ep); - return; - } - } - - /* Set the log_format */ - format = getenv(SC_LOG_ENV_LOG_FORMAT); - if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) { - format = SC_LOG_DEF_LOG_FORMAT; -#ifndef UNITTESTS - printf("Warning: Invalid global_log_format supplied by user or format " - "length exceeded limit of \"%d\" characters. Falling back on " - "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN, - format); -#endif - } - - if (format != NULL && - (sc_lc->log_format = SCStrdup(format)) == NULL) { - printf("Error allocating memory\n"); - exit(EXIT_FAILURE); - } - - /* Set the log_level */ - s = getenv(SC_LOG_ENV_LOG_LEVEL); - if (s != NULL) - log_level = SCMapEnumNameToValue(s, sc_log_level_map); - - if (log_level >= 0 && log_level < SC_LOG_LEVEL_MAX) - sc_lc->log_level = log_level; - else { - sc_lc->log_level = SC_LOG_DEF_LOG_LEVEL; -#ifndef UNITTESTS - printf("Warning: Invalid global_log_level assigned by user. Falling " - "back on default_log_level \"%s\"\n", - SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map)); -#endif - } - - /* we also set it to a global var, as it is easier to access it */ - sc_log_global_log_level = sc_lc->log_level; - - sc_log_module_initialized = 1; - sc_log_module_cleaned = 0; - - return; -} - /** * \brief Returns a full file path given a filename uses log dir specified in * conf or DEFAULT_LOG_DIR @@ -1623,11 +1654,11 @@ void SCLogRegisterTests() #ifdef UNITTESTS - UtRegisterTest("SCLogTestInit01", SCLogTestInit01, 1); - UtRegisterTest("SCLogTestInit02", SCLogTestInit02, 1); - UtRegisterTest("SCLogTestInit03", SCLogTestInit03, 1); - UtRegisterTest("SCLogTestInit04", SCLogTestInit04, 1); - UtRegisterTest("SCLogTestInit05", SCLogTestInit05, 1); + UtRegisterTest("SCLogTestInit01", SCLogTestInit01); + UtRegisterTest("SCLogTestInit02", SCLogTestInit02); + UtRegisterTest("SCLogTestInit03", SCLogTestInit03); + UtRegisterTest("SCLogTestInit04", SCLogTestInit04); + UtRegisterTest("SCLogTestInit05", SCLogTestInit05); #endif /* UNITTESTS */ diff --git a/src/util-debug.h b/src/util-debug.h index e5b4d7055025..46157763e1e9 100644 --- a/src/util-debug.h +++ b/src/util-debug.h @@ -56,6 +56,8 @@ typedef enum { SC_LOG_WARNING, SC_LOG_NOTICE, SC_LOG_INFO, + SC_LOG_PERF, + SC_LOG_CONFIG, SC_LOG_DEBUG, SC_LOG_LEVEL_MAX, } SCLogLevel; @@ -70,6 +72,11 @@ typedef enum { SC_LOG_OP_IFACE_MAX, } SCLogOPIface; +typedef enum { + SC_LOG_OP_TYPE_REGULAR = 0, + SC_LOG_OP_TYPE_JSON, +} SCLogOPType; + /* The default log_format, if it is not supplied by the user */ #ifdef RELEASE #define SC_LOG_DEF_LOG_FORMAT "%t - <%d> - " @@ -112,20 +119,26 @@ typedef struct SCLogOPBuffer_ { typedef struct SCLogOPIfaceCtx_ { SCLogOPIface iface; + int16_t use_color; + int16_t type; + /* the output file to be used if the interface is SC_LOG_IFACE_FILE */ const char *file; /* the output file descriptor for the above file */ FILE * file_d; + /* registered to be set on a file rotation signal */ + int rotation_flag; + /* the facility code if the interface is SC_LOG_IFACE_SYSLOG */ int facility; - /* override for the global_log_format(currently not used) */ - const char *log_format; - /* override for the global_log_level */ SCLogLevel log_level; + /* override for the global_log_format(currently not used) */ + const char *log_format; + struct SCLogOPIfaceCtx_ *next; } SCLogOPIfaceCtx; @@ -190,74 +203,64 @@ extern int sc_log_module_initialized; extern int sc_log_module_cleaned; - -#define SCLog(x, ...) do { \ - char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ - char *_sc_log_temp = _sc_log_msg; \ - if ( !( \ - (sc_log_global_log_level >= x) && \ - SCLogMessage(x, &_sc_log_temp, \ - __FILE__, \ - __LINE__, \ - __FUNCTION__) \ - == SC_OK) ) \ - { } else { \ - snprintf(_sc_log_temp, \ - (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_log_temp - _sc_log_msg)), \ - __VA_ARGS__); \ - SCLogOutputBuffer(x, _sc_log_msg); \ - } \ - } while(0) - -#define SCLogErr(x, err, ...) do { \ - char _sc_log_err_msg[SC_LOG_MAX_LOG_MSG_LEN] = ""; \ - char *_sc_log_err_temp = _sc_log_err_msg; \ - if ( !( \ - (sc_log_global_log_level >= x) && \ - SCLogMessage(x, &_sc_log_err_temp,\ - __FILE__, \ - __LINE__, \ - __FUNCTION__) \ - == SC_OK) ) \ - { } else { \ - _sc_log_err_temp = \ - _sc_log_err_temp + \ - snprintf(_sc_log_err_temp, \ - (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_log_err_temp - _sc_log_err_msg)), \ - "[ERRCODE: %s(%d)] - ", \ - SCErrorToString(err), \ - err); \ - if ((_sc_log_err_temp - _sc_log_err_msg) > \ - SC_LOG_MAX_LOG_MSG_LEN) { \ - printf("Warning: Log message exceeded message length limit of %d\n",\ - SC_LOG_MAX_LOG_MSG_LEN); \ - _sc_log_err_temp = _sc_log_err_msg + \ - SC_LOG_MAX_LOG_MSG_LEN; \ - } else { \ - snprintf(_sc_log_err_temp, \ - (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_log_err_temp - _sc_log_err_msg)), \ - __VA_ARGS__); \ - } \ - SCLogOutputBuffer(x, _sc_log_err_msg); \ - } \ - } while(0) +#define SCLog(x, file, func, line, ...) \ + do { \ + if (sc_log_global_log_level >= x && \ + (sc_log_fg_filters_present == 0 || \ + SCLogMatchFGFilterWL(file, func, line) == 1 || \ + SCLogMatchFGFilterBL(file, func, line) == 1) && \ + (sc_log_fd_filters_present == 0 || \ + SCLogMatchFDFilter(func) == 1)) \ + { \ + char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ + \ + snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ + \ + SCLogMessage(x, file, line, func, SC_OK, _sc_log_msg); \ + } \ + } while(0) + +#define SCLogErr(x, file, func, line, err, ...) \ + do { \ + if (sc_log_global_log_level >= x && \ + (sc_log_fg_filters_present == 0 || \ + SCLogMatchFGFilterWL(file, func, line) == 1 || \ + SCLogMatchFGFilterBL(file, func, line) == 1) && \ + (sc_log_fd_filters_present == 0 || \ + SCLogMatchFDFilter(func) == 1)) \ + { \ + char _sc_log_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ + \ + snprintf(_sc_log_msg, SC_LOG_MAX_LOG_MSG_LEN, __VA_ARGS__); \ + \ + SCLogMessage(x, file, line, func, err, _sc_log_msg); \ + } \ + } while(0) /** * \brief Macro used to log INFORMATIONAL messages. * * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogInfo(...) SCLog(SC_LOG_INFO, __VA_ARGS__) +#define SCLogInfo(...) SCLog(SC_LOG_INFO, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define SCLogInfoRaw(file, func, line, ...) SCLog(SC_LOG_INFO, \ + (file), (func), (line), __VA_ARGS__) + +#define SCLogConfig(...) SCLog(SC_LOG_CONFIG, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define SCLogPerf(...) SCLog(SC_LOG_PERF, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) /** * \brief Macro used to log NOTICE messages. * * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogNotice(...) SCLog(SC_LOG_NOTICE, __VA_ARGS__) +#define SCLogNotice(...) SCLog(SC_LOG_NOTICE, \ + __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) +#define SCLogNoticeRaw(file, func, line, ... ) SCLog(SC_LOG_NOTICE, \ + (file), (func), (line), __VA_ARGS__) /** * \brief Macro used to log WARNING messages. @@ -266,8 +269,12 @@ extern int sc_log_module_cleaned; * warning message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogWarning(err_code, ...) SCLogErr(SC_LOG_WARNING, err_code, \ - __VA_ARGS__) +#define SCLogWarning(err_code, ...) SCLogErr(SC_LOG_WARNING, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) +#define SCLogWarningRaw(err_code, file, func, line, ...) \ + SCLogErr(SC_LOG_WARNING, (file), (func), (line), err_code, __VA_ARGS__) + /** * \brief Macro used to log ERROR messages. * @@ -275,8 +282,12 @@ extern int sc_log_module_cleaned; * error message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogError(err_code, ...) SCLogErr(SC_LOG_ERROR, err_code, \ - __VA_ARGS__) +#define SCLogError(err_code, ...) SCLogErr(SC_LOG_ERROR, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) +#define SCLogErrorRaw(err_code, file, func, line, ...) SCLogErr(SC_LOG_ERROR, \ + (file), (func), (line), err_code, __VA_ARGS__) + /** * \brief Macro used to log CRITICAL messages. * @@ -284,8 +295,9 @@ extern int sc_log_module_cleaned; * critical message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogCritical(err_code, ...) SCLogErr(SC_LOG_CRITICAL, err_code, \ - __VA_ARGS__) +#define SCLogCritical(err_code, ...) SCLogErr(SC_LOG_CRITICAL, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) /** * \brief Macro used to log ALERT messages. * @@ -293,8 +305,9 @@ extern int sc_log_module_cleaned; * alert message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogAlert(err_code, ...) SCLogErr(SC_LOG_ALERT, err_code, \ - __VA_ARGS__) +#define SCLogAlert(err_code, ...) SCLogErr(SC_LOG_ALERT, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) /** * \brief Macro used to log EMERGENCY messages. * @@ -302,8 +315,9 @@ extern int sc_log_module_cleaned; * emergency message * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogEmerg(err_code, ...) SCLogErr(SC_LOG_EMERGENCY, err_code, \ - __VA_ARGS__) +#define SCLogEmerg(err_code, ...) SCLogErr(SC_LOG_EMERGENCY, \ + __FILE__, __FUNCTION__, __LINE__, \ + err_code, __VA_ARGS__) /* Avoid the overhead of using the debugging subsystem, in production mode */ @@ -339,7 +353,7 @@ extern int sc_log_module_cleaned; * * \retval ... Takes as argument(s), a printf style format message */ -#define SCLogDebug(...) SCLog(SC_LOG_DEBUG, __VA_ARGS__) +#define SCLogDebug(...) SCLog(SC_LOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) /** * \brief Macro used to log debug messages on function entry. Comes under the @@ -350,19 +364,10 @@ extern int sc_log_module_cleaned; * \retval f An argument can be supplied, although it is not used */ #define SCEnter(f) do { \ - char _sc_enter_msg[SC_LOG_MAX_LOG_MSG_LEN]; \ - char *_sc_enter_temp = _sc_enter_msg; \ if (sc_log_global_log_level >= SC_LOG_DEBUG &&\ - SCLogCheckFDFilterEntry(__FUNCTION__) && \ - SCLogMessage(SC_LOG_DEBUG, &_sc_enter_temp, \ - __FILE__, \ - __LINE__, \ - __FUNCTION__) == SC_OK) { \ - snprintf(_sc_enter_temp, (SC_LOG_MAX_LOG_MSG_LEN - \ - (_sc_enter_msg - _sc_enter_temp)), \ - "Entering ... >>"); \ - SCLogOutputBuffer(SC_LOG_DEBUG, \ - _sc_enter_msg); \ + SCLogCheckFDFilterEntry(__FUNCTION__)) \ + { \ + SCLogDebug("Entering ... >>"); \ } \ } while(0) @@ -522,6 +527,24 @@ extern int sc_log_module_cleaned; #endif /* DEBUG */ +#define FatalError(x, ...) do { \ + SCLogError(x, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while(0) + +/** \brief Fatal error IF we're starting up, and configured to consider + * errors to be fatal errors */ +#define FatalErrorOnInit(x, ...) do { \ + int init_errors_fatal = 0; \ + ConfGetBool("engine.init-failure-fatal", &init_errors_fatal); \ + if (init_errors_fatal && (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT))\ + { \ + SCLogError(x, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } \ + SCLogWarning(x, __VA_ARGS__); \ +} while(0) + SCLogInitData *SCLogAllocLogInitData(void); @@ -532,13 +555,10 @@ void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *, SCLogInitData *); void SCLogInitLogModule(SCLogInitData *); -void SCLogInitLogModuleIfEnvSet(void); - void SCLogDeInitLogModule(void); -SCError SCLogMessage(SCLogLevel, char **, const char *, unsigned, const char *); - -void SCLogOutputBuffer(SCLogLevel, char *); +SCError SCLogMessage(const SCLogLevel, const char *, const unsigned int, + const char *, const SCError, const char *message); SCLogOPBuffer *SCLogAllocLogOPBuffer(void); diff --git a/src/util-decode-asn1.c b/src/util-decode-asn1.c index 6766af66c572..2404c3d843c6 100644 --- a/src/util-decode-asn1.c +++ b/src/util-decode-asn1.c @@ -319,7 +319,7 @@ void SCPrintByteBin(uint8_t byte) { uint8_t i = 0; for (i = 8; i > 0; i--) { - printf("%"PRIu8, ((byte >> (i - 1)) & 0x01)); + printf("%"PRIu8, (uint8_t)((byte >> (i - 1)) & 0x01)); if (i == 5) printf(" "); } @@ -373,13 +373,15 @@ void SCAsn1CtxDestroy(Asn1Ctx *ac) if (ac == NULL) return; - uint16_t i = 0; - for (; i < ac->cur_frame; i++) { + for (uint16_t i = 0; i < asn1_max_frames_config; i++) { Asn1Node *node = ASN1CTX_GET_NODE(ac, i); - if (node != NULL) { - SCFree(node); + if (node == NULL) { + break; } + SCFree(node); } + + SCFree(ac->asn1_stack); SCFree(ac); } @@ -886,19 +888,19 @@ int DecodeAsn1Test10(void) void DecodeAsn1RegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DecodeAsn1Test01", DecodeAsn1Test01, 1); - UtRegisterTest("DecodeAsn1Test02", DecodeAsn1Test02, 1); - UtRegisterTest("DecodeAsn1Test03", DecodeAsn1Test03, 1); + UtRegisterTest("DecodeAsn1Test01", DecodeAsn1Test01); + UtRegisterTest("DecodeAsn1Test02", DecodeAsn1Test02); + UtRegisterTest("DecodeAsn1Test03", DecodeAsn1Test03); - UtRegisterTest("DecodeAsn1Test04", DecodeAsn1Test04, 1); - UtRegisterTest("DecodeAsn1Test05", DecodeAsn1Test05, 1); - UtRegisterTest("DecodeAsn1Test06", DecodeAsn1Test06, 1); + UtRegisterTest("DecodeAsn1Test04", DecodeAsn1Test04); + UtRegisterTest("DecodeAsn1Test05", DecodeAsn1Test05); + UtRegisterTest("DecodeAsn1Test06", DecodeAsn1Test06); - UtRegisterTest("DecodeAsn1Test07", DecodeAsn1Test07, 1); - UtRegisterTest("DecodeAsn1Test08", DecodeAsn1Test08, 1); - UtRegisterTest("DecodeAsn1Test09", DecodeAsn1Test09, 1); + UtRegisterTest("DecodeAsn1Test07", DecodeAsn1Test07); + UtRegisterTest("DecodeAsn1Test08", DecodeAsn1Test08); + UtRegisterTest("DecodeAsn1Test09", DecodeAsn1Test09); - UtRegisterTest("DecodeAsn1Test10", DecodeAsn1Test10, 1); + UtRegisterTest("DecodeAsn1Test10", DecodeAsn1Test10); #endif } diff --git a/src/util-decode-asn1.h b/src/util-decode-asn1.h index d3ff9a3e8674..ed0fc7970932 100644 --- a/src/util-decode-asn1.h +++ b/src/util-decode-asn1.h @@ -34,7 +34,7 @@ #include #include -#define ASN1_MAX_FRAMES 128 +#define ASN1_MAX_FRAMES 256 /* For future enconding type implementations */ enum { diff --git a/src/util-decode-der-get.c b/src/util-decode-der-get.c index f2ac3f74be9e..3e90788f7459 100644 --- a/src/util-decode-der-get.c +++ b/src/util-decode-der-get.c @@ -37,45 +37,111 @@ #include "util-decode-der.h" #include "util-decode-der-get.h" +static const uint8_t SEQ_IDX_SERIAL[] = { 0, 0 }; static const uint8_t SEQ_IDX_ISSUER[] = { 0, 2 }; +static const uint8_t SEQ_IDX_VALIDITY[] = { 0, 3 }; static const uint8_t SEQ_IDX_SUBJECT[] = { 0, 4 }; static const char *Oid2ShortStr(const char *oid) { - if (strcmp(oid, "1.2.840.113549.1.9.1")==0) + if (strcmp(oid, "1.2.840.113549.1.9.1") == 0) return "emailAddress"; - if (strcmp(oid, "2.5.4.3")==0) + if (strcmp(oid, "2.5.4.3") == 0) return "CN"; - if (strcmp(oid, "2.5.4.5")==0) + if (strcmp(oid, "2.5.4.5") == 0) return "serialNumber"; - if (strcmp(oid, "2.5.4.6")==0) + if (strcmp(oid, "2.5.4.6") == 0) return "C"; - if (strcmp(oid, "2.5.4.7")==0) + if (strcmp(oid, "2.5.4.7") == 0) return "L"; - if (strcmp(oid, "2.5.4.8")==0) + if (strcmp(oid, "2.5.4.8") == 0) return "ST"; - if (strcmp(oid, "2.5.4.10")==0) + if (strcmp(oid, "2.5.4.10") == 0) return "O"; - if (strcmp(oid, "2.5.4.11")==0) + if (strcmp(oid, "2.5.4.11") == 0) return "OU"; + if (strcmp(oid, "0.9.2342.19200300.100.1.25") == 0) + return "DC"; + return "unknown"; } +static time_t GentimeToTime(char *gentime) +{ + time_t time; + struct tm tm; + + /* GeneralizedTime values MUST be expressed in Greenwich Mean Time + * (Zulu) and MUST include seconds (rfc5280 4.1.2.5.2). It MUST NOT + * include fractional seconds. It should therefore be on the format + * YYYYmmddHHMMSSZ. */ + if (strlen(gentime) != 15) + goto error; + + memset(&tm, 0, sizeof(tm)); + strptime(gentime, "%Y%m%d%H%M%SZ", &tm); + time = SCMkTimeUtc(&tm); + + if (time < 0) + goto error; + + return time; + +error: + return -1; +} + +static time_t UtctimeToTime(char *utctime) +{ + time_t time; + unsigned int year; + char yy[3]; + char buf[20]; + + /* UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) + * and MUST include seconds (rfc5280 4.1.2.5.1). It should + * therefore be on the format YYmmddHHMMSSZ. */ + if (strlen(utctime) != 13) + goto error; + + /* UTCTime use two digits to represent the year. The year field (YY) + * should be interpreted as 19YY when it is greater than or equal to + * 50. If it is less than 50 it should be interpreted as 20YY. + * Because of this, GeneralizedTime must be used for dates in the + * year 2050 or later. */ + strlcpy(yy, utctime, sizeof(yy)); + year = strtol(yy, NULL, 10); + if (year >= 50) + snprintf(buf, sizeof(buf), "%i%s", 19, utctime); + else + snprintf(buf, sizeof(buf), "%i%s", 20, utctime); + + time = GentimeToTime(buf); + if (time == -1) + goto error; + + return time; + +error: + return -1; +} + /** * \brief Iterate through an ASN.1 structure, following the index sequence. * Context specific elements are skipped. * * \retval The matching node, or NULL */ -const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode) +const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, + const uint32_t seqsz, uint32_t *errcode) { const Asn1Generic * node; uint8_t idx, i; @@ -125,10 +191,107 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, return node; } -int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) +int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, + time_t *not_after, uint32_t *errcode) { - const Asn1Generic *node_oid; const Asn1Generic *node, *it; + int rc = -1; + + if (errcode) + *errcode = ERR_DER_MISSING_ELEMENT; + + node = Asn1DerGet(cert, SEQ_IDX_VALIDITY, sizeof(SEQ_IDX_VALIDITY), errcode); + if ((node == NULL) || node->type != ASN1_SEQUENCE) + goto validity_error; + + it = node->data; + if (it == NULL || it->str == NULL) + goto validity_error; + + if (it->type == ASN1_UTCTIME) + *not_before = UtctimeToTime(it->str); + else if (it->type == ASN1_GENERALIZEDTIME) + *not_before = GentimeToTime(it->str); + else + goto validity_error; + + if (*not_before == -1) + goto validity_error; + + if (node->next == NULL) + goto validity_error; + + it = node->next->data; + + if (it == NULL || it->str == NULL) + goto validity_error; + + if (it->type == ASN1_UTCTIME) + *not_after = UtctimeToTime(it->str); + else if (it->type == ASN1_GENERALIZEDTIME) + *not_after = GentimeToTime(it->str); + else + goto validity_error; + + if (*not_after == -1) + goto validity_error; + + rc = 0; + +validity_error: + return rc; +} + +int Asn1DerGetSerial(const Asn1Generic *cert, char *buffer, uint32_t length, + uint32_t *errcode) +{ + const Asn1Generic *node; + uint32_t node_len, i; + int rc = -1; + + if (errcode) + *errcode = ERR_DER_MISSING_ELEMENT; + + buffer[0] = '\0'; + + node = Asn1DerGet(cert, SEQ_IDX_SERIAL, sizeof(SEQ_IDX_SERIAL), errcode); + if ((node == NULL) || node->type != ASN1_INTEGER || node->str == NULL) + goto serial_error; + + node_len = strlen(node->str); + + /* make sure the buffer is big enough */ + if (node_len + (node_len / 2) > length) + goto serial_error; + + /* format serial number (e.g. XX:XX:XX:XX:XX) */ + for (i = 0; i < node_len; i++) { + char c[3]; + /* insert separator before each even number */ + if (((i % 2) == 0) && (i != 0)) { + snprintf(c, sizeof(c), ":%c", node->str[i]); + } else { + snprintf(c, sizeof(c), "%c", node->str[i]); + } + + strlcat(buffer, c, length); + } + + if (errcode) + *errcode = 0; + + rc = 0; + +serial_error: + return rc; +} + +int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, + uint32_t *errcode) +{ + const Asn1Generic *node_oid; + const Asn1Generic *node; + const Asn1Generic *it; const Asn1Generic *node_set; const Asn1Generic *node_str; const char *shortname; @@ -140,6 +303,7 @@ int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, u if (length < 10) goto issuer_dn_error; + buffer[0] = '\0'; node = Asn1DerGet(cert, SEQ_IDX_ISSUER, sizeof(SEQ_IDX_ISSUER), errcode); @@ -183,7 +347,7 @@ int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, u goto issuer_dn_error; } - if (strcmp(shortname,"CN")==0) + if (strcmp(shortname,"CN") == 0) separator = "/"; if (it->next != NULL) strlcat(buffer, separator, length); @@ -198,10 +362,12 @@ int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, u return rc; } -int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode) +int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, + uint32_t *errcode) { const Asn1Generic *node_oid; - const Asn1Generic *node, *it; + const Asn1Generic *node; + const Asn1Generic *it; const Asn1Generic *node_set; const Asn1Generic *node_str; const char *shortname; @@ -213,6 +379,7 @@ int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, if (length < 10) goto subject_dn_error; + buffer[0] = '\0'; node = Asn1DerGet(cert, SEQ_IDX_SUBJECT, sizeof(SEQ_IDX_SUBJECT), errcode); @@ -257,7 +424,7 @@ int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, goto subject_dn_error; } - if (strcmp(shortname,"CN")==0) + if (strcmp(shortname,"CN") == 0) separator = "/"; if (it->next != NULL) strlcat(buffer, separator, length); @@ -272,4 +439,3 @@ int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, return rc; } -/* vim: set et ts=4 sw=4: */ diff --git a/src/util-decode-der-get.h b/src/util-decode-der-get.h index 79ecd7879c84..bed1cfebedba 100644 --- a/src/util-decode-der-get.h +++ b/src/util-decode-der-get.h @@ -38,6 +38,8 @@ const Asn1Generic * Asn1DerGet(const Asn1Generic *top, const uint8_t *seq_index, const uint32_t seqsz, uint32_t *errcode); int Asn1DerGetIssuerDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); +int Asn1DerGetSerial(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); +int Asn1DerGetValidity(const Asn1Generic *cert, time_t *not_before, time_t *not_after, uint32_t *errcode); int Asn1DerGetSubjectDN(const Asn1Generic *cert, char *buffer, uint32_t length, uint32_t *errcode); #endif /* __UTIL_DECODE_DER_GET_H__ */ diff --git a/src/util-decode-der.c b/src/util-decode-der.c index 3e7324be9cdb..d3fb3237f364 100644 --- a/src/util-decode-der.c +++ b/src/util-decode-der.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 ANSSI + * Copyright (C) 2011-2015 ANSSI * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,19 +49,48 @@ #define MAX_OID_LENGTH 256 -static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); -static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); +static Asn1Generic * DecodeAsn1DerGeneralizedTime(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode); static Asn1Generic * Asn1GenericNew(void) { @@ -98,7 +127,9 @@ static int Asn1SequenceAppend(Asn1Generic *seq, Asn1Generic *node) return 0; } -static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t max_size, uint8_t depth, int seq_index, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + int seq_index, uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t numbytes, el_max_size; @@ -119,23 +150,26 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t switch (el.cls) { case ASN1_CLASS_CONTEXTSPEC: - /* get element type from definition - * see http://www.ietf.org/rfc/rfc3280.txt) - */ + /* get element type from definition, see: + http://www.ietf.org/rfc/rfc3280.txt */ if (depth == 2 && el.tag == 0) { - el_type = ASN1_SEQUENCE; /* TBSCertificate */ + /* TBSCertificate */ + el_type = ASN1_SEQUENCE; break; } if (depth == 2 && el.tag == 1) { - el_type = ASN1_BITSTRING; /* issuerUniqueID */ + /* issuerUniqueID */ + el_type = ASN1_BITSTRING; break; } if (depth == 2 && el.tag == 2) { - el_type = ASN1_BITSTRING; /* subjectUniqueID */ + /* subjectUniqueID */ + el_type = ASN1_BITSTRING; break; } if (depth == 2 && el.tag == 3) { - el_type = ASN1_SEQUENCE; /* extensions */ + /* extensions */ + el_type = ASN1_SEQUENCE; break; } /* unknown context specific value - do not decode */ @@ -154,22 +188,27 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t child = DecodeAsn1DerNull(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_BITSTRING: - child = DecodeAsn1DerBitstring(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerBitstring(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_OID: child = DecodeAsn1DerOid(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_IA5STRING: - child = DecodeAsn1DerIA5String(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerIA5String(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_OCTETSTRING: - child = DecodeAsn1DerOctetString(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerOctetString(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_UTF8STRING: - child = DecodeAsn1DerUTF8String(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerUTF8String(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_PRINTSTRING: - child = DecodeAsn1DerPrintableString(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerPrintableString(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_SEQUENCE: child = DecodeAsn1DerSequence(d_ptr, el_max_size, depth+1, errcode); @@ -178,26 +217,35 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t child = DecodeAsn1DerSet(d_ptr, el_max_size, depth+1, errcode); break; case ASN1_T61STRING: - child = DecodeAsn1DerT61String(d_ptr, el_max_size, depth+1, errcode); + child = DecodeAsn1DerT61String(d_ptr, el_max_size, depth+1, + errcode); break; case ASN1_UTCTIME: child = DecodeAsn1DerUTCTime(d_ptr, el_max_size, depth+1, errcode); break; + case ASN1_GENERALIZEDTIME: + child = DecodeAsn1DerGeneralizedTime(d_ptr, el_max_size, depth+1, errcode); + break; default: /* unknown ASN.1 type */ child = NULL; child = Asn1GenericNew(); if (child == NULL) break; + child->type = el.tag; + /* total sequence length */ const unsigned char * save_d_ptr = d_ptr; d_ptr++; c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { child->length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; if (numbytes > el_max_size) { SCFree(child); @@ -212,20 +260,35 @@ static Asn1Generic * DecodeAsn1DerGeneric(const unsigned char *buffer, uint32_t d_ptr++; } } - /* fix the length for unknown objects, else - * sequence parsing will fail - */ + + /* fix the length for unknown objects, else sequence parsing + will fail */ child->length += (d_ptr - save_d_ptr); + + if (child->length > max_size - (d_ptr - buffer)) { + SCFree(child); + return NULL; + } + break; }; + if (child == NULL) return NULL; + /* child length should never be zero */ + if (child->length == 0) { + SCFree(child); + return NULL; + } + child->header = el; return child; } -static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; @@ -244,6 +307,7 @@ static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t d_ptr += 2; value = 0; + /* Here we need to ensure that numbytes is less than 4 so integer affectation is possible. We set the value to 0xffffffff which is by convention the unknown value. @@ -259,6 +323,7 @@ static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_INTEGER; a->length = (d_ptr - buffer) + numbytes; a->value = value; @@ -268,21 +333,25 @@ static Asn1Generic * DecodeAsn1DerInteger(const unsigned char *buffer, uint32_t SCFree(a); return NULL; } + for (i=0; istr + 2*i, 2*(numbytes-i)+1, "%02X", d_ptr[i]); } - a->str[2*numbytes]='\0'; + a->str[2*numbytes]= '\0'; return a; } -static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, uint8_t numbytes, uint32_t *errcode) +static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, + uint8_t numbytes, uint32_t *errcode) { int i; uint32_t value = 0; + if (numbytes > 4) { if (errcode) *errcode = ERR_DER_INVALID_SIZE; + /* too big won't fit: set it to 0xffffffff by convention */ value = 0xffffffff; *val = value; @@ -293,11 +362,14 @@ static int DecodeAsn1BuildValue(const unsigned char **d_ptr, uint32_t *val, uint (*d_ptr)++; } } + *val = value; return 0; } -static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; @@ -310,9 +382,11 @@ static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) { return NULL; } + a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_BOOLEAN; a->length = (d_ptr - buffer); a->value = value; @@ -320,7 +394,9 @@ static Asn1Generic * DecodeAsn1DerBoolean(const unsigned char *buffer, uint32_t return a; } -static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, + uint32_t size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint8_t numbytes; @@ -329,12 +405,15 @@ static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t siz numbytes = d_ptr[1]; d_ptr += 2; + if (DecodeAsn1BuildValue(&d_ptr, &value, numbytes, errcode) == -1) { return NULL; } + a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_NULL; a->length = (d_ptr - buffer); a->value = 0; @@ -342,7 +421,9 @@ static Asn1Generic * DecodeAsn1DerNull(const unsigned char *buffer, uint32_t siz return a; } -static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length; @@ -353,24 +434,29 @@ static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_ /* size */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } + if (length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_BITSTRING; a->strlen = length; + a->str = SCMalloc(length); if (a->str == NULL) { SCFree(a); @@ -384,7 +470,9 @@ static Asn1Generic * DecodeAsn1DerBitstring(const unsigned char *buffer, uint32_ return a; } -static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t oid_length, oid_value; @@ -396,23 +484,28 @@ static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_ /* size */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { oid_length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &oid_length, numbytes, errcode) == -1) { return NULL; } } + if (oid_length > max_size) return NULL; a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_OID; + a->str = SCMalloc(MAX_OID_LENGTH); if (a->str == NULL) { SCFree(a); @@ -423,8 +516,8 @@ static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_ snprintf(a->str, MAX_OID_LENGTH, "%d.%d", (d_ptr[0]/40), (d_ptr[0]%40)); d_ptr++; - /* sub-identifiers are multi valued, coded and 7 bits, first bit of the 8bits is used - to indicate, if a new value is starting */ + /* sub-identifiers are multi-valued, coded and 7 bits, first bit of + the 8bits is used to indicate, if a new value is starting */ for (i=1; istr); c = d_ptr[0]; @@ -445,7 +538,9 @@ static Asn1Generic * DecodeAsn1DerOid(const unsigned char *buffer, uint32_t max_ return a; } -static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; @@ -456,30 +551,39 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } - if (length > max_size) + + if (length == UINT32_MAX || length > max_size) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; + } a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_IA5STRING; a->strlen = length; + a->str = SCMalloc(length+1); if (a->str == NULL) { SCFree(a); return NULL; } - strlcpy(a->str, (const char*)d_ptr, length+1); + memcpy(a->str, (const char*)d_ptr, length); + a->str[length] = 0; d_ptr += length; @@ -487,7 +591,9 @@ static Asn1Generic * DecodeAsn1DerIA5String(const unsigned char *buffer, uint32_ return a; } -static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; @@ -498,26 +604,34 @@ static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint3 /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } - if (length > max_size) + + if (length == UINT32_MAX || length > max_size) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; + } a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_OCTETSTRING; a->strlen = length; - /* Add one to the octet string for the 0. This will then - * allow us to use the string in printf */ + + /* add one to the octet string for the 0. This will then allow us to + use the string in printf */ a->str = SCMalloc(length + 1); if (a->str == NULL) { SCFree(a); @@ -532,15 +646,21 @@ static Asn1Generic * DecodeAsn1DerOctetString(const unsigned char *buffer, uint3 return a; } -static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerUTF8String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { Asn1Generic *a = DecodeAsn1DerOctetString(buffer, max_size, depth, errcode); if (a != NULL) a->type = ASN1_UTF8STRING; + return a; } -static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, + uint32_t max_size, + uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t length, numbytes; @@ -551,31 +671,39 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &length, numbytes, errcode) == -1) { return NULL; } } - if (length > max_size) + + if (length == UINT32_MAX || length > max_size) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; return NULL; + } a = Asn1GenericNew(); if (a == NULL) return NULL; + a->type = ASN1_PRINTSTRING; a->strlen = length; + a->str = SCMalloc(length+1); if (a->str == NULL) { SCFree(a); return NULL; } - strlcpy(a->str, (const char*)d_ptr, length+1); - a->str[length] = '\0'; + memcpy(a->str, (const char*)d_ptr, length); + a->str[length] = 0; d_ptr += length; @@ -583,7 +711,9 @@ static Asn1Generic * DecodeAsn1DerPrintableString(const unsigned char *buffer, u return a; } -static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, parsed_bytes, numbytes, el_max_size; @@ -596,14 +726,17 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t node = Asn1GenericNew(); if (node == NULL) return NULL; + node->type = ASN1_SEQUENCE; /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { d_length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { @@ -612,7 +745,9 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t } } node->length = d_length + (d_ptr - buffer); - if (node->length > max_size) { + if (node->length > max_size || node->length < d_length /* wrap */) { + if (errcode) + *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; SCFree(node); return NULL; } @@ -624,8 +759,13 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t while (parsed_bytes < d_length) { el_max_size = max_size - (d_ptr-buffer); - Asn1Generic *child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); + Asn1Generic *child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, + seq_index, errcode); if (child == NULL) { + if (errcode && *errcode != 0) { + DerFree(node); + return NULL; + } break; } @@ -638,13 +778,14 @@ static Asn1Generic * DecodeAsn1DerSequence(const unsigned char *buffer, uint32_t parsed_bytes += child->length; d_ptr += child->length; seq_index++; - } return (Asn1Generic *)node; } -static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, numbytes, el_max_size; @@ -663,10 +804,12 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ /* total sequence length */ c = d_ptr[0]; - if ((c & (1<<7))>>7 == 0) { /* short form 8.1.3.4 */ + /* short form 8.1.3.4 */ + if ((c & (1<<7))>>7 == 0) { d_length = c; d_ptr++; - } else { /* long form 8.1.3.5 */ + /* long form 8.1.3.5 */ + } else { numbytes = c & 0x7f; d_ptr++; if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { @@ -674,9 +817,10 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ return NULL; } } + node->length = d_length + (d_ptr - buffer); - if (node->length > max_size) { + if (node->length > max_size || node->length < d_length /* wrap */) { if (errcode) *errcode = ERR_DER_ELEMENT_SIZE_TOO_BIG; SCFree(node); @@ -686,14 +830,21 @@ static Asn1Generic * DecodeAsn1DerSet(const unsigned char *buffer, uint32_t max_ seq_index = 0; el_max_size = max_size - (d_ptr-buffer); + child = DecodeAsn1DerGeneric(d_ptr, el_max_size, depth, seq_index, errcode); + if (child == NULL) { + DerFree(node); + return NULL; + } node->data = child; return (Asn1Generic *)node; } -static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { Asn1Generic *a; @@ -704,7 +855,9 @@ static Asn1Generic * DecodeAsn1DerT61String(const unsigned char *buffer, uint32_ return a; } -static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t max_size, uint8_t depth, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, + uint32_t max_size, uint8_t depth, + uint32_t *errcode) { Asn1Generic *a; @@ -715,14 +868,32 @@ static Asn1Generic * DecodeAsn1DerUTCTime(const unsigned char *buffer, uint32_t return a; } -Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode) +static Asn1Generic * DecodeAsn1DerGeneralizedTime(const unsigned char *buffer, + uint32_t max_size, + uint8_t depth, + uint32_t *errcode) +{ + Asn1Generic *a; + + a = DecodeAsn1DerIA5String(buffer, max_size, depth, errcode); + if (a != NULL) + a->type = ASN1_GENERALIZEDTIME; + + return a; +} + +Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, + uint32_t *errcode) { const unsigned char *d_ptr = buffer; uint32_t d_length, numbytes; Asn1Generic *cert; uint8_t c; - /* Check that buffer is an ASN.1 structure (basic checks) */ + if (size < 2) + return NULL; + + /* check that buffer is an ASN.1 structure (basic checks) */ if (d_ptr[0] != 0x30 && d_ptr[1] != 0x82) /* Sequence */ return NULL; @@ -735,6 +906,7 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *er if (DecodeAsn1BuildValue(&d_ptr, &d_length, numbytes, errcode) == -1) { return NULL; } + if (d_length+(d_ptr-buffer) != size) return NULL; @@ -746,6 +918,33 @@ Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *er return cert; } +#ifdef AFLFUZZ_DER +int DerParseDataFromFile(char *filename) +{ + uint8_t buffer[65536]; + uint32_t errcode = 0; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + size_t result = fread(&buffer, 1, sizeof(buffer), fp); + DecodeDer(buffer, result, &errcode); + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + return 0; +} +#endif /* AFLFUZZ_DER */ + void DerFree(Asn1Generic *a) { Asn1Generic *it, *n; diff --git a/src/util-decode-der.h b/src/util-decode-der.h index 4c4b1aaf1c4a..5383b4f1d1db 100644 --- a/src/util-decode-der.h +++ b/src/util-decode-der.h @@ -40,20 +40,21 @@ #define ASN1_CLASS_CONTEXTSPEC 2 #define ASN1_CLASS_PRIVATE 3 -#define ASN1_UNKNOWN 0 -#define ASN1_BOOLEAN 0x01 -#define ASN1_INTEGER 0x02 -#define ASN1_BITSTRING 0x03 -#define ASN1_OCTETSTRING 0x04 -#define ASN1_NULL 0x05 -#define ASN1_OID 0x06 -#define ASN1_UTF8STRING 0x0c -#define ASN1_SEQUENCE 0x10 -#define ASN1_SET 0x11 -#define ASN1_PRINTSTRING 0x13 -#define ASN1_T61STRING 0x14 -#define ASN1_IA5STRING 0x16 -#define ASN1_UTCTIME 0x17 +#define ASN1_UNKNOWN 0 +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BITSTRING 0x03 +#define ASN1_OCTETSTRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8STRING 0x0c +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTSTRING 0x13 +#define ASN1_T61STRING 0x14 +#define ASN1_IA5STRING 0x16 +#define ASN1_UTCTIME 0x17 +#define ASN1_GENERALIZEDTIME 0x18 typedef struct Asn1ElementType_ { uint8_t cls:2; @@ -93,4 +94,8 @@ typedef struct Asn1Generic_ { Asn1Generic * DecodeDer(const unsigned char *buffer, uint32_t size, uint32_t *errcode); void DerFree(Asn1Generic *a); +#ifdef AFLFUZZ_DER +int DerParseDataFromFile(char *filename); +#endif + #endif /* __UTIL_DECODE_DER_H__ */ diff --git a/src/util-decode-mime.c b/src/util-decode-mime.c new file mode 100644 index 000000000000..fcda28c05585 --- /dev/null +++ b/src/util-decode-mime.c @@ -0,0 +1,3061 @@ +/* Copyright (C) 2012 BAE Systems + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#include "suricata-common.h" + +#include "util-decode-mime.h" + +#include "util-spm-bs.h" +#include "util-unittest.h" +#include "util-memcmp.h" +#include "util-print.h" + +/* Character constants */ +#ifndef CR +#define CR 13 +#define LF 10 +#endif + +#define CRLF "\r\n" +#define COLON 58 +#define DASH 45 +#define PRINTABLE_START 33 +#define PRINTABLE_END 126 +#define UC_START 65 +#define UC_END 90 +#define LC_START 97 +#define LC_END 122 +#define UC_LC_DIFF 32 +#define EOL_LEN 2 + +/* Base-64 constants */ +#define BASE64_STR "Base64" + +/* Mime Constants */ +#define MAX_LINE_LEN 998 /* Def in RFC 2045, excluding CRLF sequence */ +#define MAX_ENC_LINE_LEN 76 /* Def in RFC 2045, excluding CRLF sequence */ +#define MAX_HEADER_NAME 75 /* 75 + ":" = 76 */ +#define MAX_HEADER_VALUE 2000 /* Default - arbitrary limit */ +#define BOUNDARY_BUF 256 +#define CTNT_TYPE_STR "content-type" +#define CTNT_DISP_STR "content-disposition" +#define CTNT_TRAN_STR "content-transfer-encoding" +#define MSG_ID_STR "message-id" +#define BND_START_STR "boundary=" +#define TOK_END_STR "\"" +#define MSG_STR "message/" +#define MULTIPART_STR "multipart/" +#define QP_STR "quoted-printable" +#define TXT_STR "text/plain" +#define HTML_STR "text/html" +#define URL_STR "http://" + +/* Memory Usage Constants */ +#define STACK_FREE_NODES 10 + +/* Other Constants */ +#define MAX_IP4_CHARS 15 +#define MAX_IP6_CHARS 39 + +/* Globally hold configuration data */ +static MimeDecConfig mime_dec_config = { 1, 1, 1, 0, MAX_HEADER_VALUE }; + +/* Mime Parser String translation */ +static const char *StateFlags[] = { "NONE", + "HEADER_READY", + "HEADER_STARTED", + "HEADER_DONE", + "BODY_STARTED", + "BODY_DONE", + "BODY_END_BOUND", + "PARSE_DONE", + "PARSE_ERROR", + NULL }; + +/* URL executable file extensions */ +static const char *UrlExeExts[] = { ".exe", + ".vbs", + ".bin", + ".cmd", + ".bat", + ".jar", + ".js", + NULL }; + +/** + * \brief Function used to print character strings that are not null-terminated + * + * \param log_level The logging level in which to print + * \param label A label for the string to print + * \param src The source string + * \param len The length of the string + * + * \return none + */ +static void PrintChars(int log_level, char *label, const uint8_t *src, uint32_t len) +{ +#ifdef DEBUG + if (log_level <= sc_log_global_log_level) { + printf("[%s]\n", label); + PrintRawDataFp(stdout, (uint8_t *)src, len); + } +#endif +} + +/** + * \brief Set global config policy + * + * \param config Config policy to set + * \return none + */ +void MimeDecSetConfig(MimeDecConfig *config) +{ + if (config != NULL) { + mime_dec_config = *config; + + /* Set to default */ + if (mime_dec_config.header_value_depth == 0) { + mime_dec_config.header_value_depth = MAX_HEADER_VALUE; + } + } else { + SCLogWarning(SC_ERR_MISSING_CONFIG_PARAM, "Invalid null configuration parameters"); + } +} + +/** + * \brief Get global config policy + * + * \return config data structure + */ +MimeDecConfig * MimeDecGetConfig(void) +{ + return &mime_dec_config; +} + +/** + * \brief Follow the 'next' pointers to the leaf + * + * \param node The root entity + * + * \return Pointer to leaf on 'next' side + * + */ +static MimeDecEntity *findLastSibling(MimeDecEntity *node) +{ + if (node == NULL) + return NULL; + while(node->next != NULL) + node = node->next; + return node; +} + +/** + * \brief Frees a mime entity tree + * + * \param entity The root entity + * + * \return none + * + */ +void MimeDecFreeEntity (MimeDecEntity *entity) +{ + if (entity == NULL) + return; + MimeDecEntity *lastSibling = findLastSibling(entity); + while (entity != NULL) + { + /** + * Move child to next + * Transform tree into list + */ + if (entity->child != NULL) + { + lastSibling->next = entity->child; + lastSibling = findLastSibling(lastSibling); + } + + /** + * Move to next element + */ + MimeDecEntity *old = entity; + entity = entity->next; + + MimeDecFreeField(old->field_list); + MimeDecFreeUrl(old->url_list); + SCFree(old->filename); + + SCFree(old); + } +} + +/** + * \brief Iteratively frees a header field entry list + * + * \param field The header field + * + * \return none + * + */ +void MimeDecFreeField(MimeDecField *field) +{ + MimeDecField *temp, *curr; + + if (field != NULL) { + + curr = field; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Free contents of node */ + SCFree(temp->name); + SCFree(temp->value); + + /* Now free node data */ + SCFree(temp); + } + } +} + +/** + * \brief Iteratively frees a URL entry list + * + * \param url The url entry + * + * \return none + * + */ +void MimeDecFreeUrl(MimeDecUrl *url) +{ + MimeDecUrl *temp, *curr; + + if (url != NULL) { + + curr = url; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node data */ + SCFree(temp->url); + SCFree(temp); + } + } +} + +/** + * \brief Creates and adds a header field entry to an entity + * + * The entity is optional. If NULL is specified, than a new stand-alone field + * is created. + * + * \param entity The parent entity + * + * \return The field object, or NULL if the operation fails + * + */ +MimeDecField * MimeDecAddField(MimeDecEntity *entity) +{ + MimeDecField *node = SCMalloc(sizeof(MimeDecField)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(MimeDecField)); + + /* If list is empty, then set as head of list */ + if (entity->field_list == NULL) { + entity->field_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->field_list; + entity->field_list = node; + } + + return node; +} + + +/** + * \brief Searches for header fields with the specified name + * + * \param entity The entity to search + * \param name The header name (lowercase) + * + * \return number of items found + * + */ +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data) +{ + MimeDecField *curr = entity->field_list; + int found = 0; + + while (curr != NULL) { + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + if (DataCallback(curr->value, curr->value_len, data)) + found++; + } + } + curr = curr->next; + } + + return found; +} + +/** + * \brief Searches for a header field with the specified name + * + * \param entity The entity to search + * \param name The header name (lowercase) + * + * \return The field object, or NULL if not found + * + */ +MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name) { + MimeDecField *curr = entity->field_list; + + while (curr != NULL) { + /* name is stored lowercase */ + if (strlen(name) == curr->name_len) { + if (SCMemcmp(curr->name, name, curr->name_len) == 0) { + break; + } + } + curr = curr->next; + } + + return curr; +} + +/** + * \brief Creates and adds a URL entry to the specified entity + * + * The entity is optional and if NULL is specified, then a new list will be created. + * + * \param entity The entity + * + * \return URL entry or NULL if the operation fails + * + */ +static MimeDecUrl * MimeDecAddUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len, uint8_t flags) +{ + MimeDecUrl *node = SCMalloc(sizeof(MimeDecUrl)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(MimeDecUrl)); + + node->url = url; + node->url_len = url_len; + node->url_flags = flags; + + /* If list is empty, then set as head of list */ + if (entity->url_list == NULL) { + entity->url_list = node; + } else { + /* Otherwise add to beginning of list since these are out-of-order in + * the message */ + node->next = entity->url_list; + entity->url_list = node; + } + + return node; +} + +/** + * \brief Creates and adds a child entity to the specified parent entity + * + * \param parent The parent entity + * + * \return The child entity, or NULL if the operation fails + * + */ +MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent) +{ + MimeDecEntity *curr, *node = SCMalloc(sizeof(MimeDecEntity)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(MimeDecEntity)); + + /* If parent is NULL then just return the new pointer */ + if (parent != NULL) { + if (parent->child == NULL) { + parent->child = node; + } else { + curr = parent->child; + while (curr->next != NULL) { + curr = curr->next; + } + curr->next = node; + } + } + + return node; +} + +/** + * \brief Creates a mime header field and fills in its values and adds it to the + * specified entity + * + * \param entity Entity in which to add the field + * \param name String containing the name + * \param nlen Length of the name + * \param value String containing the value + * \param vlen Length of the value + * + * \return The field or NULL if the operation fails + */ +static MimeDecField * MimeDecFillField(MimeDecEntity *entity, uint8_t *name, + uint32_t nlen, const uint8_t *value, uint32_t vlen) +{ + if (nlen == 0 && vlen == 0) + return NULL; + + MimeDecField *field = MimeDecAddField(entity); + if (unlikely(field == NULL)) { + return NULL; + } + + if (nlen > 0) { + /* convert to lowercase and store */ + uint32_t u; + for (u = 0; u < nlen; u++) + name[u] = tolower(name[u]); + + field->name = (uint8_t *)name; + field->name_len = nlen; + } + + if (vlen > 0) { + field->value = (uint8_t *)value; + field->value_len = vlen; + } + + return field; +} + +/** + * \brief Pushes a node onto a stack and returns the new node. + * + * \param stack The top of the stack + * + * \return pointer to a new node, otherwise NULL if it fails + */ +static MimeDecStackNode * PushStack(MimeDecStack *stack) +{ + /* Attempt to pull from free nodes list */ + MimeDecStackNode *node = stack->free_nodes; + if (node == NULL) { + node = SCMalloc(sizeof(MimeDecStackNode)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + } else { + /* Move free nodes pointer over */ + stack->free_nodes = stack->free_nodes->next; + stack->free_nodes_cnt--; + } + memset(node, 0x00, sizeof(MimeDecStackNode)); + + /* Push to top of stack */ + node->next = stack->top; + stack->top = node; + + /* Return a pointer to the top of the stack */ + return node; +} + +/** + * \brief Pops the top node from the stack and returns the next node. + * + * \param stack The top of the stack + * + * \return pointer to the next node, otherwise NULL if no nodes remain + */ +static MimeDecStackNode * PopStack(MimeDecStack *stack) +{ + /* Move stack pointer to next item */ + MimeDecStackNode *curr = stack->top; + if (curr != NULL) { + curr = curr->next; + } + + /* Always free alloc'd memory */ + SCFree(stack->top->bdef); + + /* Now move head to free nodes list */ + if (stack->free_nodes_cnt < STACK_FREE_NODES) { + stack->top->next = stack->free_nodes; + stack->free_nodes = stack->top; + stack->free_nodes_cnt++; + } else { + SCFree(stack->top); + } + stack->top = curr; + + /* Return a pointer to the top of the stack */ + return curr; +} + +/** + * \brief Frees the stack along with the free-nodes list + * + * \param stack The stack pointer + * + * \return none + */ +static void FreeMimeDecStack(MimeDecStack *stack) +{ + MimeDecStackNode *temp, *curr; + + if (stack != NULL) { + /* Top of stack */ + curr = stack->top; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp->bdef); + SCFree(temp); + } + + /* Free nodes */ + curr = stack->free_nodes; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp); + } + + SCFree(stack); + } +} + +/** + * \brief Adds a data value to the data values linked list + * + * \param dv The head of the linked list (NULL if new list) + * + * \return pointer to a new node, otherwise NULL if it fails + */ +static DataValue * AddDataValue(DataValue *dv) +{ + DataValue *curr, *node = SCMalloc(sizeof(DataValue)); + if (unlikely(node == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(node, 0x00, sizeof(DataValue)); + + if (dv != NULL) { + curr = dv; + while (curr->next != NULL) { + curr = curr->next; + } + + curr->next = node; + } + + return node; +} + +/** + * \brief Frees a linked list of data values starting at the head + * + * \param dv The head of the linked list + * + * \return none + */ +static void FreeDataValue(DataValue *dv) +{ + DataValue *temp, *curr; + + if (dv != NULL) { + curr = dv; + while (curr != NULL) { + temp = curr; + curr = curr->next; + + /* Now free node */ + SCFree(temp->value); + SCFree(temp); + } + } +} + +/** + * \brief Converts a list of data values into a single value (returns dynamically + * allocated memory) + * + * \param dv The head of the linked list (NULL if new list) + * \param len The output length of the single value + * + * \return pointer to a single value, otherwise NULL if it fails or is zero-length + */ +static uint8_t * GetFullValue(DataValue *dv, uint32_t *len) +{ + DataValue *curr; + uint32_t offset = 0; + uint8_t *val = NULL; + + /* First calculate total length */ + *len = 0; + curr = dv; + while (curr != NULL) { + *len += curr->value_len; + +#if 0 + /* Add CRLF except on last one */ + if (curr->next != NULL) { + *len += 2; + } +#endif + curr = curr->next; + } + + /* Must have at least one character in the value */ + if (*len > 0) { + val = SCCalloc(1, *len); + if (unlikely(val == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + *len = 0; + return NULL; + } + + curr = dv; + while (curr != NULL) { + memcpy(val + offset, curr->value, curr->value_len); + offset += curr->value_len; + +#if 0 /* VJ unclear why this is needed ? */ + /* Add CRLF except on last one */ + if (curr->next != NULL) { + memcpy(val + offset, CRLF, 2); + offset += 2; + } +#endif + curr = curr->next; + } + } + + return val; +} + +/** + * \brief Find a string while searching up to N characters within a source + * buffer + * + * \param src The source string (not null-terminated) + * \param len The length of the source string + * \param find The string to find (null-terminated) + * \param find_len length of the 'find' string + * + * \return Pointer to the position it was found, otherwise NULL if not found + */ +static inline uint8_t * FindBuffer(const uint8_t *src, uint32_t len, const uint8_t *find, uint32_t find_len) +{ + /* Use utility search function */ + return BasicSearchNocase(src, len, find, find_len); +} + +/** + * \brief Get a line (CRLF or just CR or LF) from a buffer (similar to GetToken) + * + * \param buf The input buffer (not null-terminated) + * \param blen The length of the input buffer + * \param remainPtr Pointer to remaining after tokenizing iteration + * \param tokLen Output token length (if non-null line) + * + * \return Pointer to line + */ +static uint8_t * GetLine(uint8_t *buf, uint32_t blen, uint8_t **remainPtr, + uint32_t *tokLen) +{ + uint32_t i; + uint8_t *tok; + + /* So that it can be used just like strtok_r */ + if (buf == NULL) { + buf = *remainPtr; + } else { + *remainPtr = buf; + } + if (buf == NULL) + return NULL; + + tok = buf; + + /* length must be specified */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* Found delimiter */ + if (buf[i] == CR || buf[i] == LF) { + + /* Add another if we find either CRLF or LFCR */ + *remainPtr += (i + 1); + if ((i + 1 < blen) && buf[i] != buf[i + 1] && + (buf[i + 1] == CR || buf[i + 1] == LF)) { + (*remainPtr)++; + } + break; + } + } + + /* If no delimiter found, then point to end of buffer */ + if (buf == *remainPtr) { + (*remainPtr) += i; + } + + /* Calculate token length */ + *tokLen = (buf + i) - tok; + + return tok; +} + +/** + * \brief Get token from buffer and return pointer to it + * + * \param buf The input buffer (not null-terminated) + * \param blen The length of the input buffer + * \param delims Character delimiters (null-terminated) + * \param remainPtr Pointer to remaining after tokenizing iteration + * \param tokLen Output token length (if non-null line) + * + * \return Pointer to token, or NULL if not found + */ +static uint8_t * GetToken(uint8_t *buf, uint32_t blen, const char *delims, + uint8_t **remainPtr, uint32_t *tokenLen) +{ + uint32_t i, j, delimFound = 0; + uint8_t *tok = NULL; + + /* So that it can be used just like strtok_r */ + if (buf == NULL) { + buf = *remainPtr; + } else { + *remainPtr = buf; + } + if (buf == NULL) + return NULL; + + /* Must specify length */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* Look for delimiters */ + for (j = 0; delims[j] != 0; j++) { + if (buf[i] == delims[j]) { + /* Data must be found before delimiter matters */ + if (tok != NULL) { + (*remainPtr) += (i + 1); + } + delimFound = 1; + break; + } + } + + /* If at least one non-delimiter found, then a token is found */ + if (tok == NULL && !delimFound) { + tok = buf + i; + } else { + /* Reset delimiter */ + delimFound = 0; + } + + /* If delimiter found, then break out of loop */ + if (buf != *remainPtr) { + break; + } + } + + /* Make sure remaining points to end of buffer if delimiters not found */ + if (tok != NULL) { + if (buf == *remainPtr) { + (*remainPtr) += i; + } + + /* Calculate token length */ + *tokenLen = (buf + i) - tok; + } + + return tok; +} + +/** + * \brief Stores the final MIME header value into the current entity on the + * stack. + * + * \param state The parser state + * + * \return MIME_DEC_OK if stored, otherwise a negative number indicating error + */ +static int StoreMimeHeader(MimeDecParseState *state) +{ + int ret = MIME_DEC_OK, stored = 0; + uint8_t *val; + uint32_t vlen; + + /* Lets save the most recent header */ + if (state->hname != NULL || state->hvalue != NULL) { + SCLogDebug("Storing last header"); + val = GetFullValue(state->hvalue, &vlen); + if (val != NULL) { + if (state->hname == NULL) { + SCLogDebug("Error: Invalid parser state - header value without" + " name"); + ret = MIME_DEC_ERR_PARSE; + } else if (state->stack->top != NULL) { + /* Store each header name and value */ + if (MimeDecFillField(state->stack->top->data, state->hname, + state->hlen, val, vlen) == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "MimeDecFillField() function failed"); + ret = MIME_DEC_ERR_MEM; + } else { + stored = 1; + } + } else { + SCLogDebug("Error: Stack pointer missing"); + ret = MIME_DEC_ERR_DATA; + } + } else if (state->hvalue != NULL) { + /* Memory allocation must have failed since val is NULL */ + SCLogError(SC_ERR_MEM_ALLOC, "GetFullValue() function failed"); + ret = MIME_DEC_ERR_MEM; + } + + /* Do cleanup here */ + if (!stored) { + SCFree(state->hname); + SCFree(val); + } + state->hname = NULL; + FreeDataValue(state->hvalue); + state->hvalue = NULL; + state->hvlen = 0; + } + + return ret; +} + +/** + * \brief Function determines whether a url string points to an executable + * based on file extension only. + * + * \param url The url string + * \param len The url string length + * + * \retval 1 The url points to an EXE + * \retval 0 The url does NOT point to an EXE + */ +static int IsExeUrl(const uint8_t *url, uint32_t len) +{ + int isExeUrl = 0; + uint32_t i, extLen; + uint8_t *ext; + + /* Now check for executable extensions and if not found, cut off at first '/' */ + for (i = 0; UrlExeExts[i] != NULL; i++) { + extLen = strlen(UrlExeExts[i]); + ext = FindBuffer(url, len, (uint8_t *)UrlExeExts[i], strlen(UrlExeExts[i])); + if (ext != NULL && (ext + extLen - url == (int)len || ext[extLen] == '?')) { + isExeUrl = 1; + break; + } + } + + return isExeUrl; +} + +/** + * \brief Function determines whether a host string is a numeric IP v4 address + * + * \param urlhost The host string + * \param len The host string length + * + * \retval 1 The host is a numeric IP + * \retval 0 The host is NOT a numeric IP + */ +static int IsIpv4Host(const uint8_t *urlhost, uint32_t len) +{ + struct sockaddr_in sa; + char tempIp[MAX_IP4_CHARS + 1]; + + /* Cut off at '/' */ + uint32_t i = 0; + for (i = 0; i < len && urlhost[i] != 0; i++) { + + if (urlhost[i] == '/') { + break; + } + } + + /* Too many chars */ + if (i > MAX_IP4_CHARS) { + return 0; + } + + /* Create null-terminated string */ + memcpy(tempIp, urlhost, i); + tempIp[i] = '\0'; + + return inet_pton(AF_INET, tempIp, &(sa.sin_addr)); +} + +/** + * \brief Function determines whether a host string is a numeric IP v6 address + * + * \param urlhost The host string + * \param len The host string length + * + * \retval 1 The host is a numeric IP + * \retval 0 The host is NOT a numeric IP + */ +static int IsIpv6Host(const uint8_t *urlhost, uint32_t len) +{ + struct in6_addr in6; + char tempIp[MAX_IP6_CHARS + 1]; + + /* Cut off at '/' */ + uint32_t i = 0; + for (i = 0; i < len && urlhost[i] != 0; i++) { + + if (urlhost[i] == '/') { + break; + } + } + + /* Too many chars */ + if (i > MAX_IP6_CHARS) { + return 0; + } + + /* Create null-terminated string */ + memcpy(tempIp, urlhost, i); + tempIp[i] = '\0'; + + return inet_pton(AF_INET6, tempIp, &in6); +} + +/** + * \brief Traverses through the list of URLs for an exact match of the specified + * string + * + * \param entity The MIME entity + * \param url The matching URL string (lowercase) + * \param url_len The matching URL string length + * + * \return URL object or NULL if not found + */ +static MimeDecUrl *FindExistingUrl(MimeDecEntity *entity, uint8_t *url, uint32_t url_len) +{ + MimeDecUrl *curr = entity->url_list; + + while (curr != NULL) { + if (url_len == curr->url_len) { + /* search url and stored url are both in + * lowercase, so we can do an exact match */ + if (SCMemcmp(curr->url, url, url_len) == 0) { + break; + } + } + curr = curr->next; + } + + return curr; +} + +/** + * \brief This function searches a text or html line for a URL string + * + * URLS are generally truncated to the 'host.domain' format because + * some email messages contain dozens or even hundreds of URLs with + * the same host, but with only small variations in path. + * + * The exception is that URLs with executable file extensions are stored + * with the full path. They are stored in lowercase. + * + * Numeric IPs, malformed numeric IPs, and URLs pointing to executables are + * also flagged as URLs of interest. + * + * \param line the line + * \param len the line length + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int FindUrlStrings(const uint8_t *line, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + uint8_t *fptr, *remptr, *tok = NULL, *tempUrl; + uint32_t tokLen = 0, i, tempUrlLen; + uint8_t urlStrLen = 0, flags = 0; + + remptr = (uint8_t *)line; + do { + SCLogDebug("Looking for URL String starting with: %s", URL_STR); + + /* Check for token definition */ + fptr = FindBuffer(remptr, len - (remptr - line), (uint8_t *)URL_STR, strlen(URL_STR)); + if (fptr != NULL) { + + urlStrLen = strlen(URL_STR); + fptr += urlStrLen; /* Start at end of start string */ + tok = GetToken(fptr, len - (fptr - line), " \"\'<>]\t", &remptr, + &tokLen); + if (tok == fptr) { + SCLogDebug("Found url string"); + + /* First copy to temp URL string */ + tempUrl = SCMalloc(urlStrLen + tokLen); + if (unlikely(tempUrl == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + + PrintChars(SC_LOG_DEBUG, "RAW URL", tok, tokLen); + + /* Copy over to temp URL while decoding */ + tempUrlLen = 0; + for (i = 0; i < tokLen && tok[i] != 0; i++) { + + // URL decoding would probably go here + + /* url is all lowercase */ + tempUrl[tempUrlLen] = tolower(tok[i]); + tempUrlLen++; + } + + /* Determine if URL points to an EXE */ + if (IsExeUrl(tempUrl, tempUrlLen)) { + flags |= URL_IS_EXE; + + PrintChars(SC_LOG_DEBUG, "EXE URL", tempUrl, tempUrlLen); + } else { + /* Not an EXE URL */ + /* Cut off length at first '/' */ + /* If seems that BAESystems had done the following + in support of PEScan. We don't want it for logging. + Therefore its been removed. + tok = FindString(tempUrl, tempUrlLen, "/"); + if (tok != NULL) { + tempUrlLen = tok - tempUrl; + } + */ + } + + /* Make sure remaining URL exists */ + if (tempUrlLen > 0) { + if (!(FindExistingUrl(entity, tempUrl, tempUrlLen))) { + /* Now look for numeric IP */ + if (IsIpv4Host(tempUrl, tempUrlLen)) { + flags |= URL_IS_IP4; + + PrintChars(SC_LOG_DEBUG, "IP URL4", tempUrl, tempUrlLen); + } else if (IsIpv6Host(tempUrl, tempUrlLen)) { + flags |= URL_IS_IP6; + + PrintChars(SC_LOG_DEBUG, "IP URL6", tempUrl, tempUrlLen); + } + + /* Add URL list item */ + MimeDecAddUrl(entity, tempUrl, tempUrlLen, flags); + } else { + SCFree(tempUrl); + } + } else { + SCFree(tempUrl); + } + } + } + } while (fptr != NULL); + + return ret; +} + +/** + * \brief This function is a pre-processor for handling decoded data chunks that + * then invokes the caller's callback function for further processing + * + * \param chunk The decoded chunk + * \param len The decoded chunk length (varies) + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessDecodedDataChunk(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t *remainPtr, *tok; + uint32_t tokLen; + + if ((state->stack != NULL) && (state->stack->top != NULL) && + (state->stack->top->data != NULL)) { + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->extract_urls) { + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + /* If plain text or html, then look for URLs */ + if (((entity->ctnt_flags & CTNT_IS_TEXT) || + (entity->ctnt_flags & CTNT_IS_MSG) || + (entity->ctnt_flags & CTNT_IS_HTML)) && + ((entity->ctnt_flags & CTNT_IS_ATTACHMENT) == 0)) { + + /* Remainder from previous line */ + if (state->linerem_len > 0) { + // TODO + } else { + /* No remainder from previous line */ + /* Parse each line one by one */ + remainPtr = (uint8_t *)chunk; + do { + tok = GetLine(remainPtr, len - (remainPtr - (uint8_t *)chunk), + &remainPtr, &tokLen); + if (tok != remainPtr) { + // DEBUG - ADDED + /* If last token found without CR/LF delimiter, then save + * and reconstruct with next chunk + */ + if (tok + tokLen - (uint8_t *) chunk == (int)len) { + PrintChars(SC_LOG_DEBUG, "LAST CHUNK LINE - CUTOFF", + tok, tokLen); + SCLogDebug("\nCHUNK CUTOFF CHARS: %u delim %u\n", + tokLen, len - (uint32_t)(tok + tokLen - (uint8_t *) chunk)); + } else { + /* Search line for URL */ + ret = FindUrlStrings(tok, tokLen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindUrlStrings() function" + " failed: %d", ret); + break; + } + } + } + } while (tok != remainPtr && remainPtr - (uint8_t *) chunk < (int)len); + } + } + } + + /* Now invoke callback */ + if (state->DataChunkProcessorFunc != NULL) { + ret = state->DataChunkProcessorFunc(chunk, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: state->dataChunkProcessor() callback function" + " failed"); + } + } + } else { + SCLogDebug("Error: Stack pointer missing"); + ret = MIME_DEC_ERR_DATA; + } + + /* Reset data chunk buffer */ + state->data_chunk_len = 0; + + /* Mark body / file as no longer at beginning */ + state->body_begin = 0; + + return ret; +} + +/** + * \brief Processes a remainder (line % 4 = remainder) from the previous line + * such that all base64 decoding attempts are divisible by 4 + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * \param force Flag indicating whether decoding should always occur + * + * \return Number of bytes pulled from the current buffer + */ +static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len, + MimeDecParseState *state, int force) +{ + uint32_t ret; + uint8_t remainder = 0, remdec = 0; + + SCLogDebug("Base64 line remainder found: %u", state->bvr_len); + + /* Fill in block with first few bytes of current line */ + remainder = B64_BLOCK - state->bvr_len; + remainder = remainder < len ? remainder : len; + if (remainder && buf) { + memcpy(state->bvremain + state->bvr_len, buf, remainder); + } + state->bvr_len += remainder; + + /* If data chunk buffer will be full, then clear it now */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, + state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + } + } + + /* Only decode if divisible by 4 */ + if (state->bvr_len == B64_BLOCK || force) { + remdec = DecodeBase64(state->data_chunk + state->data_chunk_len, + state->bvremain, state->bvr_len, 1); + if (remdec > 0) { + + /* Track decoded length */ + state->stack->top->data->decoded_body_len += remdec; + + /* Update length */ + state->data_chunk_len += remdec; + + /* If data chunk buffer is now full, then clear */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, + state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + } else { + /* Track failed base64 */ + state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; + state->msg->anomaly_flags |= ANOM_INVALID_BASE64; + SCLogDebug("Error: DecodeBase64() function failed"); + PrintChars(SC_LOG_DEBUG, "Base64 failed string", state->bvremain, state->bvr_len); + } + + /* Reset remaining */ + state->bvr_len = 0; + } + + return remainder; +} + +/** + * \brief Processes a body line by base64-decoding and passing to the data chunk + * processing callback function when the buffer is read + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t rem1 = 0, rem2 = 0; + uint32_t numDecoded, remaining, offset, avail, tobuf; + + /* Track long line */ + if (len > MAX_ENC_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; + state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; + SCLogDebug("Error: Max encoded input line length exceeded %u > %u", + len, MAX_ENC_LINE_LEN); + } + + /* First process remaining from previous line */ + if (state->bvr_len > 0) { + + SCLogDebug("Base64 line remainder found: %u", state->bvr_len); + + /* Process remainder and return number of bytes pulled from current buffer */ + rem1 = ProcessBase64Remainder(buf, len, state, 0); + } + + /* No error and at least some more data needs to be decoded */ + if ((int) (len - rem1) > 0) { + + /* Determine whether we need to save a remainder if not divisible by 4 */ + rem2 = (len - rem1) % B64_BLOCK; + if (rem2 > 0) { + + SCLogDebug("Base64 saving remainder: %u", rem2); + + memcpy(state->bvremain, buf + (len - rem2), rem2); + state->bvr_len = rem2; + } + + /* Process remaining in loop in case buffer fills up */ + remaining = len - rem1 - rem2; + offset = rem1; + while (remaining > 0) { + + /* Determine amount to add to buffer */ + avail = (DATA_CHUNK_SIZE - state->data_chunk_len) * B64_BLOCK / ASCII_BLOCK; + tobuf = avail > remaining ? remaining : avail; + while (tobuf % 4 != 0) { + tobuf--; + } + + if (tobuf < B64_BLOCK) { + SCLogDebug("Error: Invalid state for decoding base-64 block"); + return MIME_DEC_ERR_PARSE; + } + + SCLogDebug("Decoding: %u", len - rem1 - rem2); + + numDecoded = DecodeBase64(state->data_chunk + state->data_chunk_len, + buf + offset, tobuf, 1); + if (numDecoded > 0) { + + /* Track decoded length */ + state->stack->top->data->decoded_body_len += numDecoded; + + /* Update length */ + state->data_chunk_len += numDecoded; + + if ((int) (DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { + SCLogDebug("Error: Invalid Chunk length: %u", + state->data_chunk_len); + ret = MIME_DEC_ERR_PARSE; + break; + } + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, + state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() " + "function failed"); + } + } + } else { + /* Track failed base64 */ + state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64; + state->msg->anomaly_flags |= ANOM_INVALID_BASE64; + SCLogDebug("Error: DecodeBase64() function failed"); + PrintChars(SC_LOG_DEBUG, "Base64 failed string", buf + offset, tobuf); + } + + /* Update counts */ + remaining -= tobuf; + offset += tobuf; + } + } + + return ret; +} + +/** + * \brief Decoded a hex character into its equivalent byte value for + * quoted-printable decoding + * + * \param h The hex char + * + * \return byte value on success, -1 if failed + **/ +static int16_t DecodeQPChar(char h) +{ + uint16_t res = 0; + + /* 0-9 */ + if (h >= 48 && h <= 57) { + res = h - 48; + } else if (h >= 65 && h <= 70) { + /* A-F */ + res = h - 55; + } else { + /* Invalid */ + res = -1; + } + + return res; + +} + +/** + * \brief Processes a quoted-printable encoded body line by decoding and passing + * to the data chunk processing callback function when the buffer is read + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessQuotedPrintableBodyLine(const uint8_t *buf, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint32_t remaining, offset; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + uint8_t c, h1, h2, val; + int16_t res; + + /* Track long line */ + if (len > MAX_ENC_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE; + state->msg->anomaly_flags |= ANOM_LONG_ENC_LINE; + SCLogDebug("Error: Max encoded input line length exceeded %u > %u", + len, MAX_ENC_LINE_LEN); + } + + remaining = len; + offset = 0; + while (remaining > 0) { + + c = *(buf + offset); + + /* Copy over normal character */ + if (c != '=') { + state->data_chunk[state->data_chunk_len] = c; + state->data_chunk_len++; + entity->decoded_body_len += 1; + + /* Add CRLF sequence if end of line */ + if (remaining == 1) { + memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + entity->decoded_body_len += EOL_LEN; + } + } else if (remaining > 1) { + /* If last character handle as soft line break by ignoring, + otherwise process as escaped '=' character */ + + /* Not enough characters */ + if (remaining < 3) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + h1 = *(buf + offset + 1); + res = DecodeQPChar(h1); + if (res < 0) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + val = (res << 4); /* Shift result left */ + h2 = *(buf + offset + 2); + res = DecodeQPChar(h2); + if (res < 0) { + entity->anomaly_flags |= ANOM_INVALID_QP; + state->msg->anomaly_flags |= ANOM_INVALID_QP; + SCLogDebug("Error: Quoted-printable decoding failed"); + } else { + /* Decoding sequence succeeded */ + val += res; + + state->data_chunk[state->data_chunk_len] = val; + state->data_chunk_len++; + entity->decoded_body_len++; + + /* Add CRLF sequence if end of line */ + if (remaining == 3) { + memcpy(state->data_chunk + state->data_chunk_len, + CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + entity->decoded_body_len += EOL_LEN; + } + + /* Account for extra 2 characters in 3-characted QP + * sequence */ + remaining -= 2; + offset += 2; + } + } + } + } + + /* Change by 1 */ + remaining--; + offset++; + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, + state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + } + + return ret; +} + +/** + * \brief Processes a body line by base64-decoding (if applicable) and passing to + * the data chunk processing callback function + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessBodyLine(const uint8_t *buf, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint32_t remaining, offset, avail, tobuf; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + + SCLogDebug("Processing body line"); + + /* Track length */ + entity->body_len += len + 2; /* With CRLF */ + + /* Process base-64 content if enabled */ + MimeDecConfig *mdcfg = MimeDecGetConfig(); + if (mdcfg != NULL && mdcfg->decode_base64 && + (entity->ctnt_flags & CTNT_IS_BASE64)) { + + ret = ProcessBase64BodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBase64BodyLine() function failed"); + } + } else if (mdcfg != NULL && mdcfg->decode_quoted_printable && + (entity->ctnt_flags & CTNT_IS_QP)) { + /* Process quoted-printable content if enabled */ + ret = ProcessQuotedPrintableBodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessQuotedPrintableBodyLine() function " + "failed"); + } + } else { + /* Process non-decoded content */ + remaining = len; + offset = 0; + while (remaining > 0) { + + /* Plan to add CRLF to the end of each line */ + avail = DATA_CHUNK_SIZE - state->data_chunk_len; + tobuf = avail > remaining + EOL_LEN ? remaining : avail - EOL_LEN; + + /* Copy over to buffer */ + memcpy(state->data_chunk + state->data_chunk_len, buf + offset, tobuf); + state->data_chunk_len += tobuf; + + /* Now always add a CRLF to the end */ + if (tobuf == remaining) { + memcpy(state->data_chunk + state->data_chunk_len, CRLF, EOL_LEN); + state->data_chunk_len += EOL_LEN; + } + + if ((int) (DATA_CHUNK_SIZE - state->data_chunk_len) < 0) { + SCLogDebug("Error: Invalid Chunk length: %u", + state->data_chunk_len); + ret = MIME_DEC_ERR_PARSE; + break; + } + + /* If buffer full, then invoke callback */ + if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) { + + /* Invoke pre-processor and callback */ + ret = ProcessDecodedDataChunk(state->data_chunk, + state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function " + "failed"); + } + } + + remaining -= tobuf; + offset += tobuf; + } + } + + return ret; +} + +/** + * \brief Find the start of a header name on the current line + * + * \param buf The input line (not null-terminated) + * \param blen The length of the input line + * \param glen The output length of the header name + * + * \return Pointer to header name, or NULL if not found + */ +static uint8_t * FindMimeHeaderStart(const uint8_t *buf, uint32_t blen, uint32_t *hlen) +{ + uint32_t i, valid = 0; + uint8_t *hname = NULL; + + /* Init */ + *hlen = 0; + + /* Look for sequence of printable characters followed by ':', or + CRLF then printable characters followed by ':' */ + for (i = 0; i < blen && buf[i] != 0; i++) { + + /* If ready for printable characters and found one, then increment */ + if (buf[i] != COLON && buf[i] >= PRINTABLE_START && + buf[i] <= PRINTABLE_END) { + valid++; + } else if (valid > 0 && buf[i] == COLON) { + /* If ready for printable characters, found some, and found colon + * delimiter, then a match is found */ + hname = (uint8_t *) buf + i - valid; + *hlen = valid; + break; + } else { + /* Otherwise reset and quit */ + break; + } + } + + return hname; +} + +/** + * \brief Find full header name and value on the current line based on the + * current state + * + * \param buf The current line (no CRLF) + * \param blen The length of the current line + * \param state The current state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int FindMimeHeader(const uint8_t *buf, uint32_t blen, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t *hname, *hval = NULL; + DataValue *dv; + uint32_t hlen, vlen; + int finish_header = 0, new_header = 0; + MimeDecConfig *mdcfg = MimeDecGetConfig(); + + /* Find first header */ + hname = FindMimeHeaderStart(buf, blen, &hlen); + if (hname != NULL) { + + /* Warn and track but don't do anything yet */ + if (hlen > MAX_HEADER_NAME) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_NAME; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_NAME; + SCLogDebug("Error: Header name exceeds limit (%u > %u)", + hlen, MAX_HEADER_NAME); + } + + /* Value starts after 'header:' (normalize spaces) */ + hval = hname + hlen + 1; + if (hval - buf >= (int)blen) { + SCLogDebug("No Header value found"); + hval = NULL; + } else { + while (hval[0] == ' ') { + + /* If last character before end of bounds, set to NULL */ + if (hval - buf >= (int)blen - 1) { + SCLogDebug("No Header value found"); + hval = NULL; + break; + } + + hval++; + } + } + + /* If new header found, then previous header is finished */ + if (state->state_flag == HEADER_STARTED) { + finish_header = 1; + } + + /* Now process new header */ + new_header = 1; + + /* Must wait for next line to determine if finished */ + state->state_flag = HEADER_STARTED; + } else if (blen == 0) { + /* Found body */ + /* No more headers */ + state->state_flag = HEADER_DONE; + + finish_header = 1; + + SCLogDebug("All Header processing finished"); + } else if (state->state_flag == HEADER_STARTED) { + /* Found multi-line value (ie. Received header) */ + /* If max header value exceeded, flag it */ + vlen = blen; + if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { + SCLogDebug("Error: Header value of length (%u) is too long", + state->hvlen + vlen); + vlen = mdcfg->header_value_depth - state->hvlen; + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + } + if (vlen > 0) { + dv = AddDataValue(state->hvalue); + if (dv == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "AddDataValue() function failed"); + return MIME_DEC_ERR_MEM; + } + if (state->hvalue == NULL) { + state->hvalue = dv; + } + + dv->value = SCMalloc(vlen); + if (unlikely(dv->value == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + memcpy(dv->value, buf, vlen); + dv->value_len = vlen; + state->hvlen += vlen; + } + } else { + /* Likely a body without headers */ + SCLogDebug("No headers found"); + + state->state_flag = BODY_STARTED; + + /* Flag beginning of body */ + state->body_begin = 1; + state->body_end = 0; + + ret = ProcessBodyLine(buf, blen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyLine() function failed"); + return ret; + } + } + + /* If we need to finish a header, then do so below and then cleanup */ + if (finish_header) { + /* Store the header value */ + ret = StoreMimeHeader(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: StoreMimeHeader() function failed"); + return ret; + } + } + + /* When next header is found, we always create a new one */ + if (new_header) { + /* Copy name and value to state */ + state->hname = SCMalloc(hlen); + if (unlikely(state->hname == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + memcpy(state->hname, hname, hlen); + state->hlen = hlen; + + if (state->hvalue != NULL) { + SCLogDebug("Error: Parser failed due to unexpected header " + "value"); + return MIME_DEC_ERR_DATA; + } + + if (hval != NULL) { + /* If max header value exceeded, flag it */ + vlen = blen - (hval - buf); + if ((mdcfg != NULL) && (state->hvlen + vlen > mdcfg->header_value_depth)) { + SCLogDebug("Error: Header value of length (%u) is too long", + state->hvlen + vlen); + vlen = mdcfg->header_value_depth - state->hvlen; + state->stack->top->data->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + state->msg->anomaly_flags |= ANOM_LONG_HEADER_VALUE; + } + + if (vlen > 0) { + state->hvalue = AddDataValue(NULL); + if (state->hvalue == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "AddDataValue() function failed"); + return MIME_DEC_ERR_MEM; + } + state->hvalue->value = SCMalloc(vlen); + if (unlikely(state->hvalue->value == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + memcpy(state->hvalue->value, hval, vlen); + state->hvalue->value_len = vlen; + state->hvlen += vlen; + } + } + } + + return ret; +} + +/** + * \brief Finds a mime header token within the specified field + * + * \param field The current field + * \param search_start The start of the search (ie. boundary=\") + * \param search_end The end of the search (ie. \") + * \param tlen The output length of the token (if found) + * + * \return A pointer to the token if found, otherwise NULL if not found + */ +static uint8_t * FindMimeHeaderToken(MimeDecField *field, char *search_start, + char *search_end, uint32_t *tlen) +{ + uint8_t *fptr, *tptr = NULL, *tok = NULL; + + SCLogDebug("Looking for token: %s", search_start); + + /* Check for token definition */ + fptr = FindBuffer(field->value, field->value_len, (const uint8_t *)search_start, strlen(search_start)); + if (fptr != NULL) { + fptr += strlen(search_start); /* Start at end of start string */ + tok = GetToken(fptr, field->value_len - (fptr - field->value), search_end, + &tptr, tlen); + if (tok != NULL) { + SCLogDebug("Found mime token"); + } + } + + return tok; +} + +/** + * \brief Processes the current line for mime headers and also does post-processing + * when all headers found + * + * \param buf The current line + * \param len The length of the line + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeHeaders(const uint8_t *buf, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + MimeDecField *field; + uint8_t *bptr = NULL, *rptr = NULL; + uint32_t blen = 0; + MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data; + + /* Look for mime header in current line */ + ret = FindMimeHeader(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: FindMimeHeader() function failed: %d", ret); + return ret; + } + + /* Post-processing after all headers done */ + if (state->state_flag == HEADER_DONE) { + /* First determine encoding by looking at Content-Transfer-Encoding */ + field = MimeDecFindField(entity, CTNT_TRAN_STR); + if (field != NULL) { + /* Look for base64 */ + if (FindBuffer(field->value, field->value_len, (const uint8_t *)BASE64_STR, strlen(BASE64_STR))) { + SCLogDebug("Base64 encoding found"); + entity->ctnt_flags |= CTNT_IS_BASE64; + } else if (FindBuffer(field->value, field->value_len, (const uint8_t *)QP_STR, strlen(QP_STR))) { + /* Look for quoted-printable */ + SCLogDebug("quoted-printable encoding found"); + entity->ctnt_flags |= CTNT_IS_QP; + } + } + + /* Check for file attachment in content disposition */ + field = MimeDecFindField(entity, CTNT_DISP_STR); + if (field != NULL) { + bptr = FindMimeHeaderToken(field, "filename=", TOK_END_STR, &blen); + if (bptr != NULL) { + SCLogDebug("File attachment found in disposition"); + entity->ctnt_flags |= CTNT_IS_ATTACHMENT; + + /* Copy over using dynamic memory */ + entity->filename = SCMalloc(blen); + if (unlikely(entity->filename == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + memcpy(entity->filename, bptr, blen); + entity->filename_len = blen; + } + } + + /* Check for boundary, encapsulated message, and file name in Content-Type */ + field = MimeDecFindField(entity, CTNT_TYPE_STR); + if (field != NULL) { + /* Check if child entity boundary definition found */ + bptr = FindMimeHeaderToken(field, BND_START_STR, TOK_END_STR, &blen); + if (bptr != NULL) { + state->found_child = 1; + entity->ctnt_flags |= CTNT_IS_MULTIPART; + + if (blen > (BOUNDARY_BUF - 2)) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; + return MIME_DEC_ERR_PARSE; + } + + /* Store boundary in parent node */ + state->stack->top->bdef = SCMalloc(blen); + if (unlikely(state->stack->top->bdef == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + memcpy(state->stack->top->bdef, bptr, blen); + state->stack->top->bdef_len = blen; + } + + /* Look for file name (if not already found) */ + if (!(entity->ctnt_flags & CTNT_IS_ATTACHMENT)) { + bptr = FindMimeHeaderToken(field, "name=", TOK_END_STR, &blen); + if (bptr != NULL) { + SCLogDebug("File attachment found"); + entity->ctnt_flags |= CTNT_IS_ATTACHMENT; + + /* Copy over using dynamic memory */ + entity->filename = SCMalloc(blen); + if (unlikely(entity->filename == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return MIME_DEC_ERR_MEM; + } + memcpy(entity->filename, bptr, blen); + entity->filename_len = blen; + } + } + + /* Pull out short-hand content type */ + entity->ctnt_type = GetToken(field->value, field->value_len, " \r\n;", + &rptr, &entity->ctnt_type_len); + if (entity->ctnt_type != NULL) { + /* Check for encapsulated message */ + if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)MSG_STR, strlen(MSG_STR))) + { + SCLogDebug("Found encapsulated message entity"); + + entity->ctnt_flags |= CTNT_IS_ENV; + + /* Create and push child to stack */ + MimeDecEntity *child = MimeDecAddEntity(entity); + if (child == NULL) + return MIME_DEC_ERR_MEM; + child->ctnt_flags |= (CTNT_IS_ENCAP | CTNT_IS_MSG); + PushStack(state->stack); + state->stack->top->data = child; + + /* Mark as encapsulated child */ + state->stack->top->is_encap = 1; + + /* Ready to parse headers */ + state->state_flag = HEADER_READY; + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)MULTIPART_STR, strlen(MULTIPART_STR))) + { + /* Check for multipart */ + SCLogDebug("Found multipart entity"); + entity->ctnt_flags |= CTNT_IS_MULTIPART; + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)TXT_STR, strlen(TXT_STR))) + { + /* Check for plain text */ + SCLogDebug("Found plain text entity"); + entity->ctnt_flags |= CTNT_IS_TEXT; + } else if (FindBuffer(entity->ctnt_type, entity->ctnt_type_len, + (const uint8_t *)HTML_STR, strlen(HTML_STR))) + { + /* Check for html */ + SCLogDebug("Found html entity"); + entity->ctnt_flags |= CTNT_IS_HTML; + } + } + } + + /* Store pointer to Message-ID */ + field = MimeDecFindField(entity, MSG_ID_STR); + if (field != NULL) { + entity->msg_id = field->value; + entity->msg_id_len = field->value_len; + } + + /* Flag beginning of body */ + state->body_begin = 1; + state->body_end = 0; + } + + return ret; +} + +/** + * \brief Indicates to the parser that the body of an entity has completed + * processing on the previous line + * + * \param state The current parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ + +static int ProcessBodyComplete(MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + SCLogDebug("Process body complete called"); + + /* Mark the file as hitting the end */ + state->body_end = 1; + + if (state->bvr_len > 0) { + SCLogDebug("Found (%u) remaining base64 bytes not processed", + state->bvr_len); + + /* Process the remainder */ + ret = ProcessBase64Remainder(NULL, 0, state, 1); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBase64BodyLine() function failed"); + } + } + +#ifdef HAVE_NSS + if (state->md5_ctx) { + unsigned int len = 0; + HASH_End(state->md5_ctx, state->md5, &len, sizeof(state->md5)); + } +#endif + + /* Invoke pre-processor and callback with remaining data */ + ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessDecodedDataChunk() function failed"); + } + + /* Now reset */ + state->body_begin = 0; + state->body_end = 0; + + return ret; +} + +/** + * \brief When a mime boundary is found, look for end boundary and also do stack + * management + * + * \param buf The current line + * \param len The length of the line + * \param bdef_len The length of the current boundary + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeBoundary(const uint8_t *buf, uint32_t len, uint32_t bdef_len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t *rptr; + MimeDecEntity *child; + + SCLogDebug("PROCESSING BOUNDARY - START: %d", + state->state_flag); + + /* If previous line was not an end boundary, then we process the body as + * completed */ + if (state->state_flag != BODY_END_BOUND) { + + /* First lets complete the body */ + ret = ProcessBodyComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyComplete() function failed"); + return ret; + } + } else { + /* If last line was an end boundary, then now we are ready to parse + * headers again */ + state->state_flag = HEADER_READY; + } + + /* Update remaining buffer */ + rptr = (uint8_t *) buf + bdef_len + 2; + + /* If entity is encapsulated and current and parent didn't define the boundary, + * then pop out */ + if (state->stack->top->is_encap && state->stack->top->bdef_len == 0) { + + if (state->stack->top->next == NULL) { + SCLogDebug("Error: Missing parent entity from stack"); + return MIME_DEC_ERR_DATA; + } + + if (state->stack->top->next->bdef_len == 0) { + + SCLogDebug("POPPED ENCAPSULATED CHILD FROM STACK: %p=%p", + state->stack->top, state->stack->top->data); + + /* If end of boundary found, pop the child off the stack */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + } + + /* Now check for end of nested boundary */ + if (len - (rptr - buf) > 1 && rptr[0] == DASH && rptr[1] == DASH) { + SCLogDebug("FOUND END BOUNDARY, POPPING: %p=%p", + state->stack->top, state->stack->top->data); + + /* If end of boundary found, pop the child off the stack */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* If current is an encapsulated message with a boundary definition, + * then pop him as well */ + if (state->stack->top->is_encap && state->stack->top->bdef_len != 0) { + SCLogDebug("FOUND END BOUNDARY AND ENCAP, POPPING: %p=%p", + state->stack->top, state->stack->top->data); + + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + + state->state_flag = BODY_END_BOUND; + } else if (state->found_child) { + /* Otherwise process new child */ + SCLogDebug("Child entity created"); + + /* Create and push child to stack */ + child = MimeDecAddEntity(state->stack->top->data); + if (child == NULL) + return MIME_DEC_ERR_MEM; + child->ctnt_flags |= CTNT_IS_BODYPART; + PushStack(state->stack); + state->stack->top->data = child; + + /* Reset flag */ + state->found_child = 0; + } else { + /* Otherwise process sibling */ + if (state->stack->top->next == NULL) { + SCLogDebug("Error: Missing parent entity from stack"); + return MIME_DEC_ERR_DATA; + } + + SCLogDebug("SIBLING CREATED, POPPING PARENT: %p=%p", + state->stack->top, state->stack->top->data); + + /* First pop current to get access to parent */ + PopStack(state->stack); + if (state->stack->top == NULL) { + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* Create and push child to stack */ + child = MimeDecAddEntity(state->stack->top->data); + if (child == NULL) + return MIME_DEC_ERR_MEM; + child->ctnt_flags |= CTNT_IS_BODYPART; + PushStack(state->stack); + state->stack->top->data = child; + } + + /* After boundary look for headers */ + if (state->state_flag != BODY_END_BOUND) { + state->state_flag = HEADER_READY; + } + + SCLogDebug("PROCESSING BOUNDARY - END: %d", state->state_flag); + return ret; +} + +/** + * \brief Processes the MIME Entity body based on the input line and current + * state of the parser + * + * \param buf The current line + * \param len The length of the line + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeBody(const uint8_t *buf, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + uint8_t temp[BOUNDARY_BUF]; + uint8_t *bstart; + int body_found = 0; + uint32_t tlen; + +#ifdef HAVE_NSS + if (MimeDecGetConfig()->body_md5) { + if (state->body_begin == 1) { + if (state->md5_ctx == NULL) { + state->md5_ctx = HASH_Create(HASH_AlgMD5); + HASH_Begin(state->md5_ctx); + } + } + HASH_Update(state->md5_ctx, buf, len + state->current_line_delimiter_len); + } +#endif + + /* Ignore empty lines */ + if (len == 0) { + return ret; + } + + /* First look for boundary */ + MimeDecStackNode *node = state->stack->top; + if (node == NULL) { + SCLogDebug("Error: Invalid stack state"); + return MIME_DEC_ERR_PARSE; + } + + /* Traverse through stack to find a boundary definition */ + if (state->state_flag == BODY_END_BOUND || node->bdef == NULL) { + + /* If not found, then use parent's boundary */ + node = node->next; + while (node != NULL && node->bdef == NULL) { + SCLogDebug("Traversing through stack for node with boundary"); + node = node->next; + } + } + + /* This means no boundary / parent w/boundary was found so we are in the body */ + if (node == NULL) { + body_found = 1; + } else { + + /* Now look for start of boundary */ + if (len > 1 && buf[0] == '-' && buf[1] == '-') { + + tlen = node->bdef_len + 2; + if (tlen > BOUNDARY_BUF) { + if (state->stack->top->data) + state->stack->top->data->anomaly_flags |= ANOM_LONG_BOUNDARY; + return MIME_DEC_ERR_PARSE; + } + + memcpy(temp, "--", 2); + memcpy(temp + 2, node->bdef, node->bdef_len); + + /* Find either next boundary or end boundary */ + bstart = FindBuffer((const uint8_t *)buf, len, temp, tlen); + if (bstart != NULL) { + ret = ProcessMimeBoundary(buf, len, node->bdef_len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeBoundary() function " + "failed"); + return ret; + } + } else { + /* Otherwise add value to body */ + body_found = 1; + } + } else { + /* Otherwise add value to body */ + body_found = 1; + } + } + + /* Process body line */ + if (body_found) { + state->state_flag = BODY_STARTED; + + ret = ProcessBodyLine(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyLine() function failed"); + return ret; + } + } + + return ret; +} + +const char *MimeDecParseStateGetStatus(MimeDecParseState *state) +{ + return StateFlags[state->state_flag]; +} + +/** + * \brief Processes the MIME Entity based on the input line and current state of + * the parser + * + * \param buf The current line + * \param len The length of the line + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +static int ProcessMimeEntity(const uint8_t *buf, uint32_t len, + MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + SCLogDebug("START FLAG: %s", StateFlags[state->state_flag]); + + /* Track long line */ + if (len > MAX_LINE_LEN) { + state->stack->top->data->anomaly_flags |= ANOM_LONG_LINE; + state->msg->anomaly_flags |= ANOM_LONG_LINE; + SCLogDebug("Error: Max input line length exceeded %u > %u", len, + MAX_LINE_LEN); + } + + /* Looking for headers */ + if (state->state_flag == HEADER_READY || + state->state_flag == HEADER_STARTED) { + + SCLogDebug("Processing Headers"); + + /* Process message headers */ + ret = ProcessMimeHeaders(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeHeaders() function failed: %d", + ret); + return ret; + } + } else { + /* Processing body */ + SCLogDebug("Processing Body of: %p", state->stack->top); + + ret = ProcessMimeBody(buf, len, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessMimeBody() function failed: %d", + ret); + return ret; + } + } + + SCLogDebug("END FLAG: %s", StateFlags[state->state_flag]); + + return ret; +} + +/** + * \brief Init the parser by allocating memory for the state and top-level entity + * + * \param data A caller-specified pointer to data for access within the data chunk + * processor callback function + * \param dcpfunc The data chunk processor callback function + * + * \return A pointer to the state object, or NULL if the operation fails + */ +MimeDecParseState * MimeDecInitParser(void *data, + int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state)) +{ + MimeDecParseState *state; + MimeDecEntity *mimeMsg; + + state = SCMalloc(sizeof(MimeDecParseState)); + if (unlikely(state == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + return NULL; + } + memset(state, 0x00, sizeof(MimeDecParseState)); + + state->stack = SCMalloc(sizeof(MimeDecStack)); + if (unlikely(state->stack == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(state); + return NULL; + } + memset(state->stack, 0x00, sizeof(MimeDecStack)); + + mimeMsg = SCMalloc(sizeof(MimeDecEntity)); + if (unlikely(mimeMsg == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(state->stack); + SCFree(state); + return NULL; + } + memset(mimeMsg, 0x00, sizeof(MimeDecEntity)); + mimeMsg->ctnt_flags |= CTNT_IS_MSG; + + /* Init state */ + state->msg = mimeMsg; + PushStack(state->stack); + if (state->stack->top == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "memory allocation failed"); + SCFree(state->stack); + SCFree(state); + return NULL; + } + state->stack->top->data = mimeMsg; + state->state_flag = HEADER_READY; + state->data = data; + state->DataChunkProcessorFunc = DataChunkProcessorFunc; + + return state; +} + +/** + * \brief De-Init parser by freeing up any residual memory + * + * \param state The parser state + * + * \return none + */ +void MimeDecDeInitParser(MimeDecParseState *state) +{ + uint32_t cnt = 0; + + while (state->stack->top != NULL) { + SCLogDebug("Remaining on stack: [%p]=>[%p]", + state->stack->top, state->stack->top->data); + + PopStack(state->stack); + cnt++; + } + + if (cnt > 1) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Warning: Stack is not empty upon completion of " + "processing (%u items remaining)", cnt); + } + + SCFree(state->hname); + FreeDataValue(state->hvalue); + FreeMimeDecStack(state->stack); +#ifdef HAVE_NSS + if (state->md5_ctx) + HASH_Destroy(state->md5_ctx); +#endif + SCFree(state); +} + +/** + * \brief Called to indicate that the last message line has been processed and + * the parsing operation is complete + * + * This function should be called directly by the caller. + * + * \param state The parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +int MimeDecParseComplete(MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + SCLogDebug("Parsing flagged as completed"); + + /* Store the header value */ + ret = StoreMimeHeader(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: StoreMimeHeader() function failed"); + return ret; + } + + /* Lets complete the body */ + ret = ProcessBodyComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: ProcessBodyComplete() function failed"); + return ret; + } + + if (state->stack->top == NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + + /* If encapsulated, pop off the stack */ + if (state->stack->top->is_encap) { + PopStack(state->stack); + if (state->stack->top == NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Error: Message is malformed"); + return MIME_DEC_ERR_DATA; + } + } + + /* Look extra stack items remaining */ + if (state->stack->top->next != NULL) { + state->msg->anomaly_flags |= ANOM_MALFORMED_MSG; + SCLogDebug("Warning: Message has unclosed message part boundary"); + } + + state->state_flag = PARSE_DONE; + + return ret; +} + +/** + * \brief Parse a line of a MIME message and update the parser state + * + * \param line A string representing the line (w/out CRLF) + * \param len The length of the line + * \param delim_len The length of the line end delimiter + * \param state The parser state + * + * \return MIME_DEC_OK on success, otherwise < 0 on failure + */ +int MimeDecParseLine(const uint8_t *line, const uint32_t len, + const uint8_t delim_len, MimeDecParseState *state) +{ + int ret = MIME_DEC_OK; + + /* For debugging purposes */ + if (len > 0) { + PrintChars(SC_LOG_DEBUG, "SMTP LINE", line, len); + } else { + SCLogDebug("SMTP LINE - EMPTY"); + } + + state->current_line_delimiter_len = delim_len; + /* Process the entity */ + ret = ProcessMimeEntity(line, len, state); + if (ret != MIME_DEC_OK) { + state->state_flag = PARSE_ERROR; + SCLogDebug("Error: ProcessMimeEntity() function failed: %d", ret); + } + + return ret; +} + +/** + * \brief Parses an entire message when available in its entirety (wraps the + * line-based parsing functions) + * + * \param buf Buffer pointing to the full message + * \param blen Length of the buffer + * \param data Caller data to be available in callback + * \param dcpfunc Callback for processing each decoded body data chunk + * + * \return A pointer to the decoded MIME message, or NULL if the operation fails + */ +MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, + int (*dcpfunc)(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state)) +{ + int ret = MIME_DEC_OK; + uint8_t *remainPtr, *tok; + uint32_t tokLen; + + MimeDecParseState *state = MimeDecInitParser(data, dcpfunc); + if (state == NULL) { + SCLogDebug("Error: MimeDecInitParser() function failed to create " + "state"); + return NULL; + } + + MimeDecEntity *msg = state->msg; + + /* Parse each line one by one */ + remainPtr = (uint8_t *) buf; + uint8_t *line = NULL; + do { + tok = GetLine(remainPtr, blen - (remainPtr - buf), &remainPtr, &tokLen); + if (tok != remainPtr) { + + line = tok; + + state->current_line_delimiter_len = (remainPtr - tok) - tokLen; + /* Parse the line */ + ret = MimeDecParseLine(line, tokLen, + (remainPtr - tok) - tokLen, state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: MimeDecParseLine() function failed: %d", + ret); + break; + } + } + + } while (tok != remainPtr && remainPtr - buf < (int)blen); + + if (ret == MIME_DEC_OK) { + SCLogDebug("Message parser was successful"); + + /* Now complete message */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + SCLogDebug("Error: MimeDecParseComplete() function failed"); + } + } + + /* De-allocate memory for parser */ + MimeDecDeInitParser(state); + + if (ret != MIME_DEC_OK) { + MimeDecFreeEntity(msg); + msg = NULL; + } + + return msg; +} + +#ifdef AFLFUZZ_MIME +static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) +{ + return MIME_DEC_OK; +} + +int MimeParserDataFromFile(char *filename) +{ + int result = 1; + uint8_t buffer[256]; + +#ifdef AFLFUZZ_PERSISTANT_MODE + while (__AFL_LOOP(1000)) { + /* reset state */ + memset(buffer, 0, sizeof(buffer)); +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + FILE *fp = fopen(filename, "r"); + BUG_ON(fp == NULL); + + uint32_t line_count = 0; + + MimeDecParseState *state = MimeDecInitParser(&line_count, + MimeParserDataFromFileCB); + + while (1) { + int done = 0; + size_t size = fread(&buffer, 1, sizeof(buffer), fp); + if (size < sizeof(buffer)) + done = 1; + + (void) MimeDecParseLine(buffer, size, 1, state); + + if (done) + break; + } + + /* Completed */ + (void)MimeDecParseComplete(state); + + if (state->msg) { + MimeDecFreeEntity(state->msg); + } + + /* De Init parser */ + MimeDecDeInitParser(state); + + fclose(fp); + +#ifdef AFLFUZZ_PERSISTANT_MODE + } +#endif /* AFLFUZZ_PERSISTANT_MODE */ + + result = 0; + return result; +} +#endif /* AFLFUZZ_MIME */ + +#ifdef UNITTESTS + +/* Helper body chunk callback function */ +static int TestDataChunkCallback(const uint8_t *chunk, uint32_t len, + MimeDecParseState *state) +{ + uint32_t *line_count = (uint32_t *) state->data; + + if (state->body_begin) { + SCLogDebug("Body begin (len=%u)", len); + } + + /* Add up the line counts */ + if (len > 0) { + + uint8_t *remainPtr; + uint8_t *tok; + uint32_t tokLen; + + PrintChars(SC_LOG_DEBUG, "CHUNK", chunk, len); + + /* Parse each line one by one */ + remainPtr = (uint8_t *) chunk; + do { + tok = GetLine(remainPtr, len - (remainPtr - (uint8_t *) chunk), + &remainPtr, &tokLen); + if (tok != NULL && tok != remainPtr) { + (*line_count)++; + } + + } while (tok != NULL && tok != remainPtr && + (uint32_t)(remainPtr - (uint8_t *) chunk) < len); + + SCLogDebug("line count (len=%u): %u", len, *line_count); + } + + if (state->body_end) { + SCLogDebug("Body end (len=%u)", len); + } + + return MIME_DEC_OK; +} + +/* Test simple case of line counts */ +static int MimeDecParseLineTest01(void) +{ + int ret = MIME_DEC_OK; + + uint32_t expected_count = 3; + uint32_t line_count = 0; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, + TestDataChunkCallback); + + char *str = "From: Sender1"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "To: Recipient1"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "Content-Type: text/plain"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = ""; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "A simple message line 1"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "A simple message line 2"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "A simple message line 3"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + if (ret != MIME_DEC_OK) { + return 0; + } + /* Completed */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + return 0; + } + + MimeDecEntity *msg = state->msg; + if (msg->next != NULL || msg->child != NULL) { + SCLogInfo("Error: Invalid sibling or child message"); + return 0; + } + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + SCLogInfo("LINE COUNT FINISHED: %d", line_count); + + if (expected_count != line_count) { + SCLogInfo("Error: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return 0; + } + + return 1; +} + +/* Test simple case of EXE URL extraction */ +static int MimeDecParseLineTest02(void) +{ + int ret = MIME_DEC_OK; + + uint32_t expected_count = 2; + uint32_t line_count = 0; + + MimeDecGetConfig()->decode_base64 = 1; + MimeDecGetConfig()->decode_quoted_printable = 1; + MimeDecGetConfig()->extract_urls = 1; + + /* Init parser */ + MimeDecParseState *state = MimeDecInitParser(&line_count, + TestDataChunkCallback); + + char *str = "From: Sender1"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "To: Recipient1"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "Content-Type: text/plain"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = ""; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "A simple message line 1"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + str = "A simple message line 2 click on http://www.test.com/malware.exe?" + "hahah hopefully you click this link"; + ret |= MimeDecParseLine((uint8_t *)str, strlen(str), 1, state); + + if (ret != MIME_DEC_OK) { + return 0; + } + /* Completed */ + ret = MimeDecParseComplete(state); + if (ret != MIME_DEC_OK) { + return 0; + } + + MimeDecEntity *msg = state->msg; + if (msg->url_list == NULL || (msg->url_list != NULL && + !(msg->url_list->url_flags & URL_IS_EXE))) { + SCLogInfo("Warning: Expected EXE URL not found"); + return 0; + } + + MimeDecFreeEntity(msg); + + /* De Init parser */ + MimeDecDeInitParser(state); + + SCLogInfo("LINE COUNT FINISHED: %d", line_count); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return 0; + } + + return 1; +} + +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest01(void) +{ + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender1\r\n" + "To: Recipient1\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, + TestDataChunkCallback); + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return 0; + } + + MimeDecFreeEntity(entity); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return 0; + } + + return 1; +} + +/* Test full message with linebreaks */ +static int MimeDecParseFullMsgTest02(void) +{ + uint32_t expected_count = 3; + uint32_t line_count = 0; + + char msg[] = "From: Sender2\r\n" + "To: Recipient2\r\n" + "Subject: subject2\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Line 1\r\n" + "Line 2\r\n" + "Line 3\r\n"; + + MimeDecEntity *entity = MimeDecParseFullMsg((uint8_t *)msg, strlen(msg), &line_count, + TestDataChunkCallback); + + if (entity == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return 0; + } + + MimeDecField *field = MimeDecFindField(entity, "subject"); + if (field == NULL) { + SCLogInfo("Warning: Message failed to parse"); + return 0; + } + + if (field->value_len != sizeof("subject2") - 1) { + SCLogInfo("Warning: failed to get subject"); + return 0; + } + + if (memcmp(field->value, "subject2", field->value_len) != 0) { + SCLogInfo("Warning: failed to get subject"); + return 0; + } + + + MimeDecFreeEntity(entity); + + if (expected_count != line_count) { + SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", + expected_count, line_count); + return 0; + } + + return 1; +} + +static int MimeBase64DecodeTest01(void) +{ + int ret = 0; + + char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" + "#$%^&*()-=_+,./;'[]<>?:"; + char *base64msg = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QU" + "VJTVFVWV1hZWjEyMzQ1Njc4OTBAIyQlXiYqKCktPV8rLC4vOydbXTw+Pzo="; + + uint8_t *dst = SCMalloc(strlen(msg) + 1); + if (dst == NULL) + return 0; + + ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg), 1); + + if (memcmp(dst, msg, strlen(msg)) == 0) { + ret = 1; + } + + SCFree(dst); + + return ret; +} + +static int MimeIsExeURLTest01(void) +{ + int ret = 0; + char *url1 = "http://www.google.com/"; + char *url2 = "http://www.google.com/test.exe"; + + if(IsExeUrl((const uint8_t *)url1, strlen(url1)) != 0){ + SCLogDebug("Debug: URL1 error"); + goto end; + } + if(IsExeUrl((const uint8_t *)url2, strlen(url2)) != 1){ + SCLogDebug("Debug: URL2 error"); + goto end; + } + ret = 1; + + end: + + return ret; +} + +static int MimeIsIpv4HostTest01(void) +{ + if(IsIpv4Host((const uint8_t *)"192.168.1.1", 11) != 1) { + return 0; + } + + if(IsIpv4Host((const uint8_t *)"999.oogle.com", 14) != 0) { + return 0; + } + + if(IsIpv4Host((const uint8_t *)"0:0:0:0:0:0:0:0", 15) != 0) { + return 0; + } + + if (IsIpv4Host((const uint8_t *)"192.168.255.255", 15) != 1) { + return 0; + } + + if (IsIpv4Host((const uint8_t *)"192.168.255.255/testurl.html", 28) != 1) { + return 0; + } + + if (IsIpv4Host((const uint8_t *)"www.google.com", 14) != 0) { + return 0; + } + + return 1; +} + +static int MimeIsIpv6HostTest01(void) +{ + if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { + return 0; + } + + if(IsIpv6Host((const uint8_t *)"0000:0000:0000:0000:0000:0000:0000:0000", 39) != 1) { + return 0; + } + + if(IsIpv6Host((const uint8_t *)"0:0:0:0:0:0:0:0", 19) != 1) { + return 0; + } + + if(IsIpv6Host((const uint8_t *)"192:168:1:1:0:0:0:0", 19) != 1) { + return 0; + } + + if(IsIpv6Host((const uint8_t *)"999.oogle.com", 14) != 0) { + return 0; + } + + if (IsIpv6Host((const uint8_t *)"192.168.255.255", 15) != 0) { + return 0; + } + + if (IsIpv6Host((const uint8_t *)"192.168.255.255/testurl.html", 28) != 0) { + return 0; + } + + if (IsIpv6Host((const uint8_t *)"www.google.com", 14) != 0) { + return 0; + } + + return 1; +} + +#endif /* UNITTESTS */ + +void MimeDecRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("MimeDecParseLineTest01", MimeDecParseLineTest01); + UtRegisterTest("MimeDecParseLineTest02", MimeDecParseLineTest02); + UtRegisterTest("MimeDecParseFullMsgTest01", MimeDecParseFullMsgTest01); + UtRegisterTest("MimeDecParseFullMsgTest02", MimeDecParseFullMsgTest02); + UtRegisterTest("MimeBase64DecodeTest01", MimeBase64DecodeTest01); + UtRegisterTest("MimeIsExeURLTest01", MimeIsExeURLTest01); + UtRegisterTest("MimeIsIpv4HostTest01", MimeIsIpv4HostTest01); + UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01); +#endif /* UNITTESTS */ +} diff --git a/src/util-decode-mime.h b/src/util-decode-mime.h new file mode 100644 index 000000000000..0e5fb7cb0516 --- /dev/null +++ b/src/util-decode-mime.h @@ -0,0 +1,249 @@ +/* Copyright (C) 2012 BAE Systems + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author David Abarbanel + * + */ + +#ifndef MIME_DECODE_H_ +#define MIME_DECODE_H_ + +#include +#include +#include + +#include "suricata.h" +#include "util-base64.h" +#include "util-debug.h" + +/* Content Flags */ +#define CTNT_IS_MSG 1 +#define CTNT_IS_ENV 2 +#define CTNT_IS_ENCAP 4 +#define CTNT_IS_BODYPART 8 +#define CTNT_IS_MULTIPART 16 +#define CTNT_IS_ATTACHMENT 32 +#define CTNT_IS_BASE64 64 +#define CTNT_IS_QP 128 +#define CTNT_IS_TEXT 256 +#define CTNT_IS_HTML 512 + +/* URL Flags */ +#define URL_IS_IP4 1 +#define URL_IS_IP6 2 +#define URL_IS_EXE 4 + +/* Anomaly Flags */ +#define ANOM_INVALID_BASE64 1 /* invalid base64 chars */ +#define ANOM_INVALID_QP 2 /* invalid qouted-printable chars */ +#define ANOM_LONG_HEADER_NAME 4 /* header is abnormally long */ +#define ANOM_LONG_HEADER_VALUE 8 /* header value is abnormally long + * (includes multi-line) */ +#define ANOM_LONG_LINE 16 /* Lines that exceed 998 octets */ +#define ANOM_LONG_ENC_LINE 32 /* Lines that exceed 76 octets */ +#define ANOM_MALFORMED_MSG 64 /* Misc msg format errors found */ +#define ANOM_LONG_BOUNDARY 128 /* Boundary too long */ + +/* Publicly exposed size constants */ +#define DATA_CHUNK_SIZE 3072 /* Should be divisible by 3 */ +#define LINEREM_SIZE 256 + +/* Mime Parser Constants */ +#define HEADER_READY 0x01 +#define HEADER_STARTED 0x02 +#define HEADER_DONE 0x03 +#define BODY_STARTED 0x04 +#define BODY_DONE 0x05 +#define BODY_END_BOUND 0x06 +#define PARSE_DONE 0x07 +#define PARSE_ERROR 0x08 + +/** + * \brief Mime Decoder Error Codes + */ +typedef enum MimeDecRetCode { + MIME_DEC_OK = 0, + MIME_DEC_MORE = 1, + MIME_DEC_ERR_DATA = -1, + MIME_DEC_ERR_MEM = -2, + MIME_DEC_ERR_PARSE = -3 +} MimeDecRetCode; + +/** + * \brief Structure for containing configuration options + * + */ +typedef struct MimeDecConfig { + int decode_base64; /**< Decode base64 bodies */ + int decode_quoted_printable; /**< Decode quoted-printable bodies */ + int extract_urls; /**< Extract and store URLs in data structure */ + int body_md5; /**< Compute md5 sum of body */ + uint32_t header_value_depth; /**< Depth of which to store header values + (Default is 2000) */ +} MimeDecConfig; + +/** + * \brief This represents a header field name and associated value + */ +typedef struct MimeDecField { + uint8_t *name; /**< Name of the header field */ + uint32_t name_len; /**< Length of the name */ + uint32_t value_len; /**< Length of the value */ + uint8_t *value; /**< Value of the header field */ + struct MimeDecField *next; /**< Pointer to next field */ +} MimeDecField; + +/** + * \brief This represents a URL value node in a linked list + * + * Since HTML can sometimes contain a high number of URLs, this + * structure only features the URL host name/IP or those that are + * pointing to an executable file (see url_flags to determine which). + */ +typedef struct MimeDecUrl { + uint8_t *url; /**< String representation of full or partial URL (lowercase) */ + uint32_t url_len; /**< Length of the URL string */ + uint32_t url_flags; /**< Flags indicating type of URL */ + struct MimeDecUrl *next; /**< Pointer to next URL */ +} MimeDecUrl; + +/** + * \brief This represents the MIME Entity (or also top level message) in a + * child-sibling tree + */ +typedef struct MimeDecEntity { + MimeDecField *field_list; /**< Pointer to list of header fields */ + MimeDecUrl *url_list; /**< Pointer to list of URLs */ + uint32_t body_len; /**< Length of body (prior to any decoding) */ + uint32_t decoded_body_len; /**< Length of body after decoding */ + uint32_t header_flags; /**< Flags indicating header characteristics */ + uint32_t ctnt_flags; /**< Flags indicating type of content */ + uint32_t anomaly_flags; /**< Flags indicating an anomaly in the message */ + uint32_t filename_len; /**< Length of file attachment name */ + uint8_t *filename; /**< Name of file attachment */ + uint8_t *ctnt_type; /**< Quick access pointer to short-hand content type field */ + uint32_t ctnt_type_len; /**< Length of content type field value */ + uint32_t msg_id_len; /**< Quick access pointer to message Id */ + uint8_t *msg_id; /**< Quick access pointer to message Id */ + struct MimeDecEntity *next; /**< Pointer to list of sibling entities */ + struct MimeDecEntity *child; /**< Pointer to list of child entities */ +} MimeDecEntity; + +/** + * \brief Structure contains boundary and entity for the current node (entity) + * in the stack + * + */ +typedef struct MimeDecStackNode { + MimeDecEntity *data; /**< Pointer to the entity data structure */ + uint8_t *bdef; /**< Copy of boundary definition for child entity */ + uint32_t bdef_len; /**< Boundary length for child entity */ + int is_encap; /**< Flag indicating entity is encapsulated in message */ + struct MimeDecStackNode *next; /**< Pointer to next item on the stack */ +} MimeDecStackNode; + +/** + * \brief Structure holds the top of the stack along with some free reusable nodes + * + */ +typedef struct MimeDecStack { + MimeDecStackNode *top; /**< Pointer to the top of the stack */ + MimeDecStackNode *free_nodes; /**< Pointer to the list of free nodes */ + uint32_t free_nodes_cnt; /**< Count of free nodes in the list */ +} MimeDecStack; + +/** + * \brief Structure contains a list of value and lengths for robust data processing + * + */ +typedef struct DataValue { + uint8_t *value; /**< Copy of data value */ + uint32_t value_len; /**< Length of data value */ + struct DataValue *next; /**< Pointer to next value in the list */ +} DataValue; + +/** + * \brief Structure contains the current state of the MIME parser + * + */ +typedef struct MimeDecParseState { + MimeDecEntity *msg; /**< Pointer to the top-level message entity */ + MimeDecStack *stack; /**< Pointer to the top of the entity stack */ + uint8_t *hname; /**< Copy of the last known header name */ + uint32_t hlen; /**< Length of the last known header name */ + uint32_t hvlen; /**< Total length of value list */ + DataValue *hvalue; /**< Pointer to the incomplete header value list */ + uint8_t linerem[LINEREM_SIZE]; /**< Remainder from previous line (for URL extraction) */ + uint16_t linerem_len; /**< Length of remainder from previous line */ + uint8_t bvremain[B64_BLOCK]; /**< Remainder from base64-decoded line */ + uint8_t bvr_len; /**< Length of remainder from base64-decoded line */ + uint8_t data_chunk[DATA_CHUNK_SIZE]; /**< Buffer holding data chunk */ +#ifdef HAVE_NSS + HASHContext *md5_ctx; + uint8_t md5[MD5_LENGTH]; +#endif + uint8_t state_flag; /**< Flag representing current state of parser */ + uint32_t data_chunk_len; /**< Length of data chunk */ + int found_child; /**< Flag indicating a child entity was found */ + int body_begin; /**< Currently at beginning of body */ + int body_end; /**< Currently at end of body */ + uint8_t current_line_delimiter_len; /**< Length of line delimiter */ + void *data; /**< Pointer to data specific to the caller */ + int (*DataChunkProcessorFunc) (const uint8_t *chunk, uint32_t len, + struct MimeDecParseState *state); /**< Data chunk processing function callback */ +} MimeDecParseState; + +/* Config functions */ +void MimeDecSetConfig(MimeDecConfig *config); +MimeDecConfig * MimeDecGetConfig(void); + +/* Memory functions */ +void MimeDecFreeEntity(MimeDecEntity *entity); +void MimeDecFreeField(MimeDecField *field); +void MimeDecFreeUrl(MimeDecUrl *url); + +/* List functions */ +MimeDecField * MimeDecAddField(MimeDecEntity *entity); +MimeDecField * MimeDecFindField(const MimeDecEntity *entity, const char *name); +int MimeDecFindFieldsForEach(const MimeDecEntity *entity, const char *name, int (*DataCallback)(const uint8_t *val, const size_t, void *data), void *data); +MimeDecEntity * MimeDecAddEntity(MimeDecEntity *parent); + +/* Helper functions */ +//MimeDecField * MimeDecFillField(MimeDecEntity *entity, const char *name, +// uint32_t nlen, const char *value, uint32_t vlen, int copy_name_value); + +/* Parser functions */ +MimeDecParseState * MimeDecInitParser(void *data, int (*dcpfunc)(const uint8_t *chunk, + uint32_t len, MimeDecParseState *state)); +void MimeDecDeInitParser(MimeDecParseState *state); +int MimeDecParseComplete(MimeDecParseState *state); +int MimeDecParseLine(const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state); +MimeDecEntity * MimeDecParseFullMsg(const uint8_t *buf, uint32_t blen, void *data, + int (*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)); +const char *MimeDecParseStateGetStatus(MimeDecParseState *state); + +#ifdef AFLFUZZ_MIME +int MimeParserDataFromFile(char *filename); +#endif + +/* Test functions */ +void MimeDecRegisterTests(void); + +#endif diff --git a/src/util-device.c b/src/util-device.c index a98b45759743..f8afbc239cd0 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2012 Open Information Security Foundation +/* Copyright (C) 2011-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -18,6 +18,9 @@ #include "suricata-common.h" #include "conf.h" #include "util-device.h" +#include "util-ioctl.h" + +#define MAX_DEVNAME 10 /** * \file @@ -34,6 +37,26 @@ static TAILQ_HEAD(, LiveDevice_) live_devices = /** if set to 0 when we don't have real devices */ static int live_devices_stats = 1; +static int LiveSafeDeviceName(const char *devname, + char *newdevname, size_t destlen); + +static int g_live_devices_disable_offloading = 1; + +void LiveSetOffloadDisable(void) +{ + g_live_devices_disable_offloading = 1; +} + +void LiveSetOffloadWarn(void) +{ + g_live_devices_disable_offloading = 0; +} + +int LiveGetOffload(void) +{ + return g_live_devices_disable_offloading; +} + /** * \brief Add a pcap device for monitoring * @@ -42,9 +65,9 @@ static int live_devices_stats = 1; * \retval 0 on success. * \retval -1 on failure. */ -int LiveRegisterDevice(char *dev) +int LiveRegisterDevice(const char *dev) { - LiveDevice *pd = SCMalloc(sizeof(LiveDevice)); + LiveDevice *pd = SCCalloc(1, sizeof(LiveDevice)); if (unlikely(pd == NULL)) { return -1; } @@ -54,6 +77,13 @@ int LiveRegisterDevice(char *dev) SCFree(pd); return -1; } + /* create a short version to be used in thread names */ + if (strlen(pd->dev) > MAX_DEVNAME) { + LiveSafeDeviceName(pd->dev, pd->dev_short, sizeof(pd->dev_short)); + } else { + (void)strlcpy(pd->dev_short, pd->dev, sizeof(pd->dev_short)); + } + SC_ATOMIC_INIT(pd->pkts); SC_ATOMIC_INIT(pd->drop); SC_ATOMIC_INIT(pd->invalid_checksums); @@ -89,7 +119,7 @@ int LiveGetDeviceCount(void) * \retval ptr pointer to the string containing the device * \retval NULL on error */ -char *LiveGetDeviceName(int number) +const char *LiveGetDeviceName(int number) { int i = 0; LiveDevice *pd; @@ -105,6 +135,62 @@ char *LiveGetDeviceName(int number) return NULL; } +/** \internal + * \brief Shorten a device name that is to long + * + * \param device name from config and destination for modified + * + * \retval None, is added to destination char *newdevname + */ +static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) +{ + size_t devnamelen = strlen(devname); + + /* If we have to shorten the interface name */ + if (devnamelen > MAX_DEVNAME) { + + /* IF the dest length is over 10 chars long it will not do any + * good for the shortening. The shortening is done due to the + * max length of pthread names (15 chars) and we use 3 chars + * for the threadname indicator eg. "W#-" and one-two chars for + * the thread number. And if the destination buffer is under + * 6 chars there is no point in shortening it since we must at + * least enter two periods (.) into the string. + */ + if ((destlen-1) > 10 || (destlen-1) < 6) { + return 1; + } + + size_t length; + size_t half; + size_t spaces; + + half = (destlen-1) / 2; + + /* If the destlen is an even number */ + if (half * 2 == (destlen-1)) { + half = half - 1; + } + + spaces = (destlen-1) - (half*2); + length = half; + + /* Add the first half to the new dev name */ + snprintf(newdevname, half+1, "%s", devname); + + /* Add the amount of spaces wanted */ + for (uint i = half; i < half+spaces; i++) { + length = strlcat(newdevname, ".", destlen); + } + + snprintf(newdevname+length, half+1, "%s", devname+(devnamelen-half)); + SCLogInfo("Shortening device name to: %s", newdevname); + } else { + strlcpy(newdevname, devname, destlen); + } + return 0; +} + /** * \brief Get a pointer to the device at idx * @@ -113,7 +199,7 @@ char *LiveGetDeviceName(int number) * \retval ptr pointer to the string containing the device * \retval NULL on error */ -LiveDevice *LiveGetDevice(char *name) +LiveDevice *LiveGetDevice(const char *name) { int i = 0; LiveDevice *pd; @@ -134,14 +220,20 @@ LiveDevice *LiveGetDevice(char *name) return NULL; } +const char *LiveGetShortName(const char *dev) +{ + LiveDevice *live_dev = LiveGetDevice(dev); + if (live_dev == NULL) + return NULL; + return live_dev->dev_short; +} - -int LiveBuildDeviceList(char * runmode) +int LiveBuildDeviceList(const char *runmode) { return LiveBuildDeviceListCustom(runmode, "interface"); } -int LiveBuildDeviceListCustom(char * runmode, char * itemname) +int LiveBuildDeviceListCustom(const char *runmode, const char *itemname) { ConfNode *base = ConfGetNode(runmode); ConfNode *child; @@ -151,17 +243,15 @@ int LiveBuildDeviceListCustom(char * runmode, char * itemname) return 0; TAILQ_FOREACH(child, &base->head, next) { - if (!strcmp(child->val, itemname)) { - ConfNode *subchild; - TAILQ_FOREACH(subchild, &child->head, next) { - if ((!strcmp(subchild->name, itemname))) { - if (!strcmp(subchild->val, "default")) - break; - SCLogInfo("Adding %s %s from config file", - itemname, subchild->val); - LiveRegisterDevice(subchild->val); - i++; - } + ConfNode *subchild; + TAILQ_FOREACH(subchild, &child->head, next) { + if ((!strcmp(subchild->name, itemname))) { + if (!strcmp(subchild->val, "default")) + break; + SCLogConfig("Adding %s %s from config file", + itemname, subchild->val); + LiveRegisterDevice(subchild->val); + i++; } } } @@ -192,6 +282,9 @@ int LiveDeviceListClean() 100 * (SC_ATOMIC_GET(pd->drop) * 1.0) / SC_ATOMIC_GET(pd->pkts), SC_ATOMIC_GET(pd->invalid_checksums)); } + + RestoreIfaceOffloading(pd); + if (pd->dev) SCFree(pd->dev); SC_ATOMIC_DESTROY(pd->pkts); @@ -263,7 +356,7 @@ TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data) return TM_ECODE_FAILED; } TAILQ_FOREACH(pd, &live_devices, next) { - json_array_append(jarray, json_string(pd->dev)); + json_array_append_new(jarray, json_string(pd->dev)); i++; } diff --git a/src/util-device.h b/src/util-device.h index fd6a82131333..5c4e76c09f37 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2012 Open Information Security Foundation +/* Copyright (C) 2011-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -21,25 +21,43 @@ #include "queue.h" #include "unix-manager.h" +#define OFFLOAD_FLAG_SG (1<<0) +#define OFFLOAD_FLAG_TSO (1<<1) +#define OFFLOAD_FLAG_GSO (1<<2) +#define OFFLOAD_FLAG_GRO (1<<3) +#define OFFLOAD_FLAG_LRO (1<<4) +#define OFFLOAD_FLAG_RXCSUM (1<<5) +#define OFFLOAD_FLAG_TXCSUM (1<<6) +#define OFFLOAD_FLAG_TOE (1<<7) + +void LiveSetOffloadDisable(void); +void LiveSetOffloadWarn(void); +int LiveGetOffload(void); + +#define MAX_DEVNAME 10 + /** storage for live device names */ typedef struct LiveDevice_ { char *dev; /**< the device (e.g. "eth0") */ + char dev_short[MAX_DEVNAME + 1]; int ignore_checksum; SC_ATOMIC_DECLARE(uint64_t, pkts); SC_ATOMIC_DECLARE(uint64_t, drop); SC_ATOMIC_DECLARE(uint64_t, invalid_checksums); TAILQ_ENTRY(LiveDevice_) next; -} LiveDevice; + uint32_t offload_orig; /**< original offload settings to restore @exit */ +} LiveDevice; -int LiveRegisterDevice(char *dev); +int LiveRegisterDevice(const char *dev); int LiveGetDeviceCount(void); -char *LiveGetDeviceName(int number); -LiveDevice *LiveGetDevice(char *dev); -int LiveBuildDeviceList(char * base); +const char *LiveGetDeviceName(int number); +LiveDevice *LiveGetDevice(const char *dev); +const char *LiveGetShortName(const char *dev); +int LiveBuildDeviceList(const char *base); void LiveDeviceHasNoStats(void); int LiveDeviceListClean(void); -int LiveBuildDeviceListCustom(char * base, char * itemname); +int LiveBuildDeviceListCustom(const char *base, const char *itemname); #ifdef BUILD_UNIX_SOCKET TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data); diff --git a/src/util-error.c b/src/util-error.c index b0d67508524a..99b7e55cf726 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -114,6 +114,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_THREAD_SPAWN); CASE_CODE (SC_ERR_THREAD_CREATE); CASE_CODE (SC_ERR_THREAD_INIT); + CASE_CODE (SC_ERR_THREAD_DEINIT); CASE_CODE (SC_ERR_THRESHOLD_HASH_ADD); CASE_CODE (SC_ERR_UNDEFINED_VAR); CASE_CODE (SC_ERR_RULE_KEYWORD_UNKNOWN); @@ -263,7 +264,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_SYSCALL); CASE_CODE (SC_ERR_SYSCONF); CASE_CODE (SC_ERR_INVALID_ARGUMENTS); - CASE_CODE (SC_ERR_PERF_STATS_NOT_INIT); + CASE_CODE (SC_ERR_STATS_NOT_INIT); CASE_CODE (SC_ERR_NFQ_OPEN); CASE_CODE (SC_ERR_NFQ_MAXLEN); CASE_CODE (SC_ERR_NFQ_CREATE_QUEUE); @@ -291,14 +292,54 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_THREAD_QUEUE); CASE_CODE (SC_WARN_XFF_INVALID_MODE); CASE_CODE (SC_WARN_XFF_INVALID_HEADER); + CASE_CODE (SC_WARN_XFF_INVALID_DEPLOYMENT); CASE_CODE (SC_ERR_THRESHOLD_SETUP); CASE_CODE (SC_ERR_DNS_CONFIG); + CASE_CODE (SC_ERR_MODBUS_CONFIG); CASE_CODE (SC_ERR_CONF_YAML_ERROR); + CASE_CODE (SC_ERR_ENIP_CONFIG); CASE_CODE (SC_ERR_CONF_NAME_TOO_LONG); CASE_CODE (SC_ERR_APP_LAYER_PROTOCOL_DETECTION); CASE_CODE (SC_ERR_PCIE_INIT_FAILED); CASE_CODE (SC_WARN_LUA_SCRIPT); CASE_CODE (SC_ERR_LUA_SCRIPT); + CASE_CODE (SC_WARN_NO_STATS_LOGGERS); + CASE_CODE (SC_ERR_NO_NETMAP); + CASE_CODE (SC_ERR_NETMAP_CREATE); + CASE_CODE (SC_ERR_NETMAP_READ); + CASE_CODE (SC_ERR_IPPAIR_INIT); + CASE_CODE (SC_ERR_MT_NO_SELECTOR); + CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT); + CASE_CODE (SC_ERR_MT_NO_MAPPING); + CASE_CODE (SC_ERR_NO_JSON_SUPPORT); + CASE_CODE (SC_ERR_INVALID_RULE_ARGUMENT); + CASE_CODE (SC_ERR_STATS_LOG_NEGATED); + CASE_CODE (SC_ERR_JSON_STATS_LOG_NEGATED); + CASE_CODE (SC_ERR_DEPRECATED_CONF); + CASE_CODE (SC_WARN_FASTER_CAPTURE_AVAILABLE); + CASE_CODE (SC_WARN_POOR_RULE); + CASE_CODE (SC_ERR_ALERT_PAYLOAD_BUFFER); + CASE_CODE (SC_ERR_STATS_LOG_GENERIC); + CASE_CODE (SC_ERR_TCPDATA_LOG_GENERIC); + CASE_CODE (SC_ERR_FLOW_LOG_GENERIC); + CASE_CODE (SC_ERR_NETFLOW_LOG_GENERIC); + CASE_CODE (SC_ERR_SMTP_LOG_GENERIC); + CASE_CODE (SC_ERR_SSH_LOG_GENERIC); + CASE_CODE (SC_ERR_NIC_OFFLOADING); + CASE_CODE (SC_ERR_NO_FILES_FOR_PROTOCOL); + CASE_CODE (SC_ERR_INVALID_HASH); + CASE_CODE (SC_ERR_NO_SHA1_SUPPORT); + CASE_CODE (SC_ERR_NO_SHA256_SUPPORT); + CASE_CODE (SC_ERR_DNP3_CONFIG); + CASE_CODE (SC_ERR_DIR_OPEN); + CASE_CODE(SC_WARN_REMOVE_FILE); + CASE_CODE (SC_WARN_DUPLICATE_OUTPUT); + CASE_CODE (SC_ERR_NO_MAGIC_SUPPORT); + CASE_CODE (SC_ERR_REDIS); + CASE_CODE (SC_ERR_VAR_LIMIT); + CASE_CODE (SC_WARN_CHMOD); + CASE_CODE (SC_WARN_LOG_CF_TOO_MANY_NODES); + CASE_CODE (SC_WARN_EVENT_DROPPED); } return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index ada12d53c964..dbafabe1009a 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -80,7 +80,7 @@ typedef enum { SC_ERR_SYSCALL, SC_ERR_SYSCONF, SC_ERR_INVALID_ARGUMENTS, - SC_ERR_PERF_STATS_NOT_INIT, + SC_ERR_STATS_NOT_INIT, SC_ERR_COMPLETE_PORT_SPACE_NEGATED, SC_ERR_NO_PORTS_LEFT_AFTER_MERGE, SC_ERR_NEGATED_VALUE_IN_PORT_RANGE, @@ -267,8 +267,10 @@ typedef enum { SC_ERR_THREAD_QUEUE, SC_WARN_XFF_INVALID_MODE, SC_WARN_XFF_INVALID_HEADER, + SC_WARN_XFF_INVALID_DEPLOYMENT, SC_ERR_THRESHOLD_SETUP, SC_ERR_DNS_CONFIG, + SC_ERR_MODBUS_CONFIG, SC_ERR_CONF_YAML_ERROR, SC_ERR_CONF_NAME_TOO_LONG, SC_ERR_APP_LAYER_PROTOCOL_DETECTION, @@ -288,6 +290,46 @@ typedef enum { SC_WARN_NFLOG_SETSOCKOPT, SC_WARN_LUA_SCRIPT, SC_ERR_LUA_SCRIPT, + SC_WARN_NO_STATS_LOGGERS, + SC_ERR_NO_NETMAP, + SC_ERR_NETMAP_CREATE, + SC_ERR_NETMAP_READ, + SC_ERR_THREAD_DEINIT, /**< thread's deinit function failed */ + SC_ERR_IPPAIR_INIT, + SC_ERR_MT_NO_SELECTOR, + SC_ERR_MT_DUPLICATE_TENANT, + SC_ERR_NO_JSON_SUPPORT, + SC_ERR_INVALID_RULE_ARGUMENT, /**< Generic error code for invalid + * rule argument. */ + SC_ERR_MT_NO_MAPPING, + SC_ERR_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ + SC_ERR_JSON_STATS_LOG_NEGATED, /** When totals and threads are both NO in yaml **/ + SC_ERR_DEPRECATED_CONF, /**< Deprecated configuration parameter. */ + SC_WARN_FASTER_CAPTURE_AVAILABLE, + SC_WARN_POOR_RULE, + SC_ERR_ALERT_PAYLOAD_BUFFER, + SC_ERR_STATS_LOG_GENERIC, + SC_ERR_TCPDATA_LOG_GENERIC, + SC_ERR_FLOW_LOG_GENERIC, + SC_ERR_NETFLOW_LOG_GENERIC, + SC_ERR_SMTP_LOG_GENERIC, + SC_ERR_SSH_LOG_GENERIC, + SC_ERR_NIC_OFFLOADING, + SC_ERR_NO_FILES_FOR_PROTOCOL, + SC_ERR_INVALID_HASH, + SC_ERR_NO_SHA1_SUPPORT, + SC_ERR_NO_SHA256_SUPPORT, + SC_ERR_ENIP_CONFIG, + SC_ERR_DNP3_CONFIG, + SC_ERR_DIR_OPEN, + SC_WARN_REMOVE_FILE, + SC_ERR_NO_MAGIC_SUPPORT, + SC_ERR_REDIS, + SC_ERR_VAR_LIMIT, + SC_WARN_DUPLICATE_OUTPUT, + SC_WARN_CHMOD, + SC_WARN_LOG_CF_TOO_MANY_NODES, + SC_WARN_EVENT_DROPPED, } SCError; const char *SCErrorToString(SCError); diff --git a/src/util-file.c b/src/util-file.c index 7788413ff32c..f868222a85c6 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -28,6 +28,8 @@ #include "debug.h" #include "flow.h" #include "stream.h" +#include "stream-tcp.h" +#include "runmodes.h" #include "util-hash.h" #include "util-debug.h" #include "util-memcmp.h" @@ -35,6 +37,11 @@ #include "app-layer-parser.h" #include "util-validate.h" +/** \brief switch to force filestore on all files + * regardless of the rules. + */ +static int g_file_force_filestore = 0; + /** \brief switch to force magic checks on all files * regardless of the rules. */ @@ -45,14 +52,38 @@ static int g_file_force_magic = 0; */ static int g_file_force_md5 = 0; +/** \brief switch to force sha1 calculation on all files + * regardless of the rules. + */ +static int g_file_force_sha1 = 0; + +/** \brief switch to force sha256 calculation on all files + * regardless of the rules. + */ +static int g_file_force_sha256 = 0; + /** \brief switch to force tracking off all files * regardless of the rules. */ static int g_file_force_tracking = 0; +/** \brief switch to use g_file_store_reassembly_depth + * to reassembly files + */ +static int g_file_store_enable = 0; + +/** \brief stream_config.reassembly_depth equivalent + * for files + */ +static uint32_t g_file_store_reassembly_depth = 0; + /* prototypes */ static void FileFree(File *); -static void FileDataFree(FileData *); + +void FileForceFilestoreEnable(void) +{ + g_file_force_filestore = 1; +} void FileForceMagicEnable(void) { @@ -64,6 +95,35 @@ void FileForceMd5Enable(void) g_file_force_md5 = 1; } +void FileForceSha1Enable(void) +{ + g_file_force_sha1 = 1; +} + +void FileForceSha256Enable(void) +{ + g_file_force_sha256 = 1; +} + +int FileForceFilestore(void) +{ + return g_file_force_filestore; +} + +void FileReassemblyDepthEnable(uint32_t size) +{ + g_file_store_enable = 1; + g_file_store_reassembly_depth = size; +} + +uint32_t FileReassemblyDepth(void) +{ + if (g_file_store_enable == 1) + return g_file_store_reassembly_depth; + else + return stream_config.reassembly_depth; +} + int FileForceMagic(void) { return g_file_force_magic; @@ -74,113 +134,233 @@ int FileForceMd5(void) return g_file_force_md5; } -void FileForceTrackingEnable(void) +int FileForceSha1(void) { - g_file_force_tracking = 1; + return g_file_force_sha1; } -int FileMagicSize(void) +int FileForceSha256(void) { - /** \todo make this size configurable */ - return 512; + return g_file_force_sha256; } -static int FileAppendFileDataFilePtr(File *ff, FileData *ffd) +void FileForceTrackingEnable(void) { - SCEnter(); + g_file_force_tracking = 1; +} - if (ff == NULL) { - SCReturnInt(-1); - } - if (ff->chunks_tail == NULL) { - ff->chunks_head = ffd; - ff->chunks_tail = ffd; - } else { - ff->chunks_tail->next = ffd; - ff->chunks_tail = ffd; +/** + * \brief Function to parse forced file hashing configuration. + */ +void FileForceHashParseCfg(ConfNode *conf) +{ + BUG_ON(conf == NULL); + + ConfNode *forcehash_node = NULL; + + /* legacy option */ + const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5"); + if (force_md5 != NULL) { + SCLogWarning(SC_ERR_DEPRECATED_CONF, "deprecated 'force-md5' option " + "found. Please use 'force-hash: [md5]' instead"); + + if (ConfValIsTrue(force_md5)) { +#ifdef HAVE_NSS + FileForceMd5Enable(); + SCLogInfo("forcing md5 calculation for logged files"); +#else + SCLogInfo("md5 calculation requires linking against libnss"); +#endif + } } -#ifdef DEBUG - ff->chunks_cnt++; - if (ff->chunks_cnt > ff->chunks_cnt_max) - ff->chunks_cnt_max = ff->chunks_cnt; + if (conf != NULL) + forcehash_node = ConfNodeLookupChild(conf, "force-hash"); + + if (forcehash_node != NULL) { + ConfNode *field = NULL; + + TAILQ_FOREACH(field, &forcehash_node->head, next) { + if (strcasecmp("md5", field->val) == 0) { +#ifdef HAVE_NSS + FileForceMd5Enable(); + SCLogConfig("forcing md5 calculation for logged or stored files"); +#else + SCLogInfo("md5 calculation requires linking against libnss"); #endif + } + if (strcasecmp("sha1", field->val) == 0) { #ifdef HAVE_NSS - if (ff->md5_ctx) - HASH_Update(ff->md5_ctx, ffd->data, ffd->len); + FileForceSha1Enable(); + SCLogConfig("forcing sha1 calculation for logged or stored files"); +#else + SCLogInfo("sha1 calculation requires linking against libnss"); #endif - SCReturnInt(0); + } + + if (strcasecmp("sha256", field->val) == 0) { +#ifdef HAVE_NSS + FileForceSha256Enable(); + SCLogConfig("forcing sha256 calculation for logged or stored files"); +#else + SCLogInfo("sha256 calculation requires linking against libnss"); +#endif + } + } + } } -static int FileAppendFileData(FileContainer *ffc, FileData *ffd) +uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction) { - SCEnter(); + uint16_t flags = 0; - if (ffc == NULL) { - SCReturnInt(-1); - } + if (direction == STREAM_TOSERVER) { + if (flow->file_flags & FLOWFILE_NO_STORE_TS) { + flags |= FILE_NOSTORE; + } - if (FileAppendFileDataFilePtr(ffc->tail, ffd) == -1) - { - SCReturnInt(-1); + if (flow->file_flags & FLOWFILE_NO_MAGIC_TS) { + flags |= FILE_NOMAGIC; + } + + if (flow->file_flags & FLOWFILE_NO_MD5_TS) { + flags |= FILE_NOMD5; + } + + if (flow->file_flags & FLOWFILE_NO_SHA1_TS) { + flags |= FILE_NOSHA1; + } + + if (flow->file_flags & FLOWFILE_NO_SHA256_TS) { + flags |= FILE_NOSHA256; + } + } else { + if (flow->file_flags & FLOWFILE_NO_STORE_TC) { + flags |= FILE_NOSTORE; + } + + if (flow->file_flags & FLOWFILE_NO_MAGIC_TC) { + flags |= FILE_NOMAGIC; + } + + if (flow->file_flags & FLOWFILE_NO_MD5_TC) { + flags |= FILE_NOMD5; + } + + if (flow->file_flags & FLOWFILE_NO_SHA1_TC) { + flags |= FILE_NOSHA1; + } + + if (flow->file_flags & FLOWFILE_NO_SHA256_TC) { + flags |= FILE_NOSHA256; + } } + return flags; +} - SCReturnInt(0); +int FileMagicSize(void) +{ + /** \todo make this size configurable */ + return 512; } +/** + * \brief get the size of the file data + * + * This doesn't reflect how much of the file we have in memory, just the + * total size of filedata so far. + */ +uint64_t FileDataSize(const File *file) +{ + if (file != NULL && file->sb != NULL) { + SCLogDebug("returning %"PRIu64, + file->sb->stream_offset + file->sb->buf_offset); + return file->sb->stream_offset + file->sb->buf_offset; + } + SCLogDebug("returning 0 (default)"); + return 0; +} +/** + * \brief get the size of the file + * + * This doesn't reflect how much of the file we have in memory, just the + * total size of file so far. + */ +uint64_t FileTrackedSize(const File *file) +{ + if (file != NULL) { + return file->size; + } + return 0; +} -static void FilePruneFile(File *file) +static int FilePruneFile(File *file) { SCEnter(); - - SCLogDebug("file %p, file->chunks_cnt %"PRIu64, file, file->chunks_cnt); - +#ifdef HAVE_MAGIC if (!(file->flags & FILE_NOMAGIC)) { /* need magic but haven't set it yet, bail out */ if (file->magic == NULL) - SCReturn; + SCReturnInt(0); else SCLogDebug("file->magic %s", file->magic); } else { SCLogDebug("file->flags & FILE_NOMAGIC == true"); } +#endif + uint64_t left_edge = file->content_stored; + if (file->flags & FILE_NOSTORE) { + left_edge = FileDataSize(file); + } + if (file->flags & FILE_USE_DETECT) { + left_edge = MIN(left_edge, file->content_inspected); + } - /* okay, we now know we can prune */ - FileData *fd = file->chunks_head; - - while (fd != NULL) { - SCLogDebug("fd %p", fd); + if (left_edge) { + StreamingBufferSlideToOffset(file->sb, left_edge); + } - if (file->flags & FILE_NOSTORE || fd->stored == 1) { - file->chunks_head = fd->next; - if (file->chunks_tail == fd) - file->chunks_tail = fd->next; + if (left_edge != FileDataSize(file)) { + SCReturnInt(0); + } - FileDataFree(fd); + SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s", file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no"); - fd = file->chunks_head; -#ifdef DEBUG - file->chunks_cnt--; - SCLogDebug("file->chunks_cnt %"PRIu64, file->chunks_cnt); -#endif - } else if (fd->stored == 0) { - fd = NULL; - break; - } + /* file is done when state is closed+, logging/storing is done (if any) */ + if (file->state >= FILE_STATE_CLOSED && + (!RunModeOutputFileEnabled() || (file->flags & FILE_LOGGED)) && + (!RunModeOutputFiledataEnabled() || (file->flags & FILE_STORED))) + { + SCReturnInt(1); + } else { + SCReturnInt(0); } - - SCReturn; } void FilePrune(FileContainer *ffc) { - File *file; + File *file = ffc->head; + + while (file) { + if (FilePruneFile(file) == 0) + break; + + BUG_ON(file != ffc->head); + + SCLogDebug("removing file %p", file); - for (file = ffc->head; file != NULL; file = file->next) { - FilePruneFile(file); + File *file_next = file->next; + + /* update head and tail */ + ffc->head = file_next; + if (file == ffc->tail) + ffc->tail = NULL; + + FileFree(file); + file = file_next; } } @@ -241,56 +421,6 @@ void FileContainerFree(FileContainer *ffc) SCFree(ffc); } -/** - * \internal - * - * \brief allocate a FileData chunk and set it up - * - * \param data data chunk to store in the FileData - * \param data_len lenght of the data - * - * \retval new FileData object - */ -static FileData *FileDataAlloc(uint8_t *data, uint32_t data_len) -{ - FileData *new = SCMalloc(sizeof(FileData)); - if (unlikely(new == NULL)) { - return NULL; - } - memset(new, 0, sizeof(FileData)); - - new->data = SCMalloc(data_len); - if (new->data == NULL) { - SCFree(new); - return NULL; - } - - new->len = data_len; - memcpy(new->data, data, data_len); - - new->next = NULL; - return new; -} - -/** - * \internal - * - * \brief free a FileData object - * - * \param ffd the flow file data object to free - */ -static void FileDataFree(FileData *ffd) -{ - if (ffd == NULL) - return; - - if (ffd->data != NULL) { - SCFree(ffd->data); - } - - SCFree(ffd); -} - /** * \brief Alloc a new File * @@ -299,7 +429,7 @@ static void FileDataFree(FileData *ffd) * * \retval new File object or NULL on error */ -static File *FileAlloc(uint8_t *name, uint16_t name_len) +static File *FileAlloc(const uint8_t *name, uint16_t name_len) { File *new = SCMalloc(sizeof(File)); if (unlikely(new == NULL)) { @@ -327,27 +457,23 @@ static void FileFree(File *ff) if (ff->name != NULL) SCFree(ff->name); - +#ifdef HAVE_MAGIC /* magic returned by libmagic is strdup'd by MagicLookup. */ if (ff->magic != NULL) SCFree(ff->magic); - - if (ff->chunks_head != NULL) { - FileData *ffd = ff->chunks_head; - - while (ffd != NULL) { - FileData *next_ffd = ffd->next; - FileDataFree(ffd); - ffd = next_ffd; - } +#endif + if (ff->sb != NULL) { + StreamingBufferFree(ff->sb); } #ifdef HAVE_NSS if (ff->md5_ctx) HASH_Destroy(ff->md5_ctx); + if (ff->sha1_ctx) + HASH_Destroy(ff->sha1_ctx); + if (ff->sha256_ctx) + HASH_Destroy(ff->sha256_ctx); #endif - SCLogDebug("ff chunks_cnt %"PRIu64", chunks_cnt_max %"PRIu64, - ff->chunks_cnt, ff->chunks_cnt_max); SCFree(ff); } @@ -404,7 +530,7 @@ static int FileStoreNoStoreCheck(File *ff) if (ff->flags & FILE_NOSTORE) { if (ff->state == FILE_STATE_OPENED && - ff->size >= (uint64_t)FileMagicSize()) + FileDataSize(ff) >= (uint64_t)FileMagicSize()) { SCReturnInt(1); } @@ -413,6 +539,26 @@ static int FileStoreNoStoreCheck(File *ff) SCReturnInt(0); } +static int AppendData(File *file, const uint8_t *data, uint32_t data_len) +{ + if (StreamingBufferAppendNoTrack(file->sb, data, data_len) != 0) { + SCReturnInt(-1); + } + +#ifdef HAVE_NSS + if (file->md5_ctx) { + HASH_Update(file->md5_ctx, data, data_len); + } + if (file->sha1_ctx) { + HASH_Update(file->sha1_ctx, data, data_len); + } + if (file->sha256_ctx) { + HASH_Update(file->sha256_ctx, data, data_len); + } +#endif + SCReturnInt(0); +} + /** * \brief Store a chunk of file data in the flow. The open "flowfile" * will be used. @@ -425,7 +571,7 @@ static int FileStoreNoStoreCheck(File *ff) * \retval -1 error * \retval -2 no store for this file */ -int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) +int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len) { SCEnter(); @@ -433,6 +579,8 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) SCReturnInt(-1); } + ffc->tail->size += data_len; + if (ffc->tail->state != FILE_STATE_OPENED) { if (ffc->tail->flags & FILE_NOSTORE) { SCReturnInt(-2); @@ -440,18 +588,25 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) SCReturnInt(-1); } - ffc->tail->size += data_len; - SCLogDebug("file size is now %"PRIu64, ffc->tail->size); - if (FileStoreNoStoreCheck(ffc->tail) == 1) { #ifdef HAVE_NSS - /* no storage but forced md5 */ + int hash_done = 0; + /* no storage but forced hashing */ if (ffc->tail->md5_ctx) { - if (ffc->tail->md5_ctx) - HASH_Update(ffc->tail->md5_ctx, data, data_len); + HASH_Update(ffc->tail->md5_ctx, data, data_len); + hash_done = 1; + } + if (ffc->tail->sha1_ctx) { + HASH_Update(ffc->tail->sha1_ctx, data, data_len); + hash_done = 1; + } + if (ffc->tail->sha256_ctx) { + HASH_Update(ffc->tail->sha256_ctx, data, data_len); + hash_done = 1; + } + if (hash_done) SCReturnInt(0); - } #endif if (g_file_force_tracking || (!(ffc->tail->flags & FILE_NOTRACK))) SCReturnInt(0); @@ -463,18 +618,11 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) SCLogDebug("appending %"PRIu32" bytes", data_len); - FileData *ffd = FileDataAlloc(data, data_len); - if (ffd == NULL) { + if (AppendData(ffc->tail, data, data_len) != 0) { ffc->tail->state = FILE_STATE_ERROR; SCReturnInt(-1); } - /* append the data */ - if (FileAppendFileData(ffc, ffd) < 0) { - ffc->tail->state = FILE_STATE_ERROR; - FileDataFree(ffd); - SCReturnInt(-1); - } SCReturnInt(0); } @@ -482,6 +630,7 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) * \brief Open a new File * * \param ffc flow container + * \param sbcfg buffer config * \param name filename character array * \param name_len filename len * \param data initial data @@ -492,8 +641,9 @@ int FileAppendData(FileContainer *ffc, uint8_t *data, uint32_t data_len) * * \note filename is not a string, so it's not nul terminated. */ -File *FileOpenFile(FileContainer *ffc, uint8_t *name, - uint16_t name_len, uint8_t *data, uint32_t data_len, uint8_t flags) +File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, + const uint8_t *name, uint16_t name_len, + const uint8_t *data, uint32_t data_len, uint16_t flags) { SCEnter(); @@ -504,8 +654,15 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, SCReturnPtr(NULL, "File"); } - if (flags & FILE_STORE) { - ff->flags |= FILE_STORE; + ff->sb = StreamingBufferInit(sbcfg); + if (ff->sb == NULL) { + FileFree(ff); + SCReturnPtr(NULL, "File"); + } + SCLogDebug("ff->sb %p", ff->sb); + + if (flags & FILE_STORE || g_file_force_filestore) { + FileStore(ff); } else if (flags & FILE_NOSTORE) { SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; @@ -518,6 +675,18 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, SCLogDebug("not doing md5 for this file"); ff->flags |= FILE_NOMD5; } + if (flags & FILE_NOSHA1) { + SCLogDebug("not doing sha1 for this file"); + ff->flags |= FILE_NOSHA1; + } + if (flags & FILE_NOSHA256) { + SCLogDebug("not doing sha256 for this file"); + ff->flags |= FILE_NOSHA256; + } + if (flags & FILE_USE_DETECT) { + SCLogDebug("considering content_inspect tracker when pruning"); + ff->flags |= FILE_USE_DETECT; + } #ifdef HAVE_NSS if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) { @@ -526,6 +695,18 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, HASH_Begin(ff->md5_ctx); } } + if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) { + ff->sha1_ctx = HASH_Create(HASH_AlgSHA1); + if (ff->sha1_ctx != NULL) { + HASH_Begin(ff->sha1_ctx); + } + } + if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) { + ff->sha256_ctx = HASH_Create(HASH_AlgSHA256); + if (ff->sha256_ctx != NULL) { + HASH_Begin(ff->sha256_ctx); + } + } #endif ff->state = FILE_STATE_OPENED; @@ -534,29 +715,19 @@ File *FileOpenFile(FileContainer *ffc, uint8_t *name, FileContainerAdd(ffc, ff); if (data != NULL) { - //PrintRawDataFp(stdout, data, data_len); ff->size += data_len; - SCLogDebug("file size is now %"PRIu64, ff->size); - - FileData *ffd = FileDataAlloc(data, data_len); - if (ffd == NULL) { - ff->state = FILE_STATE_ERROR; - SCReturnPtr(NULL, "File"); - } - - /* append the data */ - if (FileAppendFileData(ffc, ffd) < 0) { + if (AppendData(ff, data, data_len) != 0) { ff->state = FILE_STATE_ERROR; - FileDataFree(ffd); SCReturnPtr(NULL, "File"); } + SCLogDebug("file size is now %"PRIu64, FileTrackedSize(ff)); } SCReturnPtr(ff, "File"); } -static int FileCloseFilePtr(File *ff, uint8_t *data, - uint32_t data_len, uint8_t flags) +static int FileCloseFilePtr(File *ff, const uint8_t *data, + uint32_t data_len, uint16_t flags) { SCEnter(); @@ -568,31 +739,23 @@ static int FileCloseFilePtr(File *ff, uint8_t *data, SCReturnInt(-1); } - ff->size += data_len; - SCLogDebug("file size is now %"PRIu64, ff->size); - if (data != NULL) { - //PrintRawDataFp(stdout, data, data_len); - + ff->size += data_len; if (ff->flags & FILE_NOSTORE) { #ifdef HAVE_NSS - /* no storage but md5 */ + /* no storage but hashing */ if (ff->md5_ctx) HASH_Update(ff->md5_ctx, data, data_len); + if (ff->sha1_ctx) + HASH_Update(ff->sha1_ctx, data, data_len); + if (ff->sha256_ctx) + HASH_Update(ff->sha256_ctx, data, data_len); #endif } else { - FileData *ffd = FileDataAlloc(data, data_len); - if (ffd == NULL) { + if (AppendData(ff, data, data_len) != 0) { ff->state = FILE_STATE_ERROR; SCReturnInt(-1); } - - /* append the data */ - if (FileAppendFileDataFilePtr(ff, ffd) < 0) { - ff->state = FILE_STATE_ERROR; - FileDataFree(ffd); - SCReturnInt(-1); - } } } @@ -614,6 +777,16 @@ static int FileCloseFilePtr(File *ff, uint8_t *data, HASH_End(ff->md5_ctx, ff->md5, &len, sizeof(ff->md5)); ff->flags |= FILE_MD5; } + if (ff->sha1_ctx) { + unsigned int len = 0; + HASH_End(ff->sha1_ctx, ff->sha1, &len, sizeof(ff->sha1)); + ff->flags |= FILE_SHA1; + } + if (ff->sha256_ctx) { + unsigned int len = 0; + HASH_End(ff->sha256_ctx, ff->sha256, &len, sizeof(ff->sha256)); + ff->flags |= FILE_SHA256; + } #endif } @@ -631,8 +804,8 @@ static int FileCloseFilePtr(File *ff, uint8_t *data, * \retval 0 ok * \retval -1 error */ -int FileCloseFile(FileContainer *ffc, uint8_t *data, - uint32_t data_len, uint8_t flags) +int FileCloseFile(FileContainer *ffc, const uint8_t *data, + uint32_t data_len, uint16_t flags) { SCEnter(); @@ -662,9 +835,9 @@ void FileDisableStoring(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_STORE_TS; + f->file_flags |= FLOWFILE_NO_STORE_TS; else - f->flags |= FLOW_FILE_NO_STORE_TC; + f->file_flags |= FLOWFILE_NO_STORE_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -694,9 +867,9 @@ void FileDisableMagic(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_MAGIC_TS; + f->file_flags |= FLOWFILE_NO_MAGIC_TS; else - f->flags |= FLOW_FILE_NO_MAGIC_TC; + f->file_flags |= FLOWFILE_NO_MAGIC_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -725,9 +898,9 @@ void FileDisableMd5(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_MD5_TS; + f->file_flags |= FLOWFILE_NO_MD5_TS; else - f->flags |= FLOW_FILE_NO_MD5_TC; + f->file_flags |= FLOWFILE_NO_MD5_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -749,6 +922,84 @@ void FileDisableMd5(Flow *f, uint8_t direction) SCReturn; } +/** + * \brief disable file sha1 calc for this flow + * + * \param f *LOCKED* flow + * \param direction flow direction +*/ +void FileDisableSha1(Flow *f, uint8_t direction) +{ + File *ptr = NULL; + + SCEnter(); + + DEBUG_ASSERT_FLOW_LOCKED(f); + + if (direction == STREAM_TOSERVER) + f->file_flags |= FLOWFILE_NO_SHA1_TS; + else + f->file_flags |= FLOWFILE_NO_SHA1_TC; + + FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); + if (ffc != NULL) { + for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { + SCLogDebug("disabling sha1 for file %p from direction %s", + ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); + ptr->flags |= FILE_NOSHA1; + +#ifdef HAVE_NSS + /* destroy any ctx we may have so far */ + if (ptr->sha1_ctx != NULL) { + HASH_Destroy(ptr->sha1_ctx); + ptr->sha1_ctx = NULL; + } +#endif + } + } + + SCReturn; +} + +/** + * \brief disable file sha256 calc for this flow + * + * \param f *LOCKED* flow + * \param direction flow direction + */ +void FileDisableSha256(Flow *f, uint8_t direction) +{ + File *ptr = NULL; + + SCEnter(); + + DEBUG_ASSERT_FLOW_LOCKED(f); + + if (direction == STREAM_TOSERVER) + f->file_flags |= FLOWFILE_NO_SHA256_TS; + else + f->file_flags |= FLOWFILE_NO_SHA256_TC; + + FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); + if (ffc != NULL) { + for (ptr = ffc->head; ptr != NULL; ptr = ptr->next) { + SCLogDebug("disabling sha256 for file %p from direction %s", + ptr, direction == STREAM_TOSERVER ? "toserver":"toclient"); + ptr->flags |= FILE_NOSHA256; + +#ifdef HAVE_NSS + /* destroy any ctx we may have so far */ + if (ptr->sha256_ctx != NULL) { + HASH_Destroy(ptr->sha256_ctx); + ptr->sha256_ctx = NULL; + } +#endif + } + } + + SCReturn; +} + /** * \brief disable file size tracking for this flow * @@ -764,9 +1015,9 @@ void FileDisableFilesize(Flow *f, uint8_t direction) DEBUG_ASSERT_FLOW_LOCKED(f); if (direction == STREAM_TOSERVER) - f->flags |= FLOW_FILE_NO_SIZE_TS; + f->file_flags |= FLOWFILE_NO_SIZE_TS; else - f->flags |= FLOW_FILE_NO_SIZE_TC; + f->file_flags |= FLOWFILE_NO_SIZE_TC; FileContainer *ffc = AppLayerParserGetFiles(f->proto, f->alproto, f->alstate, direction); if (ffc != NULL) { @@ -797,9 +1048,12 @@ void FileDisableStoringForFile(File *ff) SCLogDebug("not storing this file"); ff->flags |= FILE_NOSTORE; - if (ff->state == FILE_STATE_OPENED && ff->size >= (uint64_t)FileMagicSize()) { - (void)FileCloseFilePtr(ff, NULL, 0, - (FILE_TRUNCATED|FILE_NOSTORE)); + if (ff->state == FILE_STATE_OPENED && FileDataSize(ff) >= (uint64_t)FileMagicSize()) { + if (g_file_force_md5 == 0 && g_file_force_sha1 == 0 && g_file_force_sha256 == 0 + && g_file_force_tracking == 0) { + (void)FileCloseFilePtr(ff, NULL, 0, + (FILE_TRUNCATED|FILE_NOSTORE)); + } } } @@ -841,7 +1095,7 @@ void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint64_t tx_id * \param fc file store * \param file_id the file's id */ -void FileStoreFileById(FileContainer *fc, uint16_t file_id) +void FileStoreFileById(FileContainer *fc, uint32_t file_id) { File *ptr = NULL; @@ -850,13 +1104,13 @@ void FileStoreFileById(FileContainer *fc, uint16_t file_id) if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->file_id == file_id) { - ptr->flags |= FILE_STORE; + FileStore(ptr); } } } } -void FileStoreAllFilesForTx(FileContainer *fc, uint16_t tx_id) +void FileStoreAllFilesForTx(FileContainer *fc, uint64_t tx_id) { File *ptr = NULL; @@ -865,7 +1119,7 @@ void FileStoreAllFilesForTx(FileContainer *fc, uint16_t tx_id) if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { if (ptr->txid == tx_id) { - ptr->flags |= FILE_STORE; + FileStore(ptr); } } } @@ -879,7 +1133,7 @@ void FileStoreAllFiles(FileContainer *fc) if (fc != NULL) { for (ptr = fc->head; ptr != NULL; ptr = ptr->next) { - ptr->flags |= FILE_STORE; + FileStore(ptr); } } } diff --git a/src/util-file.h b/src/util-file.h index 36419ffbf3f6..8c3828d9b956 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -29,15 +29,24 @@ #include #endif -#define FILE_TRUNCATED 0x0001 -#define FILE_NOMAGIC 0x0002 -#define FILE_NOMD5 0x0004 -#define FILE_MD5 0x0008 -#define FILE_LOGGED 0x0010 -#define FILE_NOSTORE 0x0020 -#define FILE_STORE 0x0040 -#define FILE_STORED 0x0080 -#define FILE_NOTRACK 0x0100 /**< track size of file */ +#include "conf.h" + +#include "util-streaming-buffer.h" + +#define FILE_TRUNCATED BIT_U16(0) +#define FILE_NOMAGIC BIT_U16(1) +#define FILE_NOMD5 BIT_U16(2) +#define FILE_MD5 BIT_U16(3) +#define FILE_NOSHA1 BIT_U16(4) +#define FILE_SHA1 BIT_U16(5) +#define FILE_NOSHA256 BIT_U16(6) +#define FILE_SHA256 BIT_U16(7) +#define FILE_LOGGED BIT_U16(8) +#define FILE_NOSTORE BIT_U16(9) +#define FILE_STORE BIT_U16(10) +#define FILE_STORED BIT_U16(11) +#define FILE_NOTRACK BIT_U16(12) /**< track size of file */ +#define FILE_USE_DETECT BIT_U16(13) /**< use content_inspected tracker */ typedef enum FileState_ { FILE_STATE_NONE = 0, /**< no state */ @@ -50,34 +59,30 @@ typedef enum FileState_ { FILE_STATE_MAX } FileState; -typedef struct FileData_ { - uint8_t *data; - uint32_t len; - int stored; /* true if this chunk has been stored already - * false otherwise */ - struct FileData_ *next; -} FileData; - typedef struct File_ { uint16_t flags; - uint64_t txid; /**< tx this file is part of */ - unsigned int file_id; - uint8_t *name; uint16_t name_len; int16_t state; - uint64_t size; /**< size tracked so far */ + StreamingBuffer *sb; + uint64_t txid; /**< tx this file is part of */ + uint32_t file_id; + uint8_t *name; +#ifdef HAVE_MAGIC char *magic; - FileData *chunks_head; - FileData *chunks_tail; +#endif struct File_ *next; #ifdef HAVE_NSS HASHContext *md5_ctx; uint8_t md5[MD5_LENGTH]; + HASHContext *sha1_ctx; + uint8_t sha1[SHA1_LENGTH]; + HASHContext *sha256_ctx; + uint8_t sha256[SHA256_LENGTH]; #endif -#ifdef DEBUG - uint64_t chunks_cnt; - uint64_t chunks_cnt_max; -#endif + uint64_t content_inspected; /**< used in pruning if FILE_USE_DETECT + * flag is set */ + uint64_t content_stored; + uint64_t size; } File; typedef struct FileContainer_ { @@ -96,6 +101,7 @@ void FileContainerAdd(FileContainer *, File *); * \brief Open a new File * * \param ffc flow container + * \param sbcfg buffer config * \param name filename character array * \param name_len filename len * \param data initial data @@ -105,9 +111,16 @@ void FileContainerAdd(FileContainer *, File *); * \retval ff flowfile object * * \note filename is not a string, so it's not nul terminated. + * + * If flags contains the FILE_USE_DETECT bit, the pruning code will + * consider not just the content_stored tracker, but also content_inspected. + * It's the responsibility of the API user to make sure this tracker is + * properly updated. */ -File *FileOpenFile(FileContainer *, uint8_t *name, uint16_t name_len, - uint8_t *data, uint32_t data_len, uint8_t flags); +File *FileOpenFile(FileContainer *, const StreamingBufferConfig *, + const uint8_t *name, uint16_t name_len, + const uint8_t *data, uint32_t data_len, uint16_t flags); + /** * \brief Close a File * @@ -119,7 +132,8 @@ File *FileOpenFile(FileContainer *, uint8_t *name, uint16_t name_len, * \retval 0 ok * \retval -1 error */ -int FileCloseFile(FileContainer *, uint8_t *data, uint32_t data_len, uint8_t flags); +int FileCloseFile(FileContainer *, const uint8_t *data, uint32_t data_len, + uint16_t flags); /** * \brief Store a chunk of file data in the flow. The open "flowfile" @@ -132,7 +146,7 @@ int FileCloseFile(FileContainer *, uint8_t *data, uint32_t data_len, uint8_t fla * \retval 0 ok * \retval -1 error */ -int FileAppendData(FileContainer *, uint8_t *data, uint32_t data_len); +int FileAppendData(FileContainer *, const uint8_t *data, uint32_t data_len); /** * \brief Tag a file for storing @@ -166,9 +180,13 @@ void FileDisableFilesize(Flow *f, uint8_t direction); */ void FileDisableStoringForTransaction(Flow *f, uint8_t direction, uint64_t tx_id); -void FlowFileDisableStoringForTransaction(struct Flow_ *f, uint16_t tx_id); +void FlowFileDisableStoringForTransaction(struct Flow_ *f, uint64_t tx_id); void FilePrune(FileContainer *ffc); +void FileForceFilestoreEnable(void); +int FileForceFilestore(void); +void FileReassemblyDepthEnable(uint32_t size); +uint32_t FileReassemblyDepth(void); void FileDisableMagic(Flow *f, uint8_t); void FileForceMagicEnable(void); @@ -178,12 +196,27 @@ void FileDisableMd5(Flow *f, uint8_t); void FileForceMd5Enable(void); int FileForceMd5(void); +void FileDisableSha1(Flow *f, uint8_t); +void FileForceSha1Enable(void); +int FileForceSha1(void); + +void FileDisableSha256(Flow *f, uint8_t); +void FileForceSha256Enable(void); +int FileForceSha256(void); + +void FileForceHashParseCfg(ConfNode *); + void FileForceTrackingEnable(void); void FileStoreAllFiles(FileContainer *); -void FileStoreAllFilesForTx(FileContainer *, uint16_t); -void FileStoreFileById(FileContainer *fc, uint16_t); +void FileStoreAllFilesForTx(FileContainer *, uint64_t); +void FileStoreFileById(FileContainer *fc, uint32_t); void FileTruncateAllOpenFiles(FileContainer *); +uint64_t FileDataSize(const File *file); +uint64_t FileTrackedSize(const File *file); + +uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction); + #endif /* __UTIL_FILE_H__ */ diff --git a/src/util-hash-lookup3.c b/src/util-hash-lookup3.c index f765521d6ed4..d13fa16af21b 100644 --- a/src/util-hash-lookup3.c +++ b/src/util-hash-lookup3.c @@ -449,6 +449,180 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval) } +/* +------------------------------------------------------------------------------- +hashlittle_safe() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * Note that unlike hashlittle() above, we use the "safe" version of this + * block that is #ifdef VALGRIND above, in order to avoid warnings from + * Valgrind or Address Sanitizer. + */ + + const uint8_t *k8 = (const uint8_t *)k; + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + + /* * hashlittle2: return 2 32-bit hash values * diff --git a/src/util-hash-lookup3.h b/src/util-hash-lookup3.h index 1e37e9104ed1..7ef4cf5d06d5 100644 --- a/src/util-hash-lookup3.h +++ b/src/util-hash-lookup3.h @@ -52,6 +52,11 @@ void hashword2 (const uint32_t *k, /* the key, an array of uint32_t val uint32_t hashlittle( const void *key, size_t length, uint32_t initval); +/* A variant of hashlittle() that ensures avoids accesses beyond the last byte + * of the string, which will cause warnings from tools like Valgrind or Address + * Sanitizer. */ +uint32_t hashlittle_safe(const void *key, size_t length, uint32_t initval); + void hashlittle2(const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ diff --git a/src/util-hash.c b/src/util-hash.c index 7552867fb542..9dbe36983c7c 100644 --- a/src/util-hash.c +++ b/src/util-hash.c @@ -415,18 +415,18 @@ static int HashTableTestFull02 (void) void HashTableRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HashTableTestInit01", HashTableTestInit01, 1); - UtRegisterTest("HashTableTestInit02", HashTableTestInit02, 1); - UtRegisterTest("HashTableTestInit03", HashTableTestInit03, 1); - UtRegisterTest("HashTableTestInit04", HashTableTestInit04, 1); - UtRegisterTest("HashTableTestInit05", HashTableTestInit05, 1); - UtRegisterTest("HashTableTestInit06", HashTableTestInit06, 1); - - UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01, 1); - UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02, 1); - - UtRegisterTest("HashTableTestFull01", HashTableTestFull01, 1); - UtRegisterTest("HashTableTestFull02", HashTableTestFull02, 1); + UtRegisterTest("HashTableTestInit01", HashTableTestInit01); + UtRegisterTest("HashTableTestInit02", HashTableTestInit02); + UtRegisterTest("HashTableTestInit03", HashTableTestInit03); + UtRegisterTest("HashTableTestInit04", HashTableTestInit04); + UtRegisterTest("HashTableTestInit05", HashTableTestInit05); + UtRegisterTest("HashTableTestInit06", HashTableTestInit06); + + UtRegisterTest("HashTableTestAdd01", HashTableTestAdd01); + UtRegisterTest("HashTableTestAdd02", HashTableTestAdd02); + + UtRegisterTest("HashTableTestFull01", HashTableTestFull01); + UtRegisterTest("HashTableTestFull02", HashTableTestFull02); #endif } diff --git a/src/util-hashlist.c b/src/util-hashlist.c index db8ba9050e9b..52ad1b1350c4 100644 --- a/src/util-hashlist.c +++ b/src/util-hashlist.c @@ -501,18 +501,18 @@ static int HashListTableTestFull02 (void) void HashListTableRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01, 1); - UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02, 1); - UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03, 1); - UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04, 1); - - UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01, 1); - UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02, 1); - UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03, 1); - UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04, 1); - - UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01, 1); - UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02, 1); + UtRegisterTest("HashListTableTestInit01", HashListTableTestInit01); + UtRegisterTest("HashListTableTestInit02", HashListTableTestInit02); + UtRegisterTest("HashListTableTestInit03", HashListTableTestInit03); + UtRegisterTest("HashListTableTestInit04", HashListTableTestInit04); + + UtRegisterTest("HashListTableTestAdd01", HashListTableTestAdd01); + UtRegisterTest("HashListTableTestAdd02", HashListTableTestAdd02); + UtRegisterTest("HashListTableTestAdd03", HashListTableTestAdd03); + UtRegisterTest("HashListTableTestAdd04", HashListTableTestAdd04); + + UtRegisterTest("HashListTableTestFull01", HashListTableTestFull01); + UtRegisterTest("HashListTableTestFull02", HashListTableTestFull02); #endif /* UNITTESTS */ } diff --git a/src/util-host-info.c b/src/util-host-info.c index c7ea8adf6cf7..2e06c636de10 100644 --- a/src/util-host-info.c +++ b/src/util-host-info.c @@ -86,6 +86,8 @@ int SCKernelVersionIsAtLeast(int major, int minor) kminor = atoi(list[2]); pcre_free_substring_list(list); + pcre_free_study(version_regex_study); + pcre_free(version_regex); if (kmajor > major) return 1; diff --git a/src/util-host-os-info.c b/src/util-host-os-info.c index 8438d198971b..eaea28432c08 100644 --- a/src/util-host-os-info.c +++ b/src/util-host-os-info.c @@ -230,8 +230,7 @@ int SCHInfoAddHostOSInfo(char *host_os, char *host_os_ip_range, int is_ipv4) SCHInfoAddHostOSInfo(host_os, ip_str_rem, is_ipv4); } - if (ip_str != NULL) - SCFree(ip_str); + SCFree(ip_str); if (ipv4_addr != NULL) SCFree(ipv4_addr); if (ipv6_addr != NULL) @@ -342,7 +341,7 @@ void SCHInfoLoadFromConfig(void) ConfNode *host; TAILQ_FOREACH(host, &policy->head, next) { int is_ipv4 = 1; - if (index(host->val, ':') != NULL) + if (host->val != NULL && index(host->val, ':') != NULL) is_ipv4 = 0; if (SCHInfoAddHostOSInfo(policy->name, host->val, is_ipv4) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, @@ -450,12 +449,12 @@ int SCHInfoTestInvalidIPV4Address02(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.566", SC_HINFO_IS_IPV4) != -1) { goto end; } - if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4 != -1)) { + if (SCHInfoAddHostOSInfo("linux", "192.168.1", SC_HINFO_IS_IPV4) != -1) { goto end; } if (SCHInfoAddHostOSInfo("linux", "192.", SC_HINFO_IS_IPV4) != -1) { @@ -488,7 +487,7 @@ int SCHInfoTestInvalidIPV6Address03(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2362:7322", SC_HINFO_IS_IPV6) != -1) { goto end; @@ -530,7 +529,7 @@ int SCHInfoTestValidIPV4Address04(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { goto end; @@ -643,7 +642,7 @@ int SCHInfoTestValidIPV4Address05(void) SCHInfoCreateContextBackup(); struct in_addr in; - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.1", SC_HINFO_IS_IPV4) == -1) { goto end; @@ -783,7 +782,7 @@ int SCHInfoTestValidIPV6Address06(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", @@ -919,7 +918,7 @@ int SCHInfoTestValidIPV6Address07(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", @@ -1076,7 +1075,7 @@ int SCHInfoTestValidIPV6Address08(void) SCHInfoCreateContextBackup(); struct in6_addr in6; - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "2351:2512:6211:6246:235A:6242:2352:62AD", @@ -1248,10 +1247,10 @@ int SCHInfoTestValidIPV4Address09(void) { SCHInfoCreateContextBackup(); - int result = 1; + int result = 0; if (SCHInfoAddHostOSInfo("linux", "192.168.1.0", SC_HINFO_IS_IPV4) == -1) { - goto end; + goto end; } if (SCHInfoAddHostOSInfo("windows", "192.192.1.2", SC_HINFO_IS_IPV4) == -1) { goto end; @@ -1319,22 +1318,26 @@ int SCHInfoTestValidIPV4Address09(void) goto end; } - if (SCHInfoGetHostOSFlavour("192.168.1.100") == + /* 192.168.1.100 should match "macos" as its more specific than + * "solaris". */ + if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("macos", sc_hinfo_os_policy_map)) { goto end; } + /* Remove the 192.168.1.0/20 -> macos entry. */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; } SCRadixRemoveKeyIPV4Netblock((uint8_t *)&servaddr.sin_addr, sc_hinfo_tree, 20); - if (SCHInfoGetHostOSFlavour("192.168.1.100") == + if (SCHInfoGetHostOSFlavour("192.168.1.100") != SCMapEnumNameToValue("solaris", sc_hinfo_os_policy_map)) { goto end; } + /* Remove the 192.168.1.0/16 -> solaris entry. */ bzero(&servaddr, sizeof(servaddr)); if (inet_pton(AF_INET, "192.168.0.0", &servaddr.sin_addr) <= 0) { goto end; @@ -1481,7 +1484,7 @@ host-os-policy:\n\ vista: [0.0.0.5]\n\ \n"; - int result = 1; + int result = 0; SCHInfoCreateContextBackup(); @@ -1527,7 +1530,7 @@ host-os-policy:\n\ vista: [0.0.0.5]\n\ \n"; - int result = 1; + int result = 0; SCHInfoCreateContextBackup(); @@ -1625,32 +1628,28 @@ void SCHInfoRegisterTests(void) #ifdef UNITTESTS UtRegisterTest("SCHInfoTesInvalidOSFlavour01", - SCHInfoTestInvalidOSFlavour01, 1); + SCHInfoTestInvalidOSFlavour01); UtRegisterTest("SCHInfoTestInvalidIPV4Address02", - SCHInfoTestInvalidIPV4Address02, 1); + SCHInfoTestInvalidIPV4Address02); UtRegisterTest("SCHInfoTestInvalidIPV6Address03", - SCHInfoTestInvalidIPV6Address03, 1); + SCHInfoTestInvalidIPV6Address03); UtRegisterTest("SCHInfoTestValidIPV4Address04", - SCHInfoTestValidIPV4Address04, 1); + SCHInfoTestValidIPV4Address04); UtRegisterTest("SCHInfoTestValidIPV4Address05", - SCHInfoTestValidIPV4Address05, 1); + SCHInfoTestValidIPV4Address05); UtRegisterTest("SCHInfoTestValidIPV6Address06", - SCHInfoTestValidIPV6Address06, 1); + SCHInfoTestValidIPV6Address06); UtRegisterTest("SCHInfoTestValidIPV6Address07", - SCHInfoTestValidIPV6Address07, 1); + SCHInfoTestValidIPV6Address07); UtRegisterTest("SCHInfoTestValidIPV6Address08", - SCHInfoTestValidIPV6Address08, 1); + SCHInfoTestValidIPV6Address08); UtRegisterTest("SCHInfoTestValidIPV4Address09", - SCHInfoTestValidIPV4Address09, 1); - - UtRegisterTest("SCHInfoTestLoadFromConfig01", - SCHInfoTestLoadFromConfig01, 1); - UtRegisterTest("SCHInfoTestLoadFromConfig02", - SCHInfoTestLoadFromConfig02, 1); - UtRegisterTest("SCHInfoTestLoadFromConfig03", - SCHInfoTestLoadFromConfig03, 1); - UtRegisterTest("SCHInfoTestLoadFromConfig04", - SCHInfoTestLoadFromConfig04, 1); + SCHInfoTestValidIPV4Address09); + + UtRegisterTest("SCHInfoTestLoadFromConfig01", SCHInfoTestLoadFromConfig01); + UtRegisterTest("SCHInfoTestLoadFromConfig02", SCHInfoTestLoadFromConfig02); + UtRegisterTest("SCHInfoTestLoadFromConfig03", SCHInfoTestLoadFromConfig03); + UtRegisterTest("SCHInfoTestLoadFromConfig04", SCHInfoTestLoadFromConfig04); #endif /* UNITTESTS */ } diff --git a/src/util-hyperscan.c b/src/util-hyperscan.c new file mode 100644 index 000000000000..edcf73f66580 --- /dev/null +++ b/src/util-hyperscan.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Justin Viiret + * + * Support functions for Hyperscan library integration. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#ifdef BUILD_HYPERSCAN + +/** + * \internal + * \brief Convert a pattern into a regex string accepted by the Hyperscan + * compiler. + * + * For simplicity, we just take each byte of the original pattern and render it + * with a hex escape (i.e. ' ' -> "\x20")/ + */ +char *HSRenderPattern(const uint8_t *pat, uint16_t pat_len) +{ + if (pat == NULL) { + return NULL; + } + const size_t hex_len = (pat_len * 4) + 1; + char *str = SCMalloc(hex_len); + if (str == NULL) { + return NULL; + } + memset(str, 0, hex_len); + char *sp = str; + for (uint16_t i = 0; i < pat_len; i++) { + snprintf(sp, 5, "\\x%02x", pat[i]); + sp += 4; + } + *sp = '\0'; + return str; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-hyperscan.h b/src/util-hyperscan.h new file mode 100644 index 000000000000..67bcabf49d84 --- /dev/null +++ b/src/util-hyperscan.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Justin Viiret + * + * Support functions for Hyperscan library integration. + */ + +#ifndef __UTIL_HYPERSCAN__H__ +#define __UTIL_HYPERSCAN__H__ + +char *HSRenderPattern(const uint8_t *pat, uint16_t pat_len); + +#endif /* __UTIL_HYPERSCAN__H__ */ diff --git a/src/util-ioctl.c b/src/util-ioctl.c index f46004213e28..1ec0700c8691 100644 --- a/src/util-ioctl.c +++ b/src/util-ioctl.c @@ -19,10 +19,12 @@ * \file * * \author Eric Leblond + * \author Victor Julien */ #include "suricata-common.h" #include "conf.h" +#include "util-device.h" #ifdef HAVE_SYS_IOCTL_H #include @@ -47,7 +49,7 @@ * * \param Name of a network interface */ -int GetIfaceMaxHWHeaderLength(char *pcap_dev) +int GetIfaceMaxHWHeaderLength(const char *pcap_dev) { if ((!strcmp("eth", pcap_dev)) || @@ -61,13 +63,16 @@ int GetIfaceMaxHWHeaderLength(char *pcap_dev) || (!strcmp("tap", pcap_dev)) || - (!strcmp("lo", pcap_dev))) - return ETHERNET_HEADER_LEN; + (!strcmp("lo", pcap_dev))) { + /* Add possible VLAN tag or Qing headers */ + return 8 + ETHERNET_HEADER_LEN; + } if (!strcmp("ppp", pcap_dev)) return SLL_HEADER_LEN; - /* SLL_HEADER_LEN is the biggest one */ - return SLL_HEADER_LEN; + /* SLL_HEADER_LEN is the biggest one and + add possible VLAN tag and Qing headers */ + return 8 + SLL_HEADER_LEN; } /** @@ -76,7 +81,7 @@ int GetIfaceMaxHWHeaderLength(char *pcap_dev) * \param Name of link * \retval -1 in case of error, 0 if MTU can not be found */ -int GetIfaceMTU(char *pcap_dev) +int GetIfaceMTU(const char *pcap_dev) { #ifdef SIOCGIFMTU struct ifreq ifr; @@ -90,8 +95,8 @@ int GetIfaceMTU(char *pcap_dev) if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get MTU via ioctl: %d", - errno); + "Failure when trying to get MTU via ioctl for '%s': %s (%d)", + pcap_dev, strerror(errno), errno); close(fd); return -1; } @@ -115,20 +120,18 @@ int GetIfaceMTU(char *pcap_dev) * \param Name of a network interface * \retval 0 in case of error */ -int GetIfaceMaxPacketSize(char *pcap_dev) +int GetIfaceMaxPacketSize(const char *pcap_dev) { - int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev); - int mtu = 0; - if ((pcap_dev == NULL) || strlen(pcap_dev) == 0) return 0; - mtu = GetIfaceMTU(pcap_dev); + int mtu = GetIfaceMTU(pcap_dev); switch (mtu) { case 0: case -1: return 0; } + int ll_header = GetIfaceMaxHWHeaderLength(pcap_dev); if (ll_header == -1) { /* be conservative, choose a big one */ ll_header = 16; @@ -136,77 +139,601 @@ int GetIfaceMaxPacketSize(char *pcap_dev) return ll_header + mtu; } +#ifdef SIOCGIFFLAGS /** - * \brief output offloading status of the link - * - * Test interface for GRO and LRO features. If one of them is - * activated then suricata mays received packets merge at reception. - * The result is oversized packets and this may cause some serious - * problem in some capture mode where the size of the packet is - * limited (AF_PACKET in V2 more for example). - * - * ETHTOOL_GGRO ETH_FLAG_LRO - * - * \param Name of link - * \retval -1 in case of error, 0 if none, 1 if some + * \brief Get interface flags. + * \param ifname Inteface name. + * \return Interface flags or -1 on error */ -int GetIfaceOffloading(char *pcap_dev) +int GetIfaceFlags(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to get flags for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); +#ifdef OS_FREEBSD + int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + return flags; +#else + return ifr.ifr_flags; +#endif +} +#endif + +#ifdef SIOCSIFFLAGS +/** + * \brief Set interface flags. + * \param ifname Inteface name. + * \param flags Flags to set. + * \return Zero on success. + */ +int SetIfaceFlags(const char *ifname, int flags) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +#ifdef OS_FREEBSD + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; +#else + ifr.ifr_flags = flags; +#endif + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to set flags for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif /* SIOCGIFFLAGS */ + +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to get caps for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return ifr.ifr_curcap; +} +#endif +#ifdef SIOCSIFCAP +int SetIfaceCaps(const char *ifname, int caps) +{ + struct ifreq ifr; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_reqcap = caps; + + if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) { + SCLogError(SC_ERR_SYSCALL, + "Unable to set caps for iface \"%s\": %s", + ifname, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + return 0; +} +#endif + + +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL +static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) { -#if defined (ETHTOOL_GGRO) && defined (ETHTOOL_GFLAGS) struct ifreq ifr; int fd; struct ethtool_value ethv; - int ret = 0; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { return -1; } - (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name)); + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - /* First get GRO */ - ethv.cmd = ETHTOOL_GGRO; + ethv.cmd = cmd; ifr.ifr_data = (void *) ðv; if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get feature via ioctl: %s (%d)", - strerror(errno), errno); + "Failure when trying to get feature via ioctl for '%s': %s (%d)", + dev, strerror(errno), errno); close(fd); return -1; - } else { - if (ethv.data) { - SCLogInfo("Generic Receive Offload is set on %s", pcap_dev); - ret = 1; - } else { - SCLogInfo("Generic Receive Offload is unset on %s", pcap_dev); - } } - /* Then get LRO which is set in a flag */ - ethv.data = 0; - ethv.cmd = ETHTOOL_GFLAGS; + *value = ethv.data; + close(fd); + return 0; +} + +static int SetEthtoolValue(const char *dev, int cmd, uint32_t value) +{ + struct ifreq ifr; + int fd; + struct ethtool_value ethv; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + + ethv.cmd = cmd; + ethv.data = value; ifr.ifr_data = (void *) ðv; if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { SCLogWarning(SC_ERR_SYSCALL, - "Failure when trying to get feature via ioctl: %s (%d)", - strerror(errno), errno); + "Failure when trying to get feature via ioctl for '%s': %s (%d)", + dev, strerror(errno), errno); close(fd); return -1; - } else { - if (ethv.data & ETH_FLAG_LRO) { - SCLogInfo("Large Receive Offload is set on %s", pcap_dev); + } + + close(fd); + return 0; +} + +static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) +{ + int ret = 0; + uint32_t value = 0; + + if (csum) { + char *rx = "unset", *tx = "unset"; + int csum_ret = 0; +#ifdef ETHTOOL_GRXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { + rx = "SET"; + csum_ret = 1; + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { + tx = "SET"; + csum_ret = 1; + } +#endif + if (csum_ret == 0) + SCLogPerf("NIC offloading on %s: RX %s TX %s", dev, rx, tx); + else { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "NIC offloading on %s: RX %s TX %s. Run: " + "ethtool -K %s rx off tx off", dev, rx, tx, dev); ret = 1; + } + } + + if (other) { + char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; + char *sg = "unset"; + int other_ret = 0; +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + gro = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GTSO + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + tso = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GGSO + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + gso = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GSG + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + sg = "SET"; + other_ret = 1; + } +#endif +#ifdef ETHTOOL_GFLAGS + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { + lro = "SET"; + other_ret = 1; + } + } +#endif + if (other_ret == 0) { + SCLogPerf("NIC offloading on %s: SG: %s, GRO: %s, LRO: %s, " + "TSO: %s, GSO: %s", dev, sg, gro, lro, tso, gso); } else { - SCLogInfo("Large Receive Offload is unset on %s", pcap_dev); + SCLogWarning(SC_ERR_NIC_OFFLOADING, "NIC offloading on %s: SG: %s, " + " GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: " + "ethtool -K %s sg off gro off lro off tso off gso off", + dev, sg, gro, lro, tso, gso, dev); + ret = 1; } } + return ret; +} - close(fd); +static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) +{ + int ret = 0; + uint32_t value = 0; + + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + if (csum) { +#ifdef ETHTOOL_GRXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; + } +#endif + } + if (other) { +#ifdef ETHTOOL_GGRO + if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GRO; + } +#endif +#ifdef ETHTOOL_GTSO + if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_TSO; + } +#endif +#ifdef ETHTOOL_GGSO + if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 0); + ldev->offload_orig |= OFFLOAD_FLAG_GSO; + } +#endif +#ifdef ETHTOOL_GSG + if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { + SCLogPerf("%s: disabling sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 0); + ldev->offload_orig |= OFFLOAD_FLAG_SG; + } +#endif +#ifdef ETHTOOL_GFLAGS + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + if (value & ETH_FLAG_LRO) { + SCLogPerf("%s: disabling lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); + ldev->offload_orig |= OFFLOAD_FLAG_LRO; + } + } +#endif + } return ret; +} + +static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) +{ + if (ldev == NULL) + return -1; + + const char *dev = ldev->dev; + +#ifdef ETHTOOL_GRXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogPerf("%s: restoring rxcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GTXCSUM + if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { + SCLogPerf("%s: restoring txcsum offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); + } +#endif +#ifdef ETHTOOL_GGRO + if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { + SCLogPerf("%s: restoring gro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGRO, 1); + } +#endif +#ifdef ETHTOOL_GTSO + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogPerf("%s: restoring tso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_STSO, 1); + } +#endif +#ifdef ETHTOOL_GGSO + if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { + SCLogPerf("%s: restoring gso offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SGSO, 1); + } +#endif +#ifdef ETHTOOL_GSG + if (ldev->offload_orig & OFFLOAD_FLAG_SG) { + SCLogPerf("%s: restoring sg offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SSG, 1); + } +#endif +#ifdef ETHTOOL_GFLAGS + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + uint32_t value = 0; + if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { + SCLogPerf("%s: restoring lro offloading", dev); + SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); + } + } +#endif + return 0; +} + +#endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ + +#ifdef SIOCGIFCAP +static int GetIfaceOffloadingBSD(const char *ifname) +{ + int ret = 0; + int if_caps = GetIfaceCaps(ifname); + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with RXCSUM activated can lead to capture " + "problems. Run: ifconfig %s -rxcsum", ifname, ifname); + ret = 1; + } +#ifdef IFCAP_TOE + if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with TSO, TOE or LRO activated can lead to " + "capture problems. Run: ifconfig %s -tso -toe -lro", + ifname, ifname); + ret = 1; + } +#else + if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { + SCLogWarning(SC_ERR_NIC_OFFLOADING, + "Using %s with TSO or LRO activated can lead to " + "capture problems. Run: ifconfig %s -tso -lro", + ifname, ifname); + ret = 1; + } +#endif + return ret; +} +#endif + +#ifdef SIOCSIFCAP +static int DisableIfaceOffloadingBSD(LiveDevice *ldev) +{ + int ret = 0; + + if (ldev == NULL) + return -1; + + const char *ifname = ldev->dev; + int if_caps = GetIfaceCaps(ifname); + int set_caps = if_caps; + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (if_caps & IFCAP_RXCSUM) { + SCLogPerf("%s: disabling rxcsum offloading", ifname); + set_caps &= ~IFCAP_RXCSUM; + } + +#ifdef IFCAP_TOE + if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { + SCLogPerf("%s: disabling tso|toe|lro offloading", ifname); + set_caps &= ~(IFCAP_TSO|IFCAP_LRO); + } +#else + if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { + SCLogPerf("%s: disabling tso|lro offloading", ifname); + set_caps &= ~(IFCAP_TSO|IFCAP_LRO); + } +#endif + if (set_caps != if_caps) { + if (if_caps & IFCAP_RXCSUM) + ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; + if (if_caps & IFCAP_TSO) + ldev->offload_orig |= OFFLOAD_FLAG_TSO; +#ifdef IFCAP_TOE + if (if_caps & IFCAP_TOE) + ldev->offload_orig |= OFFLOAD_FLAG_TOE; +#endif + if (if_caps & IFCAP_LRO) + ldev->offload_orig |= OFFLOAD_FLAG_LRO; + + SetIfaceCaps(ifname, set_caps); + } + return ret; +} + +static int RestoreIfaceOffloadingBSD(LiveDevice *ldev) +{ + int ret = 0; + + if (ldev == NULL) + return -1; + + const char *ifname = ldev->dev; + int if_caps = GetIfaceCaps(ifname); + int set_caps = if_caps; + if (if_caps == -1) { + return -1; + } + SCLogDebug("if_caps %X", if_caps); + + if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { + SCLogPerf("%s: restoring rxcsum offloading", ifname); + set_caps |= IFCAP_RXCSUM; + } + if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { + SCLogPerf("%s: restoring tso offloading", ifname); + set_caps |= IFCAP_TSO; + } +#ifdef IFCAP_TOE + if (ldev->offload_orig & OFFLOAD_FLAG_TOE) { + SCLogPerf("%s: restoring toe offloading", ifname); + set_caps |= IFCAP_TOE; + } +#endif + if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { + SCLogPerf("%s: restoring lro offloading", ifname); + set_caps |= IFCAP_LRO; + } + + if (set_caps != if_caps) { + SetIfaceCaps(ifname, set_caps); + } + return ret; +} +#endif + +/** + * \brief output offloading status of the link + * + * Test interface for offloading features. If one of them is + * activated then suricata mays received packets merge at reception. + * The result is oversized packets and this may cause some serious + * problem in some capture mode where the size of the packet is + * limited (AF_PACKET in V2 more for example). + * + * \param Name of link + * \param csum check if checksums are offloaded + * \param other check if other things are offloaded: TSO, GRO, etc. + * \retval -1 in case of error, 0 if none, 1 if some + */ +int GetIfaceOffloading(const char *dev, int csum, int other) +{ +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + return GetIfaceOffloadingLinux(dev, csum, other); +#elif defined SIOCGIFCAP + return GetIfaceOffloadingBSD(dev); #else - /* ioctl is not defined, let's pretend returning 0 is ok */ return 0; #endif } +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other) +{ +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + return DisableIfaceOffloadingLinux(dev, csum, other); +#elif defined SIOCSIFCAP + return DisableIfaceOffloadingBSD(dev); +#else + return 0; +#endif + +} + +void RestoreIfaceOffloading(LiveDevice *dev) +{ + if (dev->offload_orig != 0) { +#if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL + RestoreIfaceOffloadingLinux(dev); +#elif defined SIOCSIFCAP + RestoreIfaceOffloadingBSD(dev); +#endif + } +} + +int GetIfaceRSSQueuesNum(const char *pcap_dev) +{ +#if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS + struct ifreq ifr; + struct ethtool_rxnfc nfccmd; + int fd; + + (void)strlcpy(ifr.ifr_name, pcap_dev, sizeof(ifr.ifr_name)); + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + SCLogWarning(SC_ERR_SYSCALL, + "Failure when opening socket for ioctl: %s (%d)", + strerror(errno), errno); + return -1; + } + + nfccmd.cmd = ETHTOOL_GRXRINGS; + ifr.ifr_data = (void*) &nfccmd; + + if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { + if (errno != ENOTSUP) { + SCLogWarning(SC_ERR_SYSCALL, + "Failure when trying to get number of RSS queue ioctl for '%s': %s (%d)", + pcap_dev, strerror(errno), errno); + } + close(fd); + return 0; + } + close(fd); + SCLogInfo("Found %d RX RSS queues for '%s'", (int)nfccmd.data, + pcap_dev); + return (int)nfccmd.data; +#else + return 0; +#endif +} diff --git a/src/util-ioctl.h b/src/util-ioctl.h index 7bc5055710ba..54020e4c7cf8 100644 --- a/src/util-ioctl.h +++ b/src/util-ioctl.h @@ -21,6 +21,20 @@ * \author Eric Leblond */ -int GetIfaceMTU(char *pcap_dev); -int GetIfaceMaxPacketSize(char *pcap_dev); -int GetIfaceOffloading(char *pcap_dev); +#include "util-device.h" + +int GetIfaceMTU(const char *pcap_dev); +int GetIfaceMaxPacketSize(const char *pcap_dev); +int GetIfaceOffloading(const char *dev, int csum, int other); +int GetIfaceRSSQueuesNum(const char *pcap_dev); +#ifdef SIOCGIFFLAGS +int GetIfaceFlags(const char *ifname); +#endif +#ifdef SIOCSIFFLAGS +int SetIfaceFlags(const char *ifname, int flags); +#endif +#ifdef SIOCGIFCAP +int GetIfaceCaps(const char *ifname); +#endif +int DisableIfaceOffloading(LiveDevice *dev, int csum, int other); +void RestoreIfaceOffloading(LiveDevice *dev); diff --git a/src/util-ip.c b/src/util-ip.c index 1f22d8640d20..91c3baab99eb 100644 --- a/src/util-ip.c +++ b/src/util-ip.c @@ -93,15 +93,15 @@ struct in6_addr *ValidateIPV6Address(const char *addr_str) */ void MaskIPNetblock(uint8_t *stream, uint8_t netmask, uint16_t key_bitlen) { - int mask = 0; + uint32_t mask = 0; int i = 0; int bytes = key_bitlen / 8; for (i = 0; i < bytes; i++) { - mask = -1; + mask = UINT_MAX; if ( ((i + 1) * 8) > netmask) { if ( ((i + 1) * 8 - netmask) < 8) - mask = -1 << ((i + 1) * 8 - netmask); + mask = UINT_MAX << ((i + 1) * 8 - netmask); else mask = 0; } diff --git a/src/util-logopenfile-tile.c b/src/util-logopenfile-tile.c index c2414fc49b45..82e9bbf3b4a2 100644 --- a/src/util-logopenfile-tile.c +++ b/src/util-logopenfile-tile.c @@ -349,7 +349,7 @@ PcieFile *TileOpenPcieFp(LogFileCtx *log_ctx, const char *path, const char *append_setting) { PcieFile *ret = NULL; - if (strcasecmp(append_setting, "yes") == 0) { + if (ConfValIsTrue(append_setting)) { ret = TileOpenPcieFpInternal(path, 'a'); } else { ret = TileOpenPcieFpInternal(path, 'w'); diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index 4e42ceef402f..376a77af29eb 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -31,30 +31,35 @@ #include "tm-modules.h" /* LogFileCtx */ #include "conf.h" /* ConfNode, etc. */ #include "output.h" /* DEFAULT_LOG_* */ +#include "util-byte.h" #include "util-logopenfile.h" #include "util-logopenfile-tile.h" +const char * redis_push_cmd = "LPUSH"; +const char * redis_publish_cmd = "PUBLISH"; + /** \brief connect to the indicated local stream socket, logging any errors * \param path filesystem path to connect to + * \param log_err, non-zero if connect failure should be logged. * \retval FILE* on success (fdopen'd wrapper of underlying socket) * \retval NULL on error */ static FILE * -SCLogOpenUnixSocketFp(const char *path, int sock_type) +SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err) { - struct sockaddr_un sun; + struct sockaddr_un saun; int s = -1; FILE * ret = NULL; - memset(&sun, 0x00, sizeof(sun)); + memset(&saun, 0x00, sizeof(saun)); s = socket(PF_UNIX, sock_type, 0); if (s < 0) goto err; - sun.sun_family = AF_UNIX; - strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + saun.sun_family = AF_UNIX; + strlcpy(saun.sun_path, path, sizeof(saun.sun_path)); - if (connect(s, (const struct sockaddr *)&sun, sizeof(sun)) < 0) + if (connect(s, (const struct sockaddr *)&saun, sizeof(saun)) < 0) goto err; ret = fdopen(s, "w"); @@ -64,8 +69,10 @@ SCLogOpenUnixSocketFp(const char *path, int sock_type) return ret; err: - SCLogError(SC_ERR_SOCKET, "Error connecting to socket \"%s\": %s", - path, strerror(errno)); + if (log_err) + SCLogWarning(SC_ERR_SOCKET, + "Error connecting to socket \"%s\": %s (will keep trying)", + path, strerror(errno)); if (s >= 0) close(s); @@ -73,24 +80,193 @@ SCLogOpenUnixSocketFp(const char *path, int sock_type) return NULL; } -static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) +/** + * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket. + * \retval 1 if it is now connected; otherwise 0 + */ +static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx) { - /* Check for rotation. */ - if (log_ctx->rotation_flag) { - log_ctx->rotation_flag = 0; - SCConfLogReopen(log_ctx); + int disconnected = 0; + if (log_ctx->fp) { + SCLogWarning(SC_ERR_SOCKET, + "Write error on Unix socket \"%s\": %s; reconnecting...", + log_ctx->filename, strerror(errno)); + fclose(log_ctx->fp); + log_ctx->fp = NULL; + log_ctx->reconn_timer = 0; + disconnected = 1; } - int ret = 0; + struct timeval tv; + uint64_t now; + gettimeofday(&tv, NULL); + now = (uint64_t)tv.tv_sec * 1000; + now += tv.tv_usec / 1000; /* msec resolution */ + if (log_ctx->reconn_timer != 0 && + (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) { + /* Don't bother to try reconnecting too often. */ + return 0; + } + log_ctx->reconn_timer = now; + log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0); if (log_ctx->fp) { - ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); - fflush(log_ctx->fp); + /* Connected at last (or reconnected) */ + SCLogNotice("Reconnected socket \"%s\"", log_ctx->filename); + } else if (disconnected) { + SCLogWarning(SC_ERR_SOCKET, "Reconnect failed: %s (will keep trying)", + strerror(errno)); } + return log_ctx->fp ? 1 : 0; +} + +static int SCLogFileWriteSocket(const char *buffer, int buffer_len, + LogFileCtx *ctx) +{ + int tries = 0; + int ret = 0; + bool reopen = false; + + if (ctx->fp == NULL && ctx->is_sock) { + SCLogUnixSocketReconnect(ctx); + } + +tryagain: + ret = -1; + reopen = 0; + errno = 0; + if (ctx->fp != NULL) { + int fd = fileno(ctx->fp); + ssize_t size = send(fd, buffer, buffer_len, ctx->send_flags); + if (size > -1) { + ret = 0; + } else { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + SCLogDebug("Socket would block, dropping event."); + } else if (errno == EINTR) { + if (tries++ == 0) { + SCLogDebug("Interrupted system call, trying again."); + goto tryagain; + } + SCLogDebug("Too many interrupted system calls, " + "dropping event."); + } else { + /* Some other error. Assume badness and reopen. */ + SCLogDebug("Send failed: %s", strerror(errno)); + reopen = true; + } + } + } + + if (reopen && tries++ == 0) { + if (SCLogUnixSocketReconnect(ctx)) { + goto tryagain; + } + } + + if (ret == -1) { + ctx->dropped++; + } + + return ret; +} + +/** + * \brief Write buffer to log file. + * \retval 0 on failure; otherwise, the return value of fwrite (number of + * characters successfully written). + */ +static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx) +{ + SCMutexLock(&log_ctx->fp_mutex); + int ret = 0; + + if (log_ctx->is_sock) { + ret = SCLogFileWriteSocket(buffer, buffer_len, log_ctx); + } else { + + /* Check for rotation. */ + if (log_ctx->rotation_flag) { + log_ctx->rotation_flag = 0; + SCConfLogReopen(log_ctx); + } + + if (log_ctx->flags & LOGFILE_ROTATE_INTERVAL) { + time_t now = time(NULL); + if (now >= log_ctx->rotate_time) { + SCConfLogReopen(log_ctx); + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + + if (log_ctx->fp) { + clearerr(log_ctx->fp); + ret = fwrite(buffer, buffer_len, 1, log_ctx->fp); + fflush(log_ctx->fp); + } + } + + SCMutexUnlock(&log_ctx->fp_mutex); + return ret; } +/** \brief generate filename based on pattern + * \param pattern pattern to use + * \retval char* on success + * \retval NULL on error + */ +static char *SCLogFilenameFromPattern(const char *pattern) +{ + char *filename = SCMalloc(PATH_MAX); + if (filename == NULL) { + return NULL; + } + + int rc = SCTimeToStringPattern(time(NULL), pattern, filename, PATH_MAX); + if (rc != 0) { + return NULL; + } + + return filename; +} + +/** \brief recursively create missing log directories + * \param path path to log file + * \retval 0 on success + * \retval -1 on error + */ +static int SCLogCreateDirectoryTree(const char *filepath) +{ + char pathbuf[PATH_MAX]; + char *p; + size_t len = strlen(filepath); + + if (len > PATH_MAX - 1) { + return -1; + } + + strlcpy(pathbuf, filepath, len); + + for (p = pathbuf + 1; *p; p++) { + if (*p == '/') { + /* Truncate, while creating directory */ + *p = '\0'; + + if (mkdir(pathbuf, S_IRWXU | S_IRGRP | S_IXGRP) != 0) { + if (errno != EEXIST) { + return -1; + } + } + + *p = '/'; + } + } + + return 0; +} + static void SCLogFileClose(LogFileCtx *log_ctx) { if (log_ctx->fp) @@ -100,23 +276,46 @@ static void SCLogFileClose(LogFileCtx *log_ctx) /** \brief open the indicated file, logging any errors * \param path filesystem path to open * \param append_setting open file with O_APPEND: "yes" or "no" + * \param mode permissions to set on file * \retval FILE* on success * \retval NULL on error */ static FILE * -SCLogOpenFileFp(const char *path, const char *append_setting) +SCLogOpenFileFp(const char *path, const char *append_setting, uint32_t mode) { FILE *ret = NULL; - if (strcasecmp(append_setting, "yes") == 0) { - ret = fopen(path, "a"); + char *filename = SCLogFilenameFromPattern(path); + if (filename == NULL) { + return NULL; + } + + int rc = SCLogCreateDirectoryTree(filename); + if (rc < 0) { + SCFree(filename); + return NULL; + } + + if (ConfValIsTrue(append_setting)) { + ret = fopen(filename, "a"); } else { - ret = fopen(path, "w"); + ret = fopen(filename, "w"); } - if (ret == NULL) + if (ret == NULL) { SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", - path, strerror(errno)); + filename, strerror(errno)); + } else { + if (mode != 0) { + int r = chmod(filename, mode); + if (r < 0) { + SCLogWarning(SC_WARN_CHMOD, "Could not chmod %s to %u: %s", + filename, mode, strerror(errno)); + } + } + } + + SCFree(filename); return ret; } @@ -142,13 +341,15 @@ static PcieFile *SCLogOpenPcieFp(LogFileCtx *log_ctx, const char *path, * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode + * \param rotate Register the file for rotation in HUP. * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, - const char *default_filename) + const char *default_filename, + int rotate) { char log_path[PATH_MAX]; char *log_dir; @@ -182,39 +383,114 @@ SCConfLogOpenGeneric(ConfNode *conf, snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } + /* Rotate log file based on time */ + const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); + if (rotate_int != NULL) { + time_t now = time(NULL); + log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; + + /* Use a specific time */ + if (strcmp(rotate_int, "minute") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 60; + } else if (strcmp(rotate_int, "hour") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 3600; + } else if (strcmp(rotate_int, "day") == 0) { + log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); + log_ctx->rotate_interval = 86400; + } + + /* Use a timer */ + else { + log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); + if (log_ctx->rotate_interval == 0) { + SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, + "invalid rotate-interval value"); + exit(EXIT_FAILURE); + } + log_ctx->rotate_time = now + log_ctx->rotate_interval; + } + } + filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; + const char *filemode = ConfNodeLookupChildValue(conf, "filemode"); + uint32_t mode = 0; + if (filemode != NULL && + ByteExtractStringUint32(&mode, 8, strlen(filemode), + filemode) > 0) { + log_ctx->filemode = mode; + } + const char *append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; + /* JSON flags */ +#ifdef HAVE_LIBJANSSON + log_ctx->json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT| + JSON_ENSURE_ASCII|JSON_ESCAPE_SLASH; + + ConfNode *json_flags = ConfNodeLookupChild(conf, "json"); + + if (json_flags != 0) { + const char *preserve_order = ConfNodeLookupChildValue(json_flags, + "preserve-order"); + if (preserve_order != NULL && ConfValIsFalse(preserve_order)) + log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER); + + const char *compact = ConfNodeLookupChildValue(json_flags, "compact"); + if (compact != NULL && ConfValIsFalse(compact)) + log_ctx->json_flags &= ~(JSON_COMPACT); + + const char *ensure_ascii = ConfNodeLookupChildValue(json_flags, + "ensure-ascii"); + if (ensure_ascii != NULL && ConfValIsFalse(ensure_ascii)) + log_ctx->json_flags &= ~(JSON_ENSURE_ASCII); + + const char *escape_slash = ConfNodeLookupChildValue(json_flags, + "escape-slash"); + if (escape_slash != NULL && ConfValIsFalse(escape_slash)) + log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH); + } +#endif /* HAVE_LIBJANSSON */ + // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { - log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM); - if (log_ctx->fp == NULL) - return -1; // Error already logged by Open...Fp routine + /* Don't bail. May be able to connect later. */ + log_ctx->is_sock = 1; + log_ctx->sock_type = SOCK_STREAM; + log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); } else if (strcasecmp(filetype, "unix_dgram") == 0) { - log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM); - if (log_ctx->fp == NULL) - return -1; // Error already logged by Open...Fp routine + /* Don't bail. May be able to connect later. */ + log_ctx->is_sock = 1; + log_ctx->sock_type = SOCK_DGRAM; + log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0) { - log_ctx->fp = SCLogOpenFileFp(log_path, append); + log_ctx->fp = SCLogOpenFileFp(log_path, append, log_ctx->filemode); if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine log_ctx->is_regular = 1; - log_ctx->filename = SCStrdup(log_path); - if (unlikely(log_ctx->filename == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for " - "filename"); - return -1; + if (rotate) { + OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); } } else if (strcasecmp(filetype, "pcie") == 0) { log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append); if (log_ctx->pcie_fp == NULL) return -1; // Error already logged by Open...Fp routine +#ifdef HAVE_LIBHIREDIS + } else if (strcasecmp(filetype, "redis") == 0) { + ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); + if (SCConfLogOpenRedis(redis_node, log_ctx) < 0) { + SCLogError(SC_ERR_REDIS, "failed to open redis output"); + return -1; + } + log_ctx->type = LOGFILE_TYPE_REDIS; +#endif } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " @@ -222,6 +498,18 @@ SCConfLogOpenGeneric(ConfNode *conf, "or \"unix_dgram\"", conf->name); } + log_ctx->filename = SCStrdup(log_path); + if (unlikely(log_ctx->filename == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Failed to allocate memory for filename"); + return -1; + } + + /* If a socket and running live, do non-blocking writes. */ + if (log_ctx->is_sock && run_mode_offline == 0) { + SCLogInfo("Setting logging socket of non-blocking in live mode."); + log_ctx->send_flags |= MSG_DONTWAIT; + } SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); @@ -251,9 +539,10 @@ int SCConfLogReopen(LogFileCtx *log_ctx) fclose(log_ctx->fp); - /* Reopen the file. In this case do not append like may have been - * done on the initial opening of the file. */ - log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "no"); + /* Reopen the file. Append is forced in case the file was not + * moved as part of a rotation process. */ + SCLogDebug("Reopening log file %s.", log_ctx->filename); + log_ctx->fp = SCLogOpenFileFp(log_ctx->filename, "yes", log_ctx->filemode); if (log_ctx->fp == NULL) { return -1; // Already logged by Open..Fp routine. } @@ -261,6 +550,138 @@ int SCConfLogReopen(LogFileCtx *log_ctx) return 0; } + +#ifdef HAVE_LIBHIREDIS + +static void SCLogFileCloseRedis(LogFileCtx *log_ctx) +{ + if (log_ctx->redis) { + redisReply *reply; + int i; + for (i = 0; i < log_ctx->redis_setup.batch_count; i++) { + redisGetReply(log_ctx->redis, (void **)&reply); + if (reply) + freeReplyObject(reply); + } + redisFree(log_ctx->redis); + log_ctx->redis = NULL; + } + log_ctx->redis_setup.tried = 0; + log_ctx->redis_setup.batch_count = 0; +} + +int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) +{ + const char *redis_server = NULL; + const char *redis_port = NULL; + const char *redis_mode = NULL; + const char *redis_key = NULL; + + if (redis_node) { + redis_server = ConfNodeLookupChildValue(redis_node, "server"); + redis_port = ConfNodeLookupChildValue(redis_node, "port"); + redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); + redis_key = ConfNodeLookupChildValue(redis_node, "key"); + } + if (!redis_server) { + redis_server = "127.0.0.1"; + SCLogInfo("Using default redis server (127.0.0.1)"); + } + if (!redis_port) + redis_port = "6379"; + if (!redis_mode) + redis_mode = "list"; + if (!redis_key) + redis_key = "suricata"; + log_ctx->redis_setup.key = SCStrdup(redis_key); + + if (!log_ctx->redis_setup.key) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key name"); + exit(EXIT_FAILURE); + } + + log_ctx->redis_setup.batch_size = 0; + + ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining"); + if (pipelining) { + int enabled = 0; + int ret; + intmax_t val; + ret = ConfGetChildValueBool(pipelining, "enabled", &enabled); + if (ret && enabled) { + ret = ConfGetChildValueInt(pipelining, "batch-size", &val); + if (ret) { + log_ctx->redis_setup.batch_size = val; + } else { + log_ctx->redis_setup.batch_size = 10; + } + } + } + + if (!strcmp(redis_mode, "list")) { + log_ctx->redis_setup.command = redis_push_cmd; + if (!log_ctx->redis_setup.command) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); + exit(EXIT_FAILURE); + } + } else { + log_ctx->redis_setup.command = redis_publish_cmd; + if (!log_ctx->redis_setup.command) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); + exit(EXIT_FAILURE); + } + } + redisContext *c = redisConnect(redis_server, atoi(redis_port)); + if (c != NULL && c->err) { + SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s", c->errstr); + exit(EXIT_FAILURE); + } + + /* store server params for reconnection */ + log_ctx->redis_setup.server = SCStrdup(redis_server); + if (!log_ctx->redis_setup.server) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating redis server string"); + exit(EXIT_FAILURE); + } + log_ctx->redis_setup.port = atoi(redis_port); + log_ctx->redis_setup.tried = 0; + + log_ctx->redis = c; + + log_ctx->Close = SCLogFileCloseRedis; + + return 0; +} + +int SCConfLogReopenRedis(LogFileCtx *log_ctx) +{ + if (log_ctx->redis != NULL) { + redisFree(log_ctx->redis); + log_ctx->redis = NULL; + } + + /* only try to reconnect once per second */ + if (log_ctx->redis_setup.tried >= time(NULL)) { + return -1; + } + + redisContext *c = redisConnect(log_ctx->redis_setup.server, log_ctx->redis_setup.port); + if (c != NULL && c->err) { + if (log_ctx->redis_setup.tried == 0) { + SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s\n", c->errstr); + } + redisFree(c); + log_ctx->redis_setup.tried = time(NULL); + return -1; + } + log_ctx->redis = c; + log_ctx->redis_setup.tried = 0; + log_ctx->redis_setup.batch_count = 0; + return 0; +} + +#endif + /** \brief LogFileNewCtx() Get a new LogFileCtx * \retval LogFileCtx * pointer if succesful, NULL if error * */ @@ -279,6 +700,10 @@ LogFileCtx *LogFileNewCtx(void) lf_ctx->Write = SCLogFileWrite; lf_ctx->Close = SCLogFileClose; +#ifdef HAVE_LIBHIREDIS + lf_ctx->redis_setup.batch_count = 0; +#endif + return lf_ctx; } @@ -298,15 +723,144 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) SCMutexUnlock(&lf_ctx->fp_mutex); } +#ifdef HAVE_LIBHIREDIS + if (lf_ctx->type == LOGFILE_TYPE_REDIS) { + if (lf_ctx->redis) + redisFree(lf_ctx->redis); + if (lf_ctx->redis_setup.server) + SCFree(lf_ctx->redis_setup.server); + if (lf_ctx->redis_setup.key) + SCFree(lf_ctx->redis_setup.key); + } +#endif + SCMutexDestroy(&lf_ctx->fp_mutex); - if (lf_ctx->prefix != NULL) + if (lf_ctx->prefix != NULL) { SCFree(lf_ctx->prefix); + lf_ctx->prefix_len = 0; + } if(lf_ctx->filename != NULL) SCFree(lf_ctx->filename); + if (lf_ctx->sensor_name) + SCFree(lf_ctx->sensor_name); + + OutputUnregisterFileRotationFlag(&lf_ctx->rotation_flag); + SCFree(lf_ctx); SCReturnInt(1); } + +#ifdef HAVE_LIBHIREDIS +static int LogFileWriteRedis(LogFileCtx *file_ctx, const char *string, size_t string_len) +{ + if (file_ctx->redis == NULL) { + SCConfLogReopenRedis(file_ctx); + if (file_ctx->redis == NULL) { + return -1; + } else { + SCLogInfo("Reconnected to redis server"); + } + } + /* TODO go async here ? */ + if (file_ctx->redis_setup.batch_size) { + redisAppendCommand(file_ctx->redis, "%s %s %s", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string); + if (file_ctx->redis_setup.batch_count == file_ctx->redis_setup.batch_size) { + redisReply *reply; + int i; + file_ctx->redis_setup.batch_count = 0; + for (i = 0; i <= file_ctx->redis_setup.batch_size; i++) { + if (redisGetReply(file_ctx->redis, (void **)&reply) == REDIS_OK) { + freeReplyObject(reply); + } else { + if (file_ctx->redis->err) { + SCLogInfo("Error when fetching reply: %s (%d)", + file_ctx->redis->errstr, + file_ctx->redis->err); + } + switch (file_ctx->redis->err) { + case REDIS_ERR_EOF: + case REDIS_ERR_IO: + SCLogInfo("Reopening connection to redis server"); + SCConfLogReopenRedis(file_ctx); + if (file_ctx->redis) { + SCLogInfo("Reconnected to redis server"); + return 0; + } else { + SCLogInfo("Unable to reconnect to redis server"); + return 0; + } + break; + default: + SCLogWarning(SC_ERR_INVALID_VALUE, + "Unsupported error code %d", + file_ctx->redis->err); + return 0; + } + } + } + } else { + file_ctx->redis_setup.batch_count++; + } + } else { + redisReply *reply = redisCommand(file_ctx->redis, "%s %s %b", + file_ctx->redis_setup.command, + file_ctx->redis_setup.key, + string, string_len); + + /* We may lose the reply if disconnection happens! */ + if (reply) { + switch (reply->type) { + case REDIS_REPLY_ERROR: + SCLogWarning(SC_ERR_SOCKET, "Redis error: %s", reply->str); + SCConfLogReopenRedis(file_ctx); + break; + case REDIS_REPLY_INTEGER: + SCLogDebug("Redis integer %lld", reply->integer); + break; + default: + SCLogError(SC_ERR_INVALID_VALUE, + "Redis default triggered with %d", reply->type); + SCConfLogReopenRedis(file_ctx); + break; + } + freeReplyObject(reply); + } else { + SCConfLogReopenRedis(file_ctx); + } + } + return 0; +} +#endif + +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer) +{ + if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { + syslog(file_ctx->syslog_setup.alert_syslog_level, "%s", + (const char *)MEMBUFFER_BUFFER(buffer)); + } else if (file_ctx->type == LOGFILE_TYPE_FILE || + file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || + file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) + { + /* append \n for files only */ + MemBufferWriteString(buffer, "\n"); + file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), + MEMBUFFER_OFFSET(buffer), file_ctx); + } +#ifdef HAVE_LIBHIREDIS + else if (file_ctx->type == LOGFILE_TYPE_REDIS) { + SCMutexLock(&file_ctx->fp_mutex); + LogFileWriteRedis(file_ctx, (const char *)MEMBUFFER_BUFFER(buffer), + MEMBUFFER_OFFSET(buffer)); + SCMutexUnlock(&file_ctx->fp_mutex); + } +#endif + + return 0; +} diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index 65d179a6f775..857f8b821c70 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -26,16 +26,56 @@ #include "conf.h" /* ConfNode */ #include "tm-modules.h" /* LogFileCtx */ +#include "util-buffer.h" + +#ifdef HAVE_LIBHIREDIS +#include "hiredis/hiredis.h" +#endif typedef struct { uint16_t fileno; } PcieFile; +enum LogFileType { LOGFILE_TYPE_FILE, + LOGFILE_TYPE_SYSLOG, + LOGFILE_TYPE_UNIX_DGRAM, + LOGFILE_TYPE_UNIX_STREAM, + LOGFILE_TYPE_REDIS }; + +typedef struct SyslogSetup_ { + int alert_syslog_level; +} SyslogSetup; + +#ifdef HAVE_LIBHIREDIS +enum RedisMode { REDIS_LIST, REDIS_CHANNEL }; + +typedef struct RedisSetup_ { + enum RedisMode mode; + const char *command; + char *key; + int batch_size; + int batch_count; + char *server; + int port; + time_t tried; +} RedisSetup; +#endif + /** Global structure for Output Context */ typedef struct LogFileCtx_ { union { FILE *fp; PcieFile *pcie_fp; +#ifdef HAVE_LIBHIREDIS + redisContext *redis; +#endif + }; + + union { + SyslogSetup syslog_setup; +#ifdef HAVE_LIBHIREDIS + RedisSetup redis_setup; +#endif }; int (*Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp); @@ -45,39 +85,78 @@ typedef struct LogFileCtx_ { * record cannot be written to the file in one call */ SCMutex fp_mutex; + /** the type of file */ + enum LogFileType type; + /** The name of the file */ char *filename; + /** File permissions */ + uint32_t filemode; + + /** Suricata sensor name */ + char *sensor_name; + + /** Handle auto-connecting / reconnecting sockets */ + int is_sock; + int sock_type; + uint64_t reconn_timer; + + /** The next time to rotate log file, if rotate interval is + specified. */ + time_t rotate_time; + + /** The interval to rotate the log file */ + uint64_t rotate_interval; + /**< Used by some alert loggers like the unified ones that append * the date onto the end of files. */ char *prefix; + size_t prefix_len; /** Generic size_limit and size_current * They must be common to the threads accesing the same file */ uint64_t size_limit; /**< file size limit */ uint64_t size_current; /**< file current size */ - /* Alerts on the module (not on the file) */ - uint64_t alerts; /* flag to avoid multiple threads printing the same stats */ uint8_t flags; + /* flags to set when sending over a socket */ + uint8_t send_flags; + /* Flag if file is a regular file or not. Only regular files * allow for rotataion. */ uint8_t is_regular; + /* JSON flags */ + size_t json_flags; /* passed to json_dump_callback() */ + /* Flag set when file rotation notification is received. */ int rotation_flag; + + /* Set to true if the filename should not be timestamped. */ + bool nostamp; + + /* Socket types may need to drop events to keep from blocking + * Suricata. */ + uint64_t dropped; } LogFileCtx; +/* Min time (msecs) before trying to reconnect a Unix domain socket */ +#define LOGFILE_RECONN_MIN_TIME 500 + /* flags for LogFileCtx */ -#define LOGFILE_HEADER_WRITTEN 0x01 -#define LOGFILE_ALERTS_PRINTED 0x02 +#define LOGFILE_HEADER_WRITTEN 0x01 +#define LOGFILE_ALERTS_PRINTED 0x02 +#define LOGFILE_ROTATE_INTERVAL 0x04 LogFileCtx *LogFileNewCtx(void); int LogFileFreeCtx(LogFileCtx *); +int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer); -int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *); +int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *, const char *, int); +int SCConfLogOpenRedis(ConfNode *conf, LogFileCtx *log_ctx); int SCConfLogReopen(LogFileCtx *); #endif /* __UTIL_LOGOPENFILE_H__ */ diff --git a/src/util-lua-common.c b/src/util-lua-common.c index d89007738e36..8cf564274d70 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -113,7 +113,9 @@ static int LuaCallbackStreamingBufferPushToStack(lua_State *luastate, const LuaS { //PrintRawDataFp(stdout, (uint8_t *)b->data, b->data_len); lua_pushlstring (luastate, (const char *)b->data, b->data_len); - return 1; + lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_OPEN)); + lua_pushboolean (luastate, (b->flags & OUTPUT_STREAMING_FLAG_CLOSE)); + return 3; } /** \internal @@ -156,6 +158,21 @@ static int LuaCallbackPacketPayload(lua_State *luastate) return LuaCallbackPacketPayloadPushToStackFromPacket(luastate, p); } +/** \internal + * \brief fill lua stack with packet timestamp + * \param luastate the lua state + * \param p packet + * \retval cnt number of data items placed on the stack + * + * Places: seconds (number), microseconds (number) + */ +static int LuaCallbackTimestampPushToStack(lua_State *luastate, const struct timeval *ts) +{ + lua_pushnumber(luastate, (double)ts->tv_sec); + lua_pushnumber(luastate, (double)ts->tv_usec); + return 2; +} + /** \internal * \brief fill lua stack with header info * \param luastate the lua state @@ -172,6 +189,19 @@ static int LuaCallbackTimeStringPushToStackFromPacket(lua_State *luastate, const return 1; } +/** \internal + * \brief Wrapper for getting packet timestamp (as numbers) into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackPacketTimestamp(lua_State *luastate) +{ + const Packet *p = LuaStateGetPacket(luastate); + if (p == NULL) + return LuaCallbackError(luastate, "internal error: no packet"); + + return LuaCallbackTimestampPushToStack(luastate, &p->ts); +} + /** \internal * \brief Wrapper for getting tuple info into a lua script * \retval cnt number of items placed on the stack @@ -185,6 +215,42 @@ static int LuaCallbackPacketTimeString(lua_State *luastate) return LuaCallbackTimeStringPushToStackFromPacket(luastate, p); } +/** \internal + * \brief fill lua stack with flow timestamps + * \param luastate the lua state + * \param startts timestamp of first packet in the flow + * \param lastts timestamp of last packet in the flow + * \retval cnt number of data items placed on the stack + * + * Places: seconds (number), seconds (number), microseconds (number), + * microseconds (number) + */ +static int LuaCallbackFlowTimestampsPushToStack(lua_State *luastate, + const struct timeval *startts, + const struct timeval *lastts) +{ + lua_pushnumber(luastate, (double)startts->tv_sec); + lua_pushnumber(luastate, (double)lastts->tv_sec); + lua_pushnumber(luastate, (double)startts->tv_usec); + lua_pushnumber(luastate, (double)lastts->tv_usec); + return 4; +} + +/** \internal + * \brief Wrapper for getting flow timestamp (as numbers) into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowTimestamps(lua_State *luastate) +{ + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) { + return LuaCallbackError(luastate, "internal error: no flow"); + } + + return LuaCallbackFlowTimestampsPushToStack(luastate, &flow->startts, + &flow->lastts); +} + /** \internal * \brief fill lua stack with time string * \param luastate the lua state @@ -208,18 +274,43 @@ static int LuaCallbackTimeStringPushToStackFromFlow(lua_State *luastate, const F static int LuaCallbackFlowTimeString(lua_State *luastate) { int r = 0; - int locked = 0; - Flow *flow = LuaStateGetFlow(luastate, &locked); + Flow *flow = LuaStateGetFlow(luastate); if (flow == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (locked == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(flow); - r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); - FLOWLOCK_UNLOCK(flow); - } else { - r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); - } + r = LuaCallbackTimeStringPushToStackFromFlow(luastate, flow); + + return r; +} + +/** \internal + * \brief fill lua stack with flow has alerts + * \param luastate the lua state + * \param flow flow + * \retval cnt number of data items placed on the stack + * + * Places alerts (bool) + */ +static int LuaCallbackHasAlertsPushToStackFromFlow(lua_State *luastate, const Flow *flow) +{ + lua_pushboolean(luastate, FlowHasAlerts(flow)); + + return 1; +} + +/** \internal + * \brief Wrapper for getting flow has alerts info into a lua script + * \retval cnt number of items placed on the stack + */ +static int LuaCallbackFlowHasAlerts(lua_State *luastate) +{ + int r = 0; + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = LuaCallbackHasAlertsPushToStackFromFlow(luastate, flow); + return r; } @@ -343,18 +434,12 @@ static int LuaCallbackTuplePushToStackFromFlow(lua_State *luastate, const Flow * static int LuaCallbackTupleFlow(lua_State *luastate) { int r = 0; - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = LuaCallbackTuplePushToStackFromFlow(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = LuaCallbackTuplePushToStackFromFlow(luastate, f); - } + r = LuaCallbackTuplePushToStackFromFlow(luastate, f); + return r; } @@ -382,18 +467,12 @@ static int LuaCallbackAppLayerProtoPushToStackFromFlow(lua_State *luastate, cons static int LuaCallbackAppLayerProtoFlow(lua_State *luastate) { int r = 0; - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f); - } + r = LuaCallbackAppLayerProtoPushToStackFromFlow(luastate, f); + return r; } @@ -421,18 +500,12 @@ static int LuaCallbackStatsPushToStackFromFlow(lua_State *luastate, const Flow * static int LuaCallbackStatsFlow(lua_State *luastate) { int r = 0; - int lock_hint = 0; - Flow *f = LuaStateGetFlow(luastate, &lock_hint); + Flow *f = LuaStateGetFlow(luastate); if (f == NULL) return LuaCallbackError(luastate, "internal error: no flow"); - if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(f); - r = LuaCallbackStatsPushToStackFromFlow(luastate, f); - FLOWLOCK_UNLOCK(f); - } else { - r = LuaCallbackStatsPushToStackFromFlow(luastate, f); - } + r = LuaCallbackStatsPushToStackFromFlow(luastate, f); + return r; } @@ -543,7 +616,12 @@ static int LuaCallbackLogInfo(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogInfo("%s", msg); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogInfoRaw(ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -552,7 +630,12 @@ static int LuaCallbackLogNotice(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogNotice("%s", msg); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogNoticeRaw(ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -561,7 +644,12 @@ static int LuaCallbackLogWarning(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogWarning(SC_WARN_LUA_SCRIPT, "%s", msg); + + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogWarningRaw(SC_WARN_LUA_SCRIPT, ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -570,7 +658,11 @@ static int LuaCallbackLogError(lua_State *luastate) const char *msg = LuaGetStringArgument(luastate, 1); if (msg == NULL) return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); - SCLogError(SC_ERR_LUA_SCRIPT, "%s", msg); + lua_Debug ar; + lua_getstack(luastate, 1, &ar); + lua_getinfo(luastate, "nSl", &ar); + const char *funcname = ar.name ? ar.name : ar.what; + SCLogErrorRaw(SC_ERR_LUA_SCRIPT, ar.short_src, funcname, ar.currentline, "%s", msg); return 0; } @@ -596,16 +688,46 @@ static int LuaCallbackFileInfoPushToStackFromFile(lua_State *luastate, const Fil strlcat(md5, one, sizeof(md5)); } } + char sha1[41] = ""; + char *sha1ptr = sha1; + if (file->flags & FILE_SHA1) { + size_t x; + for (x = 0; x < sizeof(file->sha1); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->sha1[x]); + strlcat(sha1, one, sizeof(sha1)); + } + } + char sha256[65] = ""; + char *sha256ptr = sha256; + if (file->flags & FILE_SHA256) { + size_t x; + for (x = 0; x < sizeof(file->sha256); x++) { + char one[3] = ""; + snprintf(one, sizeof(one), "%02x", file->sha256[x]); + strlcat(sha256, one, sizeof(sha256)); + } + } #else char *md5ptr = NULL; + char *sha1ptr = NULL; + char *sha256ptr = NULL; #endif lua_pushnumber(luastate, file->file_id); lua_pushnumber(luastate, file->txid); lua_pushlstring(luastate, (char *)file->name, file->name_len); - lua_pushnumber(luastate, file->size); - lua_pushstring (luastate, file->magic); + lua_pushnumber(luastate, FileTrackedSize(file)); + lua_pushstring (luastate, +#ifdef HAVE_MAGIC + file->magic +#else + "nomagic" +#endif + ); lua_pushstring(luastate, md5ptr); + lua_pushstring(luastate, sha1ptr); + lua_pushstring(luastate, sha256ptr); return 6; } @@ -698,11 +820,15 @@ int LuaRegisterFunctions(lua_State *luastate) /* registration of the callbacks */ lua_pushcfunction(luastate, LuaCallbackPacketPayload); lua_setglobal(luastate, "SCPacketPayload"); + lua_pushcfunction(luastate, LuaCallbackPacketTimestamp); + lua_setglobal(luastate, "SCPacketTimestamp"); lua_pushcfunction(luastate, LuaCallbackPacketTimeString); lua_setglobal(luastate, "SCPacketTimeString"); lua_pushcfunction(luastate, LuaCallbackTuple); lua_setglobal(luastate, "SCPacketTuple"); + lua_pushcfunction(luastate, LuaCallbackFlowTimestamps); + lua_setglobal(luastate, "SCFlowTimestamps"); lua_pushcfunction(luastate, LuaCallbackFlowTimeString); lua_setglobal(luastate, "SCFlowTimeString"); lua_pushcfunction(luastate, LuaCallbackTupleFlow); @@ -711,6 +837,8 @@ int LuaRegisterFunctions(lua_State *luastate) lua_setglobal(luastate, "SCFlowAppLayerProto"); lua_pushcfunction(luastate, LuaCallbackStatsFlow); lua_setglobal(luastate, "SCFlowStats"); + lua_pushcfunction(luastate, LuaCallbackFlowHasAlerts); + lua_setglobal(luastate, "SCFlowHasAlerts"); lua_pushcfunction(luastate, LuaCallbackStreamingBuffer); lua_setglobal(luastate, "SCStreamingBuffer"); @@ -747,4 +875,17 @@ int LuaRegisterFunctions(lua_State *luastate) return 0; } +int LuaStateNeedProto(lua_State *luastate, AppProto alproto) +{ + AppProto flow_alproto = 0; + Flow *flow = LuaStateGetFlow(luastate); + if (flow == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + flow_alproto = flow->alproto; + + return (alproto == flow_alproto); + +} + #endif /* HAVE_LUA */ diff --git a/src/util-lua-common.h b/src/util-lua-common.h index fe048fe68e0d..2e0df28751a1 100644 --- a/src/util-lua-common.h +++ b/src/util-lua-common.h @@ -35,6 +35,8 @@ void LuaPushTableKeyValueArray(lua_State *luastate, const char *key, const uint8 int LuaRegisterFunctions(lua_State *luastate); +int LuaStateNeedProto(lua_State *luastate, AppProto alproto); + #endif /* HAVE_LUA */ #endif /* __UTIL_LUA_COMMON_H__ */ diff --git a/src/util-lua-dnp3-objects.c b/src/util-lua-dnp3-objects.c new file mode 100644 index 000000000000..6c3dcc51ab33 --- /dev/null +++ b/src/util-lua-dnp3-objects.c @@ -0,0 +1,3542 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * DO NOT EDIT. THIS FILE IS AUTO-GENERATED. + * + * Generated by command: + * ./scripts/dnp3-gen/dnp3-gen.py + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" + +/** + * \brief Push an object point item onto the stack. + */ +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, + DNP3Point *point) +{ + switch (DNP3_OBJECT_CODE(object->group, object->variation)) { + case DNP3_OBJECT_CODE(1, 1): { + DNP3ObjectG1V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(1, 2): { + DNP3ObjectG1V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 1): { + DNP3ObjectG2V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 2): { + DNP3ObjectG2V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(2, 3): { + DNP3ObjectG2V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(3, 1): { + DNP3ObjectG3V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(3, 2): { + DNP3ObjectG3V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 1): { + DNP3ObjectG4V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 2): { + DNP3ObjectG4V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(4, 3): { + DNP3ObjectG4V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "chatter_filter"); + lua_pushinteger(luastate, data->chatter_filter); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "relative_time_ms"); + lua_pushinteger(luastate, data->relative_time_ms); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(10, 1): { + DNP3ObjectG10V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(10, 2): { + DNP3ObjectG10V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(11, 1): { + DNP3ObjectG11V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(11, 2): { + DNP3ObjectG11V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 1): { + DNP3ObjectG12V1 *data = point->data; + lua_pushliteral(luastate, "op_type"); + lua_pushinteger(luastate, data->op_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "qu"); + lua_pushinteger(luastate, data->qu); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "cr"); + lua_pushinteger(luastate, data->cr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "tcc"); + lua_pushinteger(luastate, data->tcc); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ontime"); + lua_pushinteger(luastate, data->ontime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "offtime"); + lua_pushinteger(luastate, data->offtime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 2): { + DNP3ObjectG12V2 *data = point->data; + lua_pushliteral(luastate, "op_type"); + lua_pushinteger(luastate, data->op_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "qu"); + lua_pushinteger(luastate, data->qu); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "cr"); + lua_pushinteger(luastate, data->cr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "tcc"); + lua_pushinteger(luastate, data->tcc); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ontime"); + lua_pushinteger(luastate, data->ontime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "offtime"); + lua_pushinteger(luastate, data->offtime); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved"); + lua_pushinteger(luastate, data->reserved); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(12, 3): { + DNP3ObjectG12V3 *data = point->data; + lua_pushliteral(luastate, "point"); + lua_pushinteger(luastate, data->point); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(13, 1): { + DNP3ObjectG13V1 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_state"); + lua_pushinteger(luastate, data->commanded_state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(13, 2): { + DNP3ObjectG13V2 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_state"); + lua_pushinteger(luastate, data->commanded_state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 1): { + DNP3ObjectG20V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 2): { + DNP3ObjectG20V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 3): { + DNP3ObjectG20V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 4): { + DNP3ObjectG20V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 5): { + DNP3ObjectG20V5 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 6): { + DNP3ObjectG20V6 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 7): { + DNP3ObjectG20V7 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(20, 8): { + DNP3ObjectG20V8 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 1): { + DNP3ObjectG21V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 2): { + DNP3ObjectG21V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 3): { + DNP3ObjectG21V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 4): { + DNP3ObjectG21V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 5): { + DNP3ObjectG21V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 6): { + DNP3ObjectG21V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 7): { + DNP3ObjectG21V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 8): { + DNP3ObjectG21V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 9): { + DNP3ObjectG21V9 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 10): { + DNP3ObjectG21V10 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 11): { + DNP3ObjectG21V11 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(21, 12): { + DNP3ObjectG21V12 *data = point->data; + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 1): { + DNP3ObjectG22V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 2): { + DNP3ObjectG22V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 3): { + DNP3ObjectG22V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 4): { + DNP3ObjectG22V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 5): { + DNP3ObjectG22V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 6): { + DNP3ObjectG22V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 7): { + DNP3ObjectG22V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(22, 8): { + DNP3ObjectG22V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 1): { + DNP3ObjectG23V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 2): { + DNP3ObjectG23V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 3): { + DNP3ObjectG23V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 4): { + DNP3ObjectG23V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 5): { + DNP3ObjectG23V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 6): { + DNP3ObjectG23V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 7): { + DNP3ObjectG23V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(23, 8): { + DNP3ObjectG23V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "rollover"); + lua_pushinteger(luastate, data->rollover); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count"); + lua_pushinteger(luastate, data->count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 1): { + DNP3ObjectG30V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 2): { + DNP3ObjectG30V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 3): { + DNP3ObjectG30V3 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 4): { + DNP3ObjectG30V4 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 5): { + DNP3ObjectG30V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(30, 6): { + DNP3ObjectG30V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 1): { + DNP3ObjectG31V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 2): { + DNP3ObjectG31V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 3): { + DNP3ObjectG31V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 4): { + DNP3ObjectG31V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 5): { + DNP3ObjectG31V5 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 6): { + DNP3ObjectG31V6 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 7): { + DNP3ObjectG31V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(31, 8): { + DNP3ObjectG31V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 1): { + DNP3ObjectG32V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 2): { + DNP3ObjectG32V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 3): { + DNP3ObjectG32V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 4): { + DNP3ObjectG32V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 5): { + DNP3ObjectG32V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 6): { + DNP3ObjectG32V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 7): { + DNP3ObjectG32V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(32, 8): { + DNP3ObjectG32V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 1): { + DNP3ObjectG33V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 2): { + DNP3ObjectG33V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 3): { + DNP3ObjectG33V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 4): { + DNP3ObjectG33V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 5): { + DNP3ObjectG33V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 6): { + DNP3ObjectG33V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 7): { + DNP3ObjectG33V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(33, 8): { + DNP3ObjectG33V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 1): { + DNP3ObjectG34V1 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushinteger(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 2): { + DNP3ObjectG34V2 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushinteger(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(34, 3): { + DNP3ObjectG34V3 *data = point->data; + lua_pushliteral(luastate, "deadband_value"); + lua_pushnumber(luastate, data->deadband_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 1): { + DNP3ObjectG40V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 2): { + DNP3ObjectG40V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 3): { + DNP3ObjectG40V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(40, 4): { + DNP3ObjectG40V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 1): { + DNP3ObjectG41V1 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 2): { + DNP3ObjectG41V2 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 3): { + DNP3ObjectG41V3 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(41, 4): { + DNP3ObjectG41V4 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "control_status"); + lua_pushinteger(luastate, data->control_status); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 1): { + DNP3ObjectG42V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 2): { + DNP3ObjectG42V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 3): { + DNP3ObjectG42V3 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 4): { + DNP3ObjectG42V4 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 5): { + DNP3ObjectG42V5 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 6): { + DNP3ObjectG42V6 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 7): { + DNP3ObjectG42V7 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(42, 8): { + DNP3ObjectG42V8 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "over_range"); + lua_pushinteger(luastate, data->over_range); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reference_err"); + lua_pushinteger(luastate, data->reference_err); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "value"); + lua_pushnumber(luastate, data->value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 1): { + DNP3ObjectG43V1 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 2): { + DNP3ObjectG43V2 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 3): { + DNP3ObjectG43V3 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 4): { + DNP3ObjectG43V4 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushinteger(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 5): { + DNP3ObjectG43V5 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 6): { + DNP3ObjectG43V6 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 7): { + DNP3ObjectG43V7 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(43, 8): { + DNP3ObjectG43V8 *data = point->data; + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "commanded_value"); + lua_pushnumber(luastate, data->commanded_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 1): { + DNP3ObjectG50V1 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 2): { + DNP3ObjectG50V2 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval"); + lua_pushinteger(luastate, data->interval); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 3): { + DNP3ObjectG50V3 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(50, 4): { + DNP3ObjectG50V4 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval_count"); + lua_pushinteger(luastate, data->interval_count); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "interval_units"); + lua_pushinteger(luastate, data->interval_units); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(51, 1): { + DNP3ObjectG51V1 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(51, 2): { + DNP3ObjectG51V2 *data = point->data; + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(52, 1): { + DNP3ObjectG52V1 *data = point->data; + lua_pushliteral(luastate, "delay_secs"); + lua_pushinteger(luastate, data->delay_secs); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(52, 2): { + DNP3ObjectG52V2 *data = point->data; + lua_pushliteral(luastate, "delay_ms"); + lua_pushinteger(luastate, data->delay_ms); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 1): { + DNP3ObjectG70V1 *data = point->data; + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filetype_code"); + lua_pushinteger(luastate, data->filetype_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "attribute_code"); + lua_pushinteger(luastate, data->attribute_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "start_record"); + lua_pushinteger(luastate, data->start_record); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "end_record"); + lua_pushinteger(luastate, data->end_record); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created_timestamp"); + lua_pushinteger(luastate, data->created_timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permission"); + lua_pushinteger(luastate, data->permission); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_id"); + lua_pushinteger(luastate, data->file_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "owner_id"); + lua_pushinteger(luastate, data->owner_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "group_id"); + lua_pushinteger(luastate, data->group_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_function_code"); + lua_pushinteger(luastate, data->file_function_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, + strlen(data->filename)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data_size"); + lua_pushinteger(luastate, data->data_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data"); + LuaPushStringBuffer(luastate, (uint8_t *)data->data, + strlen(data->data)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 2): { + DNP3ObjectG70V2 *data = point->data; + lua_pushliteral(luastate, "username_offset"); + lua_pushinteger(luastate, data->username_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_size"); + lua_pushinteger(luastate, data->username_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password_offset"); + lua_pushinteger(luastate, data->password_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password_size"); + lua_pushinteger(luastate, data->password_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "authentication_key"); + lua_pushinteger(luastate, data->authentication_key); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, + strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "password"); + LuaPushStringBuffer(luastate, (uint8_t *)data->password, + strlen(data->password)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 3): { + DNP3ObjectG70V3 *data = point->data; + lua_pushliteral(luastate, "filename_offset"); + lua_pushinteger(luastate, data->filename_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created"); + lua_pushinteger(luastate, data->created); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permissions"); + lua_pushinteger(luastate, data->permissions); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "authentication_key"); + lua_pushinteger(luastate, data->authentication_key); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "operational_mode"); + lua_pushinteger(luastate, data->operational_mode); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "maximum_block_size"); + lua_pushinteger(luastate, data->maximum_block_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, + strlen(data->filename)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 4): { + DNP3ObjectG70V4 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "maximum_block_size"); + lua_pushinteger(luastate, data->maximum_block_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "optional_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->optional_text, + strlen(data->optional_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 5): { + DNP3ObjectG70V5 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "block_number"); + lua_pushinteger(luastate, data->block_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_data"); + LuaPushStringBuffer(luastate, (uint8_t *)data->file_data, + strlen(data->file_data)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 6): { + DNP3ObjectG70V6 *data = point->data; + lua_pushliteral(luastate, "file_handle"); + lua_pushinteger(luastate, data->file_handle); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "block_number"); + lua_pushinteger(luastate, data->block_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "status_code"); + lua_pushinteger(luastate, data->status_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "optional_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->optional_text, + strlen(data->optional_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 7): { + DNP3ObjectG70V7 *data = point->data; + lua_pushliteral(luastate, "filename_offset"); + lua_pushinteger(luastate, data->filename_offset); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename_size"); + lua_pushinteger(luastate, data->filename_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_type"); + lua_pushinteger(luastate, data->file_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "file_size"); + lua_pushinteger(luastate, data->file_size); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "created_timestamp"); + lua_pushinteger(luastate, data->created_timestamp); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "permissions"); + lua_pushinteger(luastate, data->permissions); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "request_id"); + lua_pushinteger(luastate, data->request_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "filename"); + LuaPushStringBuffer(luastate, (uint8_t *)data->filename, + strlen(data->filename)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(70, 8): { + DNP3ObjectG70V8 *data = point->data; + lua_pushliteral(luastate, "file_specification"); + LuaPushStringBuffer(luastate, (uint8_t *)data->file_specification, + strlen(data->file_specification)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(80, 1): { + DNP3ObjectG80V1 *data = point->data; + lua_pushliteral(luastate, "state"); + lua_pushinteger(luastate, data->state); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(81, 1): { + DNP3ObjectG81V1 *data = point->data; + lua_pushliteral(luastate, "fill_percentage"); + lua_pushinteger(luastate, data->fill_percentage); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "overflow_state"); + lua_pushinteger(luastate, data->overflow_state); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "group"); + lua_pushinteger(luastate, data->group); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "variation"); + lua_pushinteger(luastate, data->variation); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(83, 1): { + DNP3ObjectG83V1 *data = point->data; + lua_pushliteral(luastate, "vendor_code"); + LuaPushStringBuffer(luastate, (uint8_t *)data->vendor_code, + strlen(data->vendor_code)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "object_id"); + lua_pushinteger(luastate, data->object_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "length"); + lua_pushinteger(luastate, data->length); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "data_objects"); + lua_pushlstring(luastate, (const char *)data->data_objects, + data->length); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(86, 2): { + DNP3ObjectG86V2 *data = point->data; + lua_pushliteral(luastate, "rd"); + lua_pushinteger(luastate, data->rd); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "wr"); + lua_pushinteger(luastate, data->wr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "st"); + lua_pushinteger(luastate, data->st); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "ev"); + lua_pushinteger(luastate, data->ev); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "df"); + lua_pushinteger(luastate, data->df); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding0"); + lua_pushinteger(luastate, data->padding0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding1"); + lua_pushinteger(luastate, data->padding1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "padding2"); + lua_pushinteger(luastate, data->padding2); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(102, 1): { + DNP3ObjectG102V1 *data = point->data; + lua_pushliteral(luastate, "value"); + lua_pushinteger(luastate, data->value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 1): { + DNP3ObjectG120V1 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mal"); + lua_pushinteger(luastate, data->mal); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reason"); + lua_pushinteger(luastate, data->reason); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, + data->challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 2): { + DNP3ObjectG120V2 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, + data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 3): { + DNP3ObjectG120V3 *data = point->data; + lua_pushliteral(luastate, "csq"); + lua_pushinteger(luastate, data->csq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 4): { + DNP3ObjectG120V4 *data = point->data; + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 5): { + DNP3ObjectG120V5 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "key_wrap_alg"); + lua_pushinteger(luastate, data->key_wrap_alg); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "key_status"); + lua_pushinteger(luastate, data->key_status); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mal"); + lua_pushinteger(luastate, data->mal); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data_len"); + lua_pushinteger(luastate, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, + data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, + data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 6): { + DNP3ObjectG120V6 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "wrapped_key_data"); + lua_pushlstring(luastate, (const char *)data->wrapped_key_data, + data->wrapped_key_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 7): { + DNP3ObjectG120V7 *data = point->data; + lua_pushliteral(luastate, "sequence_number"); + lua_pushinteger(luastate, data->sequence_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "usr"); + lua_pushinteger(luastate, data->usr); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "error_code"); + lua_pushinteger(luastate, data->error_code); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "time_of_error"); + lua_pushinteger(luastate, data->time_of_error); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "error_text"); + LuaPushStringBuffer(luastate, (uint8_t *)data->error_text, + strlen(data->error_text)); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 8): { + DNP3ObjectG120V8 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certificate_type"); + lua_pushinteger(luastate, data->certificate_type); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certificate"); + lua_pushlstring(luastate, (const char *)data->certificate, + data->certificate_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 9): { + DNP3ObjectG120V9 *data = point->data; + lua_pushliteral(luastate, "mac_value"); + lua_pushlstring(luastate, (const char *)data->mac_value, + data->mac_value_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 10): { + DNP3ObjectG120V10 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "operation"); + lua_pushinteger(luastate, data->operation); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "scs"); + lua_pushinteger(luastate, data->scs); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_role"); + lua_pushinteger(luastate, data->user_role); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_role_expiry_interval"); + lua_pushinteger(luastate, data->user_role_expiry_interval); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_len"); + lua_pushinteger(luastate, data->username_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_public_key_len"); + lua_pushinteger(luastate, data->user_public_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certification_data_len"); + lua_pushinteger(luastate, data->certification_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, + strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_public_key"); + lua_pushlstring(luastate, (const char *)data->user_public_key, + data->user_public_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "certification_data"); + lua_pushlstring(luastate, (const char *)data->certification_data, + data->certification_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 11): { + DNP3ObjectG120V11 *data = point->data; + lua_pushliteral(luastate, "key_change_method"); + lua_pushinteger(luastate, data->key_change_method); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username_len"); + lua_pushinteger(luastate, data->username_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "master_challenge_data_len"); + lua_pushinteger(luastate, data->master_challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "username"); + LuaPushStringBuffer(luastate, (uint8_t *)data->username, + strlen(data->username)); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "master_challenge_data"); + lua_pushlstring(luastate, (const char *)data->master_challenge_data, + data->master_challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 12): { + DNP3ObjectG120V12 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data_len"); + lua_pushinteger(luastate, data->challenge_data_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "challenge_data"); + lua_pushlstring(luastate, (const char *)data->challenge_data, + data->challenge_data_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 13): { + DNP3ObjectG120V13 *data = point->data; + lua_pushliteral(luastate, "ksq"); + lua_pushinteger(luastate, data->ksq); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "user_number"); + lua_pushinteger(luastate, data->user_number); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "encrypted_update_key_len"); + lua_pushinteger(luastate, data->encrypted_update_key_len); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "encrypted_update_key_data"); + lua_pushlstring(luastate, (const char *)data->encrypted_update_key_data, + data->encrypted_update_key_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 14): { + DNP3ObjectG120V14 *data = point->data; + lua_pushliteral(luastate, "digital_signature"); + lua_pushlstring(luastate, (const char *)data->digital_signature, + data->digital_signature_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(120, 15): { + DNP3ObjectG120V15 *data = point->data; + lua_pushliteral(luastate, "mac"); + lua_pushlstring(luastate, (const char *)data->mac, + data->mac_len); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(121, 1): { + DNP3ObjectG121V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(122, 1): { + DNP3ObjectG122V1 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + break; + } + case DNP3_OBJECT_CODE(122, 2): { + DNP3ObjectG122V2 *data = point->data; + lua_pushliteral(luastate, "online"); + lua_pushinteger(luastate, data->online); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "restart"); + lua_pushinteger(luastate, data->restart); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "comm_lost"); + lua_pushinteger(luastate, data->comm_lost); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "remote_forced"); + lua_pushinteger(luastate, data->remote_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "local_forced"); + lua_pushinteger(luastate, data->local_forced); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved0"); + lua_pushinteger(luastate, data->reserved0); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "discontinuity"); + lua_pushinteger(luastate, data->discontinuity); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "reserved1"); + lua_pushinteger(luastate, data->reserved1); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "association_id"); + lua_pushinteger(luastate, data->association_id); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "count_value"); + lua_pushinteger(luastate, data->count_value); + lua_settable(luastate, -3); + lua_pushliteral(luastate, "timestamp"); + lua_pushinteger(luastate, data->timestamp); + lua_settable(luastate, -3); + break; + } + default: + break; + } +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dnp3-objects.h b/src/util-lua-dnp3-objects.h new file mode 100644 index 000000000000..6575695a2650 --- /dev/null +++ b/src/util-lua-dnp3-objects.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_LUA_DNP3_OBJECTS_H__ +#define __UTIL_LUA_DNP3_OBJECTS_H__ + +void DNP3PushPoint(lua_State *luastate, DNP3Object *object, + DNP3Point *item); + +#endif /* ! __UTIL_LUA_DNP3_OBJECTS_H__ */ diff --git a/src/util-lua-dnp3.c b/src/util-lua-dnp3.c new file mode 100644 index 000000000000..96b7a5ea6b0f --- /dev/null +++ b/src/util-lua-dnp3.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" + +#include "app-layer-dnp3.h" +#include "app-layer-dnp3-objects.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" +#include "util-lua-dnp3-objects.h" + +/** + * \brief Helper macro to push key and integer value onto a table. + */ +#define LUA_PUSHT_INT(l, k, v) do { \ + lua_pushliteral(luastate, k); \ + lua_pushinteger(luastate, v); \ + lua_settable(luastate, -3); \ + } while (0); + +static void DNP3PushPoints(lua_State *luastate, DNP3Object *object) +{ + DNP3Point *point; + int i = 1; + + TAILQ_FOREACH(point, object->points, next) { + lua_pushinteger(luastate, i++); + lua_newtable(luastate); + + lua_pushliteral(luastate, "index"); + lua_pushinteger(luastate, point->index); + lua_settable(luastate, -3); + + DNP3PushPoint(luastate, object, point); + + lua_settable(luastate, -3); + } +} + +static void DNP3PushObjects(lua_State *luastate, DNP3ObjectList *objects) +{ + DNP3Object *object = NULL; + int i = 1; + + TAILQ_FOREACH(object, objects, next) { + lua_pushinteger(luastate, i++); + lua_newtable(luastate); + + lua_pushliteral(luastate, "group"); + lua_pushinteger(luastate, object->group); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "variation"); + lua_pushinteger(luastate, object->variation); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "points"); + lua_newtable(luastate); + DNP3PushPoints(luastate, object); + lua_settable(luastate, -3); + + lua_settable(luastate, -3); + } +} + +static void DNP3PushLinkHeader(lua_State *luastate, DNP3LinkHeader *header) +{ + LUA_PUSHT_INT(luastate, "len", header->len); + LUA_PUSHT_INT(luastate, "control", header->control); + LUA_PUSHT_INT(luastate, "dst", header->dst); + LUA_PUSHT_INT(luastate, "src", header->src); + LUA_PUSHT_INT(luastate, "crc", header->crc); +} + +static void DNP3PushApplicationHeader(lua_State *luastate, + DNP3ApplicationHeader *header) +{ + LUA_PUSHT_INT(luastate, "control", header->control); + LUA_PUSHT_INT(luastate, "function_code", header->function_code); +} + +static void DNP3PushRequest(lua_State *luastate, DNP3Transaction *tx) +{ + /* Link header. */ + lua_pushliteral(luastate, "link_header"); + lua_newtable(luastate); + DNP3PushLinkHeader(luastate, &tx->request_lh); + lua_settable(luastate, -3); + + /* Transport header. */ + LUA_PUSHT_INT(luastate, "transport_header", tx->request_th); + + /* Application header. */ + lua_pushliteral(luastate, "application_header"); + lua_newtable(luastate); + DNP3PushApplicationHeader(luastate, &tx->request_ah); + lua_settable(luastate, -3); + + lua_pushliteral(luastate, "objects"); + lua_newtable(luastate); + DNP3PushObjects(luastate, &tx->request_objects); + lua_settable(luastate, -3); +} + +static void DNP3PushResponse(lua_State *luastate, DNP3Transaction *tx) +{ + /* Link header. */ + lua_pushliteral(luastate, "link_header"); + lua_newtable(luastate); + DNP3PushLinkHeader(luastate, &tx->response_lh); + lua_settable(luastate, -3); + + /* Transport header. */ + LUA_PUSHT_INT(luastate, "transport_header", tx->response_th); + + /* Application header. */ + lua_pushliteral(luastate, "application_header"); + lua_newtable(luastate); + DNP3PushApplicationHeader(luastate, &tx->response_ah); + lua_settable(luastate, -3); + + /* Internal indicators. */ + LUA_PUSHT_INT(luastate, "indicators", + tx->response_iin.iin1 << 8 | tx->response_iin.iin2); + + lua_pushliteral(luastate, "objects"); + lua_newtable(luastate); + DNP3PushObjects(luastate, &tx->response_objects); + lua_settable(luastate, -3); +} + +static int DNP3GetTx(lua_State *luastate) +{ + if (!LuaStateNeedProto(luastate, ALPROTO_DNP3)) { + return LuaCallbackError(luastate, "error: protocol not dnp3"); + } + + DNP3Transaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) { + return LuaCallbackError(luastate, "error: no tx"); + } + + lua_newtable(luastate); + + lua_pushliteral(luastate, "tx_num"); + lua_pushinteger(luastate, tx->tx_num); + lua_settable(luastate, -3); + + LUA_PUSHT_INT(luastate, "has_request", tx->has_request); + if (tx->has_request) { + lua_pushliteral(luastate, "request"); + lua_newtable(luastate); + LUA_PUSHT_INT(luastate, "done", tx->request_done); + LUA_PUSHT_INT(luastate, "complete", tx->request_complete); + DNP3PushRequest(luastate, tx); + lua_settable(luastate, -3); + } + + LUA_PUSHT_INT(luastate, "has_response", tx->has_response); + if (tx->has_response) { + lua_pushliteral(luastate, "response"); + lua_newtable(luastate); + LUA_PUSHT_INT(luastate, "done", tx->response_done); + LUA_PUSHT_INT(luastate, "complete", tx->response_complete); + DNP3PushResponse(luastate, tx); + lua_settable(luastate, -3); + } + + return 1; +} + +int LuaRegisterDNP3Functions(lua_State *luastate) +{ + lua_pushcfunction(luastate, DNP3GetTx); + lua_setglobal(luastate, "DNP3GetTx"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dnp3.h b/src/util-lua-dnp3.h new file mode 100644 index 000000000000..3430e41b2205 --- /dev/null +++ b/src/util-lua-dnp3.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_LUA_DNP3_H__ +#define __UTIL_LUA_DNP3_H__ + +#ifdef HAVE_LUA + +int LuaRegisterDNP3Functions(lua_State *); + +#endif /* HAVE_LUA */ + +#endif /* !__UTIL_LUA_DNP3_H__ */ diff --git a/src/util-lua-dns.c b/src/util-lua-dns.c new file mode 100644 index 000000000000..b43413f377e3 --- /dev/null +++ b/src/util-lua-dns.c @@ -0,0 +1,325 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +/** + * \file + * + * \author Eric Leblond + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer-dns-common.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" + +static int DnsGetDnsRrname(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + char *c; + size_t input_len; + c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)), query->len); + if (c != NULL) { + int ret; + input_len = strlen(c); + /* sanity check */ + if (input_len > (size_t)(2 * query->len)) { + SCFree(c); + return LuaCallbackError(luastate, "invalid length"); + } + ret = LuaPushStringBuffer(luastate, (uint8_t *)c, input_len); + SCFree(c); + return ret; + } + } + + return LuaCallbackError(luastate, "no query"); +} + +static int DnsGetTxid(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + lua_pushinteger(luastate, tx->tx_id); + return 1; +} + +static int DnsGetRcode(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + if (tx->rcode) { + char rcode[16] = ""; + DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode)); + return LuaPushStringBuffer(luastate, (const uint8_t *)rcode, strlen(rcode)); + } else { + return 0; + } +} + +static int DnsGetRecursionDesired(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + lua_pushboolean(luastate, tx->recursion_desired); + return 1; +} + +static int DnsGetQueryTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + uint32_t u = 0; + lua_newtable(luastate); + DNSQueryEntry *query = NULL; + TAILQ_FOREACH(query, &tx->query_list, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + char record[16] = ""; + DNSCreateTypeString(query->type, record, sizeof(record)); + lua_pushstring(luastate, "type"); + lua_pushstring(luastate, record); + lua_settable(luastate, -3); + + { + char *c; + size_t input_len; + c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)), query->len); + if (c != NULL) { + input_len = strlen(c); + /* sanity check */ + if (input_len > (size_t)(2 * query->len)) { + SCFree(c); + return LuaCallbackError(luastate, "invalid length"); + } + lua_pushstring(luastate, "rrname"); + LuaPushStringBuffer(luastate, (uint8_t *)c, input_len); + lua_settable(luastate, -3); + SCFree(c); + } + } + + + lua_settable(luastate, -3); + } + + return 1; +} + +static int DnsGetAnswerTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + uint32_t u = 0; + lua_newtable(luastate); + DNSAnswerEntry *answer = NULL; + TAILQ_FOREACH(answer, &tx->answer_list, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + char record[16] = ""; + DNSCreateTypeString(answer->type, record, sizeof(record)); + lua_pushstring(luastate, "type"); + lua_pushstring(luastate, record); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "ttl"); + lua_pushinteger(luastate, answer->ttl); + lua_settable(luastate, -3); + + { + uint8_t *ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry)); + lua_pushstring(luastate, "rrname"); + LuaPushStringBuffer(luastate, ptr, answer->fqdn_len); + lua_settable(luastate, -3); + + ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry) + answer->fqdn_len); + if (answer->type == DNS_RECORD_TYPE_A) { + char a[16] = ""; + if (answer->data_len == 4) { + PrintInet(AF_INET, (const void *)ptr, a, sizeof(a)); + } + lua_pushstring(luastate, "addr"); + LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a)); + lua_settable(luastate, -3); + } else if (answer->type == DNS_RECORD_TYPE_AAAA) { + char a[46] = ""; + if (answer->data_len == 16) { + PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a)); + } + lua_pushstring(luastate, "addr"); + LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a)); + lua_settable(luastate, -3); + } else if (answer->data_len == 0) { + /* not setting 'addr' */ + } else { + lua_pushstring(luastate, "addr"); + LuaPushStringBuffer(luastate, (uint8_t *)ptr, answer->data_len); + lua_settable(luastate, -3); + } + } + + lua_settable(luastate, -3); + } + + return 1; +} + +static int DnsGetAuthorityTable(lua_State *luastate) +{ + if (!(LuaStateNeedProto(luastate, ALPROTO_DNS))) + return LuaCallbackError(luastate, "error: protocol not dns"); + + DNSTransaction *tx = LuaStateGetTX(luastate); + if (tx == NULL) + return LuaCallbackError(luastate, "internal error: no tx"); + + uint32_t u = 0; + lua_newtable(luastate); + DNSAnswerEntry *answer = NULL; + TAILQ_FOREACH(answer, &tx->authority_list, next) { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + char record[16] = ""; + DNSCreateTypeString(answer->type, record, sizeof(record)); + lua_pushstring(luastate, "type"); + lua_pushstring(luastate, record); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "ttl"); + lua_pushinteger(luastate, answer->ttl); + lua_settable(luastate, -3); + + { + char *c; + size_t input_len; + c = BytesToString((uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry)), answer->fqdn_len); + if (c != NULL) { + input_len = strlen(c); + /* sanity check */ + if (input_len > (size_t)(2 * answer->fqdn_len)) { + SCFree(c); + return LuaCallbackError(luastate, "invalid length"); + } + lua_pushstring(luastate, "rrname"); + LuaPushStringBuffer(luastate, (uint8_t *)c, input_len); + lua_settable(luastate, -3); + SCFree(c); + } + } + + + lua_settable(luastate, -3); + } + + return 1; +} + + +/** \brief register http lua extensions in a luastate */ +int LuaRegisterDnsFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, DnsGetDnsRrname); + lua_setglobal(luastate, "DnsGetDnsRrname"); + + lua_pushcfunction(luastate, DnsGetQueryTable); + lua_setglobal(luastate, "DnsGetQueries"); + + lua_pushcfunction(luastate, DnsGetAnswerTable); + lua_setglobal(luastate, "DnsGetAnswers"); + + lua_pushcfunction(luastate, DnsGetAuthorityTable); + lua_setglobal(luastate, "DnsGetAuthorities"); + + lua_pushcfunction(luastate, DnsGetTxid); + lua_setglobal(luastate, "DnsGetTxid"); + + lua_pushcfunction(luastate, DnsGetRcode); + lua_setglobal(luastate, "DnsGetRcode"); + + lua_pushcfunction(luastate, DnsGetRecursionDesired); + lua_setglobal(luastate, "DnsGetRecursionDesired"); + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-dns.h b/src/util-lua-dns.h new file mode 100644 index 000000000000..582fdea75715 --- /dev/null +++ b/src/util-lua-dns.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Eric Leblond + */ + +#ifndef __UTIL_LUA_DNS_H__ +#define __UTIL_LUA_DNS_H__ + +#ifdef HAVE_LUA + +int LuaRegisterDnsFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_HTTP_H__ */ diff --git a/src/util-lua-http.c b/src/util-lua-http.c index e5957afdd47e..1207f7f9ef3e 100644 --- a/src/util-lua-http.c +++ b/src/util-lua-http.c @@ -56,26 +56,6 @@ #include "util-lua.h" #include "util-lua-common.h" -int LuaStateNeedProto(lua_State *luastate, AppProto alproto) -{ - AppProto flow_alproto = 0; - int locked = 0; - Flow *flow = LuaStateGetFlow(luastate, &locked); - if (flow == NULL) - return LuaCallbackError(luastate, "internal error: no flow"); - - if (locked == LUA_FLOW_NOT_LOCKED_BY_PARENT) { - FLOWLOCK_RDLOCK(flow); - flow_alproto = flow->alproto; - FLOWLOCK_UNLOCK(flow); - } else { - flow_alproto = flow->alproto; - } - - return (alproto == flow_alproto); - -} - static int HttpGetRequestHost(lua_State *luastate) { if (!(LuaStateNeedProto(luastate, ALPROTO_HTTP))) @@ -305,7 +285,12 @@ static int HttpGetBody(lua_State *luastate, int dir) lua_newtable(luastate); while (chunk != NULL) { lua_pushinteger(luastate, index); - LuaPushStringBuffer(luastate, chunk->data, chunk->len); + + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(body->sb, &chunk->sbseg, &data, &data_len); + LuaPushStringBuffer(luastate, data, data_len); + lua_settable(luastate, -3); chunk = chunk->next; @@ -313,8 +298,8 @@ static int HttpGetBody(lua_State *luastate, int dir) } if (body->first && body->last) { - lua_pushinteger(luastate, body->first->stream_offset); - lua_pushinteger(luastate, body->last->stream_offset + body->last->len); + lua_pushinteger(luastate, body->first->sbseg.stream_offset); + lua_pushinteger(luastate, body->last->sbseg.stream_offset + body->last->sbseg.segment_len); return 3; } else { return 1; diff --git a/src/util-lua-smtp.c b/src/util-lua-smtp.c new file mode 100644 index 000000000000..8fca9131a1bd --- /dev/null +++ b/src/util-lua-smtp.c @@ -0,0 +1,342 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author casec Bachelors group + * \author Lauritz Prag Sømme + * \author Levi Tobiassen + * \author Stian Hoel Bergseth + * \author Vinjar Hillestad + */ + +#include "suricata-common.h" + +#include "debug.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" +#include "output.h" + +#include "app-layer-smtp.h" + +#ifdef HAVE_LUA + +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" +#include "util-file.h" + +/* + * \brief internal function used by SMTPGetMimeField + * + * \param luastate luastate stack to use and push attributes to + * \param flow network flow of SMTP packets + * \param name name of the attribute to extract from MimeDecField + * + * \retval 1 if success mimefield found and pushed to stack. Returns error + * int and msg pushed to luastate stack if error occurs. + */ + +static int GetMimeDecField(lua_State *luastate, Flow *flow, const char *name) +{ + /* extract state from flow */ + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + /* check that state exsists */ + if(state == NULL) { + return LuaCallbackError(luastate, "Internal error: no state in flow"); + } + /* pointer to current transaction in state */ + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "Transaction ending or not found"); + } + /* pointer to tail of msg list of MimeDecEntitys in current transaction. */ + MimeDecEntity *mime = smtp_tx->msg_tail; + /* check if msg_tail was hit */ + if(mime == NULL){ + return LuaCallbackError(luastate, "Internal error: no fields in transaction"); + } + /* extract MIME field based on spesific field name. */ + MimeDecField *field = MimeDecFindField(mime, name); + /* check MIME field */ + if(field == NULL) { + return LuaCallbackError(luastate, "Error: mimefield not found"); + } + /* return extracted field. */ + if(field->value == NULL || field->value_len == 0){ + return LuaCallbackError(luastate, "Error, pointer error"); + } + + return LuaPushStringBuffer(luastate, field->value, field->value_len); +} + +/** + * \brief Function extracts specific MIME field based on argument from luastate + * stack then pushing the attribute onto the luastate stack. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua + * + * \retval 1 if success mimefield found and pushed to stack. Returns error + * int and msg pushed to luastate stack if error occurs. + */ + +static int SMTPGetMimeField(lua_State *luastate) +{ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "error: protocol not SMTP"); + } + Flow *flow = LuaStateGetFlow(luastate); + /* check that flow exist */ + if(flow == NULL) { + return LuaCallbackError(luastate, "Error: no flow found"); + } + const char *name = LuaGetStringArgument(luastate, 1); + if (name == NULL) + return LuaCallbackError(luastate, "1st argument missing, empty or wrong type"); + + GetMimeDecField(luastate, flow, name); + + return 1; +} + +/** + * \brief Internal function used by SMTPGetMimeList + * + * \param luastate luastate stack to pop and push attributes for I/O to lua + * \param flow network flow of SMTP packets + * + * \retval 1 if the mimelist table is pushed to luastate stack. + * Returns error int and msg pushed to luastate stack if error occurs. +*/ + +static int GetMimeList(lua_State *luastate, Flow *flow) +{ + + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + if(state == NULL) { + return LuaCallbackError(luastate, "Error: no SMTP state"); + } + /* Create a pointer to the current SMTPtransaction */ + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "Error: no SMTP transaction found"); + } + /* Create a pointer to the tail of MimeDecEntity list */ + MimeDecEntity *mime = smtp_tx->msg_tail; + if(mime == NULL) { + return LuaCallbackError(luastate, "Error: no mime entity found"); + } + MimeDecField *field = mime->field_list; + if(field == NULL) { + return LuaCallbackError(luastate, "Error: no field_list found"); + } + if(field->name == NULL || field->name_len == 0) { + return LuaCallbackError(luastate, "Error: field has no name"); + } + /* Counter of MIME fields found */ + int num = 1; + /* loop trough the list of mimeFields, printing each name found */ + lua_newtable(luastate); + while (field != NULL) { + if(field->name != NULL && field->name_len != 0) { + lua_pushinteger(luastate,num++); + LuaPushStringBuffer(luastate, field->name, field->name_len); + lua_settable(luastate,-3); + } + field = field->next; + } + return 1; +} + +/** + * \brief Lists name and value to all MIME fields which + * is included in a SMTP transaction. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + * + */ + +static int SMTPGetMimeList(lua_State *luastate) +{ + /* Check if right protocol */ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* Extract network flow */ + Flow *flow = LuaStateGetFlow(luastate); + if(flow == NULL) { + return LuaCallbackError(luastate, "Error: no flow found"); + } + + GetMimeList(luastate, flow); + + return 1; +} + +/** + * \brief internal function used by SMTPGetMailFrom + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * \param flow flow to get state for SMTP + * + * \retval 1 if mailfrom field found. + * Retruns error int and msg pushed to luastate stack if error occurs + */ + +static int GetMailFrom(lua_State *luastate, Flow *flow) +{ + /* Extract SMTPstate from current flow */ + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + + if(state == NULL) { + return LuaCallbackError(luastate, "Internal Error: no state"); + } + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "Internal Error: no SMTP transaction"); + } + if(smtp_tx->mail_from == NULL || smtp_tx->mail_from_len == 0) { + return LuaCallbackError(luastate, "MailFrom not found"); + } + return LuaPushStringBuffer(luastate, smtp_tx->mail_from, smtp_tx->mail_from_len); + /* Returns 1 because we never push more then 1 item to the lua stack */ +} + +/** + * \brief Extracts mail_from parameter from SMTPState. + * Attribute may also be available from mimefields, although there is no + * guarantee of it existing as mime. + * + * \param luastate luastate stack to pop and push attributes for I/O to lua. + * + * \retval 1 if mailfrom field found. + * Retruns error int and msg pushed to luastate stack if error occurs + */ + +static int SMTPGetMailFrom(lua_State *luastate) +{ + /* check protocol */ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* Extract flow, with lockhint to check mutexlocking */ + Flow *flow = LuaStateGetFlow(luastate); + if(flow == NULL) { + return LuaCallbackError(luastate, "Internal Error: no flow"); + } + + GetMailFrom(luastate, flow); + + return 1; +} + +/** + * \brief intern function used by SMTPGetRcpList + * + * \params luastate luastate stack for internal communication with Lua. + * Used to hand over data to the recieveing luascript. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int GetRcptList(lua_State *luastate, Flow *flow) +{ + + SMTPState *state = (SMTPState *) FlowGetAppState(flow); + if(state == NULL) { + return LuaCallbackError(luastate, "Internal error, no state"); + } + + SMTPTransaction *smtp_tx = state->curr_tx; + if(smtp_tx == NULL) { + return LuaCallbackError(luastate, "No more tx, or tx not found"); + } + + /* Create a new table in luastate for rcpt list */ + lua_newtable(luastate); + /* rcpt var for iterator */ + int u = 1; + SMTPString *rcpt; + + TAILQ_FOREACH(rcpt, &smtp_tx->rcpt_to_list, next) { + lua_pushinteger(luastate, u++); + LuaPushStringBuffer(luastate, rcpt->str, rcpt->len); + lua_settable(luastate, -3); + } + /* return 1 since we allways push one table to luastate */ + return 1; +} + +/** + * \brief function loops through rcpt-list located in + * flow->SMTPState->SMTPTransaction, adding all items to a table. + * Then pushing it to the luastate stack. + * + * \params luastate luastate stack for internal communication with Lua. + * Used to hand over data to the recieveing luascript. + * + * \retval 1 if the table is pushed to lua. + * Returns error int and msg pushed to luastate stack if error occurs + */ + +static int SMTPGetRcptList(lua_State *luastate) +{ + /* check protocol */ + if(!(LuaStateNeedProto(luastate, ALPROTO_SMTP))) { + return LuaCallbackError(luastate, "Error: protocol not SMTP"); + } + /* Extract flow, with lockhint to check mutexlocking */ + Flow *flow = LuaStateGetFlow(luastate); + if(flow == NULL) { + return LuaCallbackError(luastate, "Internal error: no flow"); + } + + GetRcptList(luastate, flow); + + /* return 1 since we allways push one table to luastate */ + return 1; +} + +int LuaRegisterSmtpFunctions(lua_State *luastate) +{ + + lua_pushcfunction(luastate, SMTPGetMimeField); + lua_setglobal(luastate, "SMTPGetMimeField"); + + lua_pushcfunction(luastate, SMTPGetMimeList); + lua_setglobal(luastate, "SMTPGetMimeList"); + + lua_pushcfunction(luastate, SMTPGetMailFrom); + lua_setglobal(luastate, "SMTPGetMailFrom"); + + lua_pushcfunction(luastate, SMTPGetRcptList); + lua_setglobal(luastate, "SMTPGetRcptList"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-smtp.h b/src/util-lua-smtp.h new file mode 100644 index 000000000000..26750b8fbf22 --- /dev/null +++ b/src/util-lua-smtp.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_LUA_SMTP_H__ +#define __UTIL_LUA_SMTP_H__ + +#ifdef HAVE_LUA + +int LuaRegisterSmtpFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_SMTP_H__ */ diff --git a/src/util-lua-ssh.c b/src/util-lua-ssh.c new file mode 100644 index 000000000000..892190080fa2 --- /dev/null +++ b/src/util-lua-ssh.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +/** + * \file + * + * \author Mats Klepsland + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssh.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" + +static int GetServerProtoVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->srv_hdr.proto_version == NULL) + return LuaCallbackError(luastate, "error: no server proto version"); + + return LuaPushStringBuffer(luastate, ssh_state->srv_hdr.proto_version, + strlen((char *)ssh_state->srv_hdr.proto_version)); +} + +static int SshGetServerProtoVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetServerProtoVersion(luastate, f); + + return r; +} + +static int GetServerSoftwareVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->srv_hdr.software_version == NULL) + return LuaCallbackError(luastate, "error: no server software version"); + + return LuaPushStringBuffer(luastate, ssh_state->srv_hdr.software_version, + strlen((char *)ssh_state->srv_hdr.software_version)); +} + +static int SshGetServerSoftwareVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetServerSoftwareVersion(luastate, f); + + return r; +} + +static int GetClientProtoVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->cli_hdr.proto_version == NULL) + return LuaCallbackError(luastate, "error: no client proto version"); + + return LuaPushStringBuffer(luastate, ssh_state->cli_hdr.proto_version, + strlen((char *)ssh_state->cli_hdr.proto_version)); +} + +static int SshGetClientProtoVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetClientProtoVersion(luastate, f); + + return r; +} + +static int GetClientSoftwareVersion(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SshState *ssh_state = (SshState *)state; + + if (ssh_state->cli_hdr.software_version == NULL) + return LuaCallbackError(luastate, "error: no client software version"); + + return LuaPushStringBuffer(luastate, ssh_state->cli_hdr.software_version, + strlen((char *)ssh_state->cli_hdr.software_version)); +} + +static int SshGetClientSoftwareVersion(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_SSH))) + return LuaCallbackError(luastate, "error: protocol not ssh"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetClientSoftwareVersion(luastate, f); + + return r; +} + +/** \brief register ssh lua extensions in a luastate */ +int LuaRegisterSshFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, SshGetServerProtoVersion); + lua_setglobal(luastate, "SshGetServerProtoVersion"); + + lua_pushcfunction(luastate, SshGetServerSoftwareVersion); + lua_setglobal(luastate, "SshGetServerSoftwareVersion"); + + lua_pushcfunction(luastate, SshGetClientProtoVersion); + lua_setglobal(luastate, "SshGetClientProtoVersion"); + + lua_pushcfunction(luastate, SshGetClientSoftwareVersion); + lua_setglobal(luastate, "SshGetClientSoftwareVersion"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-ssh.h b/src/util-lua-ssh.h new file mode 100644 index 000000000000..aa6b6d704253 --- /dev/null +++ b/src/util-lua-ssh.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mats Klepsland + */ + +#ifndef __UTIL_LUA_SSH_H__ +#define __UTIL_LUA_SSH_H__ + +#ifdef HAVE_LUA + +int LuaRegisterSshFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_SSH_H__ */ diff --git a/src/util-lua-tls.c b/src/util-lua-tls.c new file mode 100644 index 000000000000..8472c0f6db4c --- /dev/null +++ b/src/util-lua-tls.c @@ -0,0 +1,356 @@ +/* Copyright (C) 2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +/** + * \file + * + * \author Eric Leblond + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "pkt-var.h" +#include "conf.h" + +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "util-print.h" +#include "util-unittest.h" + +#include "util-debug.h" + +#include "output.h" +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-ssl.h" +#include "util-privs.h" +#include "util-buffer.h" +#include "util-proto-name.h" +#include "util-logopenfile.h" +#include "util-time.h" + +#ifdef HAVE_LUA + +#include +#include +#include + +#include "util-lua.h" +#include "util-lua-common.h" + +static int GetCertNotBefore(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_not_before == 0) + return LuaCallbackError(luastate, "error: no certificate NotBefore"); + + int r = LuaPushInteger(luastate, connp->cert0_not_before); + + return r; +} + +static int TlsGetCertNotBefore(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertNotBefore(luastate, f, direction); + + return r; +} + +static int GetCertNotAfter(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_not_after == 0) + return LuaCallbackError(luastate, "error: no certificate NotAfter"); + + int r = LuaPushInteger(luastate, connp->cert0_not_after); + + return r; +} + +static int TlsGetCertNotAfter(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertNotAfter(luastate, f, direction); + + return r; +} + +static int GetCertInfo(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + if (connp->cert0_subject == NULL) + return LuaCallbackError(luastate, "error: no cert"); + + /* tls.version */ + char ssl_version[32] = ""; + switch (ssl_state->server_connp.version) { + case TLS_VERSION_UNKNOWN: + snprintf(ssl_version, sizeof(ssl_version), "UNDETERMINED"); + break; + case SSL_VERSION_2: + snprintf(ssl_version, sizeof(ssl_version), "SSLv2"); + break; + case SSL_VERSION_3: + snprintf(ssl_version, sizeof(ssl_version), "SSLv3"); + break; + case TLS_VERSION_10: + snprintf(ssl_version, sizeof(ssl_version), "TLSv1"); + break; + case TLS_VERSION_11: + snprintf(ssl_version, sizeof(ssl_version), "TLS 1.1"); + break; + case TLS_VERSION_12: + snprintf(ssl_version, sizeof(ssl_version), "TLS 1.2"); + break; + default: + snprintf(ssl_version, sizeof(ssl_version), "0x%04x", + ssl_state->server_connp.version); + break; + } + + int r = LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version)); + r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_subject, strlen(connp->cert0_subject)); + r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_issuerdn, strlen(connp->cert0_issuerdn)); + r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_fingerprint, strlen(connp->cert0_fingerprint)); + return r; +} + +static int TlsGetCertInfo(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertInfo(luastate, f, direction); + + return r; +} + +static int GetSNI(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->client_connp.sni == NULL) + return LuaCallbackError(luastate, "error: no server name indication"); + + return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->client_connp.sni, + strlen(ssl_state->client_connp.sni)); +} + +static int TlsGetSNI(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetSNI(luastate, f); + + return r; +} + +static int GetCertSerial(lua_State *luastate, const Flow *f) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + + if (ssl_state->server_connp.cert0_serial == NULL) + return LuaCallbackError(luastate, "error: no certificate serial"); + + return LuaPushStringBuffer(luastate, + (uint8_t *)ssl_state->server_connp.cert0_serial, + strlen(ssl_state->server_connp.cert0_serial)); +} + +static int TlsGetCertSerial(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertSerial(luastate, f); + + return r; +} + +static int GetCertChain(lua_State *luastate, const Flow *f, int direction) +{ + void *state = FlowGetAppState(f); + if (state == NULL) + return LuaCallbackError(luastate, "error: no app layer state"); + + SSLState *ssl_state = (SSLState *)state; + SSLStateConnp *connp = NULL; + + if (direction) { + connp = &ssl_state->client_connp; + } else { + connp = &ssl_state->server_connp; + } + + uint32_t u = 0; + lua_newtable(luastate); + SSLCertsChain *cert = NULL; + TAILQ_FOREACH(cert, &connp->certs, next) + { + lua_pushinteger(luastate, u++); + + lua_newtable(luastate); + + lua_pushstring(luastate, "length"); + lua_pushinteger(luastate, cert->cert_len); + lua_settable(luastate, -3); + + lua_pushstring(luastate, "data"); + LuaPushStringBuffer(luastate, cert->cert_data, cert->cert_len); + + lua_settable(luastate, -3); + lua_settable(luastate, -3); + } + + return 1; +} + +static int TlsGetCertChain(lua_State *luastate) +{ + int r; + + if (!(LuaStateNeedProto(luastate, ALPROTO_TLS))) + return LuaCallbackError(luastate, "error: protocol not tls"); + + int direction = LuaStateGetDirection(luastate); + + Flow *f = LuaStateGetFlow(luastate); + if (f == NULL) + return LuaCallbackError(luastate, "internal error: no flow"); + + r = GetCertChain(luastate, f, direction); + + return r; +} + +/** \brief register tls lua extensions in a luastate */ +int LuaRegisterTlsFunctions(lua_State *luastate) +{ + /* registration of the callbacks */ + lua_pushcfunction(luastate, TlsGetCertNotBefore); + lua_setglobal(luastate, "TlsGetCertNotBefore"); + + lua_pushcfunction(luastate, TlsGetCertNotAfter); + lua_setglobal(luastate, "TlsGetCertNotAfter"); + + lua_pushcfunction(luastate, TlsGetCertInfo); + lua_setglobal(luastate, "TlsGetCertInfo"); + + lua_pushcfunction(luastate, TlsGetSNI); + lua_setglobal(luastate, "TlsGetSNI"); + + lua_pushcfunction(luastate, TlsGetCertSerial); + lua_setglobal(luastate, "TlsGetCertSerial"); + + lua_pushcfunction(luastate, TlsGetCertChain); + lua_setglobal(luastate, "TlsGetCertChain"); + + return 0; +} + +#endif /* HAVE_LUA */ diff --git a/src/util-lua-tls.h b/src/util-lua-tls.h new file mode 100644 index 000000000000..57a27b5500be --- /dev/null +++ b/src/util-lua-tls.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_LUA_TLS_H__ +#define __UTIL_LUA_TLS_H__ + +#ifdef HAVE_LUA + +int LuaRegisterTlsFunctions(lua_State *luastate); + +#endif /* HAVE_LUA */ + +#endif /* __UTIL_LUA_TLS_H__ */ diff --git a/src/util-lua.c b/src/util-lua.c index a93dcb5d80b0..bc0c20c88715 100644 --- a/src/util-lua.c +++ b/src/util-lua.c @@ -56,6 +56,28 @@ #include "util-lua.h" +lua_State *LuaGetState(void) +{ + lua_State *s = NULL; +#ifdef HAVE_LUAJIT + s = LuajitGetState(); +#else + s = luaL_newstate(); +#endif + return s; +} + +void LuaReturnState(lua_State *s) +{ + if (s != NULL) { +#ifdef HAVE_LUAJIT + LuajitReturnState(s); +#else + lua_close(s); +#endif + } +} + /* key for tv (threadvars) pointer */ const char lua_ext_key_tv[] = "suricata:lua:tv:ptr"; /* key for tx pointer */ @@ -66,6 +88,8 @@ const char lua_ext_key_p[] = "suricata:lua:pkt:ptr"; const char lua_ext_key_flow[] = "suricata:lua:flow:ptr"; /* key for flow lock hint bool */ const char lua_ext_key_flow_lock_hint[] = "suricata:lua:flow:lock_hint"; +/* key for direction */ +const char lua_ext_key_direction[] = "suricata:lua:direction"; /* key for pa (packet alert) pointer */ const char lua_ext_key_pa[] = "suricata:lua:pkt:alert:ptr"; @@ -122,10 +146,9 @@ void LuaStateSetTX(lua_State *luastate, void *txptr) lua_settable(luastate, LUA_REGISTRYINDEX); } -Flow *LuaStateGetFlow(lua_State *luastate, int *lock_hint) +Flow *LuaStateGetFlow(lua_State *luastate) { Flow *f = NULL; - int need_flow_lock = 0; lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); lua_gettable(luastate, LUA_REGISTRYINDEX); @@ -134,13 +157,11 @@ Flow *LuaStateGetFlow(lua_State *luastate, int *lock_hint) /* need flow lock hint */ lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); lua_gettable(luastate, LUA_REGISTRYINDEX); - need_flow_lock = lua_toboolean(luastate, -1); - *lock_hint = need_flow_lock; return f; } -void LuaStateSetFlow(lua_State *luastate, Flow *f, int need_flow_lock) +void LuaStateSetFlow(lua_State *luastate, Flow *f) { /* flow */ lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow); @@ -149,7 +170,8 @@ void LuaStateSetFlow(lua_State *luastate, Flow *f, int need_flow_lock) /* flow lock status hint */ lua_pushlightuserdata(luastate, (void *)&lua_ext_key_flow_lock_hint); - lua_pushboolean(luastate, need_flow_lock); + /* locking is not required, set to 0 for backwards compatibility */ + lua_pushboolean(luastate, 0); lua_settable(luastate, LUA_REGISTRYINDEX); } @@ -200,6 +222,22 @@ void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b) lua_settable(luastate, LUA_REGISTRYINDEX); } +/** \brief get packet pointer from the lua state */ +int LuaStateGetDirection(lua_State *luastate) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); + lua_gettable(luastate, LUA_REGISTRYINDEX); + int dir = lua_toboolean(luastate, -1); + return dir; +} + +void LuaStateSetDirection(lua_State *luastate, int direction) +{ + lua_pushlightuserdata(luastate, (void *)&lua_ext_key_direction); + lua_pushboolean(luastate, direction); + lua_settable(luastate, LUA_REGISTRYINDEX); +} + /** \brief dump stack from lua state to screen */ void LuaPrintStack(lua_State *state) { int size = lua_gettop(state); @@ -255,4 +293,10 @@ int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_ return 1; } +int LuaPushInteger(lua_State *luastate, lua_Integer n) +{ + lua_pushinteger(luastate, n); + return 1; +} + #endif /* HAVE_LUA */ diff --git a/src/util-lua.h b/src/util-lua.h index 7ea69915b9e0..d6a9838cd896 100644 --- a/src/util-lua.h +++ b/src/util-lua.h @@ -26,14 +26,16 @@ #ifdef HAVE_LUA +#include "util-luajit.h" + typedef struct LuaStreamingBuffer_ { const uint8_t *data; uint32_t data_len; uint8_t flags; } LuaStreamingBuffer; -#define LUA_FLOW_LOCKED_BY_PARENT 0 -#define LUA_FLOW_NOT_LOCKED_BY_PARENT 1 +lua_State *LuaGetState(void); +void LuaReturnState(lua_State *s); /* gets */ @@ -44,14 +46,10 @@ Packet *LuaStateGetPacket(lua_State *luastate); void *LuaStateGetTX(lua_State *luastate); /** \brief get flow pointer from lua state - * - * \param locked_by_parent[out] bool indicating if flow is locked - * (LUA_FLOW_LOCKED_BY_PARENT) or unlocked - * (LUA_FLOW_NOT_LOCKED_BY_PARENT) * * \retval f flow poiner or NULL if it was not set */ -Flow *LuaStateGetFlow(lua_State *luastate, int *locked_by_parent); +Flow *LuaStateGetFlow(lua_State *luastate); PacketAlert *LuaStateGetPacketAlert(lua_State *luastate); @@ -60,6 +58,8 @@ File *LuaStateGetFile(lua_State *luastate); LuaStreamingBuffer *LuaStateGetStreamingBuffer(lua_State *luastate); +int LuaStateGetDirection(lua_State *luastate); + /* sets */ void LuaStateSetPacket(lua_State *luastate, Packet *p); @@ -68,11 +68,8 @@ void LuaStateSetTX(lua_State *luastate, void *tx); /** \brief set a flow pointer in the lua state * * \param f flow pointer - * \param locked_by_parent bool indicating if flow is locked - * (LUA_FLOW_LOCKED_BY_PARENT) or unlocked - * (LUA_FLOW_NOT_LOCKED_BY_PARENT) */ -void LuaStateSetFlow(lua_State *luastate, Flow *f, int locked_by_parent); +void LuaStateSetFlow(lua_State *luastate, Flow *f); void LuaStateSetPacketAlert(lua_State *luastate, PacketAlert *pa); @@ -82,10 +79,14 @@ void LuaStateSetThreadVars(lua_State *luastate, ThreadVars *tv); void LuaStateSetStreamingBuffer(lua_State *luastate, LuaStreamingBuffer *b); +void LuaStateSetDirection(lua_State *luastate, int direction); + void LuaPrintStack(lua_State *state); int LuaPushStringBuffer(lua_State *luastate, const uint8_t *input, size_t input_len); +int LuaPushInteger(lua_State *luastate, lua_Integer n); + #endif /* HAVE_LUA */ #endif /* __UTIL_LUA_H__ */ diff --git a/src/util-luajit.c b/src/util-luajit.c new file mode 100644 index 000000000000..cb11dc79af46 --- /dev/null +++ b/src/util-luajit.c @@ -0,0 +1,155 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#include "suricata-common.h" + +#ifdef HAVE_LUAJIT +#include "conf.h" +#include "util-pool.h" +#include "util-lua.h" + +/** \brief lua_State pool + * + * Lua requires states to be alloc'd in memory <2GB. For this reason we + * prealloc the states early during engine startup so we have a better chance + * of getting the states. We protect the pool with a lock as the detect + * threads access it during their init and cleanup. + * + * Pool size is automagically determined based on number of keyword occurences, + * cpus/cores and rule reloads being enabled or not. + * + * Alternatively, the "detect-engine.luajit-states" var can be set. + */ +static Pool *luajit_states = NULL; +static pthread_mutex_t luajit_states_lock = SCMUTEX_INITIALIZER; +static int luajit_states_cnt = 0; +static int luajit_states_cnt_max = 0; +static int luajit_states_size = 0; +#define LUAJIT_DEFAULT_STATES 128 + +static void *LuaStatePoolAlloc(void) +{ + return luaL_newstate(); +} + +static void LuaStatePoolFree(void *d) +{ + lua_State *s = (lua_State *)d; + if (s != NULL) + lua_close(s); +} + +/** \brief Populate lua states pool + * + * \param num keyword instances + * \param reloads bool indicating we have rule reloads enabled + */ +int LuajitSetupStatesPool(void) +{ + int retval = 0; + pthread_mutex_lock(&luajit_states_lock); + + if (luajit_states == NULL) { + intmax_t cnt = 0; + if (ConfGetInt("luajit.states", &cnt) != 1) { + ConfNode *denode = NULL; + ConfNode *decnf = ConfGetNode("detect-engine"); + if (decnf != NULL) { + TAILQ_FOREACH(denode, &decnf->head, next) { + if (strcmp(denode->val, "luajit-states") == 0) { + ConfGetChildValueInt(denode, "luajit-states", &cnt); + } + } + } + } + if (cnt == 0) { + cnt = LUAJIT_DEFAULT_STATES; + } + luajit_states_size = cnt; + + luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, NULL, LuaStatePoolFree); + if (luajit_states == NULL) { + SCLogError(SC_ERR_LUA_ERROR, "luastate pool init failed, lua/luajit keywords won't work"); + retval = -1; + } + + if (retval == 0) { + SCLogConfig("luajit states preallocated: %d", luajit_states_size); + } + } + + pthread_mutex_unlock(&luajit_states_lock); + return retval; +} + +void LuajitFreeStatesPool(void) +{ + pthread_mutex_lock(&luajit_states_lock); + if (luajit_states_cnt_max > luajit_states_size) { + SCLogNotice("luajit states used %d is bigger than pool size %d. Set " + "luajit.states to %d to avoid memory issues. " + "See #1577 and #1955.", luajit_states_cnt_max, luajit_states_size, + luajit_states_cnt_max); + } + PoolFree(luajit_states); + luajit_states = NULL; + luajit_states_size = 0; + luajit_states_cnt = 0; + pthread_mutex_unlock(&luajit_states_lock); +} + +lua_State *LuajitGetState(void) +{ + lua_State *s = NULL; + pthread_mutex_lock(&luajit_states_lock); + if (luajit_states != NULL) { + s = (lua_State *)PoolGet(luajit_states); + if (s != NULL) { + if (luajit_states_cnt == luajit_states_size) { + SCLogWarning(SC_WARN_LUA_SCRIPT, "luajit states pool size %d " + "reached. Increase luajit.states config option. " + "See #1577 and #1955", luajit_states_size); + } + + luajit_states_cnt++; + if (luajit_states_cnt > luajit_states_cnt_max) + luajit_states_cnt_max = luajit_states_cnt; + } + } + pthread_mutex_unlock(&luajit_states_lock); + return s; +} + +void LuajitReturnState(lua_State *s) +{ + if (s != NULL) { + pthread_mutex_lock(&luajit_states_lock); + PoolReturn(luajit_states, (void *)s); + BUG_ON(luajit_states_cnt <= 0); + luajit_states_cnt--; + pthread_mutex_unlock(&luajit_states_lock); + } +} + +#endif /* HAVE_LUAJIT */ diff --git a/src/util-luajit.h b/src/util-luajit.h new file mode 100644 index 000000000000..5aa810b1eaa9 --- /dev/null +++ b/src/util-luajit.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_LUAJIT_H__ +#define __UTIL_LUAJIT_H__ + +#ifdef HAVE_LUAJIT + +int LuajitSetupStatesPool(void); +void LuajitFreeStatesPool(void); +lua_State *LuajitGetState(void); +void LuajitReturnState(lua_State *s); + +#endif /* HAVE_LUAJIT */ + +#endif /* __UTIL_LUAJIT_H__ */ diff --git a/src/util-magic.c b/src/util-magic.c index 8b077d31c075..96af56e17103 100644 --- a/src/util-magic.c +++ b/src/util-magic.c @@ -28,10 +28,11 @@ */ #include "suricata-common.h" + +#ifdef HAVE_MAGIC #include "conf.h" #include "util-unittest.h" -#include static magic_t g_magic_ctx = NULL; static SCMutex g_magic_lock; @@ -53,23 +54,36 @@ int MagicInit(void) g_magic_ctx = magic_open(0); if (g_magic_ctx == NULL) { - SCLogError(SC_ERR_MAGIC_OPEN, "magic_open failed: %s", magic_error(g_magic_ctx)); + SCLogError(SC_ERR_MAGIC_OPEN, "magic_open failed: %s", + magic_error(g_magic_ctx)); goto error; } (void)ConfGet("magic-file", &filename); + + if (filename != NULL) { - SCLogInfo("using magic-file %s", filename); + if (strlen(filename) == 0) { + /* set filename to NULL on *nix systems so magic_load uses system + * default path (see man libmagic) */ + SCLogConfig("using system default magic-file"); + filename = NULL; + } + else { + SCLogConfig("using magic-file %s", filename); - if ( (fd = fopen(filename, "r")) == NULL) { - SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); - goto error; + if ( (fd = fopen(filename, "r")) == NULL) { + SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", + filename, strerror(errno)); + goto error; + } + fclose(fd); } - fclose(fd); } if (magic_load(g_magic_ctx, filename) != 0) { - SCLogError(SC_ERR_MAGIC_LOAD, "magic_load failed: %s", magic_error(g_magic_ctx)); + SCLogError(SC_ERR_MAGIC_LOAD, "magic_load failed: %s", + magic_error(g_magic_ctx)); goto error; } @@ -94,7 +108,7 @@ int MagicInit(void) * * \retval result pointer to null terminated string */ -char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen) +char *MagicGlobalLookup(const uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; @@ -123,7 +137,7 @@ char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen) * * \retval result pointer to null terminated string */ -char *MagicThreadLookup(magic_t *ctx, uint8_t *buf, uint32_t buflen) +char *MagicThreadLookup(magic_t *ctx, const uint8_t *buf, uint32_t buflen) { const char *result = NULL; char *magic = NULL; @@ -294,9 +308,6 @@ int MagicDetectTest02(void) /** \test magic lib calls -- lookup */ int MagicDetectTest03(void) { - magic_t magic_ctx; - char *result = NULL; - char buffer[] = { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x55, 0x2a, 0x36, 0x5e, 0xc6, @@ -322,29 +333,23 @@ int MagicDetectTest03(void) 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, }; size_t buffer_len = sizeof(buffer); - int retval = 0; - magic_ctx = magic_open(0); - if (magic_ctx == NULL) { - printf("failure retrieving magic_ctx\n"); - return 0; - } + magic_t magic_ctx = magic_open(0); + FAIL_IF_NULL(magic_ctx); - if (magic_load(magic_ctx, NULL) == -1) { - printf("magic_load failure\n"); - goto end; - } + FAIL_IF(magic_load(magic_ctx, NULL) == -1); - result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenDocument Text") != 0) { - printf("result %p:%s, not \"OpenDocument Text\": ", result,result?result:"(null)"); - goto end; + char *result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); + FAIL_IF_NULL(result); + + char *str = strstr(result, "OpenDocument Text"); + if (str == NULL) { + printf("result %s, not \"OpenDocument Text\": ", str); + FAIL; } - retval = 1; -end: magic_close(magic_ctx); - return retval; + PASS; } /** \test magic lib calls -- lookup */ @@ -398,8 +403,8 @@ int MagicDetectTest04(void) } result = (char *)magic_buffer(magic_ctx, (void *)buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenOffice.org 1.x Database file") != 0) { - printf("result %p:%s, not \"OpenOffice.org 1.x Database file\": ", result,result?result:"(null)"); + if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { + printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result,result?result:"(null)"); goto end; } @@ -504,23 +509,20 @@ int MagicDetectTest07(void) 0x04, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0b, }; size_t buffer_len = sizeof(buffer); - int retval = 0; - if (MagicInit() < 0) { - printf("MagicInit() failure\n"); - return 0; - } + FAIL_IF(MagicInit() < 0); result = MagicGlobalLookup(buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenDocument Text") != 0) { - printf("result %p:%s, not \"OpenDocument Text\": ", result,result?result:"(null)"); - goto end; + FAIL_IF_NULL(result); + + char *str = strstr(result, "OpenDocument Text"); + if (str == NULL) { + printf("result %s, not \"OpenDocument Text\": ", str); + FAIL; } - retval = 1; -end: MagicDeinit(); - return retval; + PASS; } /** \test magic api calls -- lookup */ @@ -566,8 +568,8 @@ int MagicDetectTest08(void) } result = MagicGlobalLookup(buffer, buffer_len); - if (result == NULL || strcmp(result, "OpenOffice.org 1.x Database file") != 0) { - printf("result %p:%s, not \"OpenOffice.org 1.x Database file\": ", result,result?result:"(null)"); + if (result == NULL || strncmp(result, "OpenOffice.org 1.x", 18) != 0) { + printf("result %p:%s, not \"OpenOffice.org 1.x\": ", result,result?result:"(null)"); goto end; } @@ -653,24 +655,28 @@ static int MagicDetectTest10ValgrindError(void) } #endif /* UNITTESTS */ - +#endif void MagicRegisterTests(void) { +#ifdef HAVE_MAGIC #ifdef UNITTESTS - UtRegisterTest("MagicInitTest01", MagicInitTest01, 1); - UtRegisterTest("MagicInitTest02", MagicInitTest02, 1); - UtRegisterTest("MagicDetectTest01", MagicDetectTest01, 1); + UtRegisterTest("MagicInitTest01", MagicInitTest01); + UtRegisterTest("MagicInitTest02", MagicInitTest02); + UtRegisterTest("MagicDetectTest01", MagicDetectTest01); //UtRegisterTest("MagicDetectTest02", MagicDetectTest02, 1); - UtRegisterTest("MagicDetectTest03", MagicDetectTest03, 1); - UtRegisterTest("MagicDetectTest04", MagicDetectTest04, 1); - UtRegisterTest("MagicDetectTest05", MagicDetectTest05, 1); + UtRegisterTest("MagicDetectTest03", MagicDetectTest03); + UtRegisterTest("MagicDetectTest04", MagicDetectTest04); + UtRegisterTest("MagicDetectTest05", MagicDetectTest05); //UtRegisterTest("MagicDetectTest06", MagicDetectTest06, 1); - UtRegisterTest("MagicDetectTest07", MagicDetectTest07, 1); - UtRegisterTest("MagicDetectTest08", MagicDetectTest08, 1); + UtRegisterTest("MagicDetectTest07", MagicDetectTest07); + UtRegisterTest("MagicDetectTest08", MagicDetectTest08); /* fails in valgrind, somehow it returns different pointers then. UtRegisterTest("MagicDetectTest09", MagicDetectTest09, 1); */ - UtRegisterTest("MagicDetectTest10ValgrindError", MagicDetectTest10ValgrindError, 1); + UtRegisterTest("MagicDetectTest10ValgrindError", + MagicDetectTest10ValgrindError); #endif /* UNITTESTS */ +#endif /* HAVE_MAGIC */ } + diff --git a/src/util-magic.h b/src/util-magic.h index 0efdbd147b48..a2ffc7bac550 100644 --- a/src/util-magic.h +++ b/src/util-magic.h @@ -24,12 +24,12 @@ #ifndef __UTIL_MAGIC_H__ #define __UTIL_MAGIC_H__ -#include - +#ifdef HAVE_MAGIC int MagicInit(void); void MagicDeinit(void); -char *MagicGlobalLookup(uint8_t *, uint32_t); -char *MagicThreadLookup(magic_t *, uint8_t *, uint32_t); +char *MagicGlobalLookup(const uint8_t *, uint32_t); +char *MagicThreadLookup(magic_t *, const uint8_t *, uint32_t); +#endif void MagicRegisterTests(void); #endif /* __UTIL_MAGIC_H__ */ diff --git a/src/util-mem.h b/src/util-mem.h index b720ac361781..799c942c3ead 100644 --- a/src/util-mem.h +++ b/src/util-mem.h @@ -223,9 +223,9 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage); ptrmem = strdup((a)); \ if (ptrmem == NULL) { \ if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\ - size_t len = strlen((a)); \ + size_t _scstrdup_len = strlen((a)); \ SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \ - "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)len); \ + "to allocate %"PRIuMAX" bytes", strerror(errno), (uintmax_t)_scstrdup_len); \ SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \ exit(EXIT_FAILURE); \ } \ diff --git a/src/util-memcmp.c b/src/util-memcmp.c index f5ab3d095f0a..2dd06ecc7f46 100644 --- a/src/util-memcmp.c +++ b/src/util-memcmp.c @@ -339,28 +339,69 @@ static int MemcmpTest17 (void) return 1; } +struct MemcmpTest18Tests { + char *a; + char *b; + int result; +} memcmp_tests18_tests[] = { + { "abcdefgh", "!bcdefgh", 1, }, + { "?bcdefgh", "!bcdefgh", 1, }, + { "!bcdefgh", "abcdefgh", 1, }, + { "!bcdefgh", "?bcdefgh", 1, }, + { "zbcdefgh", "bbcdefgh", 1, }, + + { "abcdefgh12345678", "!bcdefgh12345678", 1, }, + { "?bcdefgh12345678", "!bcdefgh12345678", 1, }, + { "!bcdefgh12345678", "abcdefgh12345678", 1, }, + { "!bcdefgh12345678", "?bcdefgh12345678", 1, }, + { "bbcdefgh12345678", "zbcdefgh12345678", 1, }, + + { "abcdefgh", "abcdefgh", 0, }, + { "abcdefgh", "Abcdefgh", 0, }, + { "abcdefgh12345678", "Abcdefgh12345678", 0, }, + + { NULL, NULL, 0 }, + + }; + +static int MemcmpTest18 (void) +{ + struct MemcmpTest18Tests *t = memcmp_tests18_tests; + + while (t && t->a != NULL) { + + if (SCMemcmpLowercase(t->a, t->b, strlen(t->a)-1) != t->result) + return 0; + SCLogInfo("ok"); + t++; + } + + return 1; +} + #endif /* UNITTESTS */ void MemcmpRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MemcmpTest01", MemcmpTest01, 1); - UtRegisterTest("MemcmpTest02", MemcmpTest02, 1); - UtRegisterTest("MemcmpTest03", MemcmpTest03, 1); - UtRegisterTest("MemcmpTest04", MemcmpTest04, 1); - UtRegisterTest("MemcmpTest05", MemcmpTest05, 1); - UtRegisterTest("MemcmpTest06", MemcmpTest06, 1); - UtRegisterTest("MemcmpTest07", MemcmpTest07, 1); - UtRegisterTest("MemcmpTest08", MemcmpTest08, 1); - UtRegisterTest("MemcmpTest09", MemcmpTest09, 1); - UtRegisterTest("MemcmpTest10", MemcmpTest10, 1); - UtRegisterTest("MemcmpTest11", MemcmpTest11, 1); - UtRegisterTest("MemcmpTest12", MemcmpTest12, 1); - UtRegisterTest("MemcmpTest13", MemcmpTest13, 1); - UtRegisterTest("MemcmpTest14", MemcmpTest14, 1); - UtRegisterTest("MemcmpTest15", MemcmpTest15, 1); - UtRegisterTest("MemcmpTest16", MemcmpTest16, 1); - UtRegisterTest("MemcmpTest17", MemcmpTest17, 1); + UtRegisterTest("MemcmpTest01", MemcmpTest01); + UtRegisterTest("MemcmpTest02", MemcmpTest02); + UtRegisterTest("MemcmpTest03", MemcmpTest03); + UtRegisterTest("MemcmpTest04", MemcmpTest04); + UtRegisterTest("MemcmpTest05", MemcmpTest05); + UtRegisterTest("MemcmpTest06", MemcmpTest06); + UtRegisterTest("MemcmpTest07", MemcmpTest07); + UtRegisterTest("MemcmpTest08", MemcmpTest08); + UtRegisterTest("MemcmpTest09", MemcmpTest09); + UtRegisterTest("MemcmpTest10", MemcmpTest10); + UtRegisterTest("MemcmpTest11", MemcmpTest11); + UtRegisterTest("MemcmpTest12", MemcmpTest12); + UtRegisterTest("MemcmpTest13", MemcmpTest13); + UtRegisterTest("MemcmpTest14", MemcmpTest14); + UtRegisterTest("MemcmpTest15", MemcmpTest15); + UtRegisterTest("MemcmpTest16", MemcmpTest16); + UtRegisterTest("MemcmpTest17", MemcmpTest17); + UtRegisterTest("MemcmpTest18", MemcmpTest18); #endif /* UNITTESTS */ } diff --git a/src/util-memcmp.h b/src/util-memcmp.h index 4a5be891ee17..9248f8422e83 100644 --- a/src/util-memcmp.h +++ b/src/util-memcmp.h @@ -41,12 +41,12 @@ void MemcmpRegisterTests(void); static inline int MemcmpLowercase(const void *s1, const void *s2, size_t n) { - size_t i; + ssize_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { + for (i = n - 1; i >= 0; i--) { if (((uint8_t *)s1)[i] != u8_tolower(*(((uint8_t *)s2)+i))) return 1; } @@ -365,14 +365,12 @@ static inline int SCMemcmpLowercase(const void *s1, const void *s2, size_t len) #include -static inline int SCMemcmp(const void *s1, const void *s2, size_t len) +/* Compare to non-zero sequence of bytes. */ +static inline int SCMemcmpNZ(const void *s1, const void *s2, size_t len) { uint64_t b1, w1, aligned1; uint64_t b2, w2, aligned2; - if (len == 0) - return 0; - /* Load aligned words containing the beginning of each string. * These loads don't trigger unaligned events. */ @@ -411,6 +409,13 @@ static inline int SCMemcmp(const void *s1, const void *s2, size_t len) return 0; } +/* Compare two sequences of bytes. */ +static inline int SCMemcmp(const void *s1, const void *s2, size_t len) +{ + if (len == 0) + return 0; + return SCMemcmpNZ(s1, s2, len); +} /** \brief Convert 8 characters to lower case using SIMD. * \param Word containing the 8 bytes. * \return Word containing 8-bytes each converted to lowercase. diff --git a/src/util-memcpy.h b/src/util-memcpy.h index bdb80242b726..c2b8cd7997fc 100644 --- a/src/util-memcpy.h +++ b/src/util-memcpy.h @@ -35,7 +35,7 @@ * \param s Pointer to the src string for memcpy. * \param len len of the string sent in s. */ -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) +static inline void memcpy_tolower(uint8_t *d, const uint8_t *s, uint16_t len) { uint16_t i; for (i = 0; i < len; i++) diff --git a/src/util-memrchr.c b/src/util-memrchr.c index ebac1764f02f..6e49fc86f49e 100644 --- a/src/util-memrchr.c +++ b/src/util-memrchr.c @@ -62,6 +62,6 @@ static int MemrchrTest01 (void) void MemrchrRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("MemrchrTest01", MemrchrTest01, 1); + UtRegisterTest("MemrchrTest01", MemrchrTest01); #endif } diff --git a/src/util-misc.c b/src/util-misc.c index fdb3eaeae8c8..53ee0d3dc89b 100644 --- a/src/util-misc.c +++ b/src/util-misc.c @@ -34,7 +34,7 @@ static pcre_extra *parse_regex_study = NULL; void ParseSizeInit(void) { - const char *eb; + const char *eb = NULL; int eo; int opts = 0; @@ -125,8 +125,9 @@ static int ParseSizeString(const char *size, double *res) } else if (strcasecmp(str2, "gb") == 0) { *res *= 1024 * 1024 * 1024; } else { - /* not possible */ - BUG_ON(1); + /* Bad unit. */ + retval = -1; + goto end; } } @@ -1118,6 +1119,11 @@ int UtilMiscParseSizeStringTest01(void) goto error; } + /* Should fail on unknown units. */ + if (ParseSizeString("32eb", &result) > 0) { + goto error; + } + return 1; error: return 0; @@ -1128,7 +1134,8 @@ int UtilMiscParseSizeStringTest01(void) void UtilMiscRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UtilMiscParseSizeStringTest01", UtilMiscParseSizeStringTest01, 1); + UtRegisterTest("UtilMiscParseSizeStringTest01", + UtilMiscParseSizeStringTest01); #endif /* UNITTESTS */ return; diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index faec5b2a591d..56ccbc8cf8d8 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -61,24 +61,22 @@ #include "util-memcpy.h" void SCACBSInitCtx(MpmCtx *); -void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCACBSInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCACBSDestroyCtx(MpmCtx *); void SCACBSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACBSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACBSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACBSPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); void SCACBSPrintInfo(MpmCtx *mpm_ctx); void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACBSRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_BS_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 @@ -97,9 +95,6 @@ typedef struct StateQueue_ { void MpmACBSRegister(void) { mpm_table[MPM_AC_BS].name = "ac-bs"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC_BS].max_pattern_length = 0; - mpm_table[MPM_AC_BS].InitCtx = SCACBSInitCtx; mpm_table[MPM_AC_BS].InitThreadCtx = SCACBSInitThreadCtx; mpm_table[MPM_AC_BS].DestroyCtx = SCACBSDestroyCtx; @@ -108,7 +103,6 @@ void MpmACBSRegister(void) mpm_table[MPM_AC_BS].AddPatternNocase = SCACBSAddPatternCI; mpm_table[MPM_AC_BS].Prepare = SCACBSPreparePatterns; mpm_table[MPM_AC_BS].Search = SCACBSSearch; - mpm_table[MPM_AC_BS].Cleanup = NULL; mpm_table[MPM_AC_BS].PrintCtx = SCACBSPrintInfo; mpm_table[MPM_AC_BS].PrintThreadCtx = SCACBSPrintSearchStats; mpm_table[MPM_AC_BS].RegisterUnittests = SCACBSRegisterTests; @@ -132,253 +126,6 @@ static void SCACBSGetConfig() return; } -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACBSInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACBSPattern *SCACBSInitHashLookup(SCACBSCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = SCACBSInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCACBSPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) - return t; - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACBSPattern *SCACBSAllocPattern(MpmCtx *mpm_ctx) -{ - SCACBSPattern *p = SCMalloc(sizeof(SCACBSPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACBSPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACBSPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACBSPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACBSPattern instance to be freed. - */ -static inline void SCACBSFreePattern(MpmCtx *mpm_ctx, SCACBSPattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACBSPattern); - } - return; -} - -static inline uint32_t SCACBSInitHash(SCACBSPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACBSInitHashAdd(SCACBSCtx *ctx, SCACBSPattern *p) -{ - uint32_t hash = SCACBSInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACBSPattern *tt = NULL; - SCACBSPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACBSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) -{ - SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCACBSPattern *p = SCACBSInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACBSAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACBSInitHashAdd(ctx, p); - - //if (mpm_ctx->pattern_cnt == 65535) { - // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - // "insert anymore. Exiting"); - // exit(EXIT_FAILURE); - //} - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - } - - return 0; - -error: - SCACBSFreePattern(mpm_ctx, p); - return -1; -} - /** * \internal * \brief Initialize a new state in the goto and output tables. @@ -480,7 +227,7 @@ static void SCACBSSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) * \param mpm_ctx Pointer to the mpm context. */ static inline void SCACBSEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, - MpmCtx *mpm_ctx) + MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int32_t state = 0; @@ -972,7 +719,6 @@ static inline void SCACBSCreateModDeltaTable(MpmCtx *mpm_ctx) uint16_t *curr_loc = (uint16_t *)ctx->state_table_mod; uint16_t *no_of_entries = NULL; uint16_t *ascii_codes = NULL; - state = 0; uint16_t ascii_code = 0; uint16_t k = 0; for (state = 0; state < ctx->state_count; state++) { @@ -1047,7 +793,6 @@ static inline void SCACBSCreateModDeltaTable(MpmCtx *mpm_ctx) uint32_t *curr_loc = (uint32_t *)ctx->state_table_mod; uint32_t *no_of_entries = NULL; uint32_t *ascii_codes = NULL; - state = 0; uint32_t ascii_code = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { @@ -1144,24 +889,24 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) { SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ - ctx->parray = (SCACBSPattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACBSPattern *)); + ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt * + sizeof(MpmPattern *)); if (ctx->parray == NULL) goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACBSPattern *node = ctx->init_hash[i], *nnode = NULL; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; @@ -1171,19 +916,19 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) } /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACBSPatternList)); + ctx->pid_pat_list = SCMalloc((mpm_ctx->max_pat_id + 1)* sizeof(SCACBSPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACBSPatternList)); + memset(ctx->pid_pat_list, 0, (mpm_ctx->max_pat_id + 1) * sizeof(SCACBSPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { @@ -1196,6 +941,10 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; } + + /* ACPatternList now owns this memory */ + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; } /* prepare the state table required by AC */ @@ -1204,13 +953,15 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACBSFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); + + ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1; return 0; @@ -1225,7 +976,7 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ -void SCACBSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) +void SCACBSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1262,12 +1013,11 @@ void SCACBSInitCtx(MpmCtx *mpm_ctx) mpm_ctx->memory_size += sizeof(SCACBSCtx); /* initialize the hash we use to speed up pattern insertions */ - SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(SCACBSPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); + if (mpm_ctx->init_hash == NULL) { exit(EXIT_FAILURE); } - memset(ctx->init_hash, 0, sizeof(SCACBSPattern *) * INIT_HASH_SIZE); + memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ @@ -1307,25 +1057,25 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) if (ctx == NULL) return; - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACBSFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACBSPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); } if (ctx->state_table_u16 != NULL) { @@ -1355,10 +1105,12 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) } if (ctx->pid_pat_list != NULL) { - int i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { + uint32_t i; + for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); } SCFree(ctx->pid_pat_list); } @@ -1392,10 +1144,10 @@ void SCACBSDestroyCtx(MpmCtx *mpm_ctx) * * \retval matches Match count. */ -uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCACBSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { - SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; + const SCACBSCtx *ctx = (SCACBSCtx *)mpm_ctx->ctx; int i = 0; int matches = 0; uint8_t buf_local; @@ -1405,6 +1157,9 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACBSPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); + if (ctx->state_count < 32767) { register SC_AC_BS_STATE_TYPE_U16 state = 0; uint16_t no_of_entries; @@ -1435,7 +1190,6 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, int low = 0; int high = no_of_entries; int mid; - state = 0; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { @@ -1453,30 +1207,33 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, match_u16: if (state & 0x8000) { - uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries; + uint32_t nentries = ctx->output_table[state & 0x7FFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k; - for (k = 0; k < no_of_entries; k++) { + for (k = 0; k < nentries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1516,7 +1273,6 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, int low = 0; int high = no_of_entries; int mid; - state = 0; while (low <= high) { mid = (low + high) / 2; if (ascii_codes[mid] == buf_local) { @@ -1534,30 +1290,33 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, match_u32: if (state & 0xFF000000) { - uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; + uint32_t nentries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k; - for (k = 0; k < no_of_entries; k++) { + for (k = 0; k < nentries; k++) { if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1590,10 +1349,10 @@ uint32_t SCACBSSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, */ int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** @@ -1615,9 +1374,9 @@ int SCACBSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ int SCACBSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { - return SCACBSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACBSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) @@ -1643,8 +1402,8 @@ void SCACBSPrintInfo(MpmCtx *mpm_ctx) printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACBSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSCtx)); - printf(" SCACBSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSPattern)); - printf(" SCACBSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACBSPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); @@ -1663,16 +1422,16 @@ static int SCACBSTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1697,16 +1456,16 @@ static int SCACBSTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1730,12 +1489,12 @@ static int SCACBSTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1743,7 +1502,7 @@ static int SCACBSTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1767,17 +1526,17 @@ static int SCACBSTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1801,17 +1560,17 @@ static int SCACBSTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1835,15 +1594,15 @@ static int SCACBSTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1867,12 +1626,12 @@ static int SCACBSTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* should match 30 times */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); @@ -1887,7 +1646,7 @@ static int SCACBSTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); /* total matches: 135 */ SCACBSPreparePatterns(&mpm_ctx); @@ -1912,16 +1671,16 @@ static int SCACBSTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1944,16 +1703,16 @@ static int SCACBSTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -1976,16 +1735,16 @@ static int SCACBSTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2013,12 +1772,12 @@ static int SCACBSTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; @@ -2028,7 +1787,7 @@ static int SCACBSTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCACBSPreparePatterns(&mpm_ctx) == -1) goto end; @@ -2060,18 +1819,18 @@ static int SCACBSTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2095,17 +1854,17 @@ static int SCACBSTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2129,17 +1888,17 @@ static int SCACBSTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2163,17 +1922,17 @@ static int SCACBSTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2197,17 +1956,17 @@ static int SCACBSTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2231,17 +1990,17 @@ static int SCACBSTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2265,17 +2024,17 @@ static int SCACBSTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2299,17 +2058,17 @@ static int SCACBSTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2332,17 +2091,17 @@ static int SCACBSTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2366,16 +2125,16 @@ static int SCACBSTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2398,18 +2157,18 @@ static int SCACBSTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2433,16 +2192,16 @@ static int SCACBSTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2465,16 +2224,16 @@ static int SCACBSTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2497,17 +2256,17 @@ static int SCACBSTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2531,16 +2290,16 @@ static int SCACBSTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2564,16 +2323,16 @@ static int SCACBSTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2597,16 +2356,16 @@ static int SCACBSTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2630,18 +2389,18 @@ static int SCACBSTest29(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_BS); - SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACBSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdef", 5, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdefg", 5, 0, 0, 3, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"defgh", 5, 0, 0, 4, 0, 0); - PmqSetup(&pmq, 4); + PmqSetup(&pmq); SCACBSPreparePatterns(&mpm_ctx); @@ -2721,36 +2480,36 @@ void SCACBSRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCACBSTest01", SCACBSTest01, 1); - UtRegisterTest("SCACBSTest02", SCACBSTest02, 1); - UtRegisterTest("SCACBSTest03", SCACBSTest03, 1); - UtRegisterTest("SCACBSTest04", SCACBSTest04, 1); - UtRegisterTest("SCACBSTest05", SCACBSTest05, 1); - UtRegisterTest("SCACBSTest06", SCACBSTest06, 1); - UtRegisterTest("SCACBSTest07", SCACBSTest07, 1); - UtRegisterTest("SCACBSTest08", SCACBSTest08, 1); - UtRegisterTest("SCACBSTest09", SCACBSTest09, 1); - UtRegisterTest("SCACBSTest10", SCACBSTest10, 1); - UtRegisterTest("SCACBSTest11", SCACBSTest11, 1); - UtRegisterTest("SCACBSTest12", SCACBSTest12, 1); - UtRegisterTest("SCACBSTest13", SCACBSTest13, 1); - UtRegisterTest("SCACBSTest14", SCACBSTest14, 1); - UtRegisterTest("SCACBSTest15", SCACBSTest15, 1); - UtRegisterTest("SCACBSTest16", SCACBSTest16, 1); - UtRegisterTest("SCACBSTest17", SCACBSTest17, 1); - UtRegisterTest("SCACBSTest18", SCACBSTest18, 1); - UtRegisterTest("SCACBSTest19", SCACBSTest19, 1); - UtRegisterTest("SCACBSTest20", SCACBSTest20, 1); - UtRegisterTest("SCACBSTest21", SCACBSTest21, 1); - UtRegisterTest("SCACBSTest22", SCACBSTest22, 1); - UtRegisterTest("SCACBSTest23", SCACBSTest23, 1); - UtRegisterTest("SCACBSTest24", SCACBSTest24, 1); - UtRegisterTest("SCACBSTest25", SCACBSTest25, 1); - UtRegisterTest("SCACBSTest26", SCACBSTest26, 1); - UtRegisterTest("SCACBSTest27", SCACBSTest27, 1); - UtRegisterTest("SCACBSTest28", SCACBSTest28, 1); - UtRegisterTest("SCACBSTest29", SCACBSTest29, 1); - UtRegisterTest("SCACBSTest30", SCACBSTest30, 1); + UtRegisterTest("SCACBSTest01", SCACBSTest01); + UtRegisterTest("SCACBSTest02", SCACBSTest02); + UtRegisterTest("SCACBSTest03", SCACBSTest03); + UtRegisterTest("SCACBSTest04", SCACBSTest04); + UtRegisterTest("SCACBSTest05", SCACBSTest05); + UtRegisterTest("SCACBSTest06", SCACBSTest06); + UtRegisterTest("SCACBSTest07", SCACBSTest07); + UtRegisterTest("SCACBSTest08", SCACBSTest08); + UtRegisterTest("SCACBSTest09", SCACBSTest09); + UtRegisterTest("SCACBSTest10", SCACBSTest10); + UtRegisterTest("SCACBSTest11", SCACBSTest11); + UtRegisterTest("SCACBSTest12", SCACBSTest12); + UtRegisterTest("SCACBSTest13", SCACBSTest13); + UtRegisterTest("SCACBSTest14", SCACBSTest14); + UtRegisterTest("SCACBSTest15", SCACBSTest15); + UtRegisterTest("SCACBSTest16", SCACBSTest16); + UtRegisterTest("SCACBSTest17", SCACBSTest17); + UtRegisterTest("SCACBSTest18", SCACBSTest18); + UtRegisterTest("SCACBSTest19", SCACBSTest19); + UtRegisterTest("SCACBSTest20", SCACBSTest20); + UtRegisterTest("SCACBSTest21", SCACBSTest21); + UtRegisterTest("SCACBSTest22", SCACBSTest22); + UtRegisterTest("SCACBSTest23", SCACBSTest23); + UtRegisterTest("SCACBSTest24", SCACBSTest24); + UtRegisterTest("SCACBSTest25", SCACBSTest25); + UtRegisterTest("SCACBSTest26", SCACBSTest26); + UtRegisterTest("SCACBSTest27", SCACBSTest27); + UtRegisterTest("SCACBSTest28", SCACBSTest28); + UtRegisterTest("SCACBSTest29", SCACBSTest29); + UtRegisterTest("SCACBSTest30", SCACBSTest30); #endif return; diff --git a/src/util-mpm-ac-bs.h b/src/util-mpm-ac-bs.h index 46e196dd442d..80ac0f4b06e8 100644 --- a/src/util-mpm-ac-bs.h +++ b/src/util-mpm-ac-bs.h @@ -22,29 +22,18 @@ * */ +#include "util-mpm.h" + #define SC_AC_BS_STATE_TYPE_U16 uint16_t #define SC_AC_BS_STATE_TYPE_U32 uint32_t -typedef struct SCACBSPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - struct SCACBSPattern_ *next; -} SCACBSPattern; - typedef struct SCACBSPatternList_ { uint8_t *cs; uint16_t patlen; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; } SCACBSPatternList; typedef struct SCACBSOutputTable_ { @@ -55,14 +44,14 @@ typedef struct SCACBSOutputTable_ { } SCACBSOutputTable; typedef struct SCACBSCtx_ { - /* hash used during ctx initialization */ - SCACBSPattern **init_hash; - /* pattern arrays. We need this only during the goto table creation phase */ - SCACBSPattern **parray; + MpmPattern **parray; /* no of states used by ac */ uint32_t state_count; + + uint32_t pattern_id_bitarray_size; + /* the all important memory hungry state_table */ SC_AC_BS_STATE_TYPE_U16 (*state_table_u16)[256]; /* the all important memory hungry state_table */ @@ -80,7 +69,6 @@ typedef struct SCACBSCtx_ { /* the size of each state */ uint16_t single_state_size; - uint16_t max_pat_id; } SCACBSCtx; typedef struct SCACBSThreadCtx_ { diff --git a/src/util-mpm-ac-gfbs.c b/src/util-mpm-ac-gfbs.c deleted file mode 100644 index 28b1fc2b3d03..000000000000 --- a/src/util-mpm-ac-gfbs.c +++ /dev/null @@ -1,2676 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - * Implementation of aho-corasick MPM from - - * - * Efficient String Matching: An Aid to Bibliographic Search - * Alfred V. Aho and Margaret J. Corasick - * - * - We use the goto-failure table to calculate transitions. - * - If we cross 2 ** 16 states, we use 4 bytes in the transition table - * to hold each state, otherwise we use 2 bytes. - * - To reduce memory consumption, we throw all the failure transitions - * out and use binary search to pick out the right transition in - * the modified goto table. - * - * \todo - Do a proper analyis of our existing MPMs and suggest a good one based - * on the pattern distribution and the expected traffic(say http). - * - Tried out loop unrolling without any perf increase. Need to dig deeper. - * - Try out holding whether they are any output strings from a particular - * state in one of the bytes of a state var. Will be useful in cuda esp. - */ - -#include "suricata-common.h" -#include "suricata.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "util-mpm-ac-gfbs.h" - -#include "conf.h" -#include "util-memcmp.h" -#include "util-memcpy.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" - -void SCACGfbsInitCtx(MpmCtx *); -void SCACGfbsInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void SCACGfbsDestroyCtx(MpmCtx *); -void SCACGfbsDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); -int SCACGfbsAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); -int SCACGfbsAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); -int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void SCACGfbsPrintInfo(MpmCtx *mpm_ctx); -void SCACGfbsPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void SCACGfbsRegisterTests(void); - -/* a placeholder to denote a failure transition in the goto table */ -#define SC_AC_GFBS_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 - -#define STATE_QUEUE_CONTAINER_SIZE 65536 - -/** - * \brief Helper structure used by AC during state table creation - */ -typedef struct StateQueue_ { - int32_t store[STATE_QUEUE_CONTAINER_SIZE]; - int top; - int bot; -} StateQueue; - -/** - * \brief Register the goto failure table based aho-corasick mpm. - */ -void MpmACGfbsRegister(void) -{ - mpm_table[MPM_AC_GFBS].name = "ac-gfbs"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC_GFBS].max_pattern_length = 0; - - mpm_table[MPM_AC_GFBS].InitCtx = SCACGfbsInitCtx; - mpm_table[MPM_AC_GFBS].InitThreadCtx = SCACGfbsInitThreadCtx; - mpm_table[MPM_AC_GFBS].DestroyCtx = SCACGfbsDestroyCtx; - mpm_table[MPM_AC_GFBS].DestroyThreadCtx = SCACGfbsDestroyThreadCtx; - mpm_table[MPM_AC_GFBS].AddPattern = SCACGfbsAddPatternCS; - mpm_table[MPM_AC_GFBS].AddPatternNocase = SCACGfbsAddPatternCI; - mpm_table[MPM_AC_GFBS].Prepare = SCACGfbsPreparePatterns; - mpm_table[MPM_AC_GFBS].Search = SCACGfbsSearch; - mpm_table[MPM_AC_GFBS].Cleanup = NULL; - mpm_table[MPM_AC_GFBS].PrintCtx = SCACGfbsPrintInfo; - mpm_table[MPM_AC_GFBS].PrintThreadCtx = SCACGfbsPrintSearchStats; - mpm_table[MPM_AC_GFBS].RegisterUnittests = SCACGfbsRegisterTests; - - return; -} - -/** - * \internal - * \brief Initialize the AC context with user specified conf parameters. We - * aren't retrieving anything for AC conf now, but we will certainly - * need it, when we customize AC. - */ -static void SCACGfbsGetConfig() -{ - //ConfNode *ac_conf; - //const char *hash_val = NULL; - - //ConfNode *pm = ConfGetNode("pattern-matcher"); - - return; -} - -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACGfbsInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACGfbsPattern *SCACGfbsInitHashLookup(SCACGfbsCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = SCACGfbsInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) - return NULL; - - SCACGfbsPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) - return t; - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACGfbsPattern *SCACGfbsAllocPattern(MpmCtx *mpm_ctx) -{ - SCACGfbsPattern *p = SCMalloc(sizeof(SCACGfbsPattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACGfbsPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACGfbsPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACGfbsPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACGfbsPattern instance to be freed. - */ -static inline void SCACGfbsFreePattern(MpmCtx *mpm_ctx, SCACGfbsPattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACGfbsPattern); - } - return; -} - -static inline uint32_t SCACGfbsInitHash(SCACGfbsPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACGfbsInitHashAdd(SCACGfbsCtx *ctx, SCACGfbsPattern *p) -{ - uint32_t hash = SCACGfbsInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACGfbsPattern *tt = NULL; - SCACGfbsPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACGfbsAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCACGfbsPattern *p = SCACGfbsInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACGfbsAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACGfbsInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - "insert anymore. Exiting"); - exit(EXIT_FAILURE); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - } - - return 0; - -error: - SCACGfbsFreePattern(mpm_ctx, p); - return -1; -} - -/** - * \internal - * \brief Initialize a new state in the goto and output tables. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval The state id, of the newly created state. - */ -static inline int SCACGfbsInitNewState(MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int ascii_code = 0; - int size = 0; - - /* reallocate space in the goto table to include a new state */ - size = (ctx->state_count + 1) * 1024; - ptmp = SCRealloc(ctx->goto_table, size); - if (ptmp == NULL) { - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - ctx->goto_table = ptmp; - - /* set all transitions for the newly assigned state as FAIL transitions */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_GFBS_FAIL; - } - - /* reallocate space in the output table for the new state */ - size = (ctx->state_count + 1) * sizeof(SCACGfbsOutputTable); - ptmp = SCRealloc(ctx->output_table, size); - if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - ctx->output_table = ptmp; - - memset(ctx->output_table + ctx->state_count, 0, sizeof(SCACGfbsOutputTable)); - - /* \todo using it temporarily now during dev, since I have restricted - * state var in SCACGfbsCtx->state_table to uint16_t. */ - //if (ctx->state_count > 65536) { - // printf("state count exceeded\n"); - // exit(EXIT_FAILURE); - //} - - return ctx->state_count++; -} - -/** - * \internal - * \brief Adds a pid to the output table for a state. - * - * \param state The state to whose output table we should add the pid. - * \param pid The pattern id to add. - * \param mpm_ctx Pointer to the mpm context. - */ -static void SCACGfbsSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - SCACGfbsOutputTable *output_state = &ctx->output_table[state]; - uint32_t i = 0; - - for (i = 0; i < output_state->no_of_entries; i++) { - if (output_state->pids[i] == pid) - return; - } - - output_state->no_of_entries++; - ptmp = SCRealloc(output_state->pids, - output_state->no_of_entries * sizeof(uint32_t)); - if (ptmp == NULL) { - SCFree(output_state->pids); - output_state->pids = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - output_state->pids = ptmp; - - output_state->pids[output_state->no_of_entries - 1] = pid; - - return; -} - -/** - * \brief Helper function used by SCACGfbsCreateGotoTable. Adds a pattern to the - * goto table. - * - * \param pattern Pointer to the pattern. - * \param pattern_len Pattern length. - * \param pid The pattern id, that corresponds to this pattern. We - * need it to updated the output table for this pattern. - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid, - MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int32_t state = 0; - int32_t newstate = 0; - int i = 0; - int p = 0; - - /* walk down the trie till we have a match for the pattern prefix */ - state = 0; - for (i = 0; i < pattern_len; i++) { - if (ctx->goto_table[state][pattern[i]] != SC_AC_GFBS_FAIL) { - state = ctx->goto_table[state][pattern[i]]; - } else { - break; - } - } - - /* add the non-matching pattern suffix to the trie, from the last state - * we left off */ - for (p = i; p < pattern_len; p++) { - newstate = SCACGfbsInitNewState(mpm_ctx); - ctx->goto_table[state][pattern[p]] = newstate; - state = newstate; - } - - /* add this pattern id, to the output table of the last state, where the - * pattern ends in the trie */ - SCACGfbsSetOutputState(state, pid, mpm_ctx); - - return; -} - -/** - * \internal - * \brief Create the goto table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsCreateGotoTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - uint32_t i = 0; - - /* add each pattern to create the goto table */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - SCACGfbsEnter(ctx->parray[i]->ci, ctx->parray[i]->len, - ctx->parray[i]->id, mpm_ctx); - } - - int ascii_code = 0; - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[0][ascii_code] == SC_AC_GFBS_FAIL) { - ctx->goto_table[0][ascii_code] = 0; - } - } - - return; -} - -static inline int SCACGfbsStateQueueIsEmpty(StateQueue *q) -{ - if (q->top == q->bot) - return 1; - else - return 0; -} - -static inline void SCACGfbsEnqueue(StateQueue *q, int32_t state) -{ - int i = 0; - - /*if we already have this */ - for (i = q->bot; i < q->top; i++) { - if (q->store[i] == state) - return; - } - - q->store[q->top++] = state; - - if (q->top == STATE_QUEUE_CONTAINER_SIZE) - q->top = 0; - - if (q->top == q->bot) { - SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " - "Fatal Error. Exiting. Please file a bug report on this"); - exit(EXIT_FAILURE); - } - - return; -} - -static inline int32_t SCACGfbsDequeue(StateQueue *q) -{ - if (q->bot == STATE_QUEUE_CONTAINER_SIZE) - q->bot = 0; - - if (q->bot == q->top) { - SCLogCritical(SC_ERR_AHO_CORASICK, "StateQueue behaving weirdly. " - "Fatal Error. Exiting. Please file a bug report on this"); - exit(EXIT_FAILURE); - } - - return q->store[q->bot++]; -} - -/* -#define SCACGfbsStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0) - -#define SCACGfbsEnqueue(q, state) do { \ - int i = 0; \ - \ - for (i = (q)->bot; i < (q)->top; i++) { \ - if ((q)->store[i] == state) \ - return; \ - } \ - \ - (q)->store[(q)->top++] = state; \ - \ - if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \ - (q)->top = 0; \ - \ - if ((q)->top == (q)->bot) { \ - SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " \ - "Fatal Error. Exiting. Please file a bug report on this"); \ - exit(EXIT_FAILURE); \ - } \ - } while (0) - -#define SCACGfbsDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \ - (((q)->bot == (q)->top) ? \ - (printf("StateQueue behaving " \ - "weirdly. Fatal Error. Exiting. Please " \ - "file a bug report on this"), \ - exit(EXIT_FAILURE)) : 0), \ - (q)->store[(q)->bot++]) \ -*/ - -/** - * \internal - * \brief Club the output data from 2 states and store it in the 1st state. - * dst_state_data = {dst_state_data} UNION {src_state_data} - * - * \todo Use a better way to find union of 2 sets. - * - * \param dst_state First state(also the destination) for the union operation. - * \param src_state Second state for the union operation. - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsClubOutputStates(int32_t dst_state, int32_t src_state, - MpmCtx *mpm_ctx) -{ - void *ptmp; - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - uint32_t i = 0; - uint32_t j = 0; - - SCACGfbsOutputTable *output_dst_state = &ctx->output_table[dst_state]; - SCACGfbsOutputTable *output_src_state = &ctx->output_table[src_state]; - - for (i = 0; i < output_src_state->no_of_entries; i++) { - for (j = 0; j < output_dst_state->no_of_entries; j++) { - if (output_src_state->pids[i] == output_dst_state->pids[j]) { - break; - } - } - if (j == output_dst_state->no_of_entries) { - output_dst_state->no_of_entries++; - - ptmp = SCRealloc(output_dst_state->pids, - (output_dst_state->no_of_entries * sizeof(uint32_t))); - if (ptmp == NULL) { - SCFree(output_dst_state->pids); - output_dst_state->pids = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - output_dst_state->pids = ptmp; - - output_dst_state->pids[output_dst_state->no_of_entries - 1] = - output_src_state->pids[i]; - } - } - - return; -} - -/** - * \internal - * \brief Create the failure table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsCreateFailureTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int ascii_code = 0; - int32_t state = 0; - int32_t r_state = 0; - - StateQueue q; - memset(&q, 0, sizeof(StateQueue)); - - /* allot space for the failure table. A failure entry in the table for - * every state(SCACGfbsCtx->state_count) */ - ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t)); - if (ctx->failure_table == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t)); - - /* add the failure transitions for the 0th state, and add every non-fail - * transition from the 0th state to the queue for further processing - * of failure states */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[0][ascii_code]; - if (temp_state != 0) { - SCACGfbsEnqueue(&q, temp_state); - ctx->failure_table[temp_state] = 0; - } - } - - while (!SCACGfbsStateQueueIsEmpty(&q)) { - /* pick up every state from the queue and add failure transitions */ - r_state = SCACGfbsDequeue(&q); - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - int32_t temp_state = ctx->goto_table[r_state][ascii_code]; - if (temp_state == SC_AC_GFBS_FAIL) - continue; - SCACGfbsEnqueue(&q, temp_state); - state = ctx->failure_table[r_state]; - - while(ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - state = ctx->failure_table[state]; - ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code]; - SCACGfbsClubOutputStates(temp_state, ctx->failure_table[temp_state], - mpm_ctx); - } - } - - return; -} - -/** - * \internal - * \brief Creates a new goto table structure(throw out all the failure - * transitions), to hold the existing goto table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsCreateModGotoTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - if (ctx->state_count < 32767) { - int size = 0; - int32_t state = 0; - for (state = 1; state < ctx->state_count; state++) { - int k = 0; - int ascii_code = 0; - for (; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - k++; - } - - if ((k % 2) != 0) - size += 1; - } - - /* Let us use uint16_t for all. That way we don't have to worry about - * alignment. Technically 8 bits is all we need to store ascii codes, - * but by avoiding it, we save a lot of time on handling alignment */ - size += (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 3 + - ctx->state_count * sizeof(uint8_t) + - 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 1); - ctx->goto_table_mod = SCMalloc(size); - if (ctx->goto_table_mod == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod, 0, size); - //printf("size- %d\n", size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += size; - - /* buffer to hold pointers in the buffer, so that a state can use it - * directly to access its state data */ - ctx->goto_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); - if (ctx->goto_table_mod_pointers == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod_pointers, 0, - ctx->state_count * sizeof(uint8_t *)); - - SC_AC_GFBS_STATE_TYPE_U16 temp_states[256]; - uint16_t *curr_loc = (uint16_t *)ctx->goto_table_mod; - uint16_t *no_of_entries = NULL; - uint16_t *failure_entry = NULL; - uint8_t *ascii_codes = NULL; - uint16_t ascii_code = 0; - uint16_t k = 0; - for (state = 0; state < ctx->state_count; state++) { - /* store the starting location in the buffer for this state */ - ctx->goto_table_mod_pointers[state] = (uint8_t *)curr_loc; - no_of_entries = curr_loc++; - failure_entry = curr_loc++; - ascii_codes = (uint8_t *)curr_loc; - k = 0; - /* store all states that have non fail transitions in the temp buffer */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - ascii_codes[k] = ascii_code; - temp_states[k] = ctx->goto_table[state][ascii_code]; - k++; - } - /* if we have any non fail transitions from our previous for search, - * store the acii codes as well the corresponding states */ - if (k > 0) { - no_of_entries[0] = k; - if (state != 0) { - int jump = (k + 1) & 0xFFE; - curr_loc += jump / 2; - } - memcpy(curr_loc, temp_states, k * sizeof(SC_AC_GFBS_STATE_TYPE_U16)); - curr_loc += k; - } - failure_entry[0] = ctx->failure_table[state]; - } - - /* > 33766 */ - } else { - int size = 0; - int32_t state = 0; - for (state = 1; state < ctx->state_count; state++) { - int k = 0; - int ascii_code = 0; - for (; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - k++; - } - - if ( (k % 4) != 0) - size += (4 - (k % 4)); - } - - /* Let us use uint32_t for all. That way we don't have to worry about - * alignment. Technically 8 bits is all we need to store ascii codes, - * but by avoiding it, we save a lot of time on handling alignment */ - size += (ctx->state_count * (sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 3)+ - ctx->state_count * sizeof(uint8_t) + - 256 * (sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 1)); - ctx->goto_table_mod = SCMalloc(size); - if (ctx->goto_table_mod == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod, 0, size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += size; - - /* buffer to hold pointers in the buffer, so that a state can use it - * directly to access its state data */ - ctx->goto_table_mod_pointers = SCMalloc(ctx->state_count * sizeof(uint8_t *)); - if (ctx->goto_table_mod_pointers == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->goto_table_mod_pointers, 0, - ctx->state_count * sizeof(uint8_t *)); - - SC_AC_GFBS_STATE_TYPE_U32 temp_states[256]; - uint32_t *curr_loc = (uint32_t *)ctx->goto_table_mod; - uint32_t *no_of_entries = NULL; - uint32_t *failure_entry = NULL; - uint8_t *ascii_codes = NULL; - uint16_t ascii_code = 0; - uint16_t k = 0; - for (state = 0; state < ctx->state_count; state++) { - /* store the starting location in the buffer for this state */ - ctx->goto_table_mod_pointers[state] = (uint8_t *)curr_loc; - no_of_entries = curr_loc++; - failure_entry = curr_loc++; - ascii_codes = (uint8_t *)curr_loc; - k = 0; - /* store all states that have non fail transitions in the temp buffer */ - for (ascii_code = 0; ascii_code < 256; ascii_code++) { - if (ctx->goto_table[state][ascii_code] == SC_AC_GFBS_FAIL) - continue; - ascii_codes[k] = ascii_code; - temp_states[k] = ctx->goto_table[state][ascii_code]; - k++; - } - /* if we have any non fail transitions from our previous for search, - * store the acii codes as well the corresponding states */ - if (k > 0) { - no_of_entries[0] = k; - if (state != 0) { - int jump = (k + 3) & 0xFFC; - curr_loc += jump / 4; - } - memcpy(curr_loc, temp_states, k * sizeof(SC_AC_GFBS_STATE_TYPE_U32)); - curr_loc += k; - } - failure_entry[0] = ctx->failure_table[state]; - } - } - - return; -} - -static inline void SCACGfbsClubOutputStatePresenceWithModGotoTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - int state = 0; - int no_of_entries; - int i; - - if (ctx->state_count < 32767) { - uint16_t *states; - for (state = 0; state < ctx->state_count; state++) { - no_of_entries = *((uint16_t *)ctx->goto_table_mod_pointers[state]); - if (no_of_entries == 0) - continue; - - //if (*((uint16_t *)ctx->goto_table_mod_pointers[state] + 1) != 0) { - if (ctx->output_table[((uint16_t *)ctx->goto_table_mod_pointers[state] + 1)[0]].no_of_entries != 0) { - *((uint16_t *)ctx->goto_table_mod_pointers[state] + 1) |= (1 << 15); - } - - if (state == 0) - states = ((uint16_t *)ctx->goto_table_mod_pointers[state] + 2); - else - states = ((uint16_t *)ctx->goto_table_mod_pointers[state] + 2 + ((no_of_entries + 1) & 0xFFE) / 2); - for (i = 0; i < no_of_entries; i++) { - //if (states[i] == 0) - if (ctx->output_table[states[i]].no_of_entries == 0) - continue; - - states[i] |= (1 << 15); - } - } - - } else { - uint32_t *states; - for (state = 0; state < ctx->state_count; state++) { - no_of_entries = *((uint32_t *)ctx->goto_table_mod_pointers[state]); - if (no_of_entries == 0) - continue; - - //if (*((uint32_t *)ctx->goto_table_mod_pointers[state] + 1) != 0) { - if (ctx->output_table[((uint32_t *)ctx->goto_table_mod_pointers[state] + 1)[0]].no_of_entries != 0) { - *((uint32_t *)ctx->goto_table_mod_pointers[state] + 1) |= (1 << 24); - } - - if (state == 0) - states = ((uint32_t *)ctx->goto_table_mod_pointers[state] + 2); - else - states = ((uint32_t *)ctx->goto_table_mod_pointers[state] + 2 + ((no_of_entries + 3) & 0xFFC) / 4); - for (i = 0; i < no_of_entries; i++) { - //if (states[i] == 0) - if (ctx->output_table[states[i]].no_of_entries == 0) - continue; - - states[i] |= (1 << 24); - } - } - } - - return; -} - -static inline void SCACGfbsInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int32_t state = 0; - uint32_t k = 0; - - for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].no_of_entries == 0) - continue; - - for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { - if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= 0x0000FFFF; - ctx->output_table[state].pids[k] |= 1 << 16; - } - } - } - - return; -} - -/** - * \brief Process the patterns and prepare the state table. - * - * \param mpm_ctx Pointer to the mpm context. - */ -static inline void SCACGfbsPrepareStateTable(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - /* create the 0th state in the goto table and output_table */ - SCACGfbsInitNewState(mpm_ctx); - - /* create the goto table */ - SCACGfbsCreateGotoTable(mpm_ctx); - /* create the failure table */ - SCACGfbsCreateFailureTable(mpm_ctx); - /* create the final state(delta) table */ - SCACGfbsCreateModGotoTable(mpm_ctx); - /* club the output state presence with transition entries */ - SCACGfbsClubOutputStatePresenceWithModGotoTable(mpm_ctx); - - /* club nocase entries */ - SCACGfbsInsertCaseSensitiveEntriesForPatterns(mpm_ctx); - - /* we don't need this anymore */ - SCFree(ctx->goto_table); - ctx->goto_table = NULL; - SCFree(ctx->failure_table); - ctx->failure_table = NULL; - - return; -} - -/** - * \brief Process the patterns added to the mpm, and create the internal tables. - * - * \param mpm_ctx Pointer to the mpm context. - */ -int SCACGfbsPreparePatterns(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { - SCLogDebug("No patterns supplied to this mpm_ctx"); - return 0; - } - - /* alloc the pattern array */ - ctx->parray = (SCACGfbsPattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACGfbsPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACGfbsPattern *node = ctx->init_hash[i], *nnode = NULL; - while(node != NULL) { - nnode = node->next; - node->next = NULL; - ctx->parray[p++] = node; - node = nnode; - } - } - - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* the memory consumed by a single state in our goto table */ - //ctx->single_state_size = sizeof(int32_t) * 256; - - /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACGfbsPatternList)); - if (ctx->pid_pat_list == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACGfbsPatternList)); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); - if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, - ctx->parray[i]->original_pat, ctx->parray[i]->len); - ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; - } - } - - /* prepare the state table required by AC */ - SCACGfbsPrepareStateTable(mpm_ctx); - - /* free all the stored patterns. Should save us a good 100-200 mbs */ - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - SCACGfbsFreePattern(mpm_ctx, ctx->parray[i]); - } - } - SCFree(ctx->parray); - ctx->parray = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - - return 0; - -error: - return -1; -} - -/** - * \brief Init the mpm thread context. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param matchsize We don't need this. - */ -void SCACGfbsInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACGfbsThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - memset(mpm_thread_ctx->ctx, 0, sizeof(SCACGfbsThreadCtx)); - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(SCACGfbsThreadCtx); - - return; -} - -/** - * \brief Initialize the AC context. - * - * \param mpm_ctx Mpm context. - * \param module_handle Cuda module handle from the cuda handler API. We don't - * have to worry about this here. - */ -void SCACGfbsInitCtx(MpmCtx *mpm_ctx) -{ - if (mpm_ctx->ctx != NULL) - return; - - mpm_ctx->ctx = SCMalloc(sizeof(SCACGfbsCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - memset(mpm_ctx->ctx, 0, sizeof(SCACGfbsCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACGfbsCtx); - - /* initialize the hash we use to speed up pattern insertions */ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(SCACGfbsPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - memset(ctx->init_hash, 0, sizeof(SCACGfbsPattern *) * INIT_HASH_SIZE); - - /* get conf values for AC from our yaml file. We have no conf values for - * now. We will certainly need this, as we develop the algo */ - SCACGfbsGetConfig(); - - SCReturn; -} - -/** - * \brief Destroy the mpm thread context. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - */ -void SCACGfbsDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - SCACGfbsPrintSearchStats(mpm_thread_ctx); - - if (mpm_thread_ctx->ctx != NULL) { - SCFree(mpm_thread_ctx->ctx); - mpm_thread_ctx->ctx = NULL; - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(SCACGfbsThreadCtx); - } - - return; -} - -/** - * \brief Destroy the mpm context. - * - * \param mpm_ctx Pointer to the mpm context. - */ -void SCACGfbsDestroyCtx(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACGfbsPattern *)); - } - - if (ctx->parray != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - SCACGfbsFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - ctx->parray = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACGfbsPattern *)); - } - - if (ctx->goto_table_mod != NULL) { - SCFree(ctx->goto_table_mod); - ctx->goto_table_mod = NULL; - - mpm_ctx->memory_cnt--; - if (ctx->state_count < 32767) { - mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 3 + - 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U16) * 2); - } else { - mpm_ctx->memory_size -= (ctx->state_count * sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 3 + - 256 * sizeof(SC_AC_GFBS_STATE_TYPE_U32) * 2); - } - } - - if (ctx->goto_table_mod_pointers != NULL) { - SCFree(ctx->goto_table_mod_pointers); - ctx->goto_table_mod_pointers = NULL; - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= ctx->state_count * sizeof(uint8_t *); - } - - if (ctx->output_table != NULL) { - int32_t state_count; - for (state_count = 0; state_count < ctx->state_count; state_count++) { - if (ctx->output_table[state_count].pids != NULL) { - SCFree(ctx->output_table[state_count].pids); - } - } - SCFree(ctx->output_table); - } - - if (ctx->pid_pat_list != NULL) { - int i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { - if (ctx->pid_pat_list[i].cs != NULL) - SCFree(ctx->pid_pat_list[i].cs); - } - SCFree(ctx->pid_pat_list); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACGfbsCtx); - - return; -} - -/** - * \brief The aho corasick search function. - * - * \param mpm_ctx Pointer to the mpm context. - * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param pmq Pointer to the Pattern Matcher Queue to hold - * search matches. - * \param buf Buffer to be searched. - * \param buflen Buffer length. - * - * \retval matches Match count. - */ -uint32_t SCACGfbsSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - int matches = 0; - uint8_t buf_local; - - SCACGfbsPatternList *pid_pat_list = ctx->pid_pat_list; - - /* really hate the extra cmp here, but can't help it */ - if (ctx->state_count < 32767) { - /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ - int32_t temp_state; - uint16_t no_of_entries; - uint8_t *ascii_codes; - uint16_t **goto_table_mod_pointers = (uint16_t **)ctx->goto_table_mod_pointers; - - //int32_t *failure_table = ctx->failure_table; - int i; - /* \todo tried loop unrolling with register var, with no perf increase. Need - * to dig deeper */ - /* with so many var declarations the register declaration here is useless */ - register int32_t state = 0; - for (i = 0; i < buflen; i++) { - if (state == 0) { - state = (goto_table_mod_pointers[0] + 2)[u8_tolower(buf[i])]; - } else { - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x7FFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - buf_local = u8_tolower(buf[i]); - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } - while (temp_state == SC_AC_GFBS_FAIL) { - state = *(goto_table_mod_pointers[state & 0x7FFF] + 1); - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x7FFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x7FFF] + 2); - buf_local = u8_tolower(buf[i]); - if (state == 0) { - temp_state = ((uint16_t *)ascii_codes)[buf_local]; - } else { - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint16_t *)(ascii_codes + ((no_of_entries + 1) & 0xFFE)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } - } /* else - if (no_of_entries == 0) */ - } /* while (temp_state == SC_AC_GFBS_FAIL) */ - - state = temp_state; - - } - - if (state & 0x8000) { - uint32_t no_of_pid_entries = ctx->output_table[state & 0x7FFF].no_of_entries; - uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; - uint32_t k = 0; - for (k = 0; k < no_of_pid_entries; k++) { - if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { - /* inside loop */ - continue; - } - - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { - ; - } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); - } - matches++; - } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - } - matches++; - } - } - } /* if (ctx->output_table[state].no_of_entries != 0) */ - } /* for (i = 0; i < buflen; i++) */ - - } else { - /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ - int32_t temp_state = 0; - uint32_t no_of_entries; - uint8_t *ascii_codes = NULL; - uint32_t **goto_table_mod_pointers = (uint32_t **)ctx->goto_table_mod_pointers; - //int32_t *failure_table = ctx->failure_table; - int i = 0; - /* \todo tried loop unrolling with register var, with no perf increase. Need - * to dig deeper */ - register int32_t state = 0; - for (i = 0; i < buflen; i++) { - if (state == 0) { - state = (goto_table_mod_pointers[0] + 2)[u8_tolower(buf[i])]; - } else { - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x00FFFFFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - buf_local = u8_tolower(buf[i]); - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } - while (temp_state == SC_AC_GFBS_FAIL) { - state = *(goto_table_mod_pointers[state & 0x00FFFFFF] + 1); - - /* get the goto state transition */ - no_of_entries = *(goto_table_mod_pointers[state & 0x00FFFFFF]); - if (no_of_entries == 0) { - temp_state = SC_AC_GFBS_FAIL; - } else { - if (no_of_entries == 1) { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - buf_local = u8_tolower(buf[i]); - if (buf_local == ascii_codes[0]) - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[0]; - else - temp_state = SC_AC_GFBS_FAIL; - } else { - ascii_codes = (uint8_t *)(goto_table_mod_pointers[state & 0x00FFFFFF] + 2); - buf_local = u8_tolower(buf[i]); - if (state == 0) { - temp_state = ((uint32_t *)ascii_codes)[buf_local]; - } else { - int low = 0; - int high = no_of_entries; - int mid; - temp_state = SC_AC_GFBS_FAIL; - while (low <= high) { - mid = (low + high) / 2; - if (ascii_codes[mid] == buf_local) { - temp_state = ((uint32_t *)(ascii_codes + ((no_of_entries + 3) & 0xFFC)))[mid]; - break; - } else if (ascii_codes[mid] < buf_local) { - low = mid + 1; - } else { - high = mid - 1; - } - } - } - } /* else - if (no_of_entries[0] == 1) */ - } /* else - if (no_of_entries[0] == 0) */ - } /* while (temp_state == SC_AC_GFBS_FAIL) */ - state = temp_state; - - } - - if (state & 0x01000000) { - uint32_t no_of_pid_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries; - uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; - uint32_t k = 0; - for (k = 0; k < no_of_pid_entries; k++) { - if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { - /* inside loop */ - continue; - } - - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { - ; - } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = (pids[k] & 0x0000FFFF); - } - matches++; - } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - } - matches++; - } - //loop1: - //; - } - } /* if (ctx->output_table[state].no_of_entries != 0) */ - } /* for (i = 0; i < buflen; i++) */ - } - - return matches; -} - -/** - * \brief Add a case insensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patnen The pattern length. - * \param offset Ignored. - * \param depth Ignored. - * \param pid The pattern id. - * \param sid Ignored. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCACGfbsAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -/** - * \brief Add a case sensitive pattern. Although we have different calls for - * adding case sensitive and insensitive patterns, we make a single call - * for either case. No special treatment for either case. - * - * \param mpm_ctx Pointer to the mpm context. - * \param pat The pattern to add. - * \param patnen The pattern length. - * \param offset Ignored. - * \param depth Ignored. - * \param pid The pattern id. - * \param sid Ignored. - * \param flags Flags associated with this pattern. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -int SCACGfbsAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) -{ - return SCACGfbsAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -void SCACGfbsPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ - -#ifdef SC_AC_COUNTERS - SCACGfbsThreadCtx *ctx = (SCACGfbsThreadCtx *)mpm_thread_ctx->ctx; - printf("AC Thread Search stats (ctx %p)\n", ctx); - printf("Total calls: %" PRIu32 "\n", ctx->total_calls); - printf("Total matches: %" PRIu64 "\n", ctx->total_matches); -#endif /* SC_AC_COUNTERS */ - - return; -} - -void SCACGfbsPrintInfo(MpmCtx *mpm_ctx) -{ - SCACGfbsCtx *ctx = (SCACGfbsCtx *)mpm_ctx->ctx; - - printf("MPM AC Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeof:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" SCACGfbsCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsCtx)); - printf(" SCACGfbsPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsPattern)); - printf(" SCACGfbsPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACGfbsPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count); - printf("\n"); - - return; -} - -/*************************************Unittests********************************/ - -#ifdef UNITTESTS - -static int SCACGfbsTest01(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest02(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest03(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest04(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest05(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghjiklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest06(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcd"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest07(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); - /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); - /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); - /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - 30, 0, 0, 5, 0, 0); - /* total matches: 135 */ - PmqSetup(&pmq, 6); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest08(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest09(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest10(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest11(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) - goto end; - if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) - goto end; - PmqSetup(&pmq, 4); - - if (SCACGfbsPreparePatterns(&mpm_ctx) == -1) - goto end; - - result = 1; - - char *buf = "he"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "she"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - buf = "his"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 1); - buf = "hers"; - result &= (SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, - strlen(buf)) == 2); - - end: - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest12(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest13(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest14(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest15(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest16(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzABC"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzABC"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest17(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcdefghijklmnopqrstuvwxyzAB"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyzAB"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest18(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest19(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest20(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; - MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest21(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest22(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "abcdefghijklmnopqrstuvwxyz"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest23(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 0) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest24(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 1 */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)"aa", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest25(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest26(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "works"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - if (cnt == 1) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest27(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "tone"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest28(void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; - - memset(&mpm_ctx, 0, sizeof(MpmCtx)); - memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - MpmInitCtx(&mpm_ctx, MPM_AC_GFBS); - SCACGfbsInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); - - /* 0 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); - - SCACGfbsPreparePatterns(&mpm_ctx); - - char *buf = "tONE"; - uint32_t cnt = SCACGfbsSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, - (uint8_t *)buf, strlen(buf)); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - SCACGfbsDestroyCtx(&mpm_ctx); - SCACGfbsDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); - PmqFree(&pmq); - return result; -} - -static int SCACGfbsTest29(void) -{ - uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; - uint16_t buflen = strlen((char *)buf); - Packet *p = NULL; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int result = 0; - - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - goto end; - de_ctx->mpm_matcher = MPM_AC_GFBS; - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); - if (de_ctx->sig_list == NULL) - goto end; - de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any " - "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)"); - if (de_ctx->sig_list->next == NULL) - goto end; - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (PacketAlertCheck(p, 1) != 1) { - printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); - goto end; - } - if (PacketAlertCheck(p, 2) != 1) { - printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); - goto end; - } - - result = 1; -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - } - - UTHFreePackets(&p, 1); - return result; -} - -#endif /* UNITTESTS */ - -void SCACGfbsRegisterTests(void) -{ - -#ifdef UNITTESTS - UtRegisterTest("SCACGfbsTest01", SCACGfbsTest01, 1); - UtRegisterTest("SCACGfbsTest02", SCACGfbsTest02, 1); - UtRegisterTest("SCACGfbsTest03", SCACGfbsTest03, 1); - UtRegisterTest("SCACGfbsTest04", SCACGfbsTest04, 1); - UtRegisterTest("SCACGfbsTest05", SCACGfbsTest05, 1); - UtRegisterTest("SCACGfbsTest06", SCACGfbsTest06, 1); - UtRegisterTest("SCACGfbsTest07", SCACGfbsTest07, 1); - UtRegisterTest("SCACGfbsTest08", SCACGfbsTest08, 1); - UtRegisterTest("SCACGfbsTest09", SCACGfbsTest09, 1); - UtRegisterTest("SCACGfbsTest10", SCACGfbsTest10, 1); - UtRegisterTest("SCACGfbsTest11", SCACGfbsTest11, 1); - UtRegisterTest("SCACGfbsTest12", SCACGfbsTest12, 1); - UtRegisterTest("SCACGfbsTest13", SCACGfbsTest13, 1); - UtRegisterTest("SCACGfbsTest14", SCACGfbsTest14, 1); - UtRegisterTest("SCACGfbsTest15", SCACGfbsTest15, 1); - UtRegisterTest("SCACGfbsTest16", SCACGfbsTest16, 1); - UtRegisterTest("SCACGfbsTest17", SCACGfbsTest17, 1); - UtRegisterTest("SCACGfbsTest18", SCACGfbsTest18, 1); - UtRegisterTest("SCACGfbsTest19", SCACGfbsTest19, 1); - UtRegisterTest("SCACGfbsTest20", SCACGfbsTest20, 1); - UtRegisterTest("SCACGfbsTest21", SCACGfbsTest21, 1); - UtRegisterTest("SCACGfbsTest22", SCACGfbsTest22, 1); - UtRegisterTest("SCACGfbsTest23", SCACGfbsTest23, 1); - UtRegisterTest("SCACGfbsTest24", SCACGfbsTest24, 1); - UtRegisterTest("SCACGfbsTest25", SCACGfbsTest25, 1); - UtRegisterTest("SCACGfbsTest26", SCACGfbsTest26, 1); - UtRegisterTest("SCACGfbsTest27", SCACGfbsTest27, 1); - UtRegisterTest("SCACGfbsTest28", SCACGfbsTest28, 1); - UtRegisterTest("SCACGfbsTest29", SCACGfbsTest29, 1); -#endif - - return; -} diff --git a/src/util-mpm-ac-gfbs.h b/src/util-mpm-ac-gfbs.h deleted file mode 100644 index e790c685b77f..000000000000 --- a/src/util-mpm-ac-gfbs.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Anoop Saldanha - * - */ - -#define SC_AC_GFBS_STATE_TYPE_U16 uint16_t -#define SC_AC_GFBS_STATE_TYPE_U32 uint32_t - -typedef struct SCACGfbsPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - struct SCACGfbsPattern_ *next; -} SCACGfbsPattern; - -typedef struct SCACGfbsPatternList_ { - uint8_t *cs; - uint16_t patlen; -} SCACGfbsPatternList; - -typedef struct SCACGfbsOutputTable_ { - /* list of pattern sids */ - uint32_t *pids; - /* no of entries we have in pids */ - uint32_t no_of_entries; -} SCACGfbsOutputTable; - -typedef struct SCACGfbsGotoTableMod_ { - /* each of these below declarations will be of type uint32_t, if the state - * count exceeds 65535, the maximum value a 16 bit unsigned var can hold */ - - /* no of entries stored below */ - uint16_t no_of_entries; - - /* the ascii codes over which we have state transitions */ - uint16_t *ascii_codes; - /* the states that correspond to the ascii_codes above */ - uint16_t *states; -} SCACGfbsGotoTableMod_; - -typedef struct SCACGfbsCtx_ { - /* hash used during ctx initialization */ - SCACGfbsPattern **init_hash; - - /* pattern arrays. We need this only during the goto table creation phase */ - SCACGfbsPattern **parray; - - /* no of states used by ac */ - int32_t state_count; - /* the modified goto_table */ - uint8_t *goto_table_mod; - uint8_t **goto_table_mod_pointers; - - /* goto_table, failure table and output table. Needed to create state_table. - * Will be freed, once we have created the goto_table_mod */ - int32_t (*goto_table)[256]; - int32_t *failure_table; - SCACGfbsOutputTable *output_table; - SCACGfbsPatternList *pid_pat_list; - - /* the size of each state */ - uint16_t single_state_size; - uint16_t max_pat_id; -} SCACGfbsCtx; - -typedef struct SCACGfbsThreadCtx_ { - /* the total calls we make to the search function */ - uint32_t total_calls; - /* the total patterns that we ended up matching against */ - uint64_t total_matches; -} SCACGfbsThreadCtx; - -void MpmACGfbsRegister(void); diff --git a/src/util-mpm-ac-tile-small.c b/src/util-mpm-ac-tile-small.c index cb468e5a2b19..a5e1ef0eacaf 100644 --- a/src/util-mpm-ac-tile-small.c +++ b/src/util-mpm-ac-tile-small.c @@ -31,43 +31,46 @@ #ifdef FUNC_NAME /* This function handles (ctx->state_count < 32767) */ -uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t FUNC_NAME(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { int i = 0; int matches = 0; - uint8_t* restrict xlate = ctx->translate_table; + uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; + memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); + + const uint8_t* restrict xlate = ctx->translate_table; STYPE *state_table = (STYPE*)ctx->state_table; STYPE state = 0; int c = xlate[buf[0]]; /* If buflen at least 4 bytes and buf 4-byte aligned. */ - if (buflen >= 4 && ((uint64_t)buf & 0x3) == 0) { - BTYPE data = *(BTYPE* restrict)(&buf[0]); + if (buflen >= (4 + EXTRA) && ((uintptr_t)buf & 0x3) == 0) { + BUF_TYPE data = *(BUF_TYPE* restrict)(&buf[0]); uint64_t index = 0; /* Process 4*floor(buflen/4) bytes. */ i = 0; - while (i < (buflen & ~0x3)) { - BTYPE data1 = *(BTYPE* restrict)(&buf[i + 4]); + while ((i + EXTRA) < (buflen & ~0x3)) { + BUF_TYPE data1 = *(BUF_TYPE* restrict)(&buf[i + 4]); index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE1(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } i++; index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE2(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } i++; index = SINDEX(index, state); state = SLOAD(state_table + index + c); c = xlate[BYTE3(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } data = data1; i++; @@ -75,19 +78,22 @@ uint32_t FUNC_NAME(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, state = SLOAD(state_table + index + c); c = xlate[BYTE0(data)]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } i++; } } /* Process buflen % 4 bytes. */ for (; i < buflen; i++) { - uint64_t index = 0 ; + size_t index = 0 ; index = SINDEX(index, state); state = SLOAD(state_table + index + c); - c = xlate[buf[i+1]]; +#ifndef __tile__ + if (likely(i+1 < buflen)) +#endif + c = xlate[buf[i+1]]; if (unlikely(SCHECK(state))) { - matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches); + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } } /* for (i = 0; i < buflen; i++) */ diff --git a/src/util-mpm-ac-tile.c b/src/util-mpm-ac-tile.c index f74f04d2150f..e6b3d1ed5378 100644 --- a/src/util-mpm-ac-tile.c +++ b/src/util-mpm-ac-tile.c @@ -68,6 +68,8 @@ #include "suricata-common.h" #include "suricata.h" +#if __BYTE_ORDER == __LITTLE_ENDIAN + #include "detect.h" #include "detect-parse.h" #include "detect-engine.h" @@ -80,71 +82,62 @@ #include "util-memcpy.h" #include "util-mpm-ac-tile.h" -#ifndef __tile__ -void MpmACTileRegister(void) -{ -} -#endif - -/* There are Tilera Tile-Gx specific optimizations in this code. */ -#ifdef __tile__ - void SCACTileInitCtx(MpmCtx *); -void SCACTileInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCACTileInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCACTileDestroyCtx(MpmCtx *); void SCACTileDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACTileAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACTileAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACTilePreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, +uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); void SCACTilePrintInfo(MpmCtx *mpm_ctx); void SCACTilePrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACTileRegisterTests(void); -uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall256(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall128(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall64(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall32(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall16(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchSmall8(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); - -uint32_t SCACTileSearchTiny256(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny128(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny64(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny32(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny16(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); -uint32_t SCACTileSearchTiny8(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchSmall8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); + +uint32_t SCACTileSearchTiny256(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny128(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny64(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny32(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny16(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); +uint32_t SCACTileSearchTiny8(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen); static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx); @@ -152,8 +145,6 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_TILE_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 @@ -176,187 +167,6 @@ static void SCACTileGetConfig() { } -/** - * \internal - * \brief Compares 2 patterns. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param p Pointer to the first pattern(SCACTilePattern). - * \param pat Pointer to the second pattern(raw pattern array). - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline int SCACTileCmpPattern(SCACTilePattern *p, uint8_t *pat, - uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (flags & MPM_PATTERN_FLAG_NOCASE) { - // Case insensitive - if (SCMemcmpLowercase(p->cs, pat, patlen) != 0) - return 0; - - } else { - // Case sensitive - if (SCMemcmp(p->cs, pat, patlen) != 0) - return 0; - } - - return 1; -} - -/** - * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACTileInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACTilePattern *SCACTileInitHashLookup(SCACTileCtx *ctx, - uint8_t *pat, - uint16_t patlen, - char flags, - uint32_t pid) -{ - uint32_t hash = SCACTileInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCACTilePattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) { - return t; - } - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. - * - * \param mpm_ctx Pointer to the mpm context. - * - * \retval p Pointer to the newly created pattern. - */ -static inline SCACTilePattern *SCACTileAllocPattern(MpmCtx *mpm_ctx) -{ - SCACTilePattern *p = SCMalloc(sizeof(SCACTilePattern)); - if (unlikely(p == NULL)) { - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(SCACTilePattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACTilePattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACTilePattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACTilePattern instance to be freed. - * \param free Free the above pointer or not. - */ -static void SCACTileFreePattern(MpmCtx *mpm_ctx, SCACTilePattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACTilePattern); - } -} - -static inline uint32_t SCACTileInitHash(SCACTilePattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACTileInitHashAdd(SCACTileCtx *ctx, SCACTilePattern *p) -{ - uint32_t hash = SCACTileInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACTilePattern *tt = NULL; - SCACTilePattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - /** * \internal @@ -365,7 +175,7 @@ static inline int SCACTileInitHashAdd(SCACTileCtx *ctx, SCACTilePattern *p) * characters, so could just set to 1 instead of counting. */ static inline void SCACTileHistogramAlphabet(SCACTileCtx *ctx, - SCACTilePattern *p) + MpmPattern *p) { for (int i = 0; i < p->len; i++) { ctx->alpha_hist[p->ci[i]]++; @@ -416,121 +226,26 @@ static void SCACTileInitTranslateTable(SCACTileCtx *ctx) ctx->alphabet_storage = 256; } -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACTileAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) +static void SCACTileReallocOutputTable(SCACTileCtx *ctx, int new_state_count) { - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; - SCACTileCtx *ctx = search_ctx->init_ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - /* Check if we have already inserted this pattern. */ - SCACTilePattern *p = SCACTileInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACTileAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACTileInitHashAdd(ctx, p); - /* Count alphabet usages */ - SCACTileHistogramAlphabet(ctx, p); - - //if (mpm_ctx->pattern_cnt == 65535) { - // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - // "insert anymore. Exiting"); - // exit(EXIT_FAILURE); - //} - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; + /* reallocate space in the output table for the new state */ + size_t size = ctx->allocated_state_count * sizeof(SCACTileOutputTable); + void *ptmp = SCRealloc(ctx->output_table, size); + if (ptmp == NULL) { + SCFree(ctx->output_table); + ctx->output_table = NULL; + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); } - - return 0; - -error: - SCACTileFreePattern(mpm_ctx, p); - return -1; + ctx->output_table = ptmp; } static void SCACTileReallocState(SCACTileCtx *ctx, int new_state_count) { - void *ptmp; - int size = 0; - /* reallocate space in the goto table to include a new state */ - size = ctx->allocated_state_count * sizeof(int32_t) * 256; - ptmp = SCRealloc(ctx->goto_table, size); + size_t size = ctx->allocated_state_count * sizeof(int32_t) * 256; + void *ptmp = SCRealloc(ctx->goto_table, size); if (ptmp == NULL) { SCFree(ctx->goto_table); ctx->goto_table = NULL; @@ -539,16 +254,7 @@ static void SCACTileReallocState(SCACTileCtx *ctx, int new_state_count) } ctx->goto_table = ptmp; - /* reallocate space in the output table for the new state */ - size = ctx->allocated_state_count * sizeof(SCACTileOutputTable); - ptmp = SCRealloc(ctx->output_table, size); - if (ptmp == NULL) { - SCFree(ctx->output_table); - ctx->output_table = NULL; - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - ctx->output_table = ptmp; + SCACTileReallocOutputTable(ctx, new_state_count); } /** @@ -594,7 +300,7 @@ static inline int SCACTileInitNewState(MpmCtx *mpm_ctx) * \param pid The pattern id to add. * \param mpm_ctx Pointer to the mpm context. */ -static void SCACTileSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) +static void SCACTileSetOutputState(int32_t state, MpmPatternIndex pindex, MpmCtx *mpm_ctx) { void *ptmp; SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; @@ -605,24 +311,24 @@ static void SCACTileSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) /* Don't add the pattern more than once to the same state. */ for (i = 0; i < output_state->no_of_entries; i++) { - if (output_state->pids[i] == pid) + if (output_state->patterns[i] == pindex) return; } /* Increase the size of the array of pids for this state and add * the new pid. */ output_state->no_of_entries++; - ptmp = SCRealloc(output_state->pids, - output_state->no_of_entries * sizeof(uint32_t)); + ptmp = SCRealloc(output_state->patterns, + output_state->no_of_entries * sizeof(MpmPatternIndex)); if (ptmp == NULL) { - SCFree(output_state->pids); - output_state->pids = NULL; + SCFree(output_state->patterns); + output_state->patterns = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - output_state->pids = ptmp; + output_state->patterns = ptmp; - output_state->pids[output_state->no_of_entries - 1] = pid; + output_state->patterns[output_state->no_of_entries - 1] = pindex; } /** @@ -636,7 +342,7 @@ static void SCACTileSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx) * \param mpm_ctx Pointer to the mpm context. */ static void SCACTileEnter(uint8_t *pattern, uint16_t pattern_len, - uint32_t pid, MpmCtx *mpm_ctx) + MpmPatternIndex pindex, MpmCtx *mpm_ctx) { SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; SCACTileCtx *ctx = search_ctx->init_ctx; @@ -667,7 +373,7 @@ static void SCACTileEnter(uint8_t *pattern, uint16_t pattern_len, /* Add this pattern id, to the output table of the last state, where the * pattern ends in the trie */ - SCACTileSetOutputState(state, pid, mpm_ctx); + SCACTileSetOutputState(state, pindex, mpm_ctx); } /** @@ -686,7 +392,7 @@ static void SCACTileCreateGotoTable(MpmCtx *mpm_ctx) /* add each pattern to create the goto table */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { SCACTileEnter(ctx->parray[i]->ci, ctx->parray[i]->len, - ctx->parray[i]->id, mpm_ctx); + i, mpm_ctx); } int aa = 0; @@ -766,25 +472,25 @@ static void SCACTileClubOutputStates(int32_t dst_state, for (i = 0; i < output_src_state->no_of_entries; i++) { for (j = 0; j < output_dst_state->no_of_entries; j++) { - if (output_src_state->pids[i] == output_dst_state->pids[j]) { + if (output_src_state->patterns[i] == output_dst_state->patterns[j]) { break; } } if (j == output_dst_state->no_of_entries) { output_dst_state->no_of_entries++; - ptmp = SCRealloc(output_dst_state->pids, + ptmp = SCRealloc(output_dst_state->patterns, (output_dst_state->no_of_entries * sizeof(uint32_t))); if (ptmp == NULL) { - SCFree(output_dst_state->pids); - output_dst_state->pids = NULL; + SCFree(output_dst_state->patterns); + output_dst_state->patterns = NULL; SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - output_dst_state->pids = ptmp; + output_dst_state->patterns = ptmp; - output_dst_state->pids[output_dst_state->no_of_entries - 1] = - output_src_state->pids[i]; + output_dst_state->patterns[output_dst_state->no_of_entries - 1] = + output_src_state->patterns[i]; } } } @@ -1008,7 +714,7 @@ static void SCACTileClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) SCACTileCtx *ctx = search_ctx->init_ctx; int aa = 0; - int state = 0; + uint32_t state = 0; /* Allocate next-state table. */ int size = ctx->state_count * ctx->bytes_per_state * ctx->alphabet_storage; @@ -1023,7 +729,7 @@ static void SCACTileClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx) mpm_ctx->memory_cnt++; mpm_ctx->memory_size += size; - SCLogInfo("Delta Table size %d, alphabet: %d, %d-byte states: %d", + SCLogDebug("Delta Table size %d, alphabet: %d, %d-byte states: %d", size, ctx->alphabet_size, ctx->bytes_per_state, ctx->state_count); /* Copy next state from Goto table, which is 32 bits and encode it into the next @@ -1044,7 +750,7 @@ static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; SCACTileCtx *ctx = search_ctx->init_ctx; - int state = 0; + uint32_t state = 0; uint32_t k = 0; for (state = 0; state < ctx->state_count; state++) { @@ -1052,9 +758,10 @@ static inline void SCACTileInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx continue; for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { - if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= 0x0000FFFF; - ctx->output_table[state].pids[k] |= 1 << 16; + if (ctx->pattern_list[ctx->output_table[state].patterns[k]].cs != NULL) { + /* TODO - Find better way to store this. */ + ctx->output_table[state].patterns[k] &= 0x0FFFFFFF; + ctx->output_table[state].patterns[k] |= (uint32_t)1 << 31; } } } @@ -1133,7 +840,7 @@ static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) SCACTileCtx *ctx = search_ctx->init_ctx; /* Resize the output table to be only as big as its final size. */ - SCACTileReallocState(ctx, ctx->state_count); + SCACTileReallocOutputTable(ctx, ctx->state_count); search_ctx->search = ctx->search; memcpy(search_ctx->translate_table, ctx->translate_table, sizeof(ctx->translate_table)); @@ -1146,9 +853,14 @@ static void SCACTilePrepareSearch(MpmCtx *mpm_ctx) /* TODO: Could be made more compact */ search_ctx->output_table = ctx->output_table; ctx->output_table = NULL; + search_ctx->state_count = ctx->state_count; - search_ctx->pid_pat_list = ctx->pid_pat_list; - ctx->pid_pat_list = NULL; + search_ctx->pattern_list = ctx->pattern_list; + ctx->pattern_list = NULL; + search_ctx->pattern_cnt = mpm_ctx->pattern_cnt; + + /* One bit per pattern, rounded up to the next byte size. */ + search_ctx->mpm_bitarray_size = (mpm_ctx->pattern_cnt + 7) / 8; /* Can now free the Initialization data */ SCACTileDestroyInitCtx(mpm_ctx); @@ -1168,53 +880,79 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) return 0; } SCACTileCtx *ctx = search_ctx->init_ctx; - if (ctx->init_hash == NULL) { + if (mpm_ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ - ctx->parray = (SCACTilePattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACTilePattern *)); + ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt * + sizeof(MpmPattern *)); if (ctx->parray == NULL) goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACTilePattern *)); + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACTilePattern *node = ctx->init_hash[i], *nnode = NULL; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; ctx->parray[p++] = node; + SCACTileHistogramAlphabet(ctx, node); node = nnode; } } /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; - /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACTilePatternList)); - if (ctx->pid_pat_list == NULL) { + /* Handle case patterns by storing a copy of the pattern to compare + * to each possible match (no-case). + * + * Allocate the memory for the array and each of the strings as one block. + */ + size_t string_space_needed = 0; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { + /* Round up to next 8 byte aligned length */ + uint32_t space = ((ctx->parray[i]->len + 7) / 8) * 8; + string_space_needed += space; + } + } + + size_t pattern_list_size = mpm_ctx->pattern_cnt * sizeof(SCACTilePatternList); + size_t mem_size = string_space_needed + pattern_list_size; + void *mem_block = SCCalloc(1, mem_size); + if (mem_block == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACTilePatternList)); + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += mem_size; + /* Split the allocated block into pattern list array and string space. */ + ctx->pattern_list = mem_block; + uint8_t *string_space = mem_block + pattern_list_size; + /* Now make the copies of the no-case strings. */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { - ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len); - if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } - memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs, - ctx->parray[i]->original_pat, ctx->parray[i]->len); - ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; + uint32_t len = ctx->parray[i]->len; + uint32_t space = ((len + 7) / 8) * 8; + memcpy(string_space, ctx->parray[i]->original_pat, len); + ctx->pattern_list[i].cs = string_space; + ctx->pattern_list[i].patlen = len; + string_space += space; } + ctx->pattern_list[i].pid = ctx->parray[i]->id; + + /* ACPatternList now owns this memory */ + ctx->pattern_list[i].sids_size = ctx->parray[i]->sids_size; + ctx->pattern_list[i].sids = ctx->parray[i]->sids; + ctx->parray[i]->sids = NULL; + ctx->parray[i]->sids_size = 0; } /* prepare the state table required by AC */ @@ -1234,10 +972,8 @@ int SCACTilePreparePatterns(MpmCtx *mpm_ctx) * * \param mpm_ctx Pointer to the mpm context. * \param mpm_thread_ctx Pointer to the mpm thread context. - * \param matchsize We don't need this. */ -void SCACTileInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - uint32_t matchsize) +void SCACTileInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1283,12 +1019,11 @@ void SCACTileInitCtx(MpmCtx *mpm_ctx) mpm_ctx->memory_size += sizeof(SCACTileCtx); /* initialize the hash we use to speed up pattern insertions */ - SCACTileCtx *ctx = search_ctx->init_ctx; - ctx->init_hash = SCMalloc(sizeof(SCACTilePattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); + if (mpm_ctx->init_hash == NULL) { exit(EXIT_FAILURE); } - memset(ctx->init_hash, 0, sizeof(SCACTilePattern *) * INIT_HASH_SIZE); + memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ @@ -1321,16 +1056,16 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) if (ctx == NULL) return; - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACTileFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } @@ -1347,26 +1082,30 @@ static void SCACTileDestroyInitCtx(MpmCtx *mpm_ctx) } if (ctx->output_table != NULL) { - int state; + uint32_t state; for (state = 0; state < ctx->state_count; state++) { - if (ctx->output_table[state].pids != NULL) { - SCFree(ctx->output_table[state].pids); + if (ctx->output_table[state].patterns != NULL) { + SCFree(ctx->output_table[state].patterns); } } SCFree(ctx->output_table); } - if (ctx->pid_pat_list != NULL) { - int i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { - if (ctx->pid_pat_list[i].cs != NULL) - SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pattern_list != NULL) { + uint32_t i; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->pattern_list[i].cs != NULL) + SCFree(ctx->pattern_list[i].cs); + if (ctx->pattern_list[i].sids != NULL) + SCFree(ctx->pattern_list[i].sids); } - SCFree(ctx->pid_pat_list); + SCFree(ctx->pattern_list); } SCFree(ctx); search_ctx->init_ctx = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCACTileCtx); } /** @@ -1383,7 +1122,27 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) /* Destroy Initialization data */ SCACTileDestroyInitCtx(mpm_ctx); - // TODO: Free Search tables + /* Free Search tables */ + SCFree(search_ctx->state_table); + + if (search_ctx->pattern_list != NULL) { + uint32_t i; + for (i = 0; i < search_ctx->pattern_cnt; i++) { + if (search_ctx->pattern_list[i].sids != NULL) + SCFree(search_ctx->pattern_list[i].sids); + } + SCFree(search_ctx->pattern_list); + } + + if (search_ctx->output_table != NULL) { + uint32_t state; + for (state = 0; state < search_ctx->state_count; state++) { + if (search_ctx->output_table[state].patterns != NULL) { + SCFree(search_ctx->output_table[state].patterns); + } + } + SCFree(search_ctx->output_table); + } SCFree(search_ctx); mpm_ctx->ctx = NULL; @@ -1397,50 +1156,68 @@ void SCACTileDestroyCtx(MpmCtx *mpm_ctx) */ #define SCHECK(x) ((x) > 0) -#define BTYPE int32_t +#define BUF_TYPE int32_t // Extract byte N=0,1,2,3 from x +#ifdef __tile__ #define BYTE0(x) __insn_bfextu(x, 0, 7) #define BYTE1(x) __insn_bfextu(x, 8, 15) #define BYTE2(x) __insn_bfextu(x, 16, 23) #define BYTE3(x) __insn_bfextu(x, 24, 31) +#define EXTRA 0 +#else /* fallback */ +#define BYTE0(x) (((x) & 0x000000ff) >> 0) +#define BYTE1(x) (((x) & 0x0000ff00) >> 8) +#define BYTE2(x) (((x) & 0x00ff0000) >> 16) +#define BYTE3(x) (((x) & 0xff000000) >> 24) +#define EXTRA 4 // need 4 extra bytes to avoid OOB reads +#endif -int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen, - uint16_t state, int i, int matches) +int CheckMatch(const SCACTileSearchCtx *ctx, PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen, + uint16_t state, int i, int matches, + uint8_t *mpm_bitarray) { - SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; - uint8_t *buf_offset = buf + i + 1; // Lift out of loop + SCACTilePatternList *pattern_list = ctx->pattern_list; + const uint8_t *buf_offset = buf + i + 1; // Lift out of loop uint32_t no_of_entries = ctx->output_table[state].no_of_entries; - uint32_t *pids = ctx->output_table[state].pids; - uint8_t *bitarray = pmq->pattern_id_bitarray; + MpmPatternIndex *patterns = ctx->output_table[state].patterns; uint32_t k; - /* Where to start storing new patterns */ - uint32_t *orig_pattern = pmq->pattern_id_array + pmq->pattern_id_array_cnt; - uint32_t *new_pattern = orig_pattern; - for (k = 0; k < no_of_entries; k++) { - uint16_t lower_pid = pids[k] & 0x0000FFFF; - if (pids[k] & 0xFFFF0000) { - uint16_t patlen = pid_pat_list[lower_pid].patlen; - if (SCMemcmp(pid_pat_list[lower_pid].cs, buf_offset - patlen, patlen) != 0) { - /* inside loop */ + MpmPatternIndex pindex = patterns[k] & 0x0FFFFFFF; + if (mpm_bitarray[pindex / 8] & (1 << (pindex % 8))) { + /* Pattern already seen by this MPM. */ + /* NOTE: This is faster then rechecking if it is a case-sensitive match + * since we know this pattern has already been seen, but imcrementing + * matches here could over report matches. For example if the case-sensitive + * pattern is "Foo" and the string is "Foo bar foo", matches would be reported + * as 2, when it should really be 1, since "foo" is not a true match. + */ + matches++; + continue; + } + /* Double check case-sensitve match now. */ + if (patterns[k] >> 31) { + uint16_t patlen = pattern_list[pindex].patlen; +#ifdef __tile__ + if (SCMemcmpNZ(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { +#else + if (SCMemcmp(pattern_list[pindex].cs, buf_offset - patlen, patlen) != 0) { +#endif + /* Case-sensitive match failed. */ continue; } } - if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { - ; - } else { - bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); - *new_pattern++ = lower_pid; - } + /* New match found */ + mpm_bitarray[pindex / 8] |= (1 << (pindex % 8)); + + /* Always add the Signature IDs, since they could be different in the current MPM + * than in a previous MPM on the same PMQ when finding the same pattern. + */ + PrefilterAddSids(pmq, pattern_list[pindex].sids, + pattern_list[pindex].sids_size); matches++; } - /* Only update the pattern count if a new pattern was added. - * No need to compute it or dirty that cache data for no change. - */ - if (new_pattern != orig_pattern) - pmq->pattern_id_array_cnt = new_pattern - orig_pattern; return matches; } @@ -1457,10 +1234,10 @@ int CheckMatch(SCACTileSearchCtx *ctx, PatternMatcherQueue *pmq, * * \retval matches Match count. */ -uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCACTileSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { - SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; + const SCACTileSearchCtx *search_ctx = (SCACTileSearchCtx *)mpm_ctx->ctx; if (buflen == 0) return 0; @@ -1470,52 +1247,23 @@ uint32_t SCACTileSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, } /* This function handles (ctx->state_count >= 32767) */ -uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, - uint8_t *buf, uint16_t buflen) +uint32_t SCACTileSearchLarge(const SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, + const uint8_t *buf, uint16_t buflen) { int i = 0; int matches = 0; - SCACTilePatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t mpm_bitarray[ctx->mpm_bitarray_size]; + memset(mpm_bitarray, 0, ctx->mpm_bitarray_size); - uint8_t* restrict xlate = ctx->translate_table; + const uint8_t* restrict xlate = ctx->translate_table; register int state = 0; int32_t (*state_table_u32)[256] = ctx->state_table; for (i = 0; i < buflen; i++) { state = state_table_u32[state & 0x00FFFFFF][xlate[buf[i]]]; if (SCHECK(state)) { - uint32_t no_of_entries = ctx->output_table[state].no_of_entries; - uint32_t *pids = ctx->output_table[state].pids; - uint32_t k; - for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { - /* inside loop */ - continue; - } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & - (1 << ((pids[k] & 0x0000FFFF) % 8))) { - ; - } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= - (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = - pids[k] & 0x0000FFFF; - } - matches++; - } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { - ; - } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; - } - matches++; - } - } + matches = CheckMatch(ctx, pmq, buf, buflen, state, i, matches, mpm_bitarray); } } /* for (i = 0; i < buflen; i++) */ @@ -1527,13 +1275,22 @@ uint32_t SCACTileSearchLarge(SCACTileSearchCtx *ctx, MpmThreadCtx *mpm_thread_ct * Next state entry has MSB as "match" and 15 LSB bits as next-state index. */ // y = 1<pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); @@ -1726,9 +1487,11 @@ void SCACTilePrintInfo(MpmCtx *mpm_ctx) */ void MpmACTileRegister(void) { +#ifdef __tile__ mpm_table[MPM_AC_TILE].name = "ac-tile"; - mpm_table[MPM_AC_TILE].max_pattern_length = 0; - +#else + mpm_table[MPM_AC_TILE].name = "ac-ks"; +#endif mpm_table[MPM_AC_TILE].InitCtx = SCACTileInitCtx; mpm_table[MPM_AC_TILE].InitThreadCtx = SCACTileInitThreadCtx; mpm_table[MPM_AC_TILE].DestroyCtx = SCACTileDestroyCtx; @@ -1737,7 +1500,6 @@ void MpmACTileRegister(void) mpm_table[MPM_AC_TILE].AddPatternNocase = SCACTileAddPatternCI; mpm_table[MPM_AC_TILE].Prepare = SCACTilePreparePatterns; mpm_table[MPM_AC_TILE].Search = SCACTileSearch; - mpm_table[MPM_AC_TILE].Cleanup = NULL; mpm_table[MPM_AC_TILE].PrintCtx = SCACTilePrintInfo; mpm_table[MPM_AC_TILE].PrintThreadCtx = SCACTilePrintSearchStats; mpm_table[MPM_AC_TILE].RegisterUnittests = SCACTileRegisterTests; @@ -1753,16 +1515,16 @@ static int SCACTileTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1787,16 +1549,16 @@ static int SCACTileTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1820,12 +1582,12 @@ static int SCACTileTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -1833,7 +1595,7 @@ static int SCACTileTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1857,17 +1619,17 @@ static int SCACTileTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1891,17 +1653,17 @@ static int SCACTileTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1925,15 +1687,15 @@ static int SCACTileTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -1957,12 +1719,12 @@ static int SCACTileTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* should match 30 times */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); @@ -1977,7 +1739,7 @@ static int SCACTileTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); /* total matches: 135 */ SCACTilePreparePatterns(&mpm_ctx); @@ -2002,16 +1764,16 @@ static int SCACTileTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2034,16 +1796,16 @@ static int SCACTileTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2066,16 +1828,16 @@ static int SCACTileTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2103,12 +1865,12 @@ static int SCACTileTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; @@ -2118,7 +1880,7 @@ static int SCACTileTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCACTilePreparePatterns(&mpm_ctx) == -1) goto end; @@ -2150,18 +1912,18 @@ static int SCACTileTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2185,17 +1947,17 @@ static int SCACTileTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2219,17 +1981,17 @@ static int SCACTileTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2253,17 +2015,17 @@ static int SCACTileTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2287,17 +2049,17 @@ static int SCACTileTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2321,17 +2083,17 @@ static int SCACTileTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2355,17 +2117,17 @@ static int SCACTileTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2389,17 +2151,17 @@ static int SCACTileTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2423,17 +2185,17 @@ static int SCACTileTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2457,16 +2219,16 @@ static int SCACTileTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2489,18 +2251,18 @@ static int SCACTileTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2524,16 +2286,16 @@ static int SCACTileTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2556,16 +2318,16 @@ static int SCACTileTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2588,17 +2350,17 @@ static int SCACTileTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2622,16 +2384,16 @@ static int SCACTileTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2655,16 +2417,16 @@ static int SCACTileTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2688,16 +2450,16 @@ static int SCACTileTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC_TILE); - SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACTileInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACTilePreparePatterns(&mpm_ctx); @@ -2776,36 +2538,43 @@ void SCACTileRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCACTileTest01", SCACTileTest01, 1); - UtRegisterTest("SCACTileTest02", SCACTileTest02, 1); - UtRegisterTest("SCACTileTest03", SCACTileTest03, 1); - UtRegisterTest("SCACTileTest04", SCACTileTest04, 1); - UtRegisterTest("SCACTileTest05", SCACTileTest05, 1); - UtRegisterTest("SCACTileTest06", SCACTileTest06, 1); - UtRegisterTest("SCACTileTest07", SCACTileTest07, 1); - UtRegisterTest("SCACTileTest08", SCACTileTest08, 1); - UtRegisterTest("SCACTileTest09", SCACTileTest09, 1); - UtRegisterTest("SCACTileTest10", SCACTileTest10, 1); - UtRegisterTest("SCACTileTest11", SCACTileTest11, 1); - UtRegisterTest("SCACTileTest12", SCACTileTest12, 1); - UtRegisterTest("SCACTileTest13", SCACTileTest13, 1); - UtRegisterTest("SCACTileTest14", SCACTileTest14, 1); - UtRegisterTest("SCACTileTest15", SCACTileTest15, 1); - UtRegisterTest("SCACTileTest16", SCACTileTest16, 1); - UtRegisterTest("SCACTileTest17", SCACTileTest17, 1); - UtRegisterTest("SCACTileTest18", SCACTileTest18, 1); - UtRegisterTest("SCACTileTest19", SCACTileTest19, 1); - UtRegisterTest("SCACTileTest20", SCACTileTest20, 1); - UtRegisterTest("SCACTileTest21", SCACTileTest21, 1); - UtRegisterTest("SCACTileTest22", SCACTileTest22, 1); - UtRegisterTest("SCACTileTest23", SCACTileTest23, 1); - UtRegisterTest("SCACTileTest24", SCACTileTest24, 1); - UtRegisterTest("SCACTileTest25", SCACTileTest25, 1); - UtRegisterTest("SCACTileTest26", SCACTileTest26, 1); - UtRegisterTest("SCACTileTest27", SCACTileTest27, 1); - UtRegisterTest("SCACTileTest28", SCACTileTest28, 1); - UtRegisterTest("SCACTileTest29", SCACTileTest29, 1); + UtRegisterTest("SCACTileTest01", SCACTileTest01); + UtRegisterTest("SCACTileTest02", SCACTileTest02); + UtRegisterTest("SCACTileTest03", SCACTileTest03); + UtRegisterTest("SCACTileTest04", SCACTileTest04); + UtRegisterTest("SCACTileTest05", SCACTileTest05); + UtRegisterTest("SCACTileTest06", SCACTileTest06); + UtRegisterTest("SCACTileTest07", SCACTileTest07); + UtRegisterTest("SCACTileTest08", SCACTileTest08); + UtRegisterTest("SCACTileTest09", SCACTileTest09); + UtRegisterTest("SCACTileTest10", SCACTileTest10); + UtRegisterTest("SCACTileTest11", SCACTileTest11); + UtRegisterTest("SCACTileTest12", SCACTileTest12); + UtRegisterTest("SCACTileTest13", SCACTileTest13); + UtRegisterTest("SCACTileTest14", SCACTileTest14); + UtRegisterTest("SCACTileTest15", SCACTileTest15); + UtRegisterTest("SCACTileTest16", SCACTileTest16); + UtRegisterTest("SCACTileTest17", SCACTileTest17); + UtRegisterTest("SCACTileTest18", SCACTileTest18); + UtRegisterTest("SCACTileTest19", SCACTileTest19); + UtRegisterTest("SCACTileTest20", SCACTileTest20); + UtRegisterTest("SCACTileTest21", SCACTileTest21); + UtRegisterTest("SCACTileTest22", SCACTileTest22); + UtRegisterTest("SCACTileTest23", SCACTileTest23); + UtRegisterTest("SCACTileTest24", SCACTileTest24); + UtRegisterTest("SCACTileTest25", SCACTileTest25); + UtRegisterTest("SCACTileTest26", SCACTileTest26); + UtRegisterTest("SCACTileTest27", SCACTileTest27); + UtRegisterTest("SCACTileTest28", SCACTileTest28); + UtRegisterTest("SCACTileTest29", SCACTileTest29); #endif } -#endif /* __tile__ */ +#else /* we're big endian */ + +void MpmACTileRegister(void) +{ + /* no-op on big endian */ +} + +#endif /* little endian check */ diff --git a/src/util-mpm-ac-tile.h b/src/util-mpm-ac-tile.h index ce64c9b7d909..1f9ba4e5ecbb 100644 --- a/src/util-mpm-ac-tile.h +++ b/src/util-mpm-ac-tile.h @@ -26,32 +26,22 @@ #ifndef __UTIL_MPM_AC_TILE__H__ #define __UTIL_MPM_AC_TILE__H__ -typedef struct SCACTilePattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - struct SCACTilePattern_ *next; -} SCACTilePattern; - typedef struct SCACTilePatternList_ { uint8_t *cs; uint16_t patlen; + + /* Pattern Id */ + uint32_t pid; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; } SCACTilePatternList; typedef struct SCACTileOutputTable_ { - /* list of pattern sids */ - uint32_t *pids; - /* no of entries we have in pids */ + /* list of pattern indexes */ + MpmPatternIndex *patterns; + /* number of entries in pattern list */ uint32_t no_of_entries; } SCACTileOutputTable; @@ -73,8 +63,8 @@ typedef struct SCACTileCtx_ { * number of states could make the next state could be 16 bits or * 32 bits. */ - uint32_t (*search)(struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t (*search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, + PrefilterRuleStore *, const uint8_t *, uint16_t); /* Function to set the next state based on size of next state * (bytes_per_state). @@ -82,17 +72,14 @@ typedef struct SCACTileCtx_ { void (*set_next_state)(struct SCACTileCtx_ *ctx, int state, int aa, int new_state, int outputs); + /* List of patterns that match for this state. Indexed by State Number */ SCACTileOutputTable *output_table; - SCACTilePatternList *pid_pat_list; - - /* the stuff below is only used at initialization time */ - - /* hash used during ctx initialization */ - SCACTilePattern **init_hash; + /* Indexed by MpmPatternIndex */ + SCACTilePatternList *pattern_list; /* pattern arrays. We need this only during the goto table creation phase */ - SCACTilePattern **parray; + MpmPattern **parray; /* goto_table, failure table and output table. Needed to create * state_table. Will be freed, once we have created the @@ -101,12 +88,9 @@ typedef struct SCACTileCtx_ { int32_t *failure_table; /* Number of states used by ac-tile */ - int state_count; + uint32_t state_count; /* Number of states allocated for ac-tile. */ - int allocated_state_count; - - /* Largest Pattern Identifier. */ - uint16_t max_pat_id; + uint32_t allocated_state_count; uint32_t alpha_hist[256]; /* Number of characters in the compressed alphabet. */ @@ -132,8 +116,8 @@ typedef struct SCACTileSearchCtx_ { * number of states could make the next state could be 16 bits or * 32 bits. */ - uint32_t (*search)(struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, - PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t (*search)(const struct SCACTileSearchCtx_ *ctx, struct MpmThreadCtx_ *, + PrefilterRuleStore *, const uint8_t *, uint16_t); /* Convert input character to matching alphabet */ uint8_t translate_table[256]; @@ -141,8 +125,17 @@ typedef struct SCACTileSearchCtx_ { /* the all important memory hungry state_table */ void *state_table; + /* List of patterns that match for this state. Indexed by State Number */ SCACTileOutputTable *output_table; - SCACTilePatternList *pid_pat_list; + SCACTilePatternList *pattern_list; + + /* Number of bytes in the array of bits. One bit per pattern in this MPM. */ + uint32_t mpm_bitarray_size; + + /* Number of states used by ac-tile */ + uint32_t state_count; + + uint32_t pattern_cnt; /* MPM Creation data, only used at initialization. */ SCACTileCtx *init_ctx; diff --git a/src/util-mpm-ac.c b/src/util-mpm-ac.c index f8e2199a3961..6ab2e883fb1f 100644 --- a/src/util-mpm-ac.c +++ b/src/util-mpm-ac.c @@ -70,27 +70,29 @@ #endif /* __SC_CUDA_SUPPORT__ */ void SCACInitCtx(MpmCtx *); -void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *); void SCACDestroyCtx(MpmCtx *); void SCACDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, - uint32_t, uint32_t, uint8_t); + uint32_t, SigIntId, uint8_t); int SCACPreparePatterns(MpmCtx *mpm_ctx); -uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen); void SCACPrintInfo(MpmCtx *mpm_ctx); void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); void SCACRegisterTests(void); /* a placeholder to denote a failure transition in the goto table */ #define SC_AC_FAIL (-1) -/* size of the hash table used to speed up pattern insertions initially */ -#define INIT_HASH_SIZE 65536 #define STATE_QUEUE_CONTAINER_SIZE 65536 +#define AC_CASE_MASK 0x80000000 +#define AC_PID_MASK 0x7FFFFFFF +#define AC_CASE_BIT 31 + static int construct_both_16_and_32_state_tables = 0; /** @@ -120,250 +122,24 @@ static void SCACGetConfig() /** * \internal - * \brief Creates a hash of the pattern. We use it for the hashing process - * during the initial pattern insertion time, to cull duplicate sigs. - * - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline uint32_t SCACInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -/** - * \internal - * \brief Looks up a pattern. We use it for the hashing process during the - * the initial pattern insertion time, to cull duplicate sigs. - * - * \param ctx Pointer to the AC ctx. - * \param pat Pointer to the pattern. - * \param patlen Pattern length. - * \param flags Flags. We don't need this. - * - * \retval hash A 32 bit unsigned hash. - */ -static inline SCACPattern *SCACInitHashLookup(SCACCtx *ctx, uint8_t *pat, - uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = SCACInitHashRaw(pat, patlen); - - if (ctx->init_hash == NULL) { - return NULL; - } - - SCACPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (t->id == pid) - return t; - } - - return NULL; -} - -/** - * \internal - * \brief Allocs a new pattern instance. + * \brief Check if size_t multiplication would overflow and perform operation + * if safe. In case of an overflow we exit(). * - * \param mpm_ctx Pointer to the mpm context. + * \param a First size_t value to multiplicate. + * \param b Second size_t value to multiplicate. * - * \retval p Pointer to the newly created pattern. + * \retval The product of a and b, guaranteed to not overflow. */ -static inline SCACPattern *SCACAllocPattern(MpmCtx *mpm_ctx) +static inline size_t SCACCheckSafeSizetMult(size_t a, size_t b) { - SCACPattern *p = SCMalloc(sizeof(SCACPattern)); - if (unlikely(p == NULL)) { + /* check for safety of multiplication operation */ + if (b > 0 && a > SIZE_MAX / b) { + SCLogError(SC_ERR_MEM_ALLOC, "%"PRIuMAX" * %"PRIuMAX" > %" + PRIuMAX" would overflow size_t calculating buffer size", + (uintmax_t) a, (uintmax_t) b, (uintmax_t) SIZE_MAX); exit(EXIT_FAILURE); } - memset(p, 0, sizeof(SCACPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(SCACPattern); - - return p; -} - -/** - * \internal - * \brief Used to free SCACPattern instances. - * - * \param mpm_ctx Pointer to the mpm context. - * \param p Pointer to the SCACPattern instance to be freed. - * \param free Free the above pointer or not. - */ -static inline void SCACFreePattern(MpmCtx *mpm_ctx, SCACPattern *p) -{ - if (p != NULL && p->cs != NULL && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->ci != NULL) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(SCACPattern); - } - return; -} - -static inline uint32_t SCACInitHash(SCACPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int SCACInitHashAdd(SCACCtx *ctx, SCACPattern *p) -{ - uint32_t hash = SCACInitHash(p); - - if (ctx->init_hash == NULL) { - return 0; - } - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - SCACPattern *tt = NULL; - SCACPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -/** - * \internal - * \brief Add a pattern to the mpm-ac context. - * - * \param mpm_ctx Mpm context. - * \param pat Pointer to the pattern. - * \param patlen Length of the pattern. - * \param pid Pattern id - * \param sid Signature id (internal id). - * \param flags Pattern's MPM_PATTERN_* flags. - * - * \retval 0 On success. - * \retval -1 On failure. - */ -static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) -{ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - - SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, - ctx, patlen, pid); - - if (patlen == 0) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); - return 0; - } - - /* check if we have already inserted this pattern */ - SCACPattern *p = SCACInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("Allocing new pattern"); - - /* p will never be NULL */ - p = SCACAllocPattern(mpm_ctx); - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci, pat, p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - /* put in the pattern hash */ - SCACInitHashAdd(ctx, p); - - //if (mpm_ctx->pattern_cnt == 65535) { - // SCLogError(SC_ERR_AHO_CORASICK, "Max search words reached. Can't " - // "insert anymore. Exiting"); - // exit(EXIT_FAILURE); - //} - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - - if (mpm_ctx->minlen == 0) { - mpm_ctx->minlen = patlen; - } else { - if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - /* we need the max pat id */ - if (pid > ctx->max_pat_id) - ctx->max_pat_id = pid; - } - - return 0; - -error: - SCACFreePattern(mpm_ctx, p); - return -1; + return a * b; } /** @@ -376,12 +152,13 @@ static int SCACAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt) { - void *ptmp; - int size = 0; + void *ptmp = NULL; + size_t size = 0; /* reallocate space in the goto table to include a new state */ - size = cnt * ctx->single_state_size; - ptmp = SCRealloc(ctx->goto_table, size); + size = SCACCheckSafeSizetMult((size_t) cnt, (size_t) ctx->single_state_size); + if (size > 0) + ptmp = SCRealloc(ctx->goto_table, size); if (ptmp == NULL) { SCFree(ctx->goto_table); ctx->goto_table = NULL; @@ -391,12 +168,15 @@ static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt) ctx->goto_table = ptmp; /* reallocate space in the output table for the new state */ - int oldsize = ctx->state_count * sizeof(SCACOutputTable); - size = cnt * sizeof(SCACOutputTable); - SCLogDebug("oldsize %d size %d cnt %u ctx->state_count %u", - oldsize, size, cnt, ctx->state_count); - - ptmp = SCRealloc(ctx->output_table, size); + size_t oldsize = SCACCheckSafeSizetMult((size_t) ctx->state_count, + sizeof(SCACOutputTable)); + size = SCACCheckSafeSizetMult((size_t) cnt, sizeof(SCACOutputTable)); + SCLogDebug("oldsize %"PRIuMAX" size %"PRIuMAX" cnt %d ctx->state_count %u", + (uintmax_t) oldsize, (uintmax_t) size, cnt, ctx->state_count); + + ptmp = NULL; + if (size > 0) + ptmp = SCRealloc(ctx->output_table, size); if (ptmp == NULL) { SCFree(ctx->output_table); ctx->output_table = NULL; @@ -924,8 +704,8 @@ static inline void SCACInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx) for (k = 0; k < ctx->output_table[state].no_of_entries; k++) { if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) { - ctx->output_table[state].pids[k] &= 0x0000FFFF; - ctx->output_table[state].pids[k] |= 1 << 16; + ctx->output_table[state].pids[k] &= AC_PID_MASK; + ctx->output_table[state].pids[k] |= ((uint32_t)1 << AC_CASE_BIT); } } } @@ -958,7 +738,7 @@ static void SCACPrintDeltaTable(MpmCtx *mpm_ctx) * * \param mpm_ctx Pointer to the mpm context. */ -static inline void SCACPrepareStateTable(MpmCtx *mpm_ctx) +static void SCACPrepareStateTable(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; @@ -1004,24 +784,24 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) { SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { SCLogDebug("no patterns supplied to this mpm_ctx"); return 0; } /* alloc the pattern array */ - ctx->parray = (SCACPattern **)SCMalloc(mpm_ctx->pattern_cnt * - sizeof(SCACPattern *)); + ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt * + sizeof(MpmPattern *)); if (ctx->parray == NULL) goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); /* populate it with the patterns in the hash */ uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - SCACPattern *node = ctx->init_hash[i], *nnode = NULL; + for (i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; while(node != NULL) { nnode = node->next; node->next = NULL; @@ -1031,19 +811,19 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) } /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; /* the memory consumed by a single state in our goto table */ ctx->single_state_size = sizeof(int32_t) * 256; /* handle no case patterns */ - ctx->pid_pat_list = SCMalloc((ctx->max_pat_id + 1)* sizeof(SCACPatternList)); + ctx->pid_pat_list = SCMalloc((mpm_ctx->max_pat_id + 1)* sizeof(SCACPatternList)); if (ctx->pid_pat_list == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memset(ctx->pid_pat_list, 0, (ctx->max_pat_id + 1) * sizeof(SCACPatternList)); + memset(ctx->pid_pat_list, 0, (mpm_ctx->max_pat_id + 1) * sizeof(SCACPatternList)); for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) { @@ -1056,6 +836,14 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) ctx->parray[i]->original_pat, ctx->parray[i]->len); ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len; } + + /* ACPatternList now owns this memory */ + //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size); + ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; + ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; + + ctx->parray[i]->sids_size = 0; + ctx->parray[i]->sids = NULL; } /* prepare the state table required by AC */ @@ -1083,13 +871,16 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) /* free all the stored patterns. Should save us a good 100-200 mbs */ for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); + + ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1; + SCLogDebug("ctx->pattern_id_bitarray_size %u", ctx->pattern_id_bitarray_size); return 0; @@ -1104,7 +895,7 @@ int SCACPreparePatterns(MpmCtx *mpm_ctx) * \param mpm_thread_ctx Pointer to the mpm thread context. * \param matchsize We don't need this. */ -void SCACInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) +void SCACInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); @@ -1139,12 +930,11 @@ void SCACInitCtx(MpmCtx *mpm_ctx) mpm_ctx->memory_size += sizeof(SCACCtx); /* initialize the hash we use to speed up pattern insertions */ - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(SCACPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); + if (mpm_ctx->init_hash == NULL) { exit(EXIT_FAILURE); } - memset(ctx->init_hash, 0, sizeof(SCACPattern *) * INIT_HASH_SIZE); + memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE); /* get conf values for AC from our yaml file. We have no conf values for * now. We will certainly need this, as we develop the algo */ @@ -1184,25 +974,25 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) if (ctx == NULL) return; - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - ctx->init_hash = NULL; + if (mpm_ctx->init_hash != NULL) { + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCACPattern *)); + mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *)); } if (ctx->parray != NULL) { uint32_t i; for (i = 0; i < mpm_ctx->pattern_cnt; i++) { if (ctx->parray[i] != NULL) { - SCACFreePattern(mpm_ctx, ctx->parray[i]); + MpmFreePattern(mpm_ctx, ctx->parray[i]); } } SCFree(ctx->parray); ctx->parray = NULL; mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(SCACPattern *)); + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *)); } if (ctx->state_table_u16 != NULL) { @@ -1233,10 +1023,12 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) } if (ctx->pid_pat_list != NULL) { - int i; - for (i = 0; i < (ctx->max_pat_id + 1); i++) { + uint32_t i; + for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) { if (ctx->pid_pat_list[i].cs != NULL) SCFree(ctx->pid_pat_list[i].cs); + if (ctx->pid_pat_list[i].sids != NULL) + SCFree(ctx->pid_pat_list[i].sids); } SCFree(ctx->pid_pat_list); } @@ -1260,10 +1052,10 @@ void SCACDestroyCtx(MpmCtx *mpm_ctx) * * \retval matches Match count. */ -uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, - PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) +uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint16_t buflen) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; + const SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; int i = 0; int matches = 0; @@ -1272,6 +1064,9 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */ SCACPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); + if (ctx->state_count < 32767) { register SC_AC_STATE_TYPE_U16 state = 0; SC_AC_STATE_TYPE_U16 (*state_table_u16)[256] = ctx->state_table_u16; @@ -1282,26 +1077,29 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t *pids = ctx->output_table[state & 0x7FFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + if (pids[k] & AC_CASE_MASK) { + uint32_t lower_pid = pids[k] & AC_PID_MASK; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1321,26 +1119,29 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids; uint32_t k; for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + i - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + if (pids[k] & AC_CASE_MASK) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + i - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k] & 0x0000FFFF; + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); - pmq->pattern_id_array[pmq->pattern_id_array_cnt++] = pids[k]; + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -1373,10 +1174,10 @@ uint32_t SCACSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, */ int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { flags |= MPM_PATTERN_FLAG_NOCASE; - return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } /** @@ -1398,9 +1199,9 @@ int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, */ int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, - uint32_t sid, uint8_t flags) + SigIntId sid, uint8_t flags) { - return SCACAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) @@ -1426,8 +1227,8 @@ void SCACPrintInfo(MpmCtx *mpm_ctx) printf(" Sizeof:\n"); printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); printf(" SCACCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACCtx)); - printf(" SCACPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACPattern)); - printf(" SCACPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCACPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); @@ -1495,197 +1296,9 @@ void DetermineCudaStateTableSize(DetectEngineCtx *de_ctx) ac_32_tables++; } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_uri, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcbd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hhd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrhd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hmd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hcd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hrud, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hsmd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_hscd, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 0); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_huad, 1); - if (mpm_ctx->mpm_type == MPM_AC_CUDA) { - SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx; - if (ctx->state_count < 32767) - ac_16_tables++; - else - ac_32_tables++; - } - if (ac_16_tables > 0 && ac_32_tables > 0) SCACConstructBoth16and32StateTables(); - SCLogDebug("Total mpm ac 16 bit state tables - %d\n", ac_16_tables); SCLogDebug("Total mpm ac 32 bit state tables - %d\n", ac_32_tables); @@ -1962,8 +1575,8 @@ static void *SCACCudaDispatcher(void *arg) #undef BLOCK_SIZE } -uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, - PatternMatcherQueue *pmq) +uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, + PrefilterRuleStore *pmq) { uint32_t u = 0; @@ -1991,6 +1604,9 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, SCACOutputTable *output_table = ctx->output_table; SCACPatternList *pid_pat_list = ctx->pid_pat_list; + uint8_t bitarray[ctx->pattern_id_bitarray_size]; + memset(bitarray, 0, ctx->pattern_id_bitarray_size); + for (u = 0; u < cuda_matches; u += 2) { uint32_t offset = results[u]; uint32_t state = results[u + 1]; @@ -2005,24 +1621,29 @@ uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, * don't copy the pattern id into the pattern_id_array. That's * the only change */ for (k = 0; k < no_of_entries; k++) { - if (pids[k] & 0xFFFF0000) { - if (SCMemcmp(pid_pat_list[pids[k] & 0x0000FFFF].cs, - buf + offset - pid_pat_list[pids[k] & 0x0000FFFF].patlen + 1, - pid_pat_list[pids[k] & 0x0000FFFF].patlen) != 0) { + if (pids[k] & AC_CASE_MASK) { + uint32_t lower_pid = pids[k] & 0x0000FFFF; + if (SCMemcmp(pid_pat_list[lower_pid].cs, + buf + offset - pid_pat_list[lower_pid].patlen + 1, + pid_pat_list[lower_pid].patlen) != 0) { /* inside loop */ continue; } - if (pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] & (1 << ((pids[k] & 0x0000FFFF) % 8))) { + if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) { ; } else { - pmq->pattern_id_bitarray[(pids[k] & 0x0000FFFF) / 8] |= (1 << ((pids[k] & 0x0000FFFF) % 8)); + bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8)); + PrefilterAddSids(pmq, pid_pat_list[lower_pid].sids, + pid_pat_list[lower_pid].sids_size); } matches++; } else { - if (pmq->pattern_id_bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { + if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) { ; } else { - pmq->pattern_id_bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + bitarray[pids[k] / 8] |= (1 << (pids[k] % 8)); + PrefilterAddSids(pmq, pid_pat_list[pids[k]].sids, + pid_pat_list[pids[k]].sids_size); } matches++; } @@ -2170,9 +1791,6 @@ int MpmCudaBufferDeSetup(void) void MpmACRegister(void) { mpm_table[MPM_AC].name = "ac"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC].max_pattern_length = 0; - mpm_table[MPM_AC].InitCtx = SCACInitCtx; mpm_table[MPM_AC].InitThreadCtx = SCACInitThreadCtx; mpm_table[MPM_AC].DestroyCtx = SCACDestroyCtx; @@ -2181,7 +1799,6 @@ void MpmACRegister(void) mpm_table[MPM_AC].AddPatternNocase = SCACAddPatternCI; mpm_table[MPM_AC].Prepare = SCACPreparePatterns; mpm_table[MPM_AC].Search = SCACSearch; - mpm_table[MPM_AC].Cleanup = NULL; mpm_table[MPM_AC].PrintCtx = SCACPrintInfo; mpm_table[MPM_AC].PrintThreadCtx = SCACPrintSearchStats; mpm_table[MPM_AC].RegisterUnittests = SCACRegisterTests; @@ -2197,9 +1814,6 @@ void MpmACRegister(void) void MpmACCudaRegister(void) { mpm_table[MPM_AC_CUDA].name = "ac-cuda"; - /* don't need this. isn't that awesome? no more chopping and blah blah */ - mpm_table[MPM_AC_CUDA].max_pattern_length = 0; - mpm_table[MPM_AC_CUDA].InitCtx = SCACInitCtx; mpm_table[MPM_AC_CUDA].InitThreadCtx = SCACInitThreadCtx; mpm_table[MPM_AC_CUDA].DestroyCtx = SCACDestroyCtx; @@ -2208,7 +1822,6 @@ void MpmACCudaRegister(void) mpm_table[MPM_AC_CUDA].AddPatternNocase = SCACAddPatternCI; mpm_table[MPM_AC_CUDA].Prepare = SCACPreparePatterns; mpm_table[MPM_AC_CUDA].Search = SCACSearch; - mpm_table[MPM_AC_CUDA].Cleanup = NULL; mpm_table[MPM_AC_CUDA].PrintCtx = SCACPrintInfo; mpm_table[MPM_AC_CUDA].PrintThreadCtx = SCACPrintSearchStats; mpm_table[MPM_AC_CUDA].RegisterUnittests = SCACRegisterTests; @@ -2227,16 +1840,16 @@ static int SCACTest01(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2261,16 +1874,16 @@ static int SCACTest02(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2294,12 +1907,12 @@ static int SCACTest03(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); @@ -2307,7 +1920,7 @@ static int SCACTest03(void) MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2331,17 +1944,17 @@ static int SCACTest04(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2365,17 +1978,17 @@ static int SCACTest05(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2399,15 +2012,15 @@ static int SCACTest06(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2431,12 +2044,12 @@ static int SCACTest07(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* should match 30 times */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); @@ -2451,7 +2064,7 @@ static int SCACTest07(void) /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); - PmqSetup(&pmq, 6); + PmqSetup(&pmq); /* total matches: 135 */ SCACPreparePatterns(&mpm_ctx); @@ -2476,16 +2089,16 @@ static int SCACTest08(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2508,16 +2121,16 @@ static int SCACTest09(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2540,16 +2153,16 @@ static int SCACTest10(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2577,12 +2190,12 @@ static int SCACTest11(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) goto end; @@ -2592,7 +2205,7 @@ static int SCACTest11(void) goto end; if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) goto end; - PmqSetup(&pmq, 5); + PmqSetup(&pmq); if (SCACPreparePatterns(&mpm_ctx) == -1) goto end; @@ -2624,18 +2237,18 @@ static int SCACTest12(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2659,17 +2272,17 @@ static int SCACTest13(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2693,17 +2306,17 @@ static int SCACTest14(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2727,17 +2340,17 @@ static int SCACTest15(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2761,17 +2374,17 @@ static int SCACTest16(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzABC"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2795,17 +2408,17 @@ static int SCACTest17(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcdefghijklmnopqrstuvwxyzAB"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2829,17 +2442,17 @@ static int SCACTest18(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2863,17 +2476,17 @@ static int SCACTest19(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2897,17 +2510,17 @@ static int SCACTest20(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA"; MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2931,16 +2544,16 @@ static int SCACTest21(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2963,18 +2576,18 @@ static int SCACTest22(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -2998,16 +2611,16 @@ static int SCACTest23(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3030,16 +2643,16 @@ static int SCACTest24(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 1 */ MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3062,17 +2675,17 @@ static int SCACTest25(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); - PmqSetup(&pmq, 3); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3096,16 +2709,16 @@ static int SCACTest26(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); - PmqSetup(&pmq, 2); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3129,16 +2742,16 @@ static int SCACTest27(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3162,16 +2775,16 @@ static int SCACTest28(void) int result = 0; MpmCtx mpm_ctx; MpmThreadCtx mpm_thread_ctx; - PatternMatcherQueue pmq; + PrefilterRuleStore pmq; memset(&mpm_ctx, 0, sizeof(MpmCtx)); memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); MpmInitCtx(&mpm_ctx, MPM_AC); - SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx, 0); + SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); /* 0 match */ MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); - PmqSetup(&pmq, 1); + PmqSetup(&pmq); SCACPreparePatterns(&mpm_ctx); @@ -3250,35 +2863,35 @@ void SCACRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCACTest01", SCACTest01, 1); - UtRegisterTest("SCACTest02", SCACTest02, 1); - UtRegisterTest("SCACTest03", SCACTest03, 1); - UtRegisterTest("SCACTest04", SCACTest04, 1); - UtRegisterTest("SCACTest05", SCACTest05, 1); - UtRegisterTest("SCACTest06", SCACTest06, 1); - UtRegisterTest("SCACTest07", SCACTest07, 1); - UtRegisterTest("SCACTest08", SCACTest08, 1); - UtRegisterTest("SCACTest09", SCACTest09, 1); - UtRegisterTest("SCACTest10", SCACTest10, 1); - UtRegisterTest("SCACTest11", SCACTest11, 1); - UtRegisterTest("SCACTest12", SCACTest12, 1); - UtRegisterTest("SCACTest13", SCACTest13, 1); - UtRegisterTest("SCACTest14", SCACTest14, 1); - UtRegisterTest("SCACTest15", SCACTest15, 1); - UtRegisterTest("SCACTest16", SCACTest16, 1); - UtRegisterTest("SCACTest17", SCACTest17, 1); - UtRegisterTest("SCACTest18", SCACTest18, 1); - UtRegisterTest("SCACTest19", SCACTest19, 1); - UtRegisterTest("SCACTest20", SCACTest20, 1); - UtRegisterTest("SCACTest21", SCACTest21, 1); - UtRegisterTest("SCACTest22", SCACTest22, 1); - UtRegisterTest("SCACTest23", SCACTest23, 1); - UtRegisterTest("SCACTest24", SCACTest24, 1); - UtRegisterTest("SCACTest25", SCACTest25, 1); - UtRegisterTest("SCACTest26", SCACTest26, 1); - UtRegisterTest("SCACTest27", SCACTest27, 1); - UtRegisterTest("SCACTest28", SCACTest28, 1); - UtRegisterTest("SCACTest29", SCACTest29, 1); + UtRegisterTest("SCACTest01", SCACTest01); + UtRegisterTest("SCACTest02", SCACTest02); + UtRegisterTest("SCACTest03", SCACTest03); + UtRegisterTest("SCACTest04", SCACTest04); + UtRegisterTest("SCACTest05", SCACTest05); + UtRegisterTest("SCACTest06", SCACTest06); + UtRegisterTest("SCACTest07", SCACTest07); + UtRegisterTest("SCACTest08", SCACTest08); + UtRegisterTest("SCACTest09", SCACTest09); + UtRegisterTest("SCACTest10", SCACTest10); + UtRegisterTest("SCACTest11", SCACTest11); + UtRegisterTest("SCACTest12", SCACTest12); + UtRegisterTest("SCACTest13", SCACTest13); + UtRegisterTest("SCACTest14", SCACTest14); + UtRegisterTest("SCACTest15", SCACTest15); + UtRegisterTest("SCACTest16", SCACTest16); + UtRegisterTest("SCACTest17", SCACTest17); + UtRegisterTest("SCACTest18", SCACTest18); + UtRegisterTest("SCACTest19", SCACTest19); + UtRegisterTest("SCACTest20", SCACTest20); + UtRegisterTest("SCACTest21", SCACTest21); + UtRegisterTest("SCACTest22", SCACTest22); + UtRegisterTest("SCACTest23", SCACTest23); + UtRegisterTest("SCACTest24", SCACTest24); + UtRegisterTest("SCACTest25", SCACTest25); + UtRegisterTest("SCACTest26", SCACTest26); + UtRegisterTest("SCACTest27", SCACTest27); + UtRegisterTest("SCACTest28", SCACTest28); + UtRegisterTest("SCACTest29", SCACTest29); #endif return; diff --git a/src/util-mpm-ac.h b/src/util-mpm-ac.h index 760fb70495c1..490ebfdfb9a9 100644 --- a/src/util-mpm-ac.h +++ b/src/util-mpm-ac.h @@ -38,26 +38,13 @@ #include "flow.h" #endif /* __SC_CUDA_SUPPORT__ */ -typedef struct SCACPattern_ { - /* length of the pattern */ - uint16_t len; - /* flags decribing the pattern */ - uint8_t flags; - /* holds the original pattern that was added */ - uint8_t *original_pat; - /* case sensitive */ - uint8_t *cs; - /* case INsensitive */ - uint8_t *ci; - /* pattern id */ - uint32_t id; - - struct SCACPattern_ *next; -} SCACPattern; - typedef struct SCACPatternList_ { uint8_t *cs; uint16_t patlen; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; } SCACPatternList; typedef struct SCACOutputTable_ { @@ -68,14 +55,14 @@ typedef struct SCACOutputTable_ { } SCACOutputTable; typedef struct SCACCtx_ { - /* hash used during ctx initialization */ - SCACPattern **init_hash; - /* pattern arrays. We need this only during the goto table creation phase */ - SCACPattern **parray; + MpmPattern **parray; /* no of states used by ac */ uint32_t state_count; + + uint32_t pattern_id_bitarray_size; + /* the all important memory hungry state_table */ SC_AC_STATE_TYPE_U16 (*state_table_u16)[256]; /* the all important memory hungry state_table */ @@ -89,8 +76,7 @@ typedef struct SCACCtx_ { SCACPatternList *pid_pat_list; /* the size of each state */ - uint16_t single_state_size; - uint16_t max_pat_id; + uint32_t single_state_size; uint32_t allocated_state_count; @@ -201,8 +187,8 @@ int MpmCudaBufferSetup(void); int MpmCudaBufferDeSetup(void); void SCACCudaStartDispatcher(void); void SCACCudaKillDispatcher(void); -uint32_t SCACCudaPacketResultsProcessing(Packet *p, MpmCtx *mpm_ctx, - PatternMatcherQueue *pmq); +uint32_t SCACCudaPacketResultsProcessing(Packet *p, const MpmCtx *mpm_ctx, + PrefilterRuleStore *pmq); void DetermineCudaStateTableSize(DetectEngineCtx *de_ctx); void CudaReleasePacket(Packet *p); diff --git a/src/util-mpm-b2g.c b/src/util-mpm-b2g.c deleted file mode 100644 index 31ef46b52589..000000000000 --- a/src/util-mpm-b2g.c +++ /dev/null @@ -1,2756 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implementation of the SBNDMq pattern matching algorithm. - * - * Ideas: - * - B2g does a full match in the search of up to 'm' characters, - * in case of a case insensitive search we could say it's match if - * the pattern is of len 'm' or just compare the rest of the chars. - * - * \todo Try to get the S0 calculation right. - */ - -//#define PRINTMATCH - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" -#include "util-bloomfilter.h" -#include "util-mpm-b2g.h" -#include "util-print.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-memcmp.h" -#include "util-memcpy.h" -#include "conf.h" - -#define INIT_HASH_SIZE 65536 - -#ifdef B2G_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B2G_COUNTERS */ - -static uint32_t b2g_hash_size = 0; -static uint32_t b2g_bloom_size = 0; -static uint8_t b2g_hash_shift = 0; -static void *b2g_func; - -#define B2G_HASH16(a,b) (((a) << b2g_hash_shift) | (b)) - -void B2gInitCtx (MpmCtx *); -void B2gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B2gDestroyCtx(MpmCtx *); -void B2gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gPreparePatterns(MpmCtx *mpm_ctx); -uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#ifdef B2G_SEARCH2 -uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#endif -uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void B2gPrintInfo(MpmCtx *mpm_ctx); -void B2gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void B2gRegisterTests(void); - -void MpmB2gRegister (void) -{ - mpm_table[MPM_B2G].name = "b2g"; - mpm_table[MPM_B2G].max_pattern_length = B2G_WORD_SIZE; - - mpm_table[MPM_B2G].InitCtx = B2gInitCtx; - mpm_table[MPM_B2G].InitThreadCtx = B2gThreadInitCtx; - mpm_table[MPM_B2G].DestroyCtx = B2gDestroyCtx; - mpm_table[MPM_B2G].DestroyThreadCtx = B2gThreadDestroyCtx; - mpm_table[MPM_B2G].AddPattern = B2gAddPatternCS; - mpm_table[MPM_B2G].AddPatternNocase = B2gAddPatternCI; - mpm_table[MPM_B2G].Prepare = B2gPreparePatterns; - mpm_table[MPM_B2G].Search = B2gSearchWrap; - mpm_table[MPM_B2G].Cleanup = NULL; - mpm_table[MPM_B2G].PrintCtx = B2gPrintInfo; - mpm_table[MPM_B2G].PrintThreadCtx = B2gPrintSearchStats; - mpm_table[MPM_B2G].RegisterUnittests = B2gRegisterTests; -} - -#ifdef PRINTMATCH -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%02X", buf[i]); - } - //printf("\n"); -} -#endif - -void B2gPrintInfo(MpmCtx *mpm_ctx) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - printf("MPM B2g Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B2gCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gCtx)); - printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); - printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -/** - * \brief B2gAllocPattern allocates a new pattern structure - * and initialize the data - * \initonly - */ -static inline B2gPattern *B2gAllocPattern(MpmCtx *mpm_ctx) -{ - B2gPattern *p = SCMalloc(sizeof(B2gPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B2gPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gPattern); - return p; -} - -static inline B2gPattern * -B2gAllocHashItem(MpmCtx *mpm_ctx) -{ - B2gPattern *hi = SCMalloc(sizeof(B2gPattern)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(B2gPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gPattern); - return hi; -} - -static void B2gHashFree(MpmCtx *mpm_ctx, B2gPattern *hi) -{ - if (hi == NULL) - return; - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gPattern); - B2gPattern *t = hi->next; - SCFree(hi); - - B2gHashFree(mpm_ctx, t); -} - -/* - * INIT HASH START - */ -static inline uint32_t B2gInitHash(B2gPattern *p) -{ - uint32_t hash = p->len * p->original_pat[0]; - if (p->len > 1) - hash += p->original_pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t B2gInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int B2gInitHashAdd(B2gCtx *ctx, B2gPattern *p) -{ - uint32_t hash = B2gInitHash(p); - - //printf("B2gInitHashAdd: %" PRIu32 "\n", hash); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - //printf("B2gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; - } - - B2gPattern *tt = NULL; - B2gPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - //printf("B2gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; -} - -static inline int B2gCmpPattern(B2gPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline B2gPattern *B2gInitHashLookup(B2gCtx *ctx, uint8_t *pat, uint16_t patlen, char flags, - uint32_t pid) -{ - uint32_t hash = B2gInitHashRaw(pat,patlen); - - //printf("B2gInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - B2gPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - //if (B2gCmpPattern(t,pat,patlen,flags) == 1) - if (t->id == pid) - return t; - } - - return NULL; -} - -static inline int B2gCmpPattern(B2gPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (SCMemcmp(p->cs, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void B2gFreePattern(MpmCtx *mpm_ctx, B2gPattern *p) -{ - if (p && p->cs && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->ci) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p != NULL && p->original_pat != NULL) { - SCFree(p->original_pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gPattern); - } -} - -/** \internal - * \brief add a pattern to the mpm/b2g context - * - * \param pat ptr to the pattern - * \param patlen length of the pattern - * \param pid pattern id - * \param sid signature id (internal id) - * \param flags pattern MPM_PATTERN_* flags - * - * \initonly - */ -static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); - - if (patlen == 0) - return 0; - - /* get a memory piece */ - B2gPattern *p = B2gInitHashLookup(ctx, pat, patlen, flags, pid); - if (p == NULL) { - SCLogDebug("allocing new pattern"); - - p = B2gAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->original_pat = SCMalloc(patlen); - if (p->original_pat == NULL) - goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->original_pat, pat, patlen); - - /* setup the case insensitive part of the pattern */ - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (SCMemcmp(p->ci,pat,p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - //printf("B2gAddPattern: ci \""); prt(p->ci,p->len); - //printf("\" cs \""); prt(p->cs,p->len); - //printf("\"\n"); - - /* put in the pattern hash */ - B2gInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; - } - - return 0; - -error: - B2gFreePattern(mpm_ctx, p); - return -1; -} - -int B2gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B2gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return B2gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static inline uint32_t B2gBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static void B2gPrepareHash(MpmCtx *mpm_ctx) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t idx = 0; - uint8_t idx8 = 0; - - ctx->hash = (B2gPattern **)SCMalloc(sizeof(B2gPattern *) * ctx->hash_size); - if (ctx->hash == NULL) - goto error; - memset(ctx->hash, 0, sizeof(B2gPattern *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2gPattern *) * ctx->hash_size); - -#ifdef B2G_SEARCH2 - ctx->hash2 = (B2gPattern **)SCMalloc(sizeof(B2gPattern *) * ctx->hash_size); - if (ctx->hash2 == NULL) - goto error; - memset(ctx->hash2, 0, sizeof(B2gPattern *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2gPattern *) * ctx->hash_size); -#endif - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - goto error; - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - if(ctx->parray[i]->len == 1) { - idx8 = (uint8_t)ctx->parray[i]->ci[0]; - if (ctx->hash1[idx8].flags == 0) { - ctx->hash1[idx8].flags |= MPM_PATTERN_ONE_BYTE; - - B2gPattern *hi = &ctx->hash1[idx8]; - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - - } else { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->flags |= MPM_PATTERN_ONE_BYTE; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - - /* Append this HashItem to the list */ - B2gPattern *thi = &ctx->hash1[idx8]; - while (thi->next) thi = thi->next; - thi->next = hi; - } - ctx->pat_1_cnt++; -#ifdef B2G_SEARCH2 - } else if(ctx->parray[i]->len == 2) { - idx = B2G_HASH16(ctx->parray[i]->ci[0],ctx->parray[i]->ci[1]); - if (ctx->hash2[idx] == NULL) { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= MPM_PATTERN_ONE_BYTE; - - ctx->hash2[idx] = hi; - } else { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= MPM_PATTERN_ONE_BYTE; - - /* Append this HashItem to the list */ - B2gPattern *thi = ctx->hash2[idx]; - while (thi->next) thi = thi->next; - thi->next = hi; - } - ctx->pat_2_cnt++; -#endif - } else { - idx = B2G_HASH16(ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - SCLogDebug("idx %" PRIu32 ", %c.%c", idx, ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - - if (ctx->hash[idx] == NULL) { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - ctx->pminlen[idx] = ctx->parray[i]->len; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - ctx->hash[idx] = hi; - } else { - B2gPattern *hi = B2gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - hi->flags |= MPM_PATTERN_ONE_BYTE; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->ci = ctx->parray[i]->ci; - hi->cs = ctx->parray[i]->cs; - if (ctx->parray[i]->len < ctx->pminlen[idx]) - ctx->pminlen[idx] = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - B2gPattern *thi = ctx->hash[idx]; - while (thi->next) thi = thi->next; - thi->next = hi; - } - ctx->pat_x_cnt++; - } - } - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - goto error; - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - B2gPattern *hi = ctx->hash[h]; - if (hi == NULL) - continue; - - ctx->bloom[h] = BloomFilterInit(b2g_bloom_size, 2, B2gBloomHash); - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); - - if (ctx->pminlen[h] > 8) - ctx->pminlen[h] = 8; - - B2gPattern *thi = hi; - do { - SCLogDebug("adding \"%c%c\" to the bloom", thi->ci[0], thi->ci[1]); - BloomFilterAdd(ctx->bloom[h], thi->ci, ctx->pminlen[h]); - thi = thi->next; - } while (thi != NULL); - } - - return; -error: - return; -} - -int B2gBuildMatchArray(MpmCtx *mpm_ctx) -{ - SCEnter(); - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - ctx->B2G = SCMalloc(sizeof(B2G_TYPE) * ctx->hash_size); - if (ctx->B2G == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2G_TYPE) * ctx->hash_size); - - memset(ctx->B2G,0, b2g_hash_size * sizeof(B2G_TYPE)); - - uint32_t j; - uint32_t a; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2G_Q); j++) { - for (a = 0; a < mpm_ctx->pattern_cnt; a++) { - if (ctx->parray[a]->len < ctx->m) - continue; - - uint16_t h = B2G_HASH16(u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1])); - ctx->B2G[h] = ctx->B2G[h] | (1 << (ctx->m - j)); - - SCLogDebug("h %"PRIu16", ctx->B2G[h] %"PRIu32"", h, ctx->B2G[h]); - } - } - - ctx->s0 = 1; - SCReturnInt(0); -} - -int B2gPreparePatterns(MpmCtx *mpm_ctx) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - - /* alloc the pattern array */ - ctx->parray = (B2gPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); - //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - B2gPattern *node = ctx->init_hash[i], *nnode = NULL; - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - - p++; - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B2G_WORD_SIZE) { - ctx->m = B2G_WORD_SIZE - 1; - } - if (ctx->m < 2) ctx->m = 2; - - ctx->hash_size = b2g_hash_size; - B2gPrepareHash(mpm_ctx); - B2gBuildMatchArray(mpm_ctx); - - SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); - if (ctx->pat_1_cnt) { - ctx->Search = B2gSearch1; -#ifdef B2G_SEARCH2 - ctx->Search = B2gSearch2; - if (ctx->pat_2_cnt) { - ctx->MBSearch2 = B2gSearch2; - } -#endif - ctx->MBSearch = b2g_func; -#ifdef B2G_SEARCH2 - } else if (ctx->pat_2_cnt) { - ctx->Search = B2gSearch2; - ctx->MBSearch = b2g_func; -#endif - } - - return 0; -error: - return -1; -} - -void B2gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B2G_COUNTERS - B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; - - printf("B2g Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); - printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); - printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); - printf("Avg pminlen: %0.2f\n\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); -#endif /* B2G_COUNTERS */ -} - -/** - * \brief Function to get the user defined values for b2g algorithm from the - * config file 'suricata.yaml' - */ -static void B2gGetConfig() -{ - ConfNode *b2g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b2g_hash_size = HASHSIZE_LOW; - b2g_bloom_size = BLOOMSIZE_MEDIUM; - b2g_hash_shift = B2G_HASHSHIFT_LOW; - b2g_func = B2G_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strcmp(b2g_conf->val, "b2g") == 0) { - - algo = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "algo"); - hash_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "hash_size"); - bloom_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B2gSearch") == 0) { - b2g_func = B2gSearch; - } else if (strcmp(algo, "B2gSearchBNDMq") == 0) { - b2g_func = B2gSearchBNDMq; - } - } - - if (hash_val != NULL) { - b2g_hash_size = MpmGetHashSize(hash_val); - switch (b2g_hash_size) { - case HASHSIZE_LOWEST: - b2g_hash_shift = B2G_HASHSHIFT_LOWEST; - break; - case HASHSIZE_LOW: - b2g_hash_shift = B2G_HASHSHIFT_LOW; - break; - case HASHSIZE_MEDIUM: - b2g_hash_shift = B2G_HASHSHIFT_MEDIUM; - break; - case HASHSIZE_HIGH: - b2g_hash_shift = B2G_HASHSHIFT_HIGH; - break; - case HASHSIZE_HIGHER: - b2g_hash_shift = B2G_HASHSHIFT_HIGHER; - break; - case HASHSIZE_MAX: - b2g_hash_shift = B2G_HASHSHIFT_MAX; - break; - } - } - - if (bloom_val != NULL) - b2g_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b2g_hash_size, b2g_bloom_size); - } - } - } -} - -void B2gInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); - - if (mpm_ctx->ctx != NULL) - return; - - //BUG_ON(mpm_ctx->ctx != NULL); - - mpm_ctx->ctx = SCMalloc(sizeof(B2gCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_ctx->ctx, 0, sizeof(B2gCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gCtx); - - /* initialize the hash we use to speed up pattern insertions */ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(B2gPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - - memset(ctx->init_hash, 0, sizeof(B2gPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b2g_hash_size == 0) - B2gGetConfig(); - - /* init defaults search functions */ - ctx->Search = b2g_func; - - SCReturn; -} - -void B2gDestroyCtx(MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p", mpm_ctx); - - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gPattern *)); - } - - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B2gFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gPattern)); - } - - if (ctx->B2G) { - SCFree(ctx->B2G); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2G_TYPE) * ctx->hash_size); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->hash) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) - continue; - - B2gHashFree(mpm_ctx, ctx->hash[h]); - } - - SCFree(ctx->hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2gPattern) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gCtx); -} - -void B2gThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B2gThreadCtx) > 0) { /* size can be null when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_thread_ctx->ctx, 0, sizeof(B2gThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B2gThreadCtx); - } -} - -void B2gThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B2gThreadCtx *ctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; - - B2gPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL if B2gThreadCtx is optimized to 0 */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B2gThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -uint32_t B2gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; -} - -uint32_t B2gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; -#ifdef B2G_COUNTERS - B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B2G_Q + 1, matches = 0; - B2G_TYPE d; - - //printf("\n"); - //PrintRawDataFp(stdout, buf, buflen); - - SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, - ctx->m, pos); - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (uint32_t)(buflen - B2G_Q + 1)) { - uint16_t h = B2G_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); - d = ctx->B2G[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B2G_Q + 1); - - do { - j = j - 1; - - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) pos = j; - else { - /* get our patterns from the hash */ - h = B2G_HASH16(u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - j) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - SCLogDebug("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "", - ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B2gPattern *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - if ((buflen - j) < thi->len) { - continue; - } - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - //if (memcmp_lowercase(thi->ci, buf+j, thi->len) == 0) { - if (SCMemcmpLowercase(thi->ci, buf+j, thi->len) == 0) { -#ifdef PRINTMATCH - printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (SCMemcmp(thi->cs, buf+j, thi->len) == 0) { - //if (memcmp(thi->cs, buf+j, thi->len) == 0) { -#ifdef PRINTMATCH - printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - SCLogDebug("skipped"); - //SCLogDebug("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); - ; - } - } - - if (j == 0) { - break; - } - - h = B2G_HASH16(u8_tolower(buf[j - 1]),u8_tolower(buf[j])); - d = (d << 1) & ctx->B2G[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B2G_Q + 1)); - pos = pos + ctx->m - B2G_Q + 1; - - SCLogDebug("pos %"PRIu32"", pos); - } - - SCLogDebug("matches %"PRIu32"", matches); - return matches; -} - -uint32_t B2gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; -#ifdef B2G_COUNTERS - B2gThreadCtx *tctx = (B2gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B2G_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 1; - d = ~0; - - do { - uint16_t h = B2G_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2G[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - - /* get our patterns from the hash */ - uint16_t h = B2G_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - pos) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B2gPattern *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - //B2gPattern *p = ctx->parray[thi->idx]; - - if (buflen - pos < thi->len) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (SCMemcmpLowercase(thi->ci, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (SCMemcmp(thi->cs, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - //pos = pos + ctx->s0; - pos = pos + 1; - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -#ifdef B2G_SEARCH2 -uint32_t B2gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B2gPattern *p; - B2gPattern *thi, *hi; - - if (buflen < 2) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h8 = u8_tolower(*buf); - hi = &ctx->hash1[h8]; - - if (hi->flags & MPM_PATTERN_ONE_BYTE) { - for (thi = hi; thi != NULL; thi = thi->next) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } - } - } - - /* save one conversion by reusing h8 */ - uint16_t h16 = B2G_HASH16(h8, u8_tolower(*(buf+1))); - hi = ctx->hash2[h16]; - - for (thi = hi; thi != NULL; thi = thi->next) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); -// for (em = p->em; em; em = em->next) { - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) - cnt++; -// } - } - } else { - if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B2gSearch1)\n"); -// for (em = p->em; em; em = em->next) { - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) - cnt++; -// } - } - } - } - buf += 1; - } - - //printf("B2gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt > 0) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} -#endif - -uint32_t B2gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCEnter(); - - B2gCtx *ctx = (B2gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; -// B2gPattern *p; - B2gPattern *thi, *hi; - - if (buflen == 0) - SCReturnUInt(0); - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - hi = &ctx->hash1[h]; - - for (thi = hi; thi != NULL; thi = thi->next) { - if (hi->flags & MPM_PATTERN_ONE_BYTE) { - if (thi->len != 1) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - if (u8_tolower(*buf) == thi->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } - } else { - if (*buf == thi->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } - } - } - } - buf += 1; - } - - //printf("B2gSearch1: after 1byte cnt %" PRIu32 "\n", cnt); -#ifdef B2G_SEARCH2 - if (ctx->pat_2_cnt) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B2gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } else -#endif - if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - SCReturnUInt(cnt); -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B2gTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B2gTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B2gDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B2gTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B2gTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B2gTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch05a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ - //MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -#if 0 -static int B2gTestSearchXX (void) -{ - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2G); - B2gCtx *ctx = (B2gCtx *)mpm_ctx.ctx; - - FILE *fp = fopen("/usr/share/dict/words", "r"); - if (fp == NULL) - exit(1); - - char *word; - char line[128]; - int w = 0; - int w_max = 4000; - - while((word = fgets(line, sizeof(line), fp)) != NULL) { - word[strlen(word) - 1] = '\0'; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); - - w++; - - if (w_max == w) - break; - } - - B2gPreparePatterns(&mpm_ctx); - B2gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; - uint32_t len = strlen(text) - 1; - - int i; - uint32_t cnt; - for (i = 0; i < 100; i++) { - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); - } - - printf("cnt %u ", cnt); - - B2gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gDestroyCtx(&mpm_ctx); - fclose(fp); - - return 1; -} -#endif - -void B2gRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B2gTestInit01", B2gTestInit01, 1); -/* - UtRegisterTest("B2gTestS0Init01", B2gTestS0Init01, 1); - UtRegisterTest("B2gTestS0Init02", B2gTestS0Init02, 1); - UtRegisterTest("B2gTestS0Init03", B2gTestS0Init03, 1); - UtRegisterTest("B2gTestS0Init04", B2gTestS0Init04, 1); - UtRegisterTest("B2gTestS0Init05", B2gTestS0Init05, 1); -*/ - UtRegisterTest("B2gTestSearch01", B2gTestSearch01, 1); - UtRegisterTest("B2gTestSearch02", B2gTestSearch02, 1); - UtRegisterTest("B2gTestSearch03", B2gTestSearch03, 1); - UtRegisterTest("B2gTestSearch04", B2gTestSearch04, 1); - UtRegisterTest("B2gTestSearch05", B2gTestSearch05, 1); - UtRegisterTest("B2gTestSearch05a", B2gTestSearch05a, 1); - UtRegisterTest("B2gTestSearch06", B2gTestSearch06, 1); - UtRegisterTest("B2gTestSearch07", B2gTestSearch07, 1); - UtRegisterTest("B2gTestSearch08", B2gTestSearch08, 1); - UtRegisterTest("B2gTestSearch09", B2gTestSearch09, 1); - UtRegisterTest("B2gTestSearch10", B2gTestSearch10, 1); - UtRegisterTest("B2gTestSearch11", B2gTestSearch11, 1); - UtRegisterTest("B2gTestSearch12", B2gTestSearch12, 1); - UtRegisterTest("B2gTestSearch13", B2gTestSearch13, 1); - UtRegisterTest("B2gTestSearch14", B2gTestSearch14, 1); - UtRegisterTest("B2gTestSearch15", B2gTestSearch15, 1); - UtRegisterTest("B2gTestSearch16", B2gTestSearch16, 1); - UtRegisterTest("B2gTestSearch17", B2gTestSearch17, 1); - UtRegisterTest("B2gTestSearch18", B2gTestSearch18, 1); - UtRegisterTest("B2gTestSearch19", B2gTestSearch19, 1); - UtRegisterTest("B2gTestSearch20", B2gTestSearch20, 1); - UtRegisterTest("B2gTestSearch21", B2gTestSearch21, 1); -// UtRegisterTest("B2gTestSearchXX", B2gTestSearchXX, 1); -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b2g.h b/src/util-mpm-b2g.h deleted file mode 100644 index 2d22b0ef58bf..000000000000 --- a/src/util-mpm-b2g.h +++ /dev/null @@ -1,122 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_MPM_B2G_H__ -#define __UTIL_MPM_B2G_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B2G_HASHSHIFT_MAX 8 -#define B2G_HASHSHIFT_HIGHER 7 -#define B2G_HASHSHIFT_HIGH 6 -#define B2G_HASHSHIFT_MEDIUM 5 -#define B2G_HASHSHIFT_LOW 4 -#define B2G_HASHSHIFT_LOWEST 3 - -//#define B2G_TYPE uint64_t -#define B2G_TYPE uint32_t -//#define B2G_TYPE uint16_t -//#define B2G_TYPE uint8_t -//#define B2G_WORD_SIZE 64 -#define B2G_WORD_SIZE 32 -//#define B2G_WORD_SIZE 16 -//#define B2G_WORD_SIZE 8 - -#define B2G_Q 2 - -#define B2G_SEARCHFUNC B2gSearchBNDMq -//#define B2G_SEARCHFUNC B2gSearch - -//#define B2G_SEARCH2 -//#define B2G_COUNTERS - -typedef struct B2gPattern_ { - uint16_t len; /**< \todo we're limited to 32/64 byte lengths, uint8_t would be fine here */ - uint8_t flags; - uint8_t pad0; - uint32_t id; - uint8_t *original_pat; - uint8_t *ci; /* case INsensitive */ - uint8_t *cs; /* case sensitive */ - struct B2gPattern_ *next; -} B2gPattern; - -typedef struct B2gCtx_ { - B2G_TYPE *B2G; - B2G_TYPE m; - BloomFilter **bloom; - uint8_t *pminlen; /* array containing the minimal length - of the patters in a hash bucket. Used - for the BloomFilter. */ - /* pattern arrays */ - B2gPattern **parray; - - uint16_t pat_1_cnt; -#ifdef B2G_SEARCH2 - uint16_t pat_2_cnt; -#endif - uint16_t pat_x_cnt; - - uint32_t hash_size; - B2gPattern **hash; - B2gPattern hash1[256]; -#ifdef B2G_SEARCH2 - B2gHashItem **hash2; -#endif - - /* hash used during ctx initialization */ - B2gPattern **init_hash; - - uint8_t s0; - - /* we store our own multi byte search func ptr here for B2gSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* we store our own multi byte search func ptr here for B2gSearch1 */ - uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); -} B2gCtx; - -typedef struct B2gThreadCtx_ { -#ifdef B2G_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* B2G_COUNTERS */ -} B2gThreadCtx; - -void MpmB2gRegister(void); - - -#endif - diff --git a/src/util-mpm-b2gc.c b/src/util-mpm-b2gc.c deleted file mode 100644 index b80100d5c3eb..000000000000 --- a/src/util-mpm-b2gc.c +++ /dev/null @@ -1,2946 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implementation of the SBNDMq pattern matching algorithm that tries - * to be very limiting memory use and CPU cache efficient. - * - * Things to try: - * - 1 byte pattern checks use lowercase *buf for hash, limiting the hash - * - lookup array with pminlen and pminlenb like in B2gm - */ - -//#define PRINTMATCH - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" - -#include "util-mpm-b2gc.h" -#include "util-print.h" -#include "util-bloomfilter.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-hashlist.h" -#include "util-optimize.h" -#include "util-memcmp.h" - -#include "conf.h" - -#ifdef B2GC_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B2GC_COUNTERS */ - -/* Hash table used at ctx initialization to keep and ordered list of - * patterns. The ordered list is used to build the ordered lookup - * array. */ -static uint32_t b2gc_hash_size = 0; -static int8_t b2gc_hash_shift = 0; -static uint32_t b2gc_bloom_size = 0; -static void *b2g_func; - -#define B2GC_HASH16(a,b) (((a) << b2gc_hash_shift) | (b)) - -#define B2GC_PMINLEN_MAX 8 - -/* align pattern storage to these bytes. 1 disables. */ -#define B2GC_ALIGN_PATTERNS 2 - -void B2gcInitCtx (MpmCtx *); -void B2gcThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B2gcDestroyCtx(MpmCtx *); -void B2gcThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gcAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gcAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gcPreparePatterns(MpmCtx *mpm_ctx); -uint32_t B2gcSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#ifdef B2GC_SEARCH2 -uint32_t B2gcSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#endif -uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void B2gcPrintInfo(MpmCtx *mpm_ctx); -void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void B2gcRegisterTests(void); - -void MpmB2gcRegister (void) -{ - mpm_table[MPM_B2GC].name = "b2gc"; - mpm_table[MPM_B2GC].max_pattern_length = B2GC_WORD_SIZE; - - mpm_table[MPM_B2GC].InitCtx = B2gcInitCtx; - mpm_table[MPM_B2GC].InitThreadCtx = B2gcThreadInitCtx; - mpm_table[MPM_B2GC].DestroyCtx = B2gcDestroyCtx; - mpm_table[MPM_B2GC].DestroyThreadCtx = B2gcThreadDestroyCtx; - mpm_table[MPM_B2GC].AddPattern = B2gcAddPatternCS; - mpm_table[MPM_B2GC].AddPatternNocase = B2gcAddPatternCI; - mpm_table[MPM_B2GC].Prepare = B2gcPreparePatterns; - mpm_table[MPM_B2GC].Search = B2gcSearchWrap; - mpm_table[MPM_B2GC].Cleanup = NULL; - mpm_table[MPM_B2GC].PrintCtx = B2gcPrintInfo; - mpm_table[MPM_B2GC].PrintThreadCtx = B2gcPrintSearchStats; - mpm_table[MPM_B2GC].RegisterUnittests = B2gcRegisterTests; -} - -#ifdef PRINTMATCH -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%02X", buf[i]); - } - //printf("\n"); -} -#endif - -void B2gcPrintInfo(MpmCtx *mpm_ctx) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - printf("MPM B2gc Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B2gcCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcCtx)); - printf(" B2gcPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -static inline int -memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) - if (s1[i] != u8_tolower(*(s2+i))) - return 1; - } - - return 0; -} - -static inline int -memcmp_lowercase2(uint8_t *s1, uint8_t *s2, uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) - if (u8_tolower(s1[i]) != u8_tolower(*(s2+i))) - return 1; - } - - return 0; -} - -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) -{ - uint16_t i; - for (i = 0; i < len; i++) { - d[i] = u8_tolower(s[i]); - } -} - -static inline B2gcPattern *B2gcAllocPattern(MpmCtx *mpm_ctx) -{ - B2gcPattern *p = SCMalloc(sizeof(B2gcPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B2gcPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gcPattern); - return p; -} - -/** \internal - * \brief Free a init hash pattern - */ -static void B2gcFreePattern(MpmCtx *mpm_ctx, B2gcPattern *p) -{ - if (p != NULL) { - if (p->pat != NULL) { - SCFree(p->pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gcPattern); - } -} - -/** \internal - * \brief add a pattern to the mpm/b2g context - * - * \param pat ptr to the pattern - * \param patlen length of the pattern - * \param pid pattern id - * \param sid signature id (internal id) - * \param flags pattern MPM_PATTERN_* flags - */ -static int B2gcAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); - - if (patlen == 0) - return 0; - - /* detect duplicate pattern adds */ - B2gcPattern lookup_p = { patlen, flags, 0, pid, pat }; - - /* get a memory piece */ - B2gcPattern *p = HashListTableLookup(ctx->b2gc_init_hash, (void *)&lookup_p, sizeof(B2gcPattern)); - if (p == NULL) { - SCLogDebug("allocing new pattern"); - - p = B2gcAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - p->pat = SCMalloc(patlen); - if (p->pat == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - - memcpy(p->pat, pat, patlen); - - /* put in the pattern hash */ - HashListTableAdd(ctx->b2gc_init_hash, (void *)p, sizeof(B2gcPattern)); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) - mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; -} - return 0; - -error: - B2gcFreePattern(mpm_ctx, p); - return -1; -} - -int B2gcAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B2gcAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static inline uint32_t B2gcBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static uint32_t B2gcHashPatternInitHash(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gcPattern)); - BUG_ON(pattern == NULL); - - B2gcPattern *p = (B2gcPattern *)pattern; - uint32_t hash = 0; - - uint32_t u; - for (u = 0; u < p->len; u++) { - hash += (u8_tolower(p->pat[u])); - } - - return hash % ht->array_size; -} - -#define B2GC_SORTHASH_MODE_LL 0 -#define B2GC_SORTHASH_MODE_LU 1 -#define B2GC_SORTHASH_MODE_UL 2 -#define B2GC_SORTHASH_MODE_UU 3 -#define B2GC_SORTHASH_MODE_CS 4 - -/* copy of ctx->m for use in B2gcHashPatternSortHash */ -static B2GC_TYPE m; -static int b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; - -static uint32_t B2gcHashPatternSortHash(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gcPattern)); - BUG_ON(pattern == NULL); - - B2gcPattern *p = (B2gcPattern *)pattern; - uint32_t hash = 0; - if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LL) { - hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); - } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LU) { - hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), toupper(p->pat[m - 1])); - } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UL) { - hash = B2GC_HASH16(toupper(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); - } else if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UU) { - hash = B2GC_HASH16(toupper(p->pat[m - 2]), toupper(p->pat[m - 1])); - } else { - hash = B2GC_HASH16(p->pat[m - 2], p->pat[m - 1]); - } - SCReturnUInt(hash); -} - -static uint32_t B2gcHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gcPattern)); - BUG_ON(pattern == NULL); - - B2gcPattern *p = (B2gcPattern *)pattern; - return (uint32_t)u8_tolower(p->pat[0]); -} - -static char B2gcHashPatternCompare(void *pattern1, uint16_t len1, - void *pattern2, uint16_t len2) -{ - BUG_ON(len1 != sizeof(B2gcPattern)); - BUG_ON(len2 != sizeof(B2gcPattern)); - - B2gcPattern *p1 = (B2gcPattern *)pattern1; - B2gcPattern *p2 = (B2gcPattern *)pattern2; - - if (p1->id != p2->id) { - return 0; - } - - return 1; -} - -static void B2gcHashPatternFree(void *pattern) -{ - B2gcPattern *p = (B2gcPattern *)pattern; - - SCFree(p->pat); - - SCFree(pattern); -} - -static void B2gcAddToMatchArray(MpmCtx *mpm_ctx, B2gcPattern *p, int j) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GC_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); - ctx->B2GC[uuidx] = ctx->B2GC[uuidx] | (1 << (ctx->m - j)); - - /* l, l */ - uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (llidx != uuidx) { - ctx->B2GC[llidx] = ctx->B2GC[llidx] | (1 << (ctx->m - j)); - } - /* u, l */ - uint16_t ulidx = B2GC_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (ulidx != llidx && ulidx != uuidx) { - ctx->B2GC[ulidx] = ctx->B2GC[ulidx] | (1 << (ctx->m - j)); - } - /* l, u */ - uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - ctx->B2GC[luidx] = ctx->B2GC[luidx] | (1 << (ctx->m - j)); - } - - SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); - } -} - -int B2gcBuildMatchArray(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash) -{ - SCEnter(); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - ctx->B2GC = SCMalloc(sizeof(B2GC_TYPE) * ctx->hash_size); - if (ctx->B2GC == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2GC_TYPE) * ctx->hash_size); - - memset(ctx->B2GC, 0x00, (b2gc_hash_size * sizeof(B2GC_TYPE))); - - uint32_t j; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2GC_Q); j++) { - HashListTableBucket *next = NULL; - HashListTableBucket *buck = HashListTableGetListHead(b2gc_sort_hash); - - while (buck != NULL) { - /* get the next before we free "buck" */ - next = HashListTableGetListNext(buck); - - B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); - BUG_ON(p == NULL); - - if (p->len < ctx->m) - goto next; - - uint16_t h; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - B2gcAddToMatchArray(mpm_ctx, p, j); - } else { - h = B2GC_HASH16(p->pat[j],p->pat[j+1]); - ctx->B2GC[h] = ctx->B2GC[h] | (1 << (ctx->m - j)); - SCLogDebug("h %"PRIu16", ctx->B2GC[h] %"PRIu32" (cs)", h, ctx->B2GC[h]); - } - next: - buck = next; - } - } - - SCReturnInt(0); -} - -static void B2gcAddCopyToHash(MpmCtx *mpm_ctx, HashListTable *ht, B2gcPattern *p) -{ - B2gcPattern *pcopy = B2gcAllocPattern(mpm_ctx); - BUG_ON(pcopy == NULL); - pcopy->id = p->id; - pcopy->flags = p->flags; - pcopy->len = p->len; - - pcopy->pat = SCMalloc(pcopy->len); - BUG_ON(pcopy->pat == NULL); - - memcpy(pcopy->pat, p->pat, pcopy->len); - - HashListTableAdd(ht, (void *)pcopy, sizeof(B2gcPattern)); -} - -static int B2gcAddToHash(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash, B2gcPattern *p) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - int added = 0; - //printf("%c.%c\n", p->pat[ctx->m - 2], p->pat[ctx->m - 1]); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UU; - HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); - added++; - - /* l, l */ - uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); - if (llidx != uuidx) { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; - B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); - added++; - } - /* u, l */ - uint16_t ulidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); - if (ulidx != llidx && ulidx != uuidx) { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UL; - B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); - added++; - } - /* l, u */ - uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LU; - B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); - added++; - } - - SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); - } - - return added; -} - -static void B2gcPrepareHash(MpmCtx *mpm_ctx) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - HashListTable *b2gc_sort_hash = NULL; - HashListTable *b2gc_sort_hash1 = NULL; - - /* make sure ctx->m is set */ - BUG_ON(ctx->m == 0); - m = ctx->m; - - /* convert b2gc_init_hash to b2gc_sort_hash and count size */ - uint32_t size = B2GC_ALIGN_PATTERNS; - uint16_t size1 = 1; - - /* only used at init */ - b2gc_sort_hash = HashListTableInit(b2gc_hash_size, B2gcHashPatternSortHash, B2gcHashPatternCompare, B2gcHashPatternFree); - if (b2gc_sort_hash == NULL) { - exit(EXIT_FAILURE); - } - - b2gc_sort_hash1 = HashListTableInit(256, B2gcHashPatternSortHash1, B2gcHashPatternCompare, B2gcHashPatternFree); - if (b2gc_sort_hash1 == NULL) { - exit(EXIT_FAILURE); - } - - HashListTableBucket *next = NULL; - HashListTableBucket *buck = HashListTableGetListHead(ctx->b2gc_init_hash); - while (buck != NULL) { - /* get the next before we free "buck" */ - next = HashListTableGetListNext(buck); - - B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); - BUG_ON(p == NULL); - - //printf("init_hash: "); prt(p->pat,p->len);printf("\n"); - if (p->len > 1) { - uint32_t psize; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - //prt(p->pat, p->len);printf(" (m %u)\n", m); - int added = B2gcAddToHash(mpm_ctx, b2gc_sort_hash, p); - SCLogDebug("nocase pattern was added under different hash values %d times", added); - - uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS))); - //uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS)) * 2); - psize = one * added; - } else { - b2gc_sorthash_mode = B2GC_SORTHASH_MODE_CS; - HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); - - psize = (sizeof(B2gcPatternHdr) + p->len + (p->len % B2GC_ALIGN_PATTERNS)); - } - - size += psize; - } else { - HashListTableAdd(b2gc_sort_hash1, (void *)p, sizeof(B2gcPattern)); - size1 += (sizeof(B2gcPattern1)); - } - - buck = next; - } - HashListTableFree(ctx->b2gc_init_hash); - ctx->b2gc_init_hash = NULL; - - SCLogDebug("size %u", size); - - /* alloc buf of size */ - ctx->patterns = SCMalloc(size); - BUG_ON(ctx->patterns == NULL); - memset(ctx->patterns, 0x00, size); - - ctx->patterns1 = SCMalloc(size1); - BUG_ON(ctx->patterns1 == NULL); - memset(ctx->patterns1, 0x00, size1); - - /* loop through sort list and copy to buf */ - - /* skip the first byte of the buffer */ - uint32_t offset = B2GC_ALIGN_PATTERNS; - - /* the hashlist is not sorted, it's in the order of insertion. - * We need it to be sorted by hash, so here we do something - * unclean: we bypass the hashlist api. */ - uint32_t a = 0; - for (a = 0; a < b2gc_sort_hash->array_size; a++) { - if ((buck = b2gc_sort_hash->array[a]) != NULL) { - while (buck != NULL) { - if (buck->data != NULL) { - uint32_t prev_offset = offset; - B2gcPattern *p = (B2gcPattern *) (buck->data); - BUG_ON(p == NULL); - BUG_ON(p->len == 1); - - uint16_t hash = a;//= B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); - if (ctx->pminlen[hash] == 0) { - ctx->pminlen[hash] = p->len; - } else if (p->len < ctx->pminlen[hash]) { - ctx->pminlen[hash] = p->len; - } - - if (ctx->ha[hash] == 0) - ctx->ha[hash] = offset; - - /* copy */ - B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; - h->id = p->id; - h->len = p->len; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - h->flags |= B2GC_FLAG_NOCASE; - } - - offset += sizeof(B2gcPatternHdr); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - memcpy_tolower(&ctx->patterns[offset], p->pat, p->len); - } else { - memcpy(&ctx->patterns[offset], p->pat, p->len); - } - offset += (p->len + (p->len % B2GC_ALIGN_PATTERNS)); - - h->np_offset = offset - prev_offset; - - SCLogDebug("h->offset %u", offset); - - ctx->pat_x_cnt++; - - } - buck = buck->bucknext; - } - } - } - - /* build the hash containing idx' to the pattern array */ - for (a = 0; a < b2gc_hash_size; a++) { - uint32_t offset = ctx->ha[a]; - uint32_t next_offset = 0; - - if (offset > 0) { - uint32_t b = a + 1; - while (b < b2gc_hash_size) { - if (ctx->ha[b] > 0) { - next_offset = ctx->ha[b]; - break; - } - - b++; - } - } - - while (offset > 0) { - B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; - BUG_ON(h == NULL); - BUG_ON(h->len <= 1); - - uint8_t *pattern = (uint8_t *)&ctx->patterns[offset + sizeof(B2gcPatternHdr)]; - BUG_ON(pattern == NULL); - //printf("hash %u (offset %u, h %u) sort_hash: ", a, offset, ctx->ha[a]);prt(pattern,h->len);printf("\n"); - - uint16_t hash = a; - - SCLogDebug("hash %u, offset %u", hash, offset); - - if (ctx->bloom[hash] == NULL) { - ctx->bloom[hash] = BloomFilterInit(b2gc_bloom_size, 2, B2gcBloomHash); - SCLogDebug("bloom created for hash %u", hash); - BUG_ON(ctx->bloom[hash] == NULL); - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[hash]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[hash]); - } - - if (ctx->pminlen[hash] > B2GC_PMINLEN_MAX) - ctx->pminlen[hash] = B2GC_PMINLEN_MAX; - - BloomFilterAdd(ctx->bloom[hash], pattern, ctx->pminlen[hash]); - - offset += h->np_offset; - - /* last item in the pattern storage is "final" too */ - if (offset == size) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GC_FLAG_FINAL; - break; - } - - /* next_offset points to next hash */ - if (next_offset > 0 && offset == next_offset) { - SCLogDebug("last pattern for this hash"); - h->flags |= B2GC_FLAG_FINAL; - break; - } - } - } - - /* skip the first byte of the buffer */ - uint16_t offset1 = 1; - - for (a = 0; a < b2gc_sort_hash1->array_size; a++) { - buck = b2gc_sort_hash1->array[a]; - if (buck != NULL) { - while (buck != NULL) { - if (buck->data != NULL) { - B2gcPattern *p = (B2gcPattern *) (buck->data); - BUG_ON(p == NULL); - BUG_ON(p->len != 1); - - B2gcPattern1 *h = (B2gcPattern1 *)&ctx->patterns1[offset1]; - h->id = p->id; - h->pat = p->pat[0]; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - h->flags |= B2GC_FLAG_NOCASE; - } - - offset1 += (sizeof(B2gcPattern1)); - - ctx->pat_1_cnt++; - } - buck = buck->bucknext; - } - } - } - - /* build the hash containing idx' to the pattern array */ - offset1 = 1; - - B2gcPattern1 *ph1 = NULL; - uint8_t prevhash1 = 0; - while (offset1 < size1) { - B2gcPattern1 *h = (B2gcPattern1 *)&ctx->patterns1[offset1]; - - if (ctx->ha1[u8_tolower(h->pat)] == 0) - ctx->ha1[u8_tolower(h->pat)] = offset1; - - /* check the prev pattern for setting the final flag */ - if (ph1 != NULL) { - if (h->pat != prevhash1) { - SCLogDebug("setting final flag on %p", ph1); - ph1->flags |= B2GC_FLAG_FINAL; - } - } - - prevhash1 = u8_tolower(h->pat); - ph1 = h; - - offset1 += (sizeof(B2gcPattern1)); - - /* last item is "final" too */ - if (offset1 == size1) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GC_FLAG_FINAL; - } - } - - B2gcBuildMatchArray(mpm_ctx, b2gc_sort_hash); - - /* free the hashes only used at init */ - HashListTableFree(b2gc_sort_hash); - b2gc_sort_hash = NULL; - - HashListTableFree(b2gc_sort_hash1); - b2gc_sort_hash1 = NULL; -} - -int B2gcPreparePatterns(MpmCtx *mpm_ctx) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B2GC_WORD_SIZE) { - ctx->m = B2GC_WORD_SIZE - 1; - } - if (ctx->m < 2) - ctx->m = 2; - - ctx->hash_size = b2gc_hash_size; - - /* alloc the hashes */ - ctx->ha = SCMalloc(b2gc_hash_size * sizeof(uint32_t)); - BUG_ON(ctx->ha == NULL); - memset(ctx->ha, 0x00, b2gc_hash_size * sizeof(uint32_t)); - - ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); - BUG_ON(ctx->ha1 == NULL); - memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - exit(EXIT_FAILURE); - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - exit(EXIT_FAILURE); - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - - B2gcPrepareHash(mpm_ctx); - - SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); - if (ctx->pat_1_cnt) { - ctx->Search = B2gcSearch1; - - ctx->MBSearch = b2g_func; - } - - return 0; -} - -void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B2GC_COUNTERS - B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; - - printf("B2gc Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); -#endif /* B2GC_COUNTERS */ -} - -/** - * \brief Function to get the user defined values for b2g algorithm from the - * config file 'suricata.yaml' - */ -static void B2gcGetConfig() -{ - ConfNode *b2g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b2gc_hash_size = HASHSIZE_LOW; - b2gc_hash_shift = B2GC_HASHSHIFT_LOW; - b2gc_bloom_size = BLOOMSIZE_MEDIUM; - b2g_func = B2GC_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strncmp(b2g_conf->val, "b2gc", 4) == 0) { - - algo = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "algo"); - hash_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "hash_size"); - bloom_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B2gcSearch") == 0) { - b2g_func = B2gcSearch; - } else if (strcmp(algo, "B2gcSearchBNDMq") == 0) { - b2g_func = B2gcSearchBNDMq; - } - } - - if (hash_val != NULL) { - b2gc_hash_size = MpmGetHashSize(hash_val); - switch (b2gc_hash_size) { - case HASHSIZE_LOWEST: - b2gc_hash_shift = B2GC_HASHSHIFT_LOWEST; - break; - case HASHSIZE_LOW: - b2gc_hash_shift = B2GC_HASHSHIFT_LOW; - break; - case HASHSIZE_MEDIUM: - b2gc_hash_shift = B2GC_HASHSHIFT_MEDIUM; - break; - case HASHSIZE_HIGH: - b2gc_hash_shift = B2GC_HASHSHIFT_HIGH; - break; - case HASHSIZE_HIGHER: - b2gc_hash_shift = B2GC_HASHSHIFT_HIGHER; - break; - case HASHSIZE_MAX: - b2gc_hash_shift = B2GC_HASHSHIFT_MAX; - break; - } - } - if (bloom_val != NULL) - b2gc_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b2gc_hash_size, b2gc_bloom_size); - } - } - } -} - -void B2gcInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); - - if (mpm_ctx->ctx != NULL) - return; - - //BUG_ON(mpm_ctx->ctx != NULL); - - mpm_ctx->ctx = SCMalloc(sizeof(B2gcCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_ctx->ctx, 0, sizeof(B2gcCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gcCtx); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b2gc_hash_size == 0) - B2gcGetConfig(); - - /* initialize the hash we use to speed up pattern insertions */ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - - ctx->b2gc_init_hash = HashListTableInit(4096, B2gcHashPatternInitHash, B2gcHashPatternCompare, NULL); - if (ctx->b2gc_init_hash == NULL) { - exit(EXIT_FAILURE); - } - - /* init defaults search functions */ - ctx->Search = b2g_func; - - SCReturn; -} - -void B2gcDestroyCtx(MpmCtx *mpm_ctx) -{ - - SCLogDebug("mpm_ctx %p", mpm_ctx); - - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->b2gc_init_hash != NULL) { - HashListTableFree(ctx->b2gc_init_hash); - } - - if (ctx->B2GC != NULL) { - SCFree(ctx->B2GC); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2GC_TYPE) * ctx->hash_size); - } - - if (ctx->ha != NULL) { - SCFree(ctx->ha); - } - - if (ctx->ha1 != NULL) { - SCFree(ctx->ha1); - } - - if (ctx->patterns != NULL) { - SCFree(ctx->patterns); - } - - if (ctx->patterns1 != NULL) { - SCFree(ctx->patterns1); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gcCtx); -} - -void B2gcThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B2gcThreadCtx) > 0) { /* size can be null when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gcThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_thread_ctx->ctx, 0, sizeof(B2gcThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B2gcThreadCtx); - } -} - -void B2gcThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B2gcThreadCtx *ctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; - - B2gcPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL if B2gcThreadCtx is optimized to 0 */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B2gcThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -uint32_t B2gcSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; -} - -uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; -#ifdef B2GC_COUNTERS - B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B2GC_Q + 1, matches = 0; - B2GC_TYPE d; - - //printf("\n"); - //PrintRawDataFp(stdout, buf, buflen); - - SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32, - buflen, ctx->m, pos); - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (uint32_t)(buflen - B2GC_Q + 1)) { - //uint16_t h = B2GC_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); - uint16_t h = B2GC_HASH16(buf[pos - 1], buf[pos]); - d = ctx->B2GC[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B2GC_Q + 1); - - do { - j = j - 1; - - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) - pos = j; - else { - /* get our patterns from the hash */ - h = B2GC_HASH16(buf[j + ctx->m - 2], buf[j + ctx->m - 1]); - if (ctx->pminlen[h] > 0 && (buflen - j) >= ctx->pminlen[h] && - BloomFilterTest(ctx->bloom[h], buf+pos-1, ctx->pminlen[h]) == 1) - { - uint32_t offset = ctx->ha[h]; - SCLogDebug("offset %u, hash %u", offset, h); - do { - B2gcPatternHdr *hdr = (B2gcPatternHdr *)&ctx->patterns[offset]; - //BUG_ON(hdr->len <= 1); - offset += hdr->np_offset; - SCLogDebug("next offset %u", offset); - - if (hdr->len <= (buflen - j)) { - if (hdr->flags & B2GC_FLAG_NOCASE) { - uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); - //uint8_t *pattern = (uint8_t *)hdr + hdr->nc_offset; - SCLogDebug("nocase compare"); -#ifdef PRINTMATCH - prt(pattern, hdr->len);printf("\n"); - prt(buf+pos-1, hdr->len);printf("\n"); -#endif - if (SCMemcmpLowercase(pattern, buf+pos-1, hdr->len) == 0) { - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } else { - uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); - SCLogDebug("case sensitive compare"); -#ifdef PRINTMATCH - prt(pattern, hdr->len);printf("\n"); - prt(buf+pos-1, hdr->len);printf("\n"); -#endif - if (SCMemcmp(pattern, buf+pos-1, hdr->len) == 0) { - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } - } - - if (hdr->flags & B2GC_FLAG_FINAL) { - SCLogDebug("final flag set, done matching"); - break; - } - } while(1); - } - } - } - - if (j == 0) { - break; - } - - h = B2GC_HASH16(buf[j - 1], buf[j]); - d = (d << 1) & ctx->B2GC[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B2GC_Q + 1)); - pos = pos + ctx->m - B2GC_Q + 1; - - SCLogDebug("pos %"PRIu32"", pos); - } - - SCLogDebug("matches %"PRIu32"", matches); - return matches; -} - -uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; -#ifdef B2GC_COUNTERS - B2gcThreadCtx *tctx = (B2gcThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B2GC_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 1; - d = ~0; - - do { - uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2GC[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - -#if 0 - /* get our patterns from the hash */ - uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - B2gcPattern *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - //B2gcPattern *p = ctx->parray[thi->idx]; - - if (buflen - pos < thi->len) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (memcmp_lowercase(thi->ci, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (memcmp(thi->cs, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - //pos = pos + ctx->s0; - pos = pos + 1; -#endif - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCEnter(); - - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - - if (buflen == 0) - SCReturnUInt(0); - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - uint16_t offset = ctx->ha1[h]; - SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); - - if (offset > 0) { - do { - B2gcPattern1 *hdr = (B2gcPattern1 *)&ctx->patterns1[offset]; - offset += (sizeof(B2gcPattern1)); - - SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); - - if (hdr->flags & B2GC_FLAG_NOCASE) { - SCLogDebug("nocase compare, %02X", *buf); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } else { - SCLogDebug("case sensitive compare, %02X", *buf); - - if (*buf == hdr->pat) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } - - if (hdr->flags & B2GC_FLAG_FINAL) - break; - } while(1); - } - buf += 1; - } - - //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - SCReturnUInt(cnt); -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B2gcTestMacro01 (void) -{ - int result = 1; - - B2gcPatternHdr a; - B2gcPatternHdr *b = &a; - - memset(&a, 0xff, sizeof(a)); - - printf("ID %u\n", B2GC_GET_ID(b)); - printf("FLAGS %u\n", B2GC_GET_FLAGS(b)); - printf("LEN %u\n", B2GC_GET_LEN(b)); - - return result; -} - -static int B2gcTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B2gcTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B2gcDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B2gcTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B2gcTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B2gcTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05b (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 3, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abXD", 4, 0, 0, 5, 0, 0); /* 0 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05c (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch05d (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ABCD", 4); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch06a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt; - int i; - for (i = 0; i<100000;i++) - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch07a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 30) - result = 1; - else - printf("30 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ - //MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gcTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -#if 0 -static int B2gcTestSearchXX (void) -{ - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GC); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; - - FILE *fp = fopen("/usr/share/dict/words", "r"); - if (fp == NULL) - exit(1); - - char *word; - char line[128]; - int w = 0; - int w_max = 4000; - - while((word = fgets(line, sizeof(line), fp)) != NULL) { - word[strlen(word) - 1] = '\0'; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); - - w++; - - if (w_max == w) - break; - } - - B2gcPreparePatterns(&mpm_ctx); - B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; - uint32_t len = strlen(text) - 1; - - int i; - uint32_t cnt; - for (i = 0; i < 100; i++) { - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); - } - printf("cnt %u ", cnt); - - B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gcDestroyCtx(&mpm_ctx); - fclose(fp); - - return 1; -} -#endif - -void B2gcRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B2gcTestMacro01", B2gcTestMacro01, 1); - UtRegisterTest("B2gcTestInit01", B2gcTestInit01, 1); -/* - UtRegisterTest("B2gcTestS0Init01", B2gcTestS0Init01, 1); - UtRegisterTest("B2gcTestS0Init02", B2gcTestS0Init02, 1); - UtRegisterTest("B2gcTestS0Init03", B2gcTestS0Init03, 1); - UtRegisterTest("B2gcTestS0Init04", B2gcTestS0Init04, 1); - UtRegisterTest("B2gcTestS0Init05", B2gcTestS0Init05, 1); -*/ - UtRegisterTest("B2gcTestSearch01", B2gcTestSearch01, 1); - UtRegisterTest("B2gcTestSearch02", B2gcTestSearch02, 1); - UtRegisterTest("B2gcTestSearch03", B2gcTestSearch03, 1); - UtRegisterTest("B2gcTestSearch04", B2gcTestSearch04, 1); - UtRegisterTest("B2gcTestSearch05", B2gcTestSearch05, 1); - UtRegisterTest("B2gcTestSearch05a", B2gcTestSearch05a, 1); - UtRegisterTest("B2gcTestSearch05b", B2gcTestSearch05b, 1); - UtRegisterTest("B2gcTestSearch05c", B2gcTestSearch05c, 1); - UtRegisterTest("B2gcTestSearch05d", B2gcTestSearch05d, 1); - UtRegisterTest("B2gcTestSearch06", B2gcTestSearch06, 1); - UtRegisterTest("B2gcTestSearch06a", B2gcTestSearch06a, 1); - UtRegisterTest("B2gcTestSearch07", B2gcTestSearch07, 1); - UtRegisterTest("B2gcTestSearch07a", B2gcTestSearch07a, 1); - UtRegisterTest("B2gcTestSearch08", B2gcTestSearch08, 1); - UtRegisterTest("B2gcTestSearch09", B2gcTestSearch09, 1); - UtRegisterTest("B2gcTestSearch10", B2gcTestSearch10, 1); - UtRegisterTest("B2gcTestSearch11", B2gcTestSearch11, 1); - UtRegisterTest("B2gcTestSearch12", B2gcTestSearch12, 1); - UtRegisterTest("B2gcTestSearch13", B2gcTestSearch13, 1); - UtRegisterTest("B2gcTestSearch14", B2gcTestSearch14, 1); - UtRegisterTest("B2gcTestSearch15", B2gcTestSearch15, 1); - UtRegisterTest("B2gcTestSearch16", B2gcTestSearch16, 1); - UtRegisterTest("B2gcTestSearch17", B2gcTestSearch17, 1); - UtRegisterTest("B2gcTestSearch18", B2gcTestSearch18, 1); - UtRegisterTest("B2gcTestSearch19", B2gcTestSearch19, 1); - UtRegisterTest("B2gcTestSearch20", B2gcTestSearch20, 1); - UtRegisterTest("B2gcTestSearch21", B2gcTestSearch21, 1); -/* - UtRegisterTest("B2gcTestSearchXX", B2gcTestSearchXX, 1); -*/ -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b2gc.h b/src/util-mpm-b2gc.h deleted file mode 100644 index f72e389b74b5..000000000000 --- a/src/util-mpm-b2gc.h +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_MPM_B2GC_H__ -#define __UTIL_MPM_B2GC_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B2GC_HASHSHIFT_MAX 8 -#define B2GC_HASHSHIFT_HIGHER 7 -#define B2GC_HASHSHIFT_HIGH 6 -#define B2GC_HASHSHIFT_MEDIUM 5 -#define B2GC_HASHSHIFT_LOW 4 -#define B2GC_HASHSHIFT_LOWEST 3 - -//#define B2GC_HASHSHIFT 8 -//#define B2GC_HASHSHIFT 7 -//#define B2GC_HASHSHIFT 6 -//#define B2GC_HASHSHIFT 5 -#define B2GC_HASHSHIFT 4 -//#define B2GC_HASHSHIFT 3 - -//#define B2GC_TYPE uint64_t -#define B2GC_TYPE uint32_t -//#define B2GC_TYPE uint16_t -//#define B2GC_TYPE uint8_t -//#define B2GC_WORD_SIZE 64 -#define B2GC_WORD_SIZE 32 -//#define B2GC_WORD_SIZE 16 -//#define B2GC_WORD_SIZE 8 - -#define B2GC_Q 2 - -#define B2GC_SEARCHFUNC B2gcSearchBNDMq -//#define B2GC_SEARCHFUNC B2gcSearch - -//#define B2GC_SEARCH2 -//#define B2GC_COUNTERS - -#define B2GC_FLAG_NOCASE 0x01 -#define B2GC_FLAG_FINAL 0x02 -#define B2GC_FLAG_RES1 0x04 -#define B2GC_FLAG_RES2 0x08 - -/* Bits - * flg len id pat - * |xxxx|xxxx xxxx xx|xx xxxx xxxx xxxx xxxx|xx..xx| - */ - -typedef struct B2gcPatternHdr_ { - uint32_t np_offset; /* offset of the next pattern */ - uint8_t len; - uint8_t flags; - PatIntId id; -} B2gcPatternHdr; - -#define B2GC_GET_FLAGS(hdr) ((hdr)->flags) -#define B2GC_GET_LEN(hdr) ((hdr)->len) -#define B2GC_GET_ID(hdr) ((hdr)->id) - -/* 1 byte pattern structure fitting in a double word. - * flg id pad pat/char - * |xxxx|xxxx xxxx xxxx xxxx xx|xx|xxxx xxxx| - */ - -typedef struct B2gcPattern1_ { - uint8_t flags; - uint8_t pat; - PatIntId id; -} B2gcPattern1; - -#define B2GC1_GET_FLAGS(hdr) ((hdr)->flags) -#define B2GC1_GET_LEN(hdr) 1 -#define B2GC1_GET_ID(hdr) ((hdr)->id) -#define B2GC1_GET_CHAR(hdr) ((hdr)->pat) - -typedef struct B2gcPattern_ { - uint16_t len; - uint8_t flags; - uint8_t pad0; - PatIntId id; - uint8_t *pat; -} B2gcPattern; - -typedef struct B2gcCtx_ { - /* we store our own multi byte search func ptr here for B2gcSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - /* hash for looking up the idx in the pattern array */ - uint16_t *ha1; - uint8_t *patterns1; - uint32_t pat_x_cnt; - uint32_t pat_1_cnt; - /* we store our own multi byte search func ptr here for B2gcSearch1 */ - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - B2GC_TYPE m; - uint32_t hash_size; - - B2GC_TYPE *B2GC; - - uint8_t *pminlen; /* array containing the minimal length */ - BloomFilter **bloom; - - uint32_t *ha; - /* patterns in the format |hdr|pattern|hdr|pattern|... */ - uint8_t *patterns; - - HashListTable *b2gc_init_hash; -} B2gcCtx; - -typedef struct B2gcThreadCtx_ { -#ifdef B2GC_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* B2GC_COUNTERS */ -} B2gcThreadCtx; - -void MpmB2gcRegister(void); - - -#endif - diff --git a/src/util-mpm-b2gm.c b/src/util-mpm-b2gm.c deleted file mode 100644 index 2a0dfb14a665..000000000000 --- a/src/util-mpm-b2gm.c +++ /dev/null @@ -1,2788 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implementation of the SBNDMq pattern matching algorithm. - * - * Future work: - * - parray contains 1 byte patterns while they are not used - * - 1 byte search hashes on tolower(*buf) reducing hash value - * - */ - -//#define PRINTMATCH - -#include "suricata-common.h" -#include "suricata.h" -#include "detect.h" -#include "util-bloomfilter.h" -#include "util-mpm-b2gm.h" -#include "util-print.h" -#include "util-hashlist.h" -#include "util-debug.h" -#include "util-unittest.h" -#include "util-optimize.h" -#include "conf.h" - -#define INIT_HASH_SIZE 65536 - -#ifdef B2GM_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B2GM_COUNTERS */ - -static uint32_t b2gm_hash_size = 0; -static uint32_t b2gm_bloom_size = 0; -static uint8_t b2gm_hash_shift = 0; -static void *b2g_func; - -#define B2GM_HASH16(a,b) (((a) << b2gm_hash_shift) | (b)) - -void B2gmInitCtx (MpmCtx *); -void B2gmThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B2gmDestroyCtx(MpmCtx *); -void B2gmThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B2gmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B2gmPreparePatterns(MpmCtx *mpm_ctx); -uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#ifdef B2GM_SEARCH2 -uint32_t B2gmSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -#endif -uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); -void B2gmPrintInfo(MpmCtx *mpm_ctx); -void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void B2gmRegisterTests(void); - -void MpmB2gmRegister (void) -{ - mpm_table[MPM_B2GM].name = "b2gm"; - mpm_table[MPM_B2GM].max_pattern_length = B2GM_WORD_SIZE; - - mpm_table[MPM_B2GM].InitCtx = B2gmInitCtx; - mpm_table[MPM_B2GM].InitThreadCtx = B2gmThreadInitCtx; - mpm_table[MPM_B2GM].DestroyCtx = B2gmDestroyCtx; - mpm_table[MPM_B2GM].DestroyThreadCtx = B2gmThreadDestroyCtx; - mpm_table[MPM_B2GM].AddPattern = B2gmAddPatternCS; - mpm_table[MPM_B2GM].AddPatternNocase = B2gmAddPatternCI; - mpm_table[MPM_B2GM].Prepare = B2gmPreparePatterns; - mpm_table[MPM_B2GM].Search = B2gmSearchWrap; - mpm_table[MPM_B2GM].Cleanup = NULL; - mpm_table[MPM_B2GM].PrintCtx = B2gmPrintInfo; - mpm_table[MPM_B2GM].PrintThreadCtx = B2gmPrintSearchStats; - mpm_table[MPM_B2GM].RegisterUnittests = B2gmRegisterTests; -} - -#ifdef PRINTMATCH -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%02X", buf[i]); - } - //printf("\n"); -} -#endif - -void B2gmPrintInfo(MpmCtx *mpm_ctx) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - printf("MPM B2gm Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B2gmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmCtx)); - printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); - printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -static inline B2gmPattern *B2gmAllocPattern(MpmCtx *mpm_ctx) -{ - B2gmPattern *p = SCMalloc(sizeof(B2gmPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B2gmPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gmPattern); - return p; -} - -static inline B2gmPattern * -B2gmAllocHashItem(MpmCtx *mpm_ctx) -{ - B2gmPattern *hi = SCMalloc(sizeof(B2gmPattern)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(B2gmPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gmPattern); - return hi; -} - -static void B2gmHashFree(MpmCtx *mpm_ctx, B2gmPattern *hi) -{ - if (hi == NULL) - return; - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gmPattern); - B2gmPattern *t = hi->next; - SCFree(hi); - - B2gmHashFree(mpm_ctx, t); -} - -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) -{ - uint16_t i; - for (i = 0; i < len; i++) { - d[i] = u8_tolower(s[i]); - } -} - -/* - * INIT HASH START - */ -static inline uint32_t B2gmInitHash(B2gmPattern *p) -{ - uint32_t hash = p->len * p->pat[0]; - if (p->len > 1) - hash += p->pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t B2gmInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int B2gmInitHashAdd(B2gmCtx *ctx, B2gmPattern *p) -{ - uint32_t hash = B2gmInitHash(p); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - return 0; - } - - B2gmPattern *tt = NULL; - B2gmPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - - return 0; -} - -static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline B2gmPattern *B2gmInitHashLookup(B2gmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) -{ - uint32_t hash = B2gmInitHashRaw(pat,patlen); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - B2gmPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (B2gmCmpPattern(t,pat,patlen,flags) == 1) - return t; - } - - return NULL; -} - -static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (memcmp(p->pat, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void B2gmFreePattern(MpmCtx *mpm_ctx, B2gmPattern *p) -{ - if (p != NULL) { - if (p->pat != NULL) { - SCFree(p->pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gmPattern); - } -} - -/** \internal - * \brief add a pattern to the mpm/b2g context - * - * \param pat ptr to the pattern - * \param patlen length of the pattern - * \param pid pattern id - * \param sid signature id (internal id) - * \param flags pattern MPM_PATTERN_* flags - */ -static int B2gmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); - - if (patlen == 0) - return 0; - - /* get a memory piece */ - B2gmPattern *p = B2gmInitHashLookup(ctx, pat, patlen, flags); - if (p == NULL) { - SCLogDebug("allocing new pattern"); - - B2gmPattern *p = B2gmAllocPattern(mpm_ctx); - if (p == NULL) - return -1; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - /* setup the case insensitive part of the pattern */ - p->pat = SCMalloc(patlen); - if (p->pat == NULL) { - B2gmFreePattern(mpm_ctx, p); - return -1; - } - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - memcpy_tolower(p->pat, pat, patlen); - } else { - memcpy(p->pat, pat, patlen); - } - - /* put in the pattern hash */ - B2gmInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - - mpm_ctx->pattern_cnt++; - - if (patlen == 1) { - ctx->pat_1_cnt++; - } else { - ctx->pat_x_cnt++; - } - - if (mpm_ctx->maxlen < patlen) - mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) - mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) - mpm_ctx->minlen = patlen; - } - - return 0; -} - -int B2gmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B2gmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static uint32_t B2gmHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) -{ - BUG_ON(len != sizeof(B2gmPattern)); - BUG_ON(pattern == NULL); - - B2gmPattern *p = (B2gmPattern *)pattern; - return (uint32_t)p->pat[0]; -} - -static char B2gmHashPatternCompare(void *pattern1, uint16_t len1, - void *pattern2, uint16_t len2) -{ - BUG_ON(len1 != sizeof(B2gmPattern)); - BUG_ON(len2 != sizeof(B2gmPattern)); - - B2gmPattern *p1 = (B2gmPattern *)pattern1; - B2gmPattern *p2 = (B2gmPattern *)pattern2; - - if (p1->id != p2->id) { - return 0; - } - - return 1; -} - -static inline uint32_t B2gmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static void B2gmPrepareHashAddPattern(MpmCtx *mpm_ctx, uint16_t idx, uint32_t i) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - if (ctx->lookup[idx].hash == NULL) { - B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->pat = ctx->parray[i]->pat; - - ctx->lookup[idx].pminlen = ctx->parray[i]->len; - - ctx->lookup[idx].hash = hi; - } else { - B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - - hi->len = ctx->parray[i]->len; - hi->flags |= ctx->parray[i]->flags; - hi->id = ctx->parray[i]->id; - hi->pat = ctx->parray[i]->pat; - - if (ctx->parray[i]->len < ctx->lookup[idx].pminlen) - ctx->lookup[idx].pminlen = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - B2gmPattern *thi = ctx->lookup[idx].hash; - while (thi->next) - thi = thi->next; - thi->next = hi; - } - return; -error: - return; -} - -static void B2gmPrepareHash(MpmCtx *mpm_ctx) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t size1 = 1; - - HashListTable *b2gm_sort_hash1 = HashListTableInit(256, B2gmHashPatternSortHash1, B2gmHashPatternCompare, NULL); - if (b2gm_sort_hash1 == NULL) { - exit(EXIT_FAILURE); - } - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - SCLogDebug("ctx->parray[i]->len %u", ctx->parray[i]->len); - - if(ctx->parray[i]->len == 1) { - HashListTableAdd(b2gm_sort_hash1, (void *)ctx->parray[i], sizeof(B2gmPattern)); - size1 += (sizeof(B2gmPattern1)); - } else { - if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); - B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); - - /* l, l */ - uint16_t llidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); - if (llidx != uuidx) { - B2gmPrepareHashAddPattern(mpm_ctx, llidx, i); - } - /* u, l */ - uint16_t ulidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); - if (ulidx != llidx && ulidx != uuidx) { - B2gmPrepareHashAddPattern(mpm_ctx, ulidx, i); - } - /* l, u */ - uint16_t luidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - B2gmPrepareHashAddPattern(mpm_ctx, luidx, i); - } - } else { - uint16_t uuidx = B2GM_HASH16(ctx->parray[i]->pat[ctx->m - 2], ctx->parray[i]->pat[ctx->m - 1]); - B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); - } - } - } - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - B2gmPattern *hi = ctx->lookup[h].hash; - if (hi == NULL) - continue; - - ctx->lookup[h].bloom = BloomFilterInit(b2gm_bloom_size, 2, B2gmBloomHash); - if (ctx->lookup[h].bloom == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->lookup[h].bloom); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->lookup[h].bloom); - - if (ctx->lookup[h].pminlen > 8) - ctx->lookup[h].pminlenb = 8; - else - ctx->lookup[h].pminlenb = (uint8_t)ctx->lookup[h].pminlen; - - B2gmPattern *thi = hi; - do { - SCLogDebug("adding \"%c%c\" to the bloom", thi->pat[0], thi->pat[1]); - BloomFilterAdd(ctx->lookup[h].bloom, thi->pat, ctx->lookup[h].pminlenb); - thi = thi->next; - } while (thi != NULL); - } - - /* build the 1 byte match array */ - SCLogDebug("size1 %u", size1); - ctx->patterns1 = SCMalloc(size1); - BUG_ON(ctx->patterns1 == NULL); - memset(ctx->patterns1, 0x00, size1); - - /* skip the first byte of the buffer */ - uint16_t offset1 = 1; - - uint32_t a; - for (a = 0; a < b2gm_sort_hash1->array_size; a++) { - HashListTableBucket *buck = b2gm_sort_hash1->array[a]; - if (buck != NULL) { - while (buck != NULL) { - if (buck->data != NULL) { - B2gmPattern *p = (B2gmPattern *) (buck->data); - BUG_ON(p == NULL); - BUG_ON(p->len != 1); - - B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; - h->id = p->id; - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - h->flags |= B2GM_FLAG_NOCASE; - h->pat = p->pat[0]; - } else { - h->pat = p->pat[0]; - } - - offset1 += (sizeof(B2gmPattern1)); - } - buck = buck->bucknext; - } - } - } - - /* build the hash containing idx' to the pattern array */ - offset1 = 1; - - B2gmPattern1 *ph1 = NULL; - uint8_t prevhash1 = 0; - while (offset1 < size1) { - B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; - - if (ctx->ha1[u8_tolower(h->pat)] == 0) - ctx->ha1[u8_tolower(h->pat)] = offset1; - - /* check the prev pattern for setting the final flag */ - if (ph1 != NULL) { - if (u8_tolower(h->pat) != prevhash1) { - SCLogDebug("setting final flag on %p", ph1); - ph1->flags |= B2GM_FLAG_FINAL; - } - } - - prevhash1 = u8_tolower(h->pat); - ph1 = h; - - offset1 += (sizeof(B2gmPattern1)); - - /* last item is "final" too */ - if (offset1 == size1) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GM_FLAG_FINAL; - } - - SCLogDebug("offset %u, size %u", offset1, size1); - } - - HashListTableFree(b2gm_sort_hash1); - b2gm_sort_hash1 = NULL; - return; -} - -static void B2gmAddToMatchArray(MpmCtx *mpm_ctx, B2gmPattern *p, int j) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* u, u */ - uint16_t uuidx = B2GM_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); - ctx->B2GM[uuidx] = ctx->B2GM[uuidx] | (1 << (ctx->m - j)); - - /* l, l */ - uint16_t llidx = B2GM_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (llidx != uuidx) { - ctx->B2GM[llidx] = ctx->B2GM[llidx] | (1 << (ctx->m - j)); - } - /* u, l */ - uint16_t ulidx = B2GM_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); - if (ulidx != llidx && ulidx != uuidx) { - ctx->B2GM[ulidx] = ctx->B2GM[ulidx] | (1 << (ctx->m - j)); - } - /* l, u */ - uint16_t luidx = B2GM_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); - if (luidx != ulidx && luidx != llidx && luidx != uuidx) { - ctx->B2GM[luidx] = ctx->B2GM[luidx] | (1 << (ctx->m - j)); - } - - SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); - } -} - -int B2gmBuildMatchArray(MpmCtx *mpm_ctx) -{ - SCEnter(); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - ctx->B2GM = SCMalloc(sizeof(B2GM_TYPE) * ctx->hash_size); - if (ctx->B2GM == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2GM_TYPE) * ctx->hash_size); - - memset(ctx->B2GM,0, b2gm_hash_size * sizeof(B2GM_TYPE)); - - uint32_t j; - uint32_t a; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2GM_Q); j++) { - for (a = 0; a < ctx->pat_x_cnt; a++) { - if (ctx->parray[a]->len < ctx->m) - continue; - - uint16_t h; - if (ctx->parray[a]->flags & MPM_PATTERN_FLAG_NOCASE) { - B2gmAddToMatchArray(mpm_ctx, ctx->parray[a], j); - } else { - h = B2GM_HASH16(ctx->parray[a]->pat[j], ctx->parray[a]->pat[j+1]); - ctx->B2GM[h] = ctx->B2GM[h] | (1 << (ctx->m - j)); - SCLogDebug("h %"PRIu16", ctx->B2GM[h] %"PRIu32" (cs)", h, ctx->B2GM[h]); - } - } - } - - //ctx->s0 = 1; - SCReturnInt(0); -} - -int B2gmPreparePatterns(MpmCtx *mpm_ctx) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - - /* alloc the lookup array */ - ctx->lookup = SCMalloc(b2gm_hash_size * sizeof(B2gmLookup)); - if (ctx->lookup == NULL) - goto error; - memset(ctx->lookup, 0x00, b2gm_hash_size * sizeof(B2gmLookup)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (b2gm_hash_size * sizeof(B2gmLookup)); - - /* alloc the pattern array */ - ctx->parray = (B2gmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0; - uint32_t p = 0; - - for (i = 0; i < INIT_HASH_SIZE; i++) { - B2gmPattern *node = ctx->init_hash[i]; - B2gmPattern *nnode = NULL; - - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - p++; - - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B2GM_WORD_SIZE) { - ctx->m = B2GM_WORD_SIZE - 1; - } - if (ctx->m < 2) - ctx->m = 2; - - ctx->hash_size = b2gm_hash_size; - B2gmPrepareHash(mpm_ctx); - B2gmBuildMatchArray(mpm_ctx); - - SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); - if (ctx->pat_1_cnt) { - ctx->Search = B2gmSearch1; - ctx->MBSearch = b2g_func; - } - - return 0; -error: - return -1; -} - -void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B2GM_COUNTERS - B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; - - printf("B2gm Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); - printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); - printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); - printf("Avg pminlen: %0.2f\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); - printf("Test bug %"PRIu32"\n", tctx->stat_test_buf); - printf("Test bug ok %"PRIu32"\n", tctx->stat_test_buf_ok); - printf("Test bug fail %"PRIu32"\n\n", tctx->stat_test_buf_fail); -#endif /* B2GM_COUNTERS */ -} - -static inline int -memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - if (s1[i] != u8_tolower(*(s2+i))) - return 1; - } - - return 0; -} - -/** - * \brief Function to get the user defined values for b2g algorithm from the - * config file 'suricata.yaml' - */ -static void B2gmGetConfig() -{ - ConfNode *b2g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b2gm_hash_size = HASHSIZE_LOW; - b2gm_hash_shift = B2GM_HASHSHIFT_LOW; - b2gm_bloom_size = BLOOMSIZE_MEDIUM; - b2g_func = B2GM_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - if (pm != NULL) { - TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strcmp(b2g_conf->val, "b2gm") == 0) { - - algo = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "algo"); - hash_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "hash_size"); - bloom_val = ConfNodeLookupChildValue - (b2g_conf->head.tqh_first, "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B2gmSearch") == 0) { - b2g_func = B2gmSearch; - } else if (strcmp(algo, "B2gmSearchBNDMq") == 0) { - b2g_func = B2gmSearchBNDMq; - } - } - - if (hash_val != NULL) { - b2gm_hash_size = MpmGetHashSize(hash_val); - switch (b2gm_hash_size) { - case HASHSIZE_LOWEST: - b2gm_hash_shift = B2GM_HASHSHIFT_LOWEST; - break; - case HASHSIZE_LOW: - b2gm_hash_shift = B2GM_HASHSHIFT_LOW; - break; - case HASHSIZE_MEDIUM: - b2gm_hash_shift = B2GM_HASHSHIFT_MEDIUM; - break; - case HASHSIZE_HIGH: - b2gm_hash_shift = B2GM_HASHSHIFT_HIGH; - break; - case HASHSIZE_HIGHER: - b2gm_hash_shift = B2GM_HASHSHIFT_HIGHER; - break; - case HASHSIZE_MAX: - b2gm_hash_shift = B2GM_HASHSHIFT_MAX; - break; - } - } - - if (bloom_val != NULL) - b2gm_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b2gm_hash_size, b2gm_bloom_size); - } - } - } -} - -void B2gmInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); - - BUG_ON(mpm_ctx->ctx != NULL); - - mpm_ctx->ctx = SCMalloc(sizeof(B2gmCtx)); - if (mpm_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_ctx->ctx, 0, sizeof(B2gmCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B2gmCtx); - - /* initialize the hash we use to speed up pattern insertions */ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(B2gmPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) { - exit(EXIT_FAILURE); - } - - memset(ctx->init_hash, 0, sizeof(B2gmPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b2gm_hash_size == 0) - B2gmGetConfig(); - - ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); - BUG_ON(ctx->ha1 == NULL); - memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); - - /* init defaults search functions */ - ctx->Search = b2g_func; - - SCReturn; -} - -void B2gmDestroyCtx(MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p", mpm_ctx); - - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash != NULL) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gmPattern *)); - } - - if (ctx->parray != NULL) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B2gmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gmPattern)); - } - - if (ctx->B2GM != NULL) { - SCFree(ctx->B2GM); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2GM_TYPE) * ctx->hash_size); - } - - if (ctx->lookup != NULL) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->lookup[h].bloom == NULL) - continue; - - B2gmHashFree(mpm_ctx, ctx->lookup[h].hash); - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->lookup[h].bloom); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->lookup[h].bloom); - - BloomFilterFree(ctx->lookup[h].bloom); - } - - SCFree(ctx->lookup); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2gmLookup) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B2gmCtx); -} - -void B2gmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B2gmThreadCtx) > 0) { /* size can be null when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gmThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) { - exit(EXIT_FAILURE); - } - - memset(mpm_thread_ctx->ctx, 0, sizeof(B2gmThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B2gmThreadCtx); - } -} - -void B2gmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B2gmThreadCtx *ctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; - - B2gmPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL if B2gmThreadCtx is optimized to 0 */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B2gmThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; -} - -uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; -#ifdef B2GM_COUNTERS - B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B2GM_Q + 1, matches = 0; - B2GM_TYPE d; - - //printf("\n"); - //PrintRawDataFp(stdout, buf, buflen); - - SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, - ctx->m, pos); - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (uint32_t)(buflen - B2GM_Q + 1)) { - uint16_t h = B2GM_HASH16(buf[pos - 1],buf[pos]); - d = ctx->B2GM[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B2GM_Q + 1); - - do { - j = j - 1; - - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) - pos = j; - else { - COUNT(tctx->stat_test_buf++); - h = B2GM_HASH16(buf[j + ctx->m - 2],buf[j + ctx->m - 1]); - - if (unlikely(ctx->lookup[h].pminlen > 0 && (buflen - j) >= ctx->lookup[h].pminlen && - BloomFilterTest(ctx->lookup[h].bloom, buf+j, ctx->lookup[h].pminlenb) == 1)) - { - COUNT(tctx->stat_test_buf_ok++); - /* get our patterns from the hash */ - B2gmPattern *hi = ctx->lookup[h].hash, *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - if ((buflen - j) >= thi->len) { - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (unlikely(memcmp_lowercase(thi->pat, buf+j, thi->len) == 0)) { -#ifdef PRINTMATCH - printf("CI Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (unlikely(memcmp(thi->pat, buf+j, thi->len) == 0)) { -#ifdef PRINTMATCH - printf("CS Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); -#endif - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } - } else { - COUNT(tctx->stat_test_buf_fail++); - } - } - } - - if (j == 0) { - break; - } - - h = B2GM_HASH16(buf[j - 1],buf[j]); - d = (d << 1) & ctx->B2GM[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B2GM_Q + 1)); - pos = pos + ctx->m - B2GM_Q + 1; - - SCLogDebug("pos %"PRIu32"", pos); - } - - SCLogDebug("matches %"PRIu32"", matches); - return matches; -} - -uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; -#ifdef B2GM_COUNTERS - B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B2GM_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 1; - d = ~0; - - do { - uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2GM[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - - /* get our patterns from the hash */ - uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - - if (ctx->lookup[h].pminlen > 0) { - COUNT(tctx->stat_pminlen_calls++); - - if ((buflen - pos) < ctx->lookup[h].pminlen) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->lookup[h].bloom, buf+pos, ctx->lookup[h].pminlenb) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - - B2gmPattern *hi = ctx->lookup[h].hash, *thi; - for (thi = hi; thi != NULL; thi = thi->next) { - COUNT(tctx->stat_d0_hashloop++); - //B2gmPattern *p = ctx->parray[thi->idx]; - - if (buflen - pos < thi->len) - continue; - - if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { - - if (memcmp_lowercase(thi->pat, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (memcmp(thi->pat, buf+pos, thi->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } - -skip_loop: - //pos = pos + ctx->s0; - pos = pos + 1; - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - SCEnter(); - - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - - if (buflen == 0) - SCReturnUInt(0); - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - uint16_t offset = ctx->ha1[h]; - SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); - - if (offset > 0) { - do { - B2gmPattern1 *hdr = (B2gmPattern1 *)&ctx->patterns1[offset]; - offset += (sizeof(B2gmPattern1)); - - SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); - - if (hdr->flags & B2GM_FLAG_NOCASE) { - SCLogDebug("nocase compare, %02X", *buf); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } else { - SCLogDebug("case sensitive compare, %02X", *buf); - - if (*buf == hdr->pat) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } - - if (hdr->flags & B2GM_FLAG_FINAL) - break; - } while(1); - } - buf += 1; - } - - //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - SCReturnUInt(cnt); -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B2gmTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B2gmTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B2gmDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B2gmTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch02a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch02b (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch03a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"b", 1, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"f", 1, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B2gmTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B2gmTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch05a (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 5) - result = 1; - else - printf("5 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = 0 ; - int i; - for (i = 0; i<1000;i++) - cnt= ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *buf = "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789" - "abcdefgh" - "01234567890123456789012345678901234567890123456789" - "01234567890123456789012345678901234567890123456789"; - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ - //MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} - -static int B2gmTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -#if 0 -static int B2gmTestSearchXX (void) -{ - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B2GM); - B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; - - FILE *fp = fopen("/usr/share/dict/words", "r"); - if (fp == NULL) - exit(1); - - char *word; - char line[128]; - int w = 0; - int w_max = 4000; - - while((word = fgets(line, sizeof(line), fp)) != NULL) { - word[strlen(word) - 1] = '\0'; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); - - w++; - - if (w_max == w) - break; - } - - B2gmPreparePatterns(&mpm_ctx); - B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); - - char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "we're adding a lot more text lines etc." - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" - "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; - uint32_t len = strlen(text) - 1; - - int i; - uint32_t cnt; - for (i = 0; i < 100; i++) { - cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); - } - - printf("cnt %u ", cnt); - - B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B2gmDestroyCtx(&mpm_ctx); - fclose(fp); - - return 1; -} -#endif - -void B2gmRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B2gmTestInit01", B2gmTestInit01, 1); -/* - UtRegisterTest("B2gmTestS0Init01", B2gmTestS0Init01, 1); - UtRegisterTest("B2gmTestS0Init02", B2gmTestS0Init02, 1); - UtRegisterTest("B2gmTestS0Init03", B2gmTestS0Init03, 1); - UtRegisterTest("B2gmTestS0Init04", B2gmTestS0Init04, 1); - UtRegisterTest("B2gmTestS0Init05", B2gmTestS0Init05, 1); -*/ - UtRegisterTest("B2gmTestSearch01", B2gmTestSearch01, 1); - UtRegisterTest("B2gmTestSearch02", B2gmTestSearch02, 1); - UtRegisterTest("B2gmTestSearch02a", B2gmTestSearch02a, 1); - UtRegisterTest("B2gmTestSearch02b", B2gmTestSearch02b, 1); - UtRegisterTest("B2gmTestSearch03", B2gmTestSearch03, 1); - UtRegisterTest("B2gmTestSearch03a", B2gmTestSearch03a, 1); - UtRegisterTest("B2gmTestSearch04", B2gmTestSearch04, 1); - UtRegisterTest("B2gmTestSearch05", B2gmTestSearch05, 1); - UtRegisterTest("B2gmTestSearch05a", B2gmTestSearch05a, 1); - UtRegisterTest("B2gmTestSearch06", B2gmTestSearch06, 1); - UtRegisterTest("B2gmTestSearch07", B2gmTestSearch07, 1); - UtRegisterTest("B2gmTestSearch08", B2gmTestSearch08, 1); - UtRegisterTest("B2gmTestSearch09", B2gmTestSearch09, 1); - UtRegisterTest("B2gmTestSearch10", B2gmTestSearch10, 1); - UtRegisterTest("B2gmTestSearch11", B2gmTestSearch11, 1); - UtRegisterTest("B2gmTestSearch12", B2gmTestSearch12, 1); - UtRegisterTest("B2gmTestSearch13", B2gmTestSearch13, 1); - UtRegisterTest("B2gmTestSearch14", B2gmTestSearch14, 1); - UtRegisterTest("B2gmTestSearch15", B2gmTestSearch15, 1); - UtRegisterTest("B2gmTestSearch16", B2gmTestSearch16, 1); - UtRegisterTest("B2gmTestSearch17", B2gmTestSearch17, 1); - UtRegisterTest("B2gmTestSearch18", B2gmTestSearch18, 1); - UtRegisterTest("B2gmTestSearch19", B2gmTestSearch19, 1); - UtRegisterTest("B2gmTestSearch20", B2gmTestSearch20, 1); - UtRegisterTest("B2gmTestSearch21", B2gmTestSearch21, 1); -/* - UtRegisterTest("B2gmTestSearchXX", B2gmTestSearchXX, 1); -*/ -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b2gm.h b/src/util-mpm-b2gm.h deleted file mode 100644 index 5b1316bf8564..000000000000 --- a/src/util-mpm-b2gm.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_MPM_B2GM_H__ -#define __UTIL_MPM_B2GM_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B2GM_HASHSHIFT_MAX 8 -#define B2GM_HASHSHIFT_HIGHER 7 -#define B2GM_HASHSHIFT_HIGH 6 -#define B2GM_HASHSHIFT_MEDIUM 5 -#define B2GM_HASHSHIFT_LOW 4 -#define B2GM_HASHSHIFT_LOWEST 3 - -//#define B2GM_TYPE uint64_t -#define B2GM_TYPE uint32_t -//#define B2GM_TYPE uint16_t -//#define B2GM_TYPE uint8_t - -//#define B2GM_WORD_SIZE 64 -#define B2GM_WORD_SIZE 32 -//#define B2GM_WORD_SIZE 16 -//#define B2GM_WORD_SIZE 8 - -#define B2GM_Q 2 - -#define B2GM_SEARCHFUNC B2gmSearchBNDMq -//#define B2GM_SEARCHFUNC B2gmSearch - -//#define B2GM_COUNTERS - -#define B2GM_FLAG_NOCASE 0x01 -#define B2GM_FLAG_FINAL 0x02 - -typedef struct B2gmPattern_ { - uint8_t len; - uint8_t flags; - uint16_t id; -#if __WORDSIZE == 64 - uint32_t pad; -#endif - uint8_t *pat; - struct B2gmPattern_ *next; -} B2gmPattern; - -typedef struct B2gmPattern1_ { - uint8_t flags; - uint8_t pat; - uint16_t id; -} B2gmPattern1; - -typedef struct B2gmLookup_ { - uint16_t pminlen; - uint8_t pminlenb; /* bloom */ - uint8_t pad0; -#if __WORDSIZE == 64 - uint32_t pad1; -#endif - BloomFilter *bloom; - B2gmPattern *hash; -} B2gmLookup; - -typedef struct B2gmCtx_ { - /* we store our own multi byte search func ptr here for B2gmSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* hash for looking up the idx in the pattern array */ - uint16_t *ha1; - uint8_t *patterns1; - - /* we store our own multi byte search func ptr here for B2gmSearch1 */ - //uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - uint16_t pat_1_cnt; - uint16_t pat_x_cnt; -#if __WORDSIZE == 64 - uint32_t pad1; -#endif - - B2GM_TYPE *B2GM; - B2GM_TYPE m; -#if __WORDSIZE == 64 - uint32_t pad0; -#endif - - B2gmLookup *lookup; - - /* pattern arrays */ - B2gmPattern **parray; - - /* hash used during ctx initialization */ - B2gmPattern **init_hash; - //uint8_t s0; - uint32_t hash_size; -} B2gmCtx; - -typedef struct B2gmThreadCtx_ { -#ifdef B2GM_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; - uint32_t stat_test_buf; - uint32_t stat_test_buf_ok; - uint32_t stat_test_buf_fail; -#endif /* B2GM_COUNTERS */ -} B2gmThreadCtx; - -void MpmB2gmRegister(void); - -#endif /* __UTIL_MPM_B2GM_H__ */ - diff --git a/src/util-mpm-b3g.c b/src/util-mpm-b3g.c deleted file mode 100644 index 12472528dc75..000000000000 --- a/src/util-mpm-b3g.c +++ /dev/null @@ -1,1743 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * 3 gram implementation of the (S)BNDMq pattern matching algorithm. - * - * Ideas: - * - B3g does a full match in the search of up to 'm' characters, - * in case of a case insensitive search we could say it's match if - * the pattern is of len 'm' or just compare the rest of the chars. - * - * \todo Try to get the S0 calculation right. - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-bloomfilter.h" -#include "util-mpm-b3g.h" -#include "util-unittest.h" -#include "conf.h" -#include "util-debug.h" -#include "util-memcpy.h" - -#define INIT_HASH_SIZE 65536 - -#ifdef B3G_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* B3G_COUNTERS */ - -static uint32_t b3g_hash_size = 0; -static uint32_t b3g_bloom_size = 0; -static uint8_t b3g_hash_shift = 0; -static uint8_t b3g_hash_shift2 = 0; -static void *b3g_func; - -#define B3G_HASH(a,b,c) (((a) << b3g_hash_shift) | (b) << (b3g_hash_shift2) |(c)) - -void B3gInitCtx (MpmCtx *); -void B3gThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); -void B3gDestroyCtx(MpmCtx *); -void B3gThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); -int B3gAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B3gAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int B3gPreparePatterns(MpmCtx *); -uint32_t B3gSearchWrap(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch1(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch2(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch12(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearch(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -uint32_t B3gSearchBNDMq(MpmCtx *, MpmThreadCtx *, PatternMatcherQueue *, uint8_t *, uint16_t); -void B3gPrintInfo(MpmCtx *); -void B3gPrintSearchStats(MpmThreadCtx *); -void B3gRegisterTests(void); - -/** \todo XXX Unused??? */ -#if 0 -static void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%" PRIX32, buf[i]); - } - //printf("\n"); -} -#endif - -void B3gPrintInfo(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - printf("MPM B3g Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" B3gCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B3gCtx)); - printf(" B3gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B3gPattern)); - printf(" B3gHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(B3gHashItem)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("\n"); -} - -static inline B3gPattern *B3gAllocPattern(MpmCtx *mpm_ctx) -{ - B3gPattern *p = SCMalloc(sizeof(B3gPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(B3gPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B3gPattern); - return p; -} - -static inline B3gHashItem * -B3gAllocHashItem(MpmCtx *mpm_ctx) -{ - B3gHashItem *hi = SCMalloc(sizeof(B3gHashItem)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(B3gHashItem)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B3gHashItem); - return hi; -} - -static void B3gHashFree(MpmCtx *mpm_ctx, B3gHashItem *hi) -{ - if (hi == NULL) - return; - - B3gHashItem *t = hi->nxt; - B3gHashFree(mpm_ctx, t); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B3gHashItem); - SCFree(hi); -} - -/* - * INIT HASH START - */ -static inline uint32_t B3gInitHash(B3gPattern *p) -{ - uint32_t hash = p->len * p->cs[0]; - if (p->len > 1) - hash += p->cs[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t B3gInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int B3gInitHashAdd(B3gCtx *ctx, B3gPattern *p) -{ - uint32_t hash = B3gInitHash(p); - - //printf("B3gInitHashAdd: %" PRIu32 "\n", hash); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - //printf("B3gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; - } - - B3gPattern *tt = NULL; - B3gPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - //printf("B3gInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - return 0; -} - -static inline int B3gCmpPattern(B3gPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline B3gPattern *B3gInitHashLookup(B3gCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) -{ - uint32_t hash = B3gInitHashRaw(pat,patlen); - - //printf("B3gInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - B3gPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (B3gCmpPattern(t,pat,patlen,flags) == 1) - return t; - } - - return NULL; -} - -static inline int B3gCmpPattern(B3gPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (memcmp(p->cs, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void B3gFreePattern(MpmCtx *mpm_ctx, B3gPattern *p) -{ - if (p && p->cs && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->ci) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B3gPattern); - } -} - -/* B3gAddPattern - * - * pat: ptr to the pattern - * patlen: length of the pattern - * nocase: nocase flag: 1 enabled, 0 disable - * pid: pattern id - * sid: signature id (internal id) - */ -static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - if (patlen == 0) - return 0; - - /* get a memory piece */ - B3gPattern *p = B3gInitHashLookup(ctx, pat, patlen, flags); - if (p == NULL) { - p = B3gAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - /* setup the case insensitive part of the pattern */ - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci,pat,p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - //printf("B3gAddPattern: ci \""); prt(p->ci,p->len); - //printf("\" cs \""); prt(p->cs,p->len); - //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); - - /* put in the pattern hash */ - B3gInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; - } - - return 0; - -error: - B3gFreePattern(mpm_ctx, p); - return -1; -} - -int B3gAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int B3gAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return B3gAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static uint32_t B3gBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)u8_tolower(*d); - - for (i = 1; i < datalen; i++) { - d++; - hash += (u8_tolower(*d)) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} - -static void B3gPrepareHash(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t idx = 0; - uint8_t idx8 = 0; - - ctx->hash = (B3gHashItem **)SCMalloc(sizeof(B3gHashItem *) * ctx->hash_size); - if (ctx->hash == NULL) - goto error; - memset(ctx->hash, 0, sizeof(B3gHashItem *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B3gHashItem *) * ctx->hash_size); - - /* 2 byte pattern hash */ - ctx->hash2 = (B3gHashItem **)SCMalloc(sizeof(B3gHashItem *) * ctx->hash_size); - if (ctx->hash2 == NULL) - goto error; - memset(ctx->hash2, 0, sizeof(B3gHashItem *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B3gHashItem *) * ctx->hash_size); - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - goto error; - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - if(ctx->parray[i]->len == 1) { - idx8 = (uint8_t)ctx->parray[i]->ci[0]; - if (ctx->hash1[idx8].flags == 0) { - ctx->hash1[idx8].idx = i; - ctx->hash1[idx8].flags |= 0x01; - } else { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - /* Append this HashItem to the list */ - B3gHashItem *thi = &ctx->hash1[idx8]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - ctx->pat_1_cnt++; - } else if(ctx->parray[i]->len == 2) { - idx = (uint16_t)(ctx->parray[i]->ci[0] << b3g_hash_shift | ctx->parray[i]->ci[1]); - if (ctx->hash2[idx] == NULL) { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - ctx->hash2[idx] = hi; - } else { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - /* Append this HashItem to the list */ - B3gHashItem *thi = ctx->hash2[idx]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - ctx->pat_2_cnt++; - } else { - idx = B3G_HASH(ctx->parray[i]->ci[ctx->m - 3], ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - //printf("idx %" PRIu32 ", %c.%c.%c\n", idx, ctx->parray[i]->ci[ctx->m - 3], ctx->parray[i]->ci[ctx->m - 2], ctx->parray[i]->ci[ctx->m - 1]); - - if (ctx->hash[idx] == NULL) { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - ctx->pminlen[idx] = ctx->parray[i]->len; - - ctx->hash[idx] = hi; - } else { - B3gHashItem *hi = B3gAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - if (ctx->parray[i]->len < ctx->pminlen[idx]) - ctx->pminlen[idx] = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - B3gHashItem *thi = ctx->hash[idx]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - ctx->pat_x_cnt++; - } - } - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - goto error; - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - B3gHashItem *hi = ctx->hash[h]; - if (hi == NULL) - continue; - - ctx->bloom[h] = BloomFilterInit(b3g_bloom_size, 2, B3gBloomHash); - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); - - if (ctx->pminlen[h] > 8) - ctx->pminlen[h] = 8; - - B3gHashItem *thi = hi; - do { - BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); - thi = thi->nxt; - } while (thi != NULL); - } - - return; -error: - return; -} - -int B3gBuildMatchArray(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - ctx->B3G = SCMalloc(sizeof(B3G_TYPE) * ctx->hash_size); - if (ctx->B3G == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B3G_TYPE) * ctx->hash_size); - - memset(ctx->B3G,0, b3g_hash_size * sizeof(B3G_TYPE)); - - uint32_t j; - uint32_t a; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B3G_Q); j++) { - for (a = 0; a < mpm_ctx->pattern_cnt; a++) { - if (ctx->parray[a]->len < ctx->m) - continue; - - uint16_t h = B3G_HASH(u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1]), u8_tolower(ctx->parray[a]->ci[j+2])); -//printf("B3gBuildMatchArray: h %" PRIu32 ", %c.%c.%c\n", h, u8_tolower(ctx->parray[a]->ci[j]),u8_tolower(ctx->parray[a]->ci[j+1]), u8_tolower(ctx->parray[a]->ci[j+2])); - ctx->B3G[h] = ctx->B3G[h] | (1 << (ctx->m - j)); - } - } - - ctx->s0 = 1; - return 0; -} - -int B3gPreparePatterns(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - - /* alloc the pattern array */ - ctx->parray = (B3gPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); - //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B3gPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - B3gPattern *node = ctx->init_hash[i], *nnode = NULL; - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - - p++; - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* set 'm' to the smallest pattern size */ - ctx->m = mpm_ctx->minlen; - - /* make sure 'm' stays in bounds - m can be max WORD_SIZE - 1 */ - if (ctx->m >= B3G_WORD_SIZE) { - ctx->m = B3G_WORD_SIZE - 1; - } - if (ctx->m < 3) ctx->m = 3; - - - ctx->hash_size = b3g_hash_size; - B3gPrepareHash(mpm_ctx); - B3gBuildMatchArray(mpm_ctx); - - if (ctx->pat_1_cnt) { - ctx->Search = B3gSearch1; - if (ctx->pat_2_cnt) { - ctx->Search = B3gSearch12; - ctx->MBSearch = b3g_func; - } - ctx->MBSearch = b3g_func; - } else if (ctx->pat_2_cnt) { - ctx->Search = B3gSearch2; - ctx->MBSearch = b3g_func; - } - - - return 0; -error: - return -1; -} - -void B3gPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef B3G_COUNTERS - B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; - - printf("B3g Thread Search stats (tctx %p)\n", tctx); - printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); - printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); - printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); - printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); - printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); - printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); - printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); - printf("Avg pminlen: %0.2f\n\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); -#endif /* B3G_COUNTERS */ -} - -static inline int -memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - if (u8_tolower(*(s2+i)) != s1[i]) - return 1; - } - - return 0; -} - -/** - * \brief Function to get the user defined values for b3g algorithm from the - * config file 'suricata.yaml' - */ -void B3gGetConfig() -{ - ConfNode *b3g_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - const char *algo = NULL; - - /* init defaults */ - b3g_hash_size = HASHSIZE_LOW; - b3g_bloom_size = BLOOMSIZE_MEDIUM; - b3g_func = B3G_SEARCHFUNC; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(b3g_conf, &pm->head, next) { - if (strncmp(b3g_conf->val, "b3g", 3) == 0) { - algo = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, - "algo"); - hash_val = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, - "hash_size"); - bloom_val = ConfNodeLookupChildValue(b3g_conf->head.tqh_first, - "bf_size"); - - if (algo != NULL) { - if (strcmp(algo, "B3gSearch") == 0) { - b3g_func = B3gSearch; - } else if (strcmp(algo, "B3gSearchBNDMq") == 0) { - b3g_func = B3gSearchBNDMq; - } - } - - if (hash_val != NULL) { - b3g_hash_size = MpmGetHashSize(hash_val); - switch (b3g_hash_size) { - case HASHSIZE_LOWEST: - b3g_hash_shift = B3G_HASHSHIFT_LOWEST; - b3g_hash_shift2 = B3G_HASHSHIFT_LOWEST2; - break; - case HASHSIZE_LOW: - b3g_hash_shift = B3G_HASHSHIFT_LOW; - b3g_hash_shift2 = B3G_HASHSHIFT_LOW2; - break; - case HASHSIZE_MEDIUM: - b3g_hash_shift = B3G_HASHSHIFT_MEDIUM; - b3g_hash_shift2 = B3G_HASHSHIFT_MEDIUM2; - break; - case HASHSIZE_HIGH: - b3g_hash_shift = B3G_HASHSHIFT_HIGH; - b3g_hash_shift2 = B3G_HASHSHIFT_HIGH2; - break; - case HASHSIZE_HIGHER: - b3g_hash_shift = B3G_HASHSHIFT_HIGHER; - b3g_hash_shift2 = B3G_HASHSHIFT_HIGHER2; - break; - case HASHSIZE_MAX: - b3g_hash_shift = B3G_HASHSHIFT_MAX; - b3g_hash_shift2 = B3G_HASHSHIFT_MAX2; - break; - } - } - - if (bloom_val != NULL) - b3g_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - b3g_hash_size, b3g_bloom_size); - } - } - } -} - -void B3gInitCtx (MpmCtx *mpm_ctx) -{ - //printf("B3gInitCtx: mpm_ctx %p\n", mpm_ctx); - - mpm_ctx->ctx = SCMalloc(sizeof(B3gCtx)); - if (mpm_ctx->ctx == NULL) - return; - - memset(mpm_ctx->ctx, 0, sizeof(B3gCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(B3gCtx); - - /* initialize the hash we use to speed up pattern insertions */ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(B3gPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) - return; - - memset(ctx->init_hash, 0, sizeof(B3gPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (b3g_hash_size == 0) - B3gGetConfig(); - - /* init default */ - ctx->Search = b3g_func; -} - -void B3gDestroyCtx(MpmCtx *mpm_ctx) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B3gPattern *)); - } - - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B3gFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B3gPattern)); - } - - if (ctx->B3G) { - SCFree(ctx->B3G); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B3G_TYPE) * ctx->hash_size); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->hash) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) - continue; - - B3gHashFree(mpm_ctx, ctx->hash[h]); - } - - SCFree(ctx->hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B3gHashItem) * ctx->hash_size); - } - if (ctx->hash2) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash2[h] == NULL) - continue; - - B3gHashFree(mpm_ctx, ctx->hash2[h]); - } - - SCFree(ctx->hash2); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B3gHashItem) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(B3gCtx); -} - -void B3gThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - - if (sizeof(B3gThreadCtx) > 0) { /* size can be 0 when optimized */ - mpm_thread_ctx->ctx = SCMalloc(sizeof(B3gThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) - return; - - memset(mpm_thread_ctx->ctx, 0, sizeof(B3gThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(B3gThreadCtx); - } -} - -void B3gThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - B3gThreadCtx *ctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; - - B3gPrintSearchStats(mpm_thread_ctx); - - if (ctx != NULL) { /* can be NULL when optimized */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(B3gThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -inline uint32_t B3gSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - return ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen); -} - -uint32_t B3gSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; -#ifdef B3G_COUNTERS - B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = ctx->m - B3G_Q + 1, matches = 0; - B3G_TYPE d; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (uint32_t)(buflen - B3G_Q + 1)) { - uint16_t h = B3G_HASH(u8_tolower(buf[pos - 1]), u8_tolower(buf[pos]),u8_tolower(buf[pos + 1])); - d = ctx->B3G[h]; - - if (d != 0) { - COUNT(tctx->stat_d0++); - uint32_t j = pos; - uint32_t first = pos - (ctx->m - B3G_Q + 1); - - do { - j = j - 1; - if (d >= (uint32_t)(1 << (ctx->m - 1))) { - if (j > first) pos = j; - else { - /* get our patterns from the hash */ - h = B3G_HASH(u8_tolower(buf[j + ctx->m - 3]), u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - j) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+j, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B3gHashItem *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->nxt) { - COUNT(tctx->stat_d0_hashloop++); - B3gPattern *p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (buflen - j < p->len) - continue; - - if (memcmp_lowercase(p->ci, buf+j, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (buflen - j < p->len) - continue; - - if (memcmp(p->cs, buf+j, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - //printf("output at pos %" PRIu32 ": ", j); prt(buf + (j), ctx->m); printf("\n"); - ; // gcc doesn't like the goto label without this :-S - } - } - - if (j == 0) - break; - - h = B3G_HASH(u8_tolower(buf[j - 1]), u8_tolower(buf[j - 0]),u8_tolower(buf[j+1])); - d = (d << 1) & ctx->B3G[h]; - } while (d != 0); - } - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (ctx->m - B3G_Q + 1)); - pos = pos + ctx->m - B3G_Q + 1; - } - return matches; -} - -uint32_t B3gSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; -#ifdef B3G_COUNTERS - B3gThreadCtx *tctx = (B3gThreadCtx *)mpm_thread_ctx->ctx; -#endif - uint32_t pos = 0, matches = 0; - B3G_TYPE d; - uint32_t j; - - COUNT(tctx->stat_calls++); - COUNT(tctx->stat_m_total+=ctx->m); - - if (buflen < ctx->m) - return 0; - - while (pos <= (buflen - ctx->m)) { - j = ctx->m - 2; - d = ~0; - - do { - uint16_t h = B3G_HASH(u8_tolower(buf[pos + j - 1]), u8_tolower(buf[pos + j - 0]),u8_tolower(buf[pos + j + 1])); - d = ((d << 1) & ctx->B3G[h]); - j = j - 1; - } while (d != 0 && j != 0); - - /* (partial) match, move on to verification */ - if (d != 0) { - COUNT(tctx->stat_d0++); - //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); - - /* get our patterns from the hash */ - uint16_t h = B3G_HASH(u8_tolower(buf[pos + ctx->m - 3]), u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); - - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((buflen - pos) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf+pos, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - - //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); - goto skip_loop; - } - } - } - - B3gHashItem *hi = ctx->hash[h], *thi; - for (thi = hi; thi != NULL; thi = thi->nxt) { - COUNT(tctx->stat_d0_hashloop++); - B3gPattern *p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (buflen - pos < p->len) - continue; - - if (memcmp_lowercase(p->ci, buf+pos, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (buflen - pos < p->len) - continue; - - if (memcmp(p->cs, buf+pos, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } -skip_loop: - pos = pos + 1; - //pos = pos + ctx->s0; - } else { - COUNT(tctx->stat_num_shift++); - COUNT(tctx->stat_total_shift += (j + 1)); - - pos = pos + j + 1; - } - } - - //printf("Total matches %" PRIu32 "\n", matches); - return matches; -} - -uint32_t B3gSearch12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B3gPattern *p; - B3gHashItem *thi, *hi; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h8 = u8_tolower(*buf); - hi = &ctx->hash1[h8]; - - if (hi->flags & 0x01) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } - } - } - - if (buf != bufend) { - /* save one conversion by reusing h8 */ - uint16_t h16 = (uint16_t)(h8 << b3g_hash_shift | u8_tolower(*(buf+1))); - hi = ctx->hash2[h16]; - - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (h8 == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } else { - if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } - } - } - buf += 1; - } - - //printf("B3gSearch12: after 1/2byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt > 0) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B3gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} - -uint32_t B3gSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B3gPattern *p; - B3gHashItem *thi, *hi; - - if (buflen < 2) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint16_t h = u8_tolower(*buf) << b3g_hash_shift | u8_tolower(*(buf+1)); - hi = ctx->hash2[h]; - - if (hi != NULL) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->len != 2) - continue; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (u8_tolower(*buf) == p->ci[0] && u8_tolower(*(buf+1)) == p->ci[1]) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) - cnt++; - } - } else { - if (*buf == p->cs[0] && *(buf+1) == p->cs[1]) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf(" in buf "); prt(buf, p->len);printf(" (B3gSearch1)\n"); - if (MpmVerifyMatch(mpm_thread_ctx, pmq, p->id)) - cnt++; - } - } - } - } - buf += 1; - } - - //printf("B3gSearch2: after 2byte cnt %" PRIu32 "\n", cnt); - if (ctx->pat_x_cnt) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("B3gSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} -uint32_t B3gSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - B3gCtx *ctx = (B3gCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - B3gPattern *p; - B3gHashItem *thi, *hi; - - if (buflen == 0) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - while (buf <= bufend) { - uint8_t h = u8_tolower(*buf); - hi = &ctx->hash1[h]; - - if (hi->flags & 0x01) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->len != 1) - continue; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (u8_tolower(*buf) == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } - } - } - buf += 1; - } - - if (ctx->pat_2_cnt) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch2(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } else if (ctx->pat_x_cnt) { - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - } - return cnt; -} - -void MpmB3gRegister (void) -{ - mpm_table[MPM_B3G].name = "b3g"; - mpm_table[MPM_B3G].max_pattern_length = B3G_WORD_SIZE; - mpm_table[MPM_B3G].InitCtx = B3gInitCtx; - mpm_table[MPM_B3G].InitThreadCtx = B3gThreadInitCtx; - mpm_table[MPM_B3G].DestroyCtx = B3gDestroyCtx; - mpm_table[MPM_B3G].DestroyThreadCtx = B3gThreadDestroyCtx; - mpm_table[MPM_B3G].AddPattern = B3gAddPatternCS; - mpm_table[MPM_B3G].AddPatternNocase = B3gAddPatternCI; - mpm_table[MPM_B3G].Prepare = B3gPreparePatterns; - mpm_table[MPM_B3G].Search = B3gSearchWrap; - mpm_table[MPM_B3G].Cleanup = NULL; - mpm_table[MPM_B3G].PrintCtx = B3gPrintInfo; - mpm_table[MPM_B3G].PrintThreadCtx = B3gPrintSearchStats; - mpm_table[MPM_B3G].RegisterUnittests = B3gRegisterTests; -} - -/* - * TESTS - */ - -#ifdef UNITTESTS -static int B3gTestInit01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->m == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->m); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -#if 0 -static int B3gTestS0Init01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 4) - result = 1; - else - printf("4 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 2) - result = 1; - else - printf("2 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestS0Init05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - - if (ctx->s0 == 3) - result = 1; - else - printf("3 != %" PRIu32 " ", ctx->s0); - - B3gDestroyCtx(&mpm_ctx); - return result; -} -#endif - -static int B3gTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -/* test patterns longer than 'm'. M is 4 here. */ -static int B3gTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -/* case insensitive test patterns longer than 'm'. M is 4 here. */ -static int B3gTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); - - if (cnt == 0) - result = 1; - else - printf("0 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); - - char *input = "012345679012345679012345679012345679012345679012345679" - "012345679012345679012345679012345679abcdefgh0123456790" - "123456790123456790123456790123456790123456790123456790" - "12345679012345679012345679"; - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)input, strlen(input)); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -static int B3gTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_B3G); - B3gCtx *ctx = (B3gCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ - - B3gPreparePatterns(&mpm_ctx); - B3gThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 " ",cnt); - - B3gThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - B3gDestroyCtx(&mpm_ctx); - return result; -} - -#endif /* UNITTESTS */ - -void B3gRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("B3gTestInit01", B3gTestInit01, 1); -/* - UtRegisterTest("B3gTestS0Init01", B3gTestS0Init01, 1); - UtRegisterTest("B3gTestS0Init02", B3gTestS0Init02, 1); - UtRegisterTest("B3gTestS0Init03", B3gTestS0Init03, 1); - UtRegisterTest("B3gTestS0Init04", B3gTestS0Init04, 1); - UtRegisterTest("B3gTestS0Init05", B3gTestS0Init05, 1); -*/ - UtRegisterTest("B3gTestSearch01", B3gTestSearch01, 1); - - UtRegisterTest("B3gTestSearch02", B3gTestSearch02, 1); - UtRegisterTest("B3gTestSearch03", B3gTestSearch03, 1); - UtRegisterTest("B3gTestSearch04", B3gTestSearch04, 1); - UtRegisterTest("B3gTestSearch05", B3gTestSearch05, 1); - UtRegisterTest("B3gTestSearch06", B3gTestSearch06, 1); - UtRegisterTest("B3gTestSearch07", B3gTestSearch07, 1); - UtRegisterTest("B3gTestSearch08", B3gTestSearch08, 1); - UtRegisterTest("B3gTestSearch09", B3gTestSearch09, 1); - UtRegisterTest("B3gTestSearch10", B3gTestSearch10, 1); - UtRegisterTest("B3gTestSearch11", B3gTestSearch11, 1); - UtRegisterTest("B3gTestSearch12", B3gTestSearch12, 1); -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-b3g.h b/src/util-mpm-b3g.h deleted file mode 100644 index 60107ac5f3b7..000000000000 --- a/src/util-mpm-b3g.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_MPM_B3G_H__ -#define __UTIL_MPM_B3G_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -#define B3G_HASHSHIFT_MAX 8 -#define B3G_HASHSHIFT_MAX2 5 -#define B3G_HASHSHIFT_HIGHER 7 -#define B3G_HASHSHIFT_HIGHER2 4 -#define B3G_HASHSHIFT_HIGH 6 -#define B3G_HASHSHIFT_HIGH2 3 -#define B3G_HASHSHIFT_MEDIUM 5 -#define B3G_HASHSHIFT_MEDIUM2 2 -#define B3G_HASHSHIFT_LOW 4 -#define B3G_HASHSHIFT_LOW2 1 -#define B3G_HASHSHIFT_LOWEST 3 -#define B3G_HASHSHIFT_LOWEST2 1 - -#define B3G_TYPE uint32_t -//#define B3G_TYPE uint16_t -//#define B3G_TYPE uint8_t -//#define B3G_WORD_SIZE 16 -//#define B3G_WORD_SIZE 8 -#define B3G_WORD_SIZE 32 - -#define B3G_Q 3 - -//#define B3G_SEARCHFUNC B3gSearch -#define B3G_SEARCHFUNC B3gSearchBNDMq - -//#define B3G_COUNTERS - -typedef struct B3gPattern_ { - uint8_t *cs; /* case sensitive */ - uint8_t *ci; /* case INsensitive */ - uint16_t len; - struct B3gPattern_ *next; - uint8_t flags; - uint32_t id; -} B3gPattern; - -typedef struct B3gHashItem_ { - uint8_t flags; - uint16_t idx; - struct B3gHashItem_ *nxt; -} B3gHashItem; - -typedef struct B3gCtx_ { - /* hash used during ctx initialization */ - B3gPattern **init_hash; - - B3G_TYPE m; - B3G_TYPE *B3G; - - uint8_t s0; - - uint16_t pat_1_cnt; - uint16_t pat_2_cnt; - uint16_t pat_x_cnt; - - uint32_t hash_size; - B3gHashItem **hash; - BloomFilter **bloom; - uint8_t *pminlen; /* array containing the minimal length - of the patters in a hash bucket. Used - for the BloomFilter. */ - B3gHashItem hash1[256]; - B3gHashItem **hash2; - - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* we store our own multi byte search func ptr here for B3gSearch1 */ - uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* pattern arrays */ - B3gPattern **parray; -} B3gCtx; - -typedef struct B3gThreadCtx_ { -#ifdef B3G_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_calls; - uint32_t stat_m_total; - uint32_t stat_d0; - uint32_t stat_d0_hashloop; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* B3G_COUNTERS */ -} B3gThreadCtx; - -void MpmB3gRegister(void); - -#endif - diff --git a/src/util-mpm-hs.c b/src/util-mpm-hs.c new file mode 100644 index 000000000000..2b59eeaff869 --- /dev/null +++ b/src/util-mpm-hs.c @@ -0,0 +1,2174 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jim Xu + * \author Justin Viiret + * + * MPM pattern matcher that calls the Hyperscan regex matcher. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" + +#include "conf.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-memcmp.h" +#include "util-mpm-hs.h" +#include "util-memcpy.h" +#include "util-hash.h" +#include "util-hash-lookup3.h" +#include "util-hyperscan.h" + +#ifdef BUILD_HYPERSCAN + +#include + +void SCHSInitCtx(MpmCtx *); +void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *); +void SCHSDestroyCtx(MpmCtx *); +void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *); +int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, + uint32_t, SigIntId, uint8_t); +int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, + uint32_t, SigIntId, uint8_t); +int SCHSPreparePatterns(MpmCtx *mpm_ctx); +uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, const uint16_t buflen); +void SCHSPrintInfo(MpmCtx *mpm_ctx); +void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); +void SCHSRegisterTests(void); + +/* size of the hash table used to speed up pattern insertions initially */ +#define INIT_HASH_SIZE 65536 + +/* Initial size of the global database hash (used for de-duplication). */ +#define INIT_DB_HASH_SIZE 1000 + +/* Global prototype scratch, built incrementally as Hyperscan databases are + * built and then cloned for each thread context. Access is serialised via + * g_scratch_proto_mutex. */ +static hs_scratch_t *g_scratch_proto = NULL; +static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER; + +/* Global hash table of Hyperscan databases, used for de-duplication. Access is + * serialised via g_db_table_mutex. */ +static HashTable *g_db_table = NULL; +static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER; + +/** + * \internal + * \brief Wraps SCMalloc (which is a macro) so that it can be passed to + * hs_set_allocator() for Hyperscan's use. + */ +static void *SCHSMalloc(size_t size) +{ + return SCMalloc(size); +} + +/** + * \internal + * \brief Wraps SCFree (which is a macro) so that it can be passed to + * hs_set_allocator() for Hyperscan's use. + */ +static void SCHSFree(void *ptr) +{ + SCFree(ptr); +} + +/** \brief Register Suricata malloc/free with Hyperscan. + * + * Requests that Hyperscan use Suricata's allocator for allocation of + * databases, scratch space, etc. + */ +static void SCHSSetAllocators(void) +{ + hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Failed to set Hyperscan allocator."); + exit(EXIT_FAILURE); + } +} + +/** + * \internal + * \brief Creates a hash of the pattern. We use it for the hashing process + * during the initial pattern insertion time, to cull duplicate sigs. + * + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline uint32_t SCHSInitHashRaw(uint8_t *pat, uint16_t patlen) +{ + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +/** + * \internal + * \brief Looks up a pattern. We use it for the hashing process during + * the initial pattern insertion time, to cull duplicate sigs. + * + * \param ctx Pointer to the HS ctx. + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * \param flags Flags. We don't need this. + * + * \retval hash A 32 bit unsigned hash. + */ +static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, uint8_t *pat, + uint16_t patlen, uint16_t offset, + uint16_t depth, char flags, + uint32_t pid) +{ + uint32_t hash = SCHSInitHashRaw(pat, patlen); + + if (ctx->init_hash == NULL) { + return NULL; + } + + SCHSPattern *t = ctx->init_hash[hash]; + for (; t != NULL; t = t->next) { + /* Since Hyperscan uses offset/depth, we must distinguish between + * patterns with the same ID but different offset/depth here. */ + if (t->id == pid && t->offset == offset && t->depth == depth) { + BUG_ON(t->len != patlen); + BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0); + return t; + } + } + + return NULL; +} + +/** + * \internal + * \brief Allocates a new pattern instance. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval p Pointer to the newly created pattern. + */ +static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx) +{ + SCHSPattern *p = SCMalloc(sizeof(SCHSPattern)); + if (unlikely(p == NULL)) { + exit(EXIT_FAILURE); + } + memset(p, 0, sizeof(SCHSPattern)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCHSPattern); + + return p; +} + +/** + * \internal + * \brief Used to free SCHSPattern instances. + * + * \param mpm_ctx Pointer to the mpm context. + * \param p Pointer to the SCHSPattern instance to be freed. + * \param free Free the above pointer or not. + */ +static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p) +{ + if (p != NULL && p->original_pat != NULL) { + SCFree(p->original_pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + if (p != NULL && p->sids != NULL) { + SCFree(p->sids); + } + + if (p != NULL) { + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCHSPattern); + } +} + +static inline uint32_t SCHSInitHash(SCHSPattern *p) +{ + uint32_t hash = p->len * p->original_pat[0]; + if (p->len > 1) + hash += p->original_pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p) +{ + uint32_t hash = SCHSInitHash(p); + + if (ctx->init_hash == NULL) { + return 0; + } + + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } + + SCHSPattern *tt = NULL; + SCHSPattern *t = ctx->init_hash[hash]; + + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; + + return 0; +} + +/** + * \internal + * \brief Add a pattern to the mpm-hs context. + * + * \param mpm_ctx Mpm context. + * \param pat Pointer to the pattern. + * \param patlen Length of the pattern. + * \param pid Pattern id + * \param sid Signature id (internal id). + * \param flags Pattern's MPM_PATTERN_* flags. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int SCHSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + if (offset != 0) { + flags |= MPM_PATTERN_FLAG_OFFSET; + } + if (depth != 0) { + flags |= MPM_PATTERN_FLAG_DEPTH; + } + + if (patlen == 0) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); + return 0; + } + + /* check if we have already inserted this pattern */ + SCHSPattern *p = + SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid); + if (p == NULL) { + SCLogDebug("Allocing new pattern"); + + /* p will never be NULL */ + p = SCHSAllocPattern(mpm_ctx); + + p->len = patlen; + p->flags = flags; + p->id = pid; + + p->offset = offset; + p->depth = depth; + + p->original_pat = SCMalloc(patlen); + if (p->original_pat == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->original_pat, pat, patlen); + + /* put in the pattern hash */ + SCHSInitHashAdd(ctx, p); + + mpm_ctx->pattern_cnt++; + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + + if (mpm_ctx->minlen == 0) { + mpm_ctx->minlen = patlen; + } else { + if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* TODO figure out how we can be called multiple times for the same CTX with the same sid */ + + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + if (!found) { + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } + } + + return 0; + +error: + SCHSFreePattern(mpm_ctx, p); + return -1; +} + +/** + * \brief Pattern database information used only as input to the Hyperscan + * compiler. + */ +typedef struct SCHSCompileData_ { + unsigned int *ids; + unsigned int *flags; + char **expressions; + hs_expr_ext_t **ext; + unsigned int pattern_cnt; +} SCHSCompileData; + +static SCHSCompileData *SCHSAllocCompileData(unsigned int pattern_cnt) +{ + SCHSCompileData *cd = SCMalloc(pattern_cnt * sizeof(SCHSCompileData)); + if (cd == NULL) { + goto error; + } + memset(cd, 0, pattern_cnt * sizeof(SCHSCompileData)); + + cd->pattern_cnt = pattern_cnt; + + cd->ids = SCMalloc(pattern_cnt * sizeof(unsigned int)); + if (cd->ids == NULL) { + goto error; + } + memset(cd->ids, 0, pattern_cnt * sizeof(unsigned int)); + + cd->flags = SCMalloc(pattern_cnt * sizeof(unsigned int)); + if (cd->flags == NULL) { + goto error; + } + memset(cd->flags, 0, pattern_cnt * sizeof(unsigned int)); + + cd->expressions = SCMalloc(pattern_cnt * sizeof(char *)); + if (cd->expressions == NULL) { + goto error; + } + memset(cd->expressions, 0, pattern_cnt * sizeof(char *)); + + cd->ext = SCMalloc(pattern_cnt * sizeof(hs_expr_ext_t *)); + if (cd->ext == NULL) { + goto error; + } + memset(cd->ext, 0, pattern_cnt * sizeof(hs_expr_ext_t *)); + + return cd; + +error: + SCLogDebug("SCHSCompileData alloc failed"); + if (cd) { + SCFree(cd->ids); + SCFree(cd->flags); + SCFree(cd->expressions); + SCFree(cd->ext); + SCFree(cd); + } + return NULL; +} + +static void SCHSFreeCompileData(SCHSCompileData *cd) +{ + if (cd == NULL) { + return; + } + + SCFree(cd->ids); + SCFree(cd->flags); + if (cd->expressions) { + for (unsigned int i = 0; i < cd->pattern_cnt; i++) { + SCFree(cd->expressions[i]); + } + SCFree(cd->expressions); + } + if (cd->ext) { + for (unsigned int i = 0; i < cd->pattern_cnt; i++) { + SCFree(cd->ext[i]); + } + SCFree(cd->ext); + } + SCFree(cd); +} + +typedef struct PatternDatabase_ { + SCHSPattern **parray; + hs_database_t *hs_db; + uint32_t pattern_cnt; + + /* Reference count: number of MPM contexts using this pattern database. */ + uint32_t ref_cnt; +} PatternDatabase; + +static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash) +{ + BUG_ON(p->original_pat == NULL); + BUG_ON(p->sids == NULL); + + hash = hashlittle_safe(&p->len, sizeof(p->len), hash); + hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash); + hash = hashlittle_safe(p->original_pat, p->len, hash); + hash = hashlittle_safe(&p->id, sizeof(p->id), hash); + hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash); + hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash); + hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash); + hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash); + return hash; +} + +static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2) +{ + if ((p1->len != p2->len) || (p1->flags != p2->flags) || + (p1->id != p2->id) || (p1->offset != p2->offset) || + (p1->depth != p2->depth) || (p1->sids_size != p2->sids_size)) { + return 0; + } + + if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) { + return 0; + } + + if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) != + 0) { + return 0; + } + + return 1; +} + +static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len) +{ + const PatternDatabase *pd = data; + uint32_t hash = 0; + hash = hashword(&pd->pattern_cnt, 1, hash); + + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + hash = SCHSPatternHash(pd->parray[i], hash); + } + + hash %= ht->array_size; + return hash; +} + +static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2, + uint16_t len2) +{ + const PatternDatabase *pd1 = data1; + const PatternDatabase *pd2 = data2; + + if (pd1->pattern_cnt != pd2->pattern_cnt) { + return 0; + } + + for (uint32_t i = 0; i < pd1->pattern_cnt; i++) { + if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) { + return 0; + } + } + + return 1; +} + +static void PatternDatabaseFree(PatternDatabase *pd) +{ + BUG_ON(pd->ref_cnt != 0); + + if (pd->parray != NULL) { + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + SCHSPattern *p = pd->parray[i]; + if (p != NULL) { + SCFree(p->original_pat); + SCFree(p->sids); + SCFree(p); + } + } + SCFree(pd->parray); + } + + hs_free_database(pd->hs_db); + + SCFree(pd); +} + +static void PatternDatabaseTableFree(void *data) +{ + /* Stub function handed to hash table; actual freeing of PatternDatabase + * structures is done in MPM destruction when the ref_cnt drops to zero. */ +} + +static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt) +{ + PatternDatabase *pd = SCMalloc(sizeof(PatternDatabase)); + if (pd == NULL) { + return NULL; + } + memset(pd, 0, sizeof(PatternDatabase)); + pd->pattern_cnt = pattern_cnt; + pd->ref_cnt = 0; + pd->hs_db = NULL; + + /* alloc the pattern array */ + pd->parray = + (SCHSPattern **)SCMalloc(pd->pattern_cnt * sizeof(SCHSPattern *)); + if (pd->parray == NULL) { + SCFree(pd); + return NULL; + } + memset(pd->parray, 0, pd->pattern_cnt * sizeof(SCHSPattern *)); + + return pd; +} + +/** + * \brief Process the patterns added to the mpm, and create the internal tables. + * + * \param mpm_ctx Pointer to the mpm context. + */ +int SCHSPreparePatterns(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + + hs_error_t err; + hs_compile_error_t *compile_err = NULL; + SCHSCompileData *cd = NULL; + PatternDatabase *pd = NULL; + + cd = SCHSAllocCompileData(mpm_ctx->pattern_cnt); + if (cd == NULL) { + goto error; + } + + pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt); + if (pd == NULL) { + goto error; + } + + /* populate the pattern array with the patterns in the hash */ + for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) { + SCHSPattern *node = ctx->init_hash[i], *nnode = NULL; + while (node != NULL) { + nnode = node->next; + node->next = NULL; + pd->parray[p++] = node; + node = nnode; + } + } + + /* we no longer need the hash, so free its memory */ + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + + /* Serialise whole database compilation as a relatively easy way to ensure + * dedupe is safe. */ + SCMutexLock(&g_db_table_mutex); + + /* Init global pattern database hash if necessary. */ + if (g_db_table == NULL) { + g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash, + PatternDatabaseCompare, + PatternDatabaseTableFree); + if (g_db_table == NULL) { + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + } + + /* Check global hash table to see if we've seen this pattern database + * before, and reuse the Hyperscan database if so. */ + PatternDatabase *pd_cached = HashTableLookup(g_db_table, pd, 1); + + if (pd_cached != NULL) { + SCLogDebug("Reusing cached database %p with %" PRIu32 + " patterns (ref_cnt=%" PRIu32 ")", + pd_cached->hs_db, pd_cached->pattern_cnt, + pd_cached->ref_cnt); + pd_cached->ref_cnt++; + ctx->pattern_db = pd_cached; + SCMutexUnlock(&g_db_table_mutex); + PatternDatabaseFree(pd); + SCHSFreeCompileData(cd); + return 0; + } + + BUG_ON(ctx->pattern_db != NULL); /* already built? */ + + for (uint32_t i = 0; i < pd->pattern_cnt; i++) { + const SCHSPattern *p = pd->parray[i]; + + cd->ids[i] = i; + cd->flags[i] = HS_FLAG_SINGLEMATCH; + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + cd->flags[i] |= HS_FLAG_CASELESS; + } + + cd->expressions[i] = HSRenderPattern(p->original_pat, p->len); + + if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) { + cd->ext[i] = SCMalloc(sizeof(hs_expr_ext_t)); + if (cd->ext[i] == NULL) { + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + memset(cd->ext[i], 0, sizeof(hs_expr_ext_t)); + + if (p->flags & MPM_PATTERN_FLAG_OFFSET) { + cd->ext[i]->flags |= HS_EXT_FLAG_MIN_OFFSET; + cd->ext[i]->min_offset = p->offset + p->len; + } + if (p->flags & MPM_PATTERN_FLAG_DEPTH) { + cd->ext[i]->flags |= HS_EXT_FLAG_MAX_OFFSET; + cd->ext[i]->max_offset = p->offset + p->depth; + } + } + } + + BUG_ON(mpm_ctx->pattern_cnt == 0); + + err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags, + cd->ids, (const hs_expr_ext_t *const *)cd->ext, + cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db, + &compile_err); + + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "failed to compile hyperscan database"); + if (compile_err) { + SCLogError(SC_ERR_FATAL, "compile error: %s", compile_err->message); + } + hs_free_compile_error(compile_err); + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + ctx->pattern_db = pd; + + SCMutexLock(&g_scratch_proto_mutex); + err = hs_alloc_scratch(pd->hs_db, &g_scratch_proto); + SCMutexUnlock(&g_scratch_proto_mutex); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "failed to allocate scratch"); + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + err = hs_database_size(pd->hs_db, &ctx->hs_db_size); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "failed to query database size"); + SCMutexUnlock(&g_db_table_mutex); + goto error; + } + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += ctx->hs_db_size; + + SCLogDebug("Built %" PRIu32 " patterns into a database of size %" PRIuMAX + " bytes", mpm_ctx->pattern_cnt, (uintmax_t)ctx->hs_db_size); + + /* Cache this database globally for later. */ + pd->ref_cnt = 1; + HashTableAdd(g_db_table, pd, 1); + SCMutexUnlock(&g_db_table_mutex); + + SCHSFreeCompileData(cd); + return 0; + +error: + if (pd) { + PatternDatabaseFree(pd); + } + if (cd) { + SCHSFreeCompileData(cd); + } + return -1; +} + +/** + * \brief Init the mpm thread context. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + */ +void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) +{ + memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + + SCHSThreadCtx *ctx = SCMalloc(sizeof(SCHSThreadCtx)); + if (ctx == NULL) { + exit(EXIT_FAILURE); + } + mpm_thread_ctx->ctx = ctx; + + memset(ctx, 0, sizeof(SCHSThreadCtx)); + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += sizeof(SCHSThreadCtx); + + ctx->scratch = NULL; + ctx->scratch_size = 0; + + SCMutexLock(&g_scratch_proto_mutex); + + if (g_scratch_proto == NULL) { + /* There is no scratch prototype: this means that we have not compiled + * any Hyperscan databases. */ + SCMutexUnlock(&g_scratch_proto_mutex); + SCLogDebug("No scratch space prototype"); + return; + } + + hs_error_t err = hs_clone_scratch(g_scratch_proto, + (hs_scratch_t **)&ctx->scratch); + + SCMutexUnlock(&g_scratch_proto_mutex); + + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to clone scratch prototype"); + exit(EXIT_FAILURE); + } + + err = hs_scratch_size(ctx->scratch, &ctx->scratch_size); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to query scratch size"); + exit(EXIT_FAILURE); + } + + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += ctx->scratch_size; +} + +/** + * \brief Initialize the HS context. + * + * \param mpm_ctx Mpm context. + */ +void SCHSInitCtx(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->ctx != NULL) + return; + + mpm_ctx->ctx = SCMalloc(sizeof(SCHSCtx)); + if (mpm_ctx->ctx == NULL) { + exit(EXIT_FAILURE); + } + memset(mpm_ctx->ctx, 0, sizeof(SCHSCtx)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(SCHSCtx); + + /* initialize the hash we use to speed up pattern insertions */ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + ctx->init_hash = SCMalloc(sizeof(SCHSPattern *) * INIT_HASH_SIZE); + if (ctx->init_hash == NULL) { + exit(EXIT_FAILURE); + } + memset(ctx->init_hash, 0, sizeof(SCHSPattern *) * INIT_HASH_SIZE); +} + +/** + * \brief Destroy the mpm thread context. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + */ +void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) +{ + SCHSPrintSearchStats(mpm_thread_ctx); + + if (mpm_thread_ctx->ctx != NULL) { + SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx; + + if (thr_ctx->scratch != NULL) { + hs_free_scratch(thr_ctx->scratch); + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= thr_ctx->scratch_size; + } + + SCFree(mpm_thread_ctx->ctx); + mpm_thread_ctx->ctx = NULL; + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx); + } +} + +/** + * \brief Destroy the mpm context. + * + * \param mpm_ctx Pointer to the mpm context. + */ +void SCHSDestroyCtx(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + if (ctx == NULL) + return; + + if (ctx->init_hash != NULL) { + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCHSPattern *)); + } + + /* Decrement pattern database ref count, and delete it entirely if the + * count has dropped to zero. */ + SCMutexLock(&g_db_table_mutex); + PatternDatabase *pd = ctx->pattern_db; + if (pd) { + BUG_ON(pd->ref_cnt == 0); + pd->ref_cnt--; + if (pd->ref_cnt == 0) { + HashTableRemove(g_db_table, pd, 1); + PatternDatabaseFree(pd); + } + } + SCMutexUnlock(&g_db_table_mutex); + + SCFree(mpm_ctx->ctx); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(SCHSCtx); +} + +typedef struct SCHSCallbackCtx_ { + SCHSCtx *ctx; + void *pmq; + uint32_t match_count; +} SCHSCallbackCtx; + +/* Hyperscan MPM match event handler */ +static int SCHSMatchEvent(unsigned int id, unsigned long long from, + unsigned long long to, unsigned int flags, + void *ctx) +{ + SCHSCallbackCtx *cctx = ctx; + PrefilterRuleStore *pmq = cctx->pmq; + const PatternDatabase *pd = cctx->ctx->pattern_db; + const SCHSPattern *pat = pd->parray[id]; + + SCLogDebug("Hyperscan Match %" PRIu32 ": id=%" PRIu32 " @ %" PRIuMAX + " (pat id=%" PRIu32 ")", + cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id); + + PrefilterAddSids(pmq, pat->sids, pat->sids_size); + + cctx->match_count++; + return 0; +} + +/** + * \brief The Hyperscan search function. + * + * \param mpm_ctx Pointer to the mpm context. + * \param mpm_thread_ctx Pointer to the mpm thread context. + * \param pmq Pointer to the Pattern Matcher Queue to hold + * search matches. + * \param buf Buffer to be searched. + * \param buflen Buffer length. + * + * \retval matches Match count. + */ +uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, const uint16_t buflen) +{ + uint32_t ret = 0; + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx); + const PatternDatabase *pd = ctx->pattern_db; + + if (unlikely(buflen == 0)) { + return 0; + } + + SCHSCallbackCtx cctx = {.ctx = ctx, .pmq = pmq, .match_count = 0}; + + /* scratch should have been cloned from g_scratch_proto at thread init. */ + hs_scratch_t *scratch = hs_thread_ctx->scratch; + BUG_ON(pd->hs_db == NULL); + BUG_ON(scratch == NULL); + + hs_error_t err = hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch, + SCHSMatchEvent, &cctx); + if (err != HS_SUCCESS) { + /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() + * indicates that it was passed an invalid database or scratch region, + * which is not something we can recover from at scan time. */ + SCLogError(SC_ERR_FATAL, "Hyperscan returned error %d", err); + exit(EXIT_FAILURE); + } else { + ret = cctx.match_count; + } + + return ret; +} + +/** + * \brief Add a case insensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patlen The pattern length. + * \param offset The pattern offset. + * \param depth The pattern depth. + * \param pid The pattern id. + * \param sid The pattern signature id. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCHSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + flags |= MPM_PATTERN_FLAG_NOCASE; + return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +/** + * \brief Add a case sensitive pattern. Although we have different calls for + * adding case sensitive and insensitive patterns, we make a single call + * for either case. No special treatment for either case. + * + * \param mpm_ctx Pointer to the mpm context. + * \param pat The pattern to add. + * \param patlen The pattern length. + * \param offset The pattern offset. + * \param depth The pattern depth. + * \param pid The pattern id. + * \param sid The pattern signature id. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCHSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) +{ + return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) +{ + return; +} + +void SCHSPrintInfo(MpmCtx *mpm_ctx) +{ + SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx; + + printf("MPM HS Information:\n"); + printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); + printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); + printf(" Sizeof:\n"); + printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); + printf(" SCHSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSCtx)); + printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern)); + printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); + printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); + printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); + printf("\n"); + + if (ctx) { + PatternDatabase *pd = ctx->pattern_db; + char *db_info = NULL; + if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) { + printf("HS Database Info: %s\n", db_info); + SCFree(db_info); + } + printf("HS Database Size: %" PRIuMAX " bytes\n", + (uintmax_t)ctx->hs_db_size); + } + + printf("\n"); +} + +/************************** Mpm Registration ***************************/ + +/** + * \brief Register the Hyperscan MPM. + */ +void MpmHSRegister(void) +{ + mpm_table[MPM_HS].name = "hs"; + mpm_table[MPM_HS].InitCtx = SCHSInitCtx; + mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx; + mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx; + mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx; + mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS; + mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI; + mpm_table[MPM_HS].Prepare = SCHSPreparePatterns; + mpm_table[MPM_HS].Search = SCHSSearch; + mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo; + mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats; + mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests; + + /* Set Hyperscan memory allocators */ + SCHSSetAllocators(); +} + +/** + * \brief Clean up global memory used by all Hyperscan MPM instances. + * + * Currently, this is just the global scratch prototype. + */ +void MpmHSGlobalCleanup(void) +{ + SCMutexLock(&g_scratch_proto_mutex); + if (g_scratch_proto) { + SCLogPerf("Cleaning up Hyperscan global scratch"); + hs_free_scratch(g_scratch_proto); + g_scratch_proto = NULL; + } + SCMutexUnlock(&g_scratch_proto_mutex); + + SCMutexLock(&g_db_table_mutex); + if (g_db_table != NULL) { + SCLogPerf("Clearing Hyperscan database cache"); + HashTableFree(g_db_table); + g_db_table = NULL; + } + SCMutexUnlock(&g_db_table_mutex); +} + +/*************************************Unittests********************************/ + +#ifdef UNITTESTS + +static int SCHSTest01(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest02(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest03(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest04(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest05(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest06(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcd"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest07(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* should match 30 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); + /* should match 29 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); + /* should match 28 times */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); + /* 26 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); + /* 21 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, + 0, 0, 5, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 6) + result = 1; + else + printf("6 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest08(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest09(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest10(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest11(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1) + goto end; + if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1) + goto end; + PmqSetup(&pmq); + + if (SCHSPreparePatterns(&mpm_ctx) == -1) + goto end; + + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + result = 1; + + char *buf = "he"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 1); + buf = "she"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 2); + buf = "his"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 1); + buf = "hers"; + result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)) == 2); + +end: + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest12(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest13(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABCD"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest14(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABCDE"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest15(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest16(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzABC"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyzABC"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest17(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcdefghijklmnopqrstuvwxyzAB"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyzAB"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest18(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + char *pat = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest19(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest20(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + char *pat = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest21(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest22(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest23(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 0) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest24(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 1 */ + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + uint32_t cnt = + SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest25(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest26(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0); + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "works"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest27(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "tone"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest28(void) +{ + int result = 0; + MpmCtx mpm_ctx; + MpmThreadCtx mpm_thread_ctx; + PrefilterRuleStore pmq; + + memset(&mpm_ctx, 0, sizeof(MpmCtx)); + memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + MpmInitCtx(&mpm_ctx, MPM_HS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCHSPreparePatterns(&mpm_ctx); + SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx); + + char *buf = "tONE"; + uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, + strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCHSDestroyCtx(&mpm_ctx); + SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx); + PmqFree(&pmq); + return result; +} + +static int SCHSTest29(void) +{ + uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine"; + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + de_ctx->mpm_matcher = MPM_HS; + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit( + de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + de_ctx->sig_list->next = + SigInit(de_ctx, "alert tcp any any -> any any " + "(content:\"onetwothreefourfivesixseveneightnine\"; " + "fast_pattern:3,3; sid:2;)"); + if (de_ctx->sig_list->next == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (PacketAlertCheck(p, 1) != 1) { + printf("if (PacketAlertCheck(p, 1) != 1) failure\n"); + goto end; + } + if (PacketAlertCheck(p, 2) != 1) { + printf("if (PacketAlertCheck(p, 1) != 2) failure\n"); + goto end; + } + + result = 1; +end: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + } + + UTHFreePackets(&p, 1); + return result; +} + +#endif /* UNITTESTS */ + +void SCHSRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("SCHSTest01", SCHSTest01); + UtRegisterTest("SCHSTest02", SCHSTest02); + UtRegisterTest("SCHSTest03", SCHSTest03); + UtRegisterTest("SCHSTest04", SCHSTest04); + UtRegisterTest("SCHSTest05", SCHSTest05); + UtRegisterTest("SCHSTest06", SCHSTest06); + UtRegisterTest("SCHSTest07", SCHSTest07); + UtRegisterTest("SCHSTest08", SCHSTest08); + UtRegisterTest("SCHSTest09", SCHSTest09); + UtRegisterTest("SCHSTest10", SCHSTest10); + UtRegisterTest("SCHSTest11", SCHSTest11); + UtRegisterTest("SCHSTest12", SCHSTest12); + UtRegisterTest("SCHSTest13", SCHSTest13); + UtRegisterTest("SCHSTest14", SCHSTest14); + UtRegisterTest("SCHSTest15", SCHSTest15); + UtRegisterTest("SCHSTest16", SCHSTest16); + UtRegisterTest("SCHSTest17", SCHSTest17); + UtRegisterTest("SCHSTest18", SCHSTest18); + UtRegisterTest("SCHSTest19", SCHSTest19); + UtRegisterTest("SCHSTest20", SCHSTest20); + UtRegisterTest("SCHSTest21", SCHSTest21); + UtRegisterTest("SCHSTest22", SCHSTest22); + UtRegisterTest("SCHSTest23", SCHSTest23); + UtRegisterTest("SCHSTest24", SCHSTest24); + UtRegisterTest("SCHSTest25", SCHSTest25); + UtRegisterTest("SCHSTest26", SCHSTest26); + UtRegisterTest("SCHSTest27", SCHSTest27); + UtRegisterTest("SCHSTest28", SCHSTest28); + UtRegisterTest("SCHSTest29", SCHSTest29); +#endif + + return; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-mpm-hs.h b/src/util-mpm-hs.h new file mode 100644 index 000000000000..4778ab85012a --- /dev/null +++ b/src/util-mpm-hs.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2007-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jim Xu + * \author Justin Viiret + * + * MPM pattern matcher that calls the Hyperscan regex matcher. + */ + +#ifndef __UTIL_MPM_HS__H__ +#define __UTIL_MPM_HS__H__ + +typedef struct SCHSPattern_ { + /* length of the pattern */ + uint16_t len; + /* flags describing the pattern */ + uint8_t flags; + /* holds the original pattern that was added */ + uint8_t *original_pat; + /* pattern id */ + uint32_t id; + + uint16_t offset; + uint16_t depth; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; + + /* only used at ctx init time, when this structure is part of a hash + * table. */ + struct SCHSPattern_ *next; +} SCHSPattern; + +typedef struct SCHSCtx_ { + /* hash used during ctx initialization */ + SCHSPattern **init_hash; + + /* pattern database and pattern arrays. */ + void *pattern_db; + + /* size of database, for accounting. */ + size_t hs_db_size; +} SCHSCtx; + +typedef struct SCHSThreadCtx_ { + /* Hyperscan scratch space region for this thread, capable of handling any + * database that has been compiled. */ + void *scratch; + + /* size of scratch space, for accounting. */ + size_t scratch_size; +} SCHSThreadCtx; + +void MpmHSRegister(void); + +void MpmHSGlobalCleanup(void); + +#endif /* __UTIL_MPM_HS__H__ */ diff --git a/src/util-mpm-wumanber.c b/src/util-mpm-wumanber.c deleted file mode 100644 index 15d7a23ccd19..000000000000 --- a/src/util-mpm-wumanber.c +++ /dev/null @@ -1,3150 +0,0 @@ -/* Copyright (C) 2007-2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - * - * Implementation of the Wu-Manber pattern matching algorithm. - * - * Ideas: - * - the hash contains a list of patterns. Maybe we can 'train' the hash - * so the most common patterns always appear first in this list. - * - * \todo make hash1 a array of ptr and get rid of the flag field in the - * WmHashItem - * \todo remove exit() calls - * \todo only calc prefixci_buf for nocase patterns? -- would be in a - * loop though, so probably not a performance inprovement. - * \todo make sure runtime counters can be disabled (at compile time) - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "util-mpm.h" -#include "util-mpm-wumanber.h" -#include "conf.h" - -#include "util-unittest.h" -#include "util-debug.h" - -#define INIT_HASH_SIZE 65535 - -#define HASH16_SIZE 65536 -#define HASH16(a,b) (((a)<<8) | (b)) -#define HASH15_SIZE 32768 -#define HASH15(a,b) (((a)<<7) | (b)) -#define HASH14_SIZE 16384 -#define HASH14(a,b) (((a)<<6) | (b)) -#define HASH12_SIZE 4096 -#define HASH12(a,b) (((a)<<4) | (b)) -#define HASH9_SIZE 512 -#define HASH9(a,b) (((a)<<1) | (b)) - -static uint32_t wm_hash_size = 0; -static uint32_t wm_bloom_size = 0; - -void WmInitCtx (MpmCtx *mpm_ctx); -void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t); -void WmDestroyCtx(MpmCtx *mpm_ctx); -void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx); -int WmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int WmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); -int WmPreparePatterns(MpmCtx *mpm_ctx); -uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); -void WmPrintInfo(MpmCtx *mpm_ctx); -void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); -void WmRegisterTests(void); - -/* uppercase to lowercase conversion lookup table */ -static uint8_t lowercasetable[256]; -/* marco to do the actual lookup */ -#define wm_tolower(c) lowercasetable[(c)] - -#ifdef WUMANBER_COUNTERS -#define COUNT(counter) \ - (counter) -#else -#define COUNT(counter) -#endif /* WUMANBER_COUNTERS */ - -void prt (uint8_t *buf, uint16_t buflen) -{ - uint16_t i; - - for (i = 0; i < buflen; i++) { - if (isprint(buf[i])) printf("%c", buf[i]); - else printf("\\x%" PRIX32, buf[i]); - } - //printf("\n"); -} - -void WmPrintInfo(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - - printf("MPM WuManber Information:\n"); - printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); - printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); - printf(" Sizeofs:\n"); - printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); - printf(" WmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(WmCtx)); - printf(" WmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(WmPattern)); - printf(" WmHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(WmHashItem)); - printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); - printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); - printf("Max shiftlen: %" PRIu32 "\n", ctx->shiftlen); - printf("Hash size: %" PRIu32 "\n", ctx->hash_size); - printf("Search function: "); - if (ctx->Search == WmSearch1) { - printf("WmSearch1 (allows single byte patterns)\n"); - printf("MBSearch funct: "); - if (ctx->MBSearch == WmSearch2Hash16) printf("WmSearch2Hash16\n"); - else if (ctx->MBSearch == WmSearch2Hash15) printf("WmSearch2Hash15\n"); - else if (ctx->MBSearch == WmSearch2Hash14) printf("WmSearch2Hash14\n"); - else if (ctx->MBSearch == WmSearch2Hash12) printf("WmSearch2Hash12\n"); - else if (ctx->MBSearch == WmSearch2Hash9) printf("WmSearch2Hash9\n"); - } - if (ctx->Search == WmSearch2Hash16) printf("WmSearch2Hash16 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash15) printf("WmSearch2Hash15 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash14) printf("WmSearch2Hash14 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash12) printf("WmSearch2Hash12 (only for multibyte patterns)\n"); - else if (ctx->Search == WmSearch2Hash9) printf("WmSearch2Hash9 (only for multibyte patterns)\n"); - else printf("ERROR\n"); - printf("\n"); -} - -static inline WmPattern *WmAllocPattern(MpmCtx *mpm_ctx) -{ - WmPattern *p = SCMalloc(sizeof(WmPattern)); - if (unlikely(p == NULL)) - return NULL; - memset(p,0,sizeof(WmPattern)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(WmPattern); - return p; -} - -static inline WmHashItem * -WmAllocHashItem(MpmCtx *mpm_ctx) -{ - WmHashItem *hi = SCMalloc(sizeof(WmHashItem)); - if (unlikely(hi == NULL)) - return NULL; - memset(hi,0,sizeof(WmHashItem)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(WmHashItem); - return hi; -} - -static void WmHashFree(MpmCtx *mpm_ctx, WmHashItem *hi) -{ - if (hi == NULL) - return; - - WmHashItem *t = hi->nxt; - WmHashFree(mpm_ctx, t); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(WmHashItem); - SCFree(hi); -} - -static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) -{ - uint16_t i; - for (i = 0; i < len; i++) { - d[i] = wm_tolower(s[i]); - } -} - -/* - * INIT HASH START - */ -static inline uint32_t WmInitHash(WmPattern *p) -{ - uint32_t hash = p->len * p->cs[0]; - if (p->len > 1) - hash += p->cs[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline uint32_t WmInitHashRaw(uint8_t *pat, uint16_t patlen) -{ - uint32_t hash = patlen * pat[0]; - if (patlen > 1) - hash += pat[1]; - - return (hash % INIT_HASH_SIZE); -} - -static inline int WmInitHashAdd(WmCtx *ctx, WmPattern *p) -{ - uint32_t hash = WmInitHash(p); - - //printf("WmInitHashAdd: %" PRIu32 "\n", hash); - - if (ctx->init_hash[hash] == NULL) { - ctx->init_hash[hash] = p; - //printf("WmInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - return 0; - } - - WmPattern *tt = NULL; - WmPattern *t = ctx->init_hash[hash]; - - /* get the list tail */ - do { - tt = t; - t = t->next; - } while (t != NULL); - - tt->next = p; - //printf("WmInitHashAdd: hash %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - return 0; -} - -static inline int WmCmpPattern(WmPattern *p, uint8_t *pat, uint16_t patlen, char flags); - -static inline WmPattern *WmInitHashLookup(WmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) -{ - uint32_t hash = WmInitHashRaw(pat,patlen); - - //printf("WmInitHashLookup: %" PRIu32 ", head %p\n", hash, ctx->init_hash[hash]); - - if (ctx->init_hash[hash] == NULL) { - return NULL; - } - - WmPattern *t = ctx->init_hash[hash]; - for ( ; t != NULL; t = t->next) { - if (WmCmpPattern(t,pat,patlen,flags) == 1) - return t; - } - - return NULL; -} - -static inline int WmCmpPattern(WmPattern *p, uint8_t *pat, uint16_t patlen, char flags) -{ - if (p->len != patlen) - return 0; - - if (p->flags != flags) - return 0; - - if (memcmp(p->cs, pat, patlen) != 0) - return 0; - - return 1; -} - -/* - * INIT HASH END - */ - -void WmFreePattern(MpmCtx *mpm_ctx, WmPattern *p) -{ - if (p && p->cs && p->cs != p->ci) { - SCFree(p->cs); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p && p->ci) { - SCFree(p->ci); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } - - if (p) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(WmPattern); - } -} - -/* WmAddPattern - * - * pat: ptr to the pattern - * patlen: length of the pattern - * nocase: nocase flag: 1 enabled, 0 disable - * pid: pattern id - * sid: signature id (internal id) - */ -static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - -// printf("WmAddPattern: ctx %p \"", mpm_ctx); prt(pat, patlen); -// printf("\" id %" PRIu32 ", nocase %s\n", id, nocase ? "true" : "false"); - - if (patlen == 0) - return 0; - - /* get a memory piece */ - WmPattern *p = WmInitHashLookup(ctx, pat, patlen, flags); - if (p == NULL) { -// printf("WmAddPattern: allocing new pattern\n"); - p = WmAllocPattern(mpm_ctx); - if (p == NULL) - goto error; - - p->len = patlen; - p->flags = flags; - p->id = pid; - - /* setup the case insensitive part of the pattern */ - p->ci = SCMalloc(patlen); - if (p->ci == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy_tolower(p->ci, pat, patlen); - - /* setup the case sensitive part of the pattern */ - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - /* nocase means no difference between cs and ci */ - p->cs = p->ci; - } else { - if (memcmp(p->ci,pat,p->len) == 0) { - /* no diff between cs and ci: pat is lowercase */ - p->cs = p->ci; - } else { - p->cs = SCMalloc(patlen); - if (p->cs == NULL) - goto error; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; - memcpy(p->cs, pat, patlen); - } - } - - if (p->len > 1) { - p->prefix_cs = (uint16_t)(*(p->cs)+*(p->cs+1)); - p->prefix_ci = (uint16_t)(*(p->ci)+*(p->ci+1)); - } - - //printf("WmAddPattern: ci \""); prt(p->ci,p->len); - //printf("\" cs \""); prt(p->cs,p->len); - //printf("\" prefix_ci %" PRIu32 ", prefix_cs %" PRIu32 "\n", p->prefix_ci, p->prefix_cs); - - /* put in the pattern hash */ - WmInitHashAdd(ctx, p); - - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; - - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; - } - - return 0; - -error: - WmFreePattern(mpm_ctx, p); - return -1; -} - -int WmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - flags |= MPM_PATTERN_FLAG_NOCASE; - return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -int WmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) -{ - return WmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); -} - -static uint32_t WmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint16_t i; - uint32_t hash = (uint32_t)wm_tolower(*d); - - for (i = 1; i < datalen - 1; i++) { - hash += (wm_tolower((*d++))) ^ i; - } - hash <<= (iter+1); - - hash %= hash_size; - return hash; -} -/* -static uint32_t BloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) -{ - uint8_t *d = (uint8_t *)data; - uint32_t i; - uint32_t hash = 0; - - for (i = 0; i < datalen; i++) { - if (i == 0) hash += (((uint32_t)*d++)); - else if (i == 1) hash += (((uint32_t)*d++) * datalen); - else hash *= (((uint32_t)*d++) * i); - } - - hash *= (iter + datalen); - hash %= hash_size; - return hash; -} -*/ -static void WmSearchPrepareHash(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - uint16_t i; - uint16_t idx = 0; - uint8_t idx8 = 0; - - ctx->hash = (WmHashItem **)SCMalloc(sizeof(WmHashItem *) * ctx->hash_size); - if (ctx->hash == NULL) - goto error; - memset(ctx->hash, 0, sizeof(WmHashItem *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(WmHashItem *) * ctx->hash_size); - - /* alloc the pminlen array */ - ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); - if (ctx->pminlen == NULL) - goto error; - memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - if(ctx->parray[i]->len == 1) { - idx8 = (uint8_t)ctx->parray[i]->ci[0]; - if (ctx->hash1[idx8].flags == 0) { - ctx->hash1[idx8].idx = i; - ctx->hash1[idx8].flags |= 0x01; - } else { - WmHashItem *hi = WmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - /* Append this HashItem to the list */ - WmHashItem *thi = &ctx->hash1[idx8]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - } else { - uint16_t patlen = ctx->shiftlen; - - if (ctx->hash_size == HASH9_SIZE) - idx = HASH9(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else if (ctx->hash_size == HASH12_SIZE) - idx = HASH12(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else if (ctx->hash_size == HASH14_SIZE) - idx = HASH14(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else if (ctx->hash_size == HASH15_SIZE) - idx = HASH15(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - else - idx = HASH16(ctx->parray[i]->ci[patlen-1], ctx->parray[i]->ci[patlen-2]); - - if (ctx->hash[idx] == NULL) { - WmHashItem *hi = WmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - ctx->pminlen[idx] = ctx->parray[i]->len; - - ctx->hash[idx] = hi; - } else { - WmHashItem *hi = WmAllocHashItem(mpm_ctx); - if (hi == NULL) - goto error; - hi->idx = i; - hi->flags |= 0x01; - - if (ctx->parray[i]->len < ctx->pminlen[idx]) - ctx->pminlen[idx] = ctx->parray[i]->len; - - /* Append this HashItem to the list */ - WmHashItem *thi = ctx->hash[idx]; - while (thi->nxt) thi = thi->nxt; - thi->nxt = hi; - } - } - } - - /* alloc the bloom array */ - ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); - if (ctx->bloom == NULL) - goto error; - memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - WmHashItem *hi = ctx->hash[h]; - if (hi == NULL) - continue; - - ctx->bloom[h] = BloomFilterInit(wm_bloom_size, 2, WmBloomHash); - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[h]); - - if (ctx->pminlen[h] > 8) - ctx->pminlen[h] = 8; - - WmHashItem *thi = hi; - do { - BloomFilterAdd(ctx->bloom[h], ctx->parray[thi->idx]->ci, ctx->pminlen[h]); - thi = thi->nxt; - } while (thi != NULL); - } - return; -error: - return; -} -static void WmSearchPrepareShiftTable(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - - uint16_t shift = 0, k = 0, idx = 0; - uint32_t i = 0; - - uint16_t smallest = mpm_ctx->minlen; - if (smallest > 255) smallest = 255; - if (smallest < 2) smallest = 2; - - ctx->shiftlen = smallest; - - ctx->shifttable = SCMalloc(sizeof(uint16_t) * ctx->hash_size); - if (ctx->shifttable == NULL) - return; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(uint16_t) * ctx->hash_size); - - /* default shift table is set to minimal shift */ - for (i = 0; i < ctx->hash_size; i++) - ctx->shifttable[i] = ctx->shiftlen; - - for (i = 0; i < mpm_ctx->pattern_cnt; i++) - { - /* ignore one byte patterns */ - if (ctx->parray[i]->len == 1) - continue; - - /* add the first character of the pattern preceeded by - * every possible other character. */ - for (k = 0; k < 256; k++) { - shift = ctx->shiftlen - 1; - if (shift > 255) shift = 255; - - if (ctx->hash_size == HASH9_SIZE) { - idx = HASH9(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH9 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH12_SIZE) { - idx = HASH12(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH12 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH14_SIZE) { - idx = HASH14(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH14 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH15_SIZE) { - idx = HASH15(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } else { - idx = HASH16(ctx->parray[i]->ci[0], (uint8_t)k); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } - if (shift < ctx->shifttable[idx]) { - ctx->shifttable[idx] = shift; - } - } - - for (k = 0; k < ctx->shiftlen-1; k++) - { - shift = (ctx->shiftlen - 2 - k); - if (shift > 255) shift = 255; - - if (ctx->hash_size == HASH9_SIZE) { - idx = HASH9(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH9 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH12_SIZE) { - idx = HASH12(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH12 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH14_SIZE) { - idx = HASH14(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH14 idx %" PRIu32 "\n", idx); - } else if (ctx->hash_size == HASH15_SIZE) { - idx = HASH15(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } else { - idx = HASH16(ctx->parray[i]->ci[k+1], ctx->parray[i]->ci[k]); - //printf("HASH15 idx %" PRIu32 "\n", idx); - } - if (shift < ctx->shifttable[idx]) { - ctx->shifttable[idx] = shift; - } - //printf("WmPrepareShiftTable: i %" PRIu32 ", k %" PRIu32 ", idx %" PRIu32 ", shift set to %" PRIu32 ": \"%c%c\"\n", - // i, k, idx, shift, ctx->parray[i]->ci[k], ctx->parray[i]->ci[k+1]); - } - } -} - -int WmPreparePatterns(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - - /* alloc the pattern array */ - ctx->parray = (WmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(WmPattern *)); - if (ctx->parray == NULL) - goto error; - memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(WmPattern *)); - //printf("mpm_ctx %p, parray %p\n", mpm_ctx,ctx->parray); - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(WmPattern *)); - - /* populate it with the patterns in the hash */ - uint32_t i = 0, p = 0; - for (i = 0; i < INIT_HASH_SIZE; i++) { - WmPattern *node = ctx->init_hash[i], *nnode = NULL; - for ( ; node != NULL; ) { - nnode = node->next; - node->next = NULL; - - ctx->parray[p] = node; - - p++; - node = nnode; - } - } - /* we no longer need the hash, so free it's memory */ - SCFree(ctx->init_hash); - ctx->init_hash = NULL; - - /* TODO VJ these values are chosen pretty much randomly, so - * we should do some performance testing - * */ - - if (ctx->hash_size == 0) { - if (mpm_ctx->pattern_cnt < 50) { - ctx->hash_size = HASH9_SIZE; - } else if(mpm_ctx->pattern_cnt < 300) { - ctx->hash_size = HASH12_SIZE; - } else if(mpm_ctx->pattern_cnt < 1200) { - ctx->hash_size = HASH14_SIZE; - } else if(mpm_ctx->pattern_cnt < 2400) { - ctx->hash_size = HASH15_SIZE; - } else { - ctx->hash_size = HASH16_SIZE; - } - } - - WmSearchPrepareShiftTable(mpm_ctx); - WmSearchPrepareHash(mpm_ctx); - - if (ctx->hash_size == HASH9_SIZE) { - ctx->MBSearch = WmSearch2Hash9; - ctx->Search = WmSearch2Hash9; - } else if (ctx->hash_size == HASH12_SIZE) { - ctx->MBSearch = WmSearch2Hash12; - ctx->Search = WmSearch2Hash12; - } else if (ctx->hash_size == HASH14_SIZE) { - ctx->MBSearch = WmSearch2Hash14; - ctx->Search = WmSearch2Hash14; - } else if (ctx->hash_size == HASH15_SIZE) { - ctx->MBSearch = WmSearch2Hash15; - ctx->Search = WmSearch2Hash15; - } else { - ctx->MBSearch = WmSearch2Hash16; - ctx->Search = WmSearch2Hash16; - } - - if (mpm_ctx->minlen == 1) { - ctx->Search = WmSearch1; - } - - return 0; -error: - return -1; -} - -void WmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) -{ -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; - - printf("Shift 0: %" PRIu32 "\n", tctx->stat_shift_null); - printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); - printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); - printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); - printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); -#endif /* WUMANBER_COUNTERS */ -} - -static inline int -memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) -{ - size_t i; - - /* check backwards because we already tested the first - * 2 to 4 chars. This way we are more likely to detect - * a miss and thus speed up a little... */ - for (i = n - 1; i; i--) { - if (wm_tolower(*(s2+i)) != s1[i]) - return 1; - } - - return 0; -} - -inline uint32_t WmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - return ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen); -} - -/* SCAN FUNCTIONS */ -uint32_t WmSearch2Hash9(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf(" (sl %" PRIu32 ")\n", sl); - - buf+=(sl-1); - - while (buf <= bufend) { - h = HASH9(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("%p %" PRIu32 " search: h %" PRIu32 ", shift %" PRIu32 "\n", buf, buf - bufmin, h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - //printf("cnt %" PRIu32 "\n", cnt); - return cnt; -} - -uint32_t WmSearch2Hash12(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH12(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch2Hash14(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH14(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch2Hash15(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH15(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - //printf("CI Exact match: "); prt(p->ci, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - //printf("CS Exact match: "); prt(p->cs, p->len); printf("\n"); - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch2Hash16(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; -#ifdef WUMANBER_COUNTERS - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx->ctx; -#endif /* WUMANBER_COUNTERS */ - uint32_t cnt = 0; - uint8_t *bufend = buf + buflen - 1; - uint16_t sl = ctx->shiftlen; - uint16_t h; - uint8_t shift; - WmHashItem *thi, *hi; - WmPattern *p; - uint16_t prefixci_buf; - uint16_t prefixcs_buf; - - if (buflen == 0) - return 0; - - //printf("BUF(%" PRIu32 ") ", buflen); prt(buf,buflen); printf("\n"); - - buf+=(sl-1); - //buf++; - - while (buf <= bufend) { - //h = (wm_tolower(*buf)<<8)+(wm_tolower(*(buf-1))); - h = HASH16(wm_tolower(*buf),(wm_tolower(*(buf-1)))); - shift = ctx->shifttable[h]; - //printf("search: h %" PRIu32 ", shift %" PRIu32 "\n", h, shift); - - if (shift == 0) { - COUNT(tctx->stat_shift_null++); - /* get our hash item */ - hi = ctx->hash[h]; - //printf("search: hi %p\n", hi); - if (hi != NULL) { - /* get our patterns from the hash */ - if (ctx->bloom[h] != NULL) { - COUNT(tctx->stat_pminlen_calls++); - COUNT(tctx->stat_pminlen_total+=ctx->pminlen[h]); - - if ((bufend - (buf-sl)) < ctx->pminlen[h]) { - goto skip_loop; - } else { - COUNT(tctx->stat_bloom_calls++); - - if (BloomFilterTest(ctx->bloom[h], buf-sl+1, ctx->pminlen[h]) == 0) { - COUNT(tctx->stat_bloom_hits++); - goto skip_loop; - } - } - } - - prefixci_buf = (uint16_t)(wm_tolower(*(buf-sl+1)) + wm_tolower(*(buf-sl+2))); - prefixcs_buf = (uint16_t)(*(buf-sl+1) + *(buf-sl+2)); - //printf("WmSearch2: prefixci_buf %" PRIu32 ", prefixcs_buf %" PRIu32 "\n", prefixci_buf, prefixcs_buf); - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - //printf("WmSearch2: p->prefix_ci %" PRIu32 ", p->prefix_cs %" PRIu32 "\n", - // p->prefix_ci, p->prefix_cs); - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (p->prefix_ci != prefixci_buf || p->len > (bufend-(buf-sl))) - continue; - - if (memcmp_lowercase(p->ci, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } else { - if (p->prefix_cs != prefixcs_buf || p->len > (bufend-(buf-sl))) - continue; - if (memcmp(p->cs, buf-sl+1, p->len) == 0) { - COUNT(tctx->stat_loop_match++); - - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } else { - COUNT(tctx->stat_loop_no_match++); - } - } - } - } -skip_loop: - shift = 1; - } else { - COUNT(tctx->stat_total_shift += shift); - COUNT(tctx->stat_num_shift++); - } - buf += shift; - } - - return cnt; -} - -uint32_t WmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - uint8_t *bufmin = buf; - uint8_t *bufend = buf + buflen - 1; - uint32_t cnt = 0; - WmPattern *p; - WmHashItem *thi, *hi; - - if (buflen == 0) - return 0; - - //printf("BUF "); prt(buf,buflen); printf("\n"); - - if (mpm_ctx->minlen == 1) { - while (buf <= bufend) { - uint8_t h = wm_tolower(*buf); - hi = &ctx->hash1[h]; - - if (hi->flags & 0x01) { - for (thi = hi; thi != NULL; thi = thi->nxt) { - p = ctx->parray[thi->idx]; - - if (p->len != 1) - continue; - - if (p->flags & MPM_PATTERN_FLAG_NOCASE) { - if (wm_tolower(*buf) == p->ci[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } else { - if (*buf == p->cs[0]) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, p->id); - } - } - } - } - buf += 1; - } - } - //printf("WmSearch1: after 1byte cnt %" PRIu32 "\n", cnt); - if (mpm_ctx->maxlen > 1) { - /* Pass bufmin on because buf no longer points to the - * start of the buffer. */ - cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); - //printf("WmSearch1: after 2+byte cnt %" PRIu32 "\n", cnt); - } - return cnt; -} - -/** - * \brief Function to get the user defined values for wumanber algorithm from - * the config file 'suricata.yaml' - */ -void WmGetConfig() -{ - ConfNode *wm_conf; - const char *hash_val = NULL; - const char *bloom_val = NULL; - - /* init defaults */ - wm_hash_size = HASHSIZE_LOW; - wm_bloom_size = BLOOMSIZE_MEDIUM; - - ConfNode *pm = ConfGetNode("pattern-matcher"); - - if (pm != NULL) { - - TAILQ_FOREACH(wm_conf, &pm->head, next) { - if (strncmp(wm_conf->val, "wumanber", 8) == 0) { - hash_val = ConfNodeLookupChildValue(wm_conf->head.tqh_first, - "hash_size"); - bloom_val = ConfNodeLookupChildValue(wm_conf->head.tqh_first, - "bf_size"); - - if (hash_val != NULL) - wm_hash_size = MpmGetHashSize(hash_val); - - if (bloom_val != NULL) - wm_bloom_size = MpmGetBloomSize(bloom_val); - - SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", - wm_hash_size, wm_bloom_size); - } - } - } -} - -void WmInitCtx (MpmCtx *mpm_ctx) -{ - SCLogDebug("mpm_ctx %p", mpm_ctx); - - mpm_ctx->ctx = SCMalloc(sizeof(WmCtx)); - if (mpm_ctx->ctx == NULL) - return; - memset(mpm_ctx->ctx, 0, sizeof(WmCtx)); - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += sizeof(WmCtx); - - /* initialize the hash we use to speed up pattern insertions */ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - ctx->init_hash = SCMalloc(sizeof(WmPattern *) * INIT_HASH_SIZE); - if (ctx->init_hash == NULL) - return; - - memset(ctx->init_hash, 0, sizeof(WmPattern *) * INIT_HASH_SIZE); - - /* Initialize the defaults value from the config file. The given check make - sure that we query config file only once for config values */ - if (wm_hash_size == 0) - WmGetConfig(); - -} - -void WmDestroyCtx(MpmCtx *mpm_ctx) -{ - WmCtx *ctx = (WmCtx *)mpm_ctx->ctx; - if (ctx == NULL) - return; - - if (ctx->init_hash) { - SCFree(ctx->init_hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(WmPattern *)); - } - - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - WmFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(WmPattern)); - } - - if (ctx->bloom) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->bloom[h] == NULL) - continue; - - mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); - mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); - - BloomFilterFree(ctx->bloom[h]); - } - - SCFree(ctx->bloom); - - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); - } - - if (ctx->hash) { - uint32_t h; - for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) - continue; - - WmHashFree(mpm_ctx, ctx->hash[h]); - } - - SCFree(ctx->hash); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(WmHashItem) * ctx->hash_size); - } - - if (ctx->shifttable) { - SCFree(ctx->shifttable); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint16_t) * ctx->hash_size); - } - - if (ctx->pminlen) { - SCFree(ctx->pminlen); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); - } - - SCFree(mpm_ctx->ctx); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(WmCtx); -} - -void WmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) -{ - memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); - -#ifdef WUMANBER_COUNTERS - mpm_thread_ctx->ctx = SCMalloc(sizeof(WmThreadCtx)); - if (mpm_thread_ctx->ctx == NULL) - return; - - memset(mpm_thread_ctx->ctx, 0, sizeof(WmThreadCtx)); - - mpm_thread_ctx->memory_cnt++; - mpm_thread_ctx->memory_size += sizeof(WmThreadCtx); -#endif -} - -void WmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) -{ - WmThreadCtx *ctx = (WmThreadCtx *)mpm_thread_ctx->ctx; - if (ctx != NULL) { /* size can be 0 when optimized */ - mpm_thread_ctx->memory_cnt--; - mpm_thread_ctx->memory_size -= sizeof(WmThreadCtx); - SCFree(mpm_thread_ctx->ctx); - } -} - -void MpmWuManberRegister (void) -{ - mpm_table[MPM_WUMANBER].name = "wumanber"; - mpm_table[MPM_WUMANBER].max_pattern_length = 0; - mpm_table[MPM_WUMANBER].InitCtx = WmInitCtx; - mpm_table[MPM_WUMANBER].InitThreadCtx = WmThreadInitCtx; - mpm_table[MPM_WUMANBER].DestroyCtx = WmDestroyCtx; - mpm_table[MPM_WUMANBER].DestroyThreadCtx = WmThreadDestroyCtx; - mpm_table[MPM_WUMANBER].AddPattern = WmAddPatternCS; - mpm_table[MPM_WUMANBER].AddPatternNocase = WmAddPatternCI; - mpm_table[MPM_WUMANBER].Prepare = WmPreparePatterns; - mpm_table[MPM_WUMANBER].Search = WmSearch; - mpm_table[MPM_WUMANBER].Cleanup = NULL; - mpm_table[MPM_WUMANBER].PrintCtx = WmPrintInfo; - mpm_table[MPM_WUMANBER].PrintThreadCtx = WmPrintSearchStats; - mpm_table[MPM_WUMANBER].RegisterUnittests = WmRegisterTests; - - /* create table for O(1) lowercase conversion lookup */ - int c = 0; - for ( ; c < 256; c++) { - if (c >= 'A' && c <= 'Z') - lowercasetable[c] = (c + ('a' - 'A')); - else - lowercasetable[c] = c; - } -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS -int WmTestInitCtx01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - WmInitCtx(&mpm_ctx); - - if (mpm_ctx.ctx != NULL) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitCtx02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - WmInitCtx(&mpm_ctx); - - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->parray == NULL) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitCtx03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - if (mpm_table[MPM_WUMANBER].Search == WmSearch) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestThreadInitCtx01 (void) -{ -#ifdef WUMANBER_COUNTERS - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - if (mpm_thread_ctx.memory_cnt == 2) - result = 1; - else - printf("mpm_thread_ctx.memory_cnt %"PRIu32", expected 2: ", mpm_thread_ctx.memory_cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -#else - return 1; -#endif -} - -int WmTestThreadInitCtx02 (void) -{ -#ifdef WUMANBER_COUNTERS - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - WmThreadCtx *tctx = (WmThreadCtx *)mpm_thread_ctx.ctx; - - if (tctx->search_stat_shift_null == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); -#else - int result = 1; -#endif - return result; -} - -int WmTestInitAddPattern01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - int ret = MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - if (ret == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - if (ctx->init_hash != NULL) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); - if (pat != NULL) { - if (pat->len == 4) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, MPM_PATTERN_FLAG_NOCASE); - if (pat != NULL) { - if (pat->flags & MPM_PATTERN_FLAG_NOCASE) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); - if (pat != NULL) { - if (!(pat->flags & MPM_PATTERN_FLAG_NOCASE)) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestInitAddPattern06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1234, 0, 0); - WmPattern *pat = WmInitHashLookup(ctx, (uint8_t *)"abcd", 4, 0); - if (pat != NULL) { - if (memcmp(pat->cs, "abcd", 4) == 0) - result = 1; - } - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - - if (ctx->Search == WmSearch1) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shiftlen == 4) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shifttable[1] == 4) - result = 1; - else - printf("4 != %" PRIu32 ": ", ctx->shifttable[1]); - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - - if (ctx->Search == WmSearch1) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shiftlen == 4) - result = 1; - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestPrepare06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - if (ctx->shifttable[1] == 4) - result = 1; - else - printf("4 != %" PRIu32 ": ", ctx->shifttable[1]); - - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH12_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH14_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH15_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch01Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //mpm_ctx.PrintCtx(&mpm_ctx); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); - - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch02 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abce", 4); - - if (cnt == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch03 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - if (cnt == 1) - result = 1; - else - printf("1 != %" PRIu32 " ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch04 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch05 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"efgh", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch06 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"eFgH", 4, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdEfGh", 8); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch07 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"eFgH", 4, 0, 0, 1, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdEfGh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch08 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch09 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); - - if (cnt == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch10 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bc", 2, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"gh", 2, 0, 0, 1, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch11 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"d", 1, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"h", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 3) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"d", 1, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - else - printf("2 != %" PRIu32 ": ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch13 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"h", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 3) - result = 1; - else - printf("3 != %" PRIu32 ": ", cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 0, 0); - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - if (cnt == 2) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -/** \todo VJ disabled because it tests the old match storage */ -#if 0 -int WmTestSearch15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 1, 1, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 1, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 1, 1, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - uint32_t len = mpm_thread_ctx.match[1].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 1, 1, 0, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"de",2, 0, 0, 1, 1, 1, 0, 0); - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Z", 1, 0, 0, 1, 1, 2, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefgh", 8); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch17 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch18Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch19Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCI(&mpm_ctx, (uint8_t *)"/VideoAccessCodecInstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstaLL.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; /* force hash12 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; /* force hash14 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; /* force hash15 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch20Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/VideoAccessCodecInstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 0) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -int WmTestSearch21 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH12_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH14_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH15_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch21Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"/videoaccesscodecinstall.exe", 28, 0, 0, 0, 0, 0); - ctx->hash_size = HASH16_SIZE; /* force hash16 */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1); - //WmPrintInfo(&mpm_ctx); - ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"/videoaccesscodecinstall.exe", 28); - - uint32_t len = mpm_thread_ctx.match[0].len; - - - if (len == 1) - result = 1; - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} -#endif -static int WmTestSearch22Hash9 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH9_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash12 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH12_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash14 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH14_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash15 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH15_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} - -static int WmTestSearch22Hash16 (void) -{ - int result = 0; - MpmCtx mpm_ctx; - memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); - MpmThreadCtx mpm_thread_ctx; - MpmInitCtx(&mpm_ctx, MPM_WUMANBER); - WmCtx *ctx = (WmCtx *)mpm_ctx.ctx; - - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ - MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ - /* total matches: 135 */ - - ctx->hash_size = HASH16_SIZE; /* force hash size */ - WmPreparePatterns(&mpm_ctx); - WmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); - - - if (cnt == 135) - result = 1; - else - printf("135 != %" PRIu32 " ",cnt); - - WmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); - WmDestroyCtx(&mpm_ctx); - return result; -} -#endif /* UNITTESTS */ - -void WmRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("WmTestInitCtx01", WmTestInitCtx01, 1); - UtRegisterTest("WmTestInitCtx02", WmTestInitCtx02, 1); - UtRegisterTest("WmTestInitCtx03", WmTestInitCtx03, 1); - - UtRegisterTest("WmTestThreadInitCtx01", WmTestThreadInitCtx01, 1); - UtRegisterTest("WmTestThreadInitCtx02", WmTestThreadInitCtx02, 1); - - UtRegisterTest("WmTestInitAddPattern01", WmTestInitAddPattern01, 1); - UtRegisterTest("WmTestInitAddPattern02", WmTestInitAddPattern02, 1); - UtRegisterTest("WmTestInitAddPattern03", WmTestInitAddPattern03, 1); - UtRegisterTest("WmTestInitAddPattern04", WmTestInitAddPattern04, 1); - UtRegisterTest("WmTestInitAddPattern05", WmTestInitAddPattern05, 1); - UtRegisterTest("WmTestInitAddPattern06", WmTestInitAddPattern06, 1); - - UtRegisterTest("WmTestPrepare01", WmTestPrepare01, 1); - UtRegisterTest("WmTestPrepare02", WmTestPrepare02, 1); - UtRegisterTest("WmTestPrepare03", WmTestPrepare03, 1); - UtRegisterTest("WmTestPrepare04", WmTestPrepare01, 1); - UtRegisterTest("WmTestPrepare05", WmTestPrepare02, 1); - UtRegisterTest("WmTestPrepare06", WmTestPrepare03, 1); - - UtRegisterTest("WmTestSearch01", WmTestSearch01, 1); - UtRegisterTest("WmTestSearch01Hash12", WmTestSearch01Hash12, 1); - UtRegisterTest("WmTestSearch01Hash14", WmTestSearch01Hash14, 1); - UtRegisterTest("WmTestSearch01Hash15", WmTestSearch01Hash15, 1); - UtRegisterTest("WmTestSearch01Hash16", WmTestSearch01Hash16, 1); - - UtRegisterTest("WmTestSearch02", WmTestSearch02, 1); - UtRegisterTest("WmTestSearch03", WmTestSearch03, 1); - UtRegisterTest("WmTestSearch04", WmTestSearch04, 1); - UtRegisterTest("WmTestSearch05", WmTestSearch05, 1); - UtRegisterTest("WmTestSearch06", WmTestSearch06, 1); - UtRegisterTest("WmTestSearch07", WmTestSearch07, 1); - UtRegisterTest("WmTestSearch08", WmTestSearch08, 1); - UtRegisterTest("WmTestSearch09", WmTestSearch09, 1); - UtRegisterTest("WmTestSearch10", WmTestSearch10, 1); - UtRegisterTest("WmTestSearch11", WmTestSearch11, 1); - UtRegisterTest("WmTestSearch12", WmTestSearch12, 1); - UtRegisterTest("WmTestSearch13", WmTestSearch13, 1); - - UtRegisterTest("WmTestSearch14", WmTestSearch14, 1); -#if 0 - UtRegisterTest("WmTestSearch15", WmTestSearch15, 1); - UtRegisterTest("WmTestSearch16", WmTestSearch16, 1); - UtRegisterTest("WmTestSearch17", WmTestSearch17, 1); - - UtRegisterTest("WmTestSearch18", WmTestSearch18, 1); - UtRegisterTest("WmTestSearch18Hash12", WmTestSearch18Hash12, 1); - UtRegisterTest("WmTestSearch18Hash14", WmTestSearch18Hash14, 1); - UtRegisterTest("WmTestSearch18Hash15", WmTestSearch18Hash15, 1); - UtRegisterTest("WmTestSearch18Hash16", WmTestSearch18Hash16, 1); - - UtRegisterTest("WmTestSearch19", WmTestSearch19, 1); - UtRegisterTest("WmTestSearch19Hash12", WmTestSearch19Hash12, 1); - UtRegisterTest("WmTestSearch19Hash14", WmTestSearch19Hash14, 1); - UtRegisterTest("WmTestSearch19Hash15", WmTestSearch19Hash15, 1); - UtRegisterTest("WmTestSearch19Hash16", WmTestSearch19Hash16, 1); - - UtRegisterTest("WmTestSearch20", WmTestSearch20, 1); - UtRegisterTest("WmTestSearch20Hash12", WmTestSearch20Hash12, 1); - UtRegisterTest("WmTestSearch20Hash14", WmTestSearch20Hash14, 1); - UtRegisterTest("WmTestSearch20Hash15", WmTestSearch20Hash15, 1); - UtRegisterTest("WmTestSearch20Hash16", WmTestSearch20Hash16, 1); - - UtRegisterTest("WmTestSearch21", WmTestSearch21, 1); - UtRegisterTest("WmTestSearch21Hash12", WmTestSearch21Hash12, 1); - UtRegisterTest("WmTestSearch21Hash14", WmTestSearch21Hash14, 1); - UtRegisterTest("WmTestSearch21Hash15", WmTestSearch21Hash15, 1); - UtRegisterTest("WmTestSearch21Hash16", WmTestSearch21Hash16, 1); -#endif - UtRegisterTest("WmTestSearch22Hash9", WmTestSearch22Hash9, 1); - UtRegisterTest("WmTestSearch22Hash12", WmTestSearch22Hash12, 1); - UtRegisterTest("WmTestSearch22Hash14", WmTestSearch22Hash14, 1); - UtRegisterTest("WmTestSearch22Hash15", WmTestSearch22Hash15, 1); - UtRegisterTest("WmTestSearch22Hash16", WmTestSearch22Hash16, 1); -#endif /* UNITTESTS */ -} - diff --git a/src/util-mpm-wumanber.h b/src/util-mpm-wumanber.h deleted file mode 100644 index 3d826536c2db..000000000000 --- a/src/util-mpm-wumanber.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * 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 - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef __UTIL_MPM_WUMANBER_H__ -#define __UTIL_MPM_WUMANBER_H__ - -#include "util-mpm.h" -#include "util-bloomfilter.h" - -//#define WUMANBER_COUNTERS - -typedef struct WmPattern_ { - uint8_t *cs; /* case sensitive */ - uint8_t *ci; /* case INsensitive */ - uint16_t len; - struct WmPattern_ *next; - uint16_t prefix_ci; - uint16_t prefix_cs; - uint8_t flags; - uint32_t id; /* global pattern id */ -} WmPattern; - -typedef struct WmHashItem_ { - uint8_t flags; - uint16_t idx; - struct WmHashItem_ *nxt; -} WmHashItem; - -typedef struct WmCtx_ { - /* hash used during ctx initialization */ - WmPattern **init_hash; - - uint16_t shiftlen; - - uint32_t hash_size; - WmHashItem **hash; - BloomFilter **bloom; - uint8_t *pminlen; /* array containing the minimal length - of the patters in a hash bucket. Used - for the BloomFilter. */ - WmHashItem hash1[256]; - - /* we store our own search func ptr here for WmSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - /* we store our own multi byte search func ptr here for WmSearch1 */ - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - - /* pattern arrays */ - WmPattern **parray; - - /* only used for multibyte pattern search */ - uint16_t *shifttable; -} WmCtx; - -typedef struct WmThreadCtx_ { -#ifdef WUMANBER_COUNTERS - uint32_t stat_pminlen_calls; - uint32_t stat_pminlen_total; - uint32_t stat_bloom_calls; - uint32_t stat_bloom_hits; - uint32_t stat_shift_null; - uint32_t stat_loop_match; - uint32_t stat_loop_no_match; - uint32_t stat_num_shift; - uint32_t stat_total_shift; -#endif /* WUMANBER_COUNTERS */ -} WmThreadCtx; - -void MpmWuManberRegister(void); - -#endif /* __UTIL_MPM_WUMANBER_H__ */ - diff --git a/src/util-mpm.c b/src/util-mpm.c index df81e87a2602..92fdedd52e46 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -28,15 +28,10 @@ #include "util-debug.h" /* include pattern matchers */ -#include "util-mpm-wumanber.h" -#include "util-mpm-b2g.h" -#include "util-mpm-b3g.h" -#include "util-mpm-b2gc.h" -#include "util-mpm-b2gm.h" #include "util-mpm-ac.h" -#include "util-mpm-ac-gfbs.h" #include "util-mpm-ac-bs.h" #include "util-mpm-ac-tile.h" +#include "util-mpm-hs.h" #include "util-hashlist.h" #include "detect-engine.h" @@ -50,6 +45,10 @@ #include "util-cuda-handlers.h" #include "detect-engine-mpm.h" #endif +#include "util-memcpy.h" +#ifdef BUILD_HYPERSCAN +#include "hs.h" +#endif /** * \brief Register a new Mpm Context. @@ -58,7 +57,7 @@ * * \retval id Return the id created for the new MpmCtx profile. */ -int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name, uint8_t flags) +int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *name) { void *ptmp; /* the very first entry */ @@ -76,11 +75,7 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam exit(EXIT_FAILURE); } - item[0].name = SCStrdup(name); - if (item[0].name == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } + item[0].name = name; /* toserver */ item[0].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); @@ -104,9 +99,6 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam * the array */ item[0].id = 0; - /* store the flag */ - item[0].flags = flags; - /* store the newly created item */ de_ctx->mpm_ctx_factory_container->items = item; de_ctx->mpm_ctx_factory_container->no_of_items++; @@ -137,7 +129,6 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam memset(items[i].mpm_ctx_tc, 0, sizeof(MpmCtx)); items[i].mpm_ctx_tc->global = 1; } - items[i].flags = flags; return items[i].id; } } @@ -156,11 +147,7 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam de_ctx->mpm_ctx_factory_container->items = items; MpmCtxFactoryItem *new_item = &items[de_ctx->mpm_ctx_factory_container->no_of_items]; - new_item[0].name = SCStrdup(name); - if (new_item[0].name == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); - exit(EXIT_FAILURE); - } + new_item[0].name = name; /* toserver */ new_item[0].mpm_ctx_ts = SCMalloc(sizeof(MpmCtx)); @@ -181,7 +168,6 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam new_item[0].mpm_ctx_tc->global = 1; new_item[0].id = de_ctx->mpm_ctx_factory_container->no_of_items; - new_item[0].flags = flags; de_ctx->mpm_ctx_factory_container->no_of_items++; /* the newly created id */ @@ -189,7 +175,7 @@ int32_t MpmFactoryRegisterMpmCtxProfile(DetectEngineCtx *de_ctx, const char *nam } } -int32_t MpmFactoryIsMpmCtxAvailable(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) +int32_t MpmFactoryIsMpmCtxAvailable(const DetectEngineCtx *de_ctx, const MpmCtx *mpm_ctx) { if (mpm_ctx == NULL) return 0; @@ -208,7 +194,7 @@ int32_t MpmFactoryIsMpmCtxAvailable(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) } } -MpmCtx *MpmFactoryGetMpmCtxForProfile(DetectEngineCtx *de_ctx, int32_t id, int direction) +MpmCtx *MpmFactoryGetMpmCtxForProfile(const DetectEngineCtx *de_ctx, int32_t id, int direction) { if (id == MPM_CTX_FACTORY_UNIQUE_CONTEXT) { MpmCtx *mpm_ctx = SCMalloc(sizeof(MpmCtx)); @@ -231,7 +217,7 @@ MpmCtx *MpmFactoryGetMpmCtxForProfile(DetectEngineCtx *de_ctx, int32_t id, int d } } -void MpmFactoryReClaimMpmCtx(DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) +void MpmFactoryReClaimMpmCtx(const DetectEngineCtx *de_ctx, MpmCtx *mpm_ctx) { if (mpm_ctx == NULL) return; @@ -253,8 +239,6 @@ void MpmFactoryDeRegisterAllMpmCtxProfiles(DetectEngineCtx *de_ctx) int i = 0; MpmCtxFactoryItem *items = de_ctx->mpm_ctx_factory_container->items; for (i = 0; i < de_ctx->mpm_ctx_factory_container->no_of_items; i++) { - if (items[i].name != NULL) - SCFree(items[i].name); if (items[i].mpm_ctx_ts != NULL) { if (items[i].mpm_ctx_ts->mpm_type != MPM_NOTSET) mpm_table[items[i].mpm_ctx_ts->mpm_type].DestroyCtx(items[i].mpm_ctx_ts); @@ -410,265 +394,362 @@ void MpmCudaEnvironmentSetup() #endif -/** - * \brief Setup a pmq - * - * \param pmq Pattern matcher queue to be initialized - * \param maxid Max sig id to be matched on - * \param patmaxid Max pattern id to be matched on - * - * \retval -1 error - * \retval 0 ok - */ -int PmqSetup(PatternMatcherQueue *pmq, uint32_t patmaxid) +void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher) { - SCEnter(); - SCLogDebug("patmaxid %u", patmaxid); - - if (pmq == NULL) { - SCReturnInt(-1); - } - - memset(pmq, 0, sizeof(PatternMatcherQueue)); + mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx); +} - if (patmaxid > 0) { - pmq->pattern_id_array_size = patmaxid * sizeof(uint32_t); +void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher) +{ + mpm_ctx->mpm_type = matcher; + mpm_table[matcher].InitCtx(mpm_ctx); +} - pmq->pattern_id_array = SCMalloc(pmq->pattern_id_array_size); - if (pmq->pattern_id_array == NULL) { - SCReturnInt(-1); - } - memset(pmq->pattern_id_array, 0, pmq->pattern_id_array_size); - pmq->pattern_id_array_cnt = 0; +/* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". + * If Hyperscan is available, use it. Otherwise, use AC. */ +#ifdef BUILD_HYPERSCAN +# define DEFAULT_MPM MPM_HS +# ifdef __tile__ +# define DEFAULT_MPM_AC MPM_AC_TILE +# else +# define DEFAULT_MPM_AC MPM_AC +# endif +#else +# ifdef __tile__ +# define DEFAULT_MPM MPM_AC_TILE +# else +# define DEFAULT_MPM MPM_AC +# endif +#endif - /* lookup bitarray */ - pmq->pattern_id_bitarray_size = (patmaxid / 8) + 1; +void MpmTableSetup(void) +{ + memset(mpm_table, 0, sizeof(mpm_table)); + mpm_default_matcher = DEFAULT_MPM; - pmq->pattern_id_bitarray = SCMalloc(pmq->pattern_id_bitarray_size); - if (pmq->pattern_id_bitarray == NULL) { - SCReturnInt(-1); + MpmACRegister(); + MpmACBSRegister(); + MpmACTileRegister(); +#ifdef BUILD_HYPERSCAN + #ifdef HAVE_HS_VALID_PLATFORM + /* Enable runtime check for SSSE3. Do not use Hyperscan MPM matcher if + * check is not successful. */ + if (hs_valid_platform() != HS_SUCCESS) { + SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " + "MPM"); + /* Fall back to best Aho-Corasick variant. */ + mpm_default_matcher = DEFAULT_MPM_AC; + } else { + MpmHSRegister(); } - memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); + #else + MpmHSRegister(); + #endif /* HAVE_HS_VALID_PLATFORM */ +#endif /* BUILD_HYPERSCAN */ +#ifdef __SC_CUDA_SUPPORT__ + MpmACCudaRegister(); +#endif /* __SC_CUDA_SUPPORT__ */ +} - SCLogDebug("pmq->pattern_id_array %p, pmq->pattern_id_bitarray %p", - pmq->pattern_id_array, pmq->pattern_id_bitarray); - } +int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, + uint32_t pid, SigIntId sid, uint8_t flags) +{ + return mpm_table[mpm_ctx->mpm_type].AddPattern(mpm_ctx, pat, patlen, + offset, depth, + pid, sid, flags); +} - SCReturnInt(0); +int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, + uint32_t pid, SigIntId sid, uint8_t flags) +{ + return mpm_table[mpm_ctx->mpm_type].AddPatternNocase(mpm_ctx, pat, patlen, + offset, depth, + pid, sid, flags); } -/** \brief Verify and store a match - * - * used at search runtime + +/** + * \internal + * \brief Creates a hash of the pattern. We use it for the hashing process + * during the initial pattern insertion time, to cull duplicate sigs. * - * \param thread_ctx mpm thread ctx - * \param pmq storage for match results - * \param list end match to check against (entire list will be checked) - * \param offset match offset in the buffer - * \param patlen length of the pattern we're checking + * \param pat Pointer to the pattern. + * \param patlen Pattern length. * - * \retval 0 no match after all - * \retval 1 (new) match + * \retval hash A 32 bit unsigned hash. */ -int -MpmVerifyMatch(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, uint32_t patid) +static inline uint32_t MpmInitHashRaw(uint8_t *pat, uint16_t patlen) { - SCEnter(); - - /* Handle pattern id storage */ - if (pmq != NULL && pmq->pattern_id_bitarray != NULL) { - SCLogDebug("using pattern id arrays, storing %"PRIu32, patid); - - if (!(pmq->pattern_id_bitarray[(patid / 8)] & (1<<(patid % 8)))) { - /* flag this pattern id as being added now */ - pmq->pattern_id_bitarray[(patid / 8)] |= (1<<(patid % 8)); - /* append the pattern_id to the array with matches */ - pmq->pattern_id_array[pmq->pattern_id_array_cnt] = patid; - pmq->pattern_id_array_cnt++; - SCLogDebug("pattern_id_array_cnt %u", pmq->pattern_id_array_cnt); - } - } + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; - SCReturnInt(1); + return (hash % MPM_INIT_HASH_SIZE); } /** - * \brief Merge two pmq's bitarrays + * \internal + * \brief Looks up a pattern. We use it for the hashing process during the + * the initial pattern insertion time, to cull duplicate sigs. + * + * \param ctx Pointer to the AC ctx. + * \param pat Pointer to the pattern. + * \param patlen Pattern length. + * \param flags Flags. We don't need this. * - * \param src source pmq - * \param dst destination pmq to merge into + * \retval hash A 32 bit unsigned hash. */ -void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst) +static inline MpmPattern *MpmInitHashLookup(MpmCtx *ctx, uint8_t *pat, + uint16_t patlen, char flags, + uint32_t pid) { - uint32_t u; + uint32_t hash = MpmInitHashRaw(pat, patlen); - if (src->pattern_id_array_cnt == 0) - return; + if (ctx->init_hash == NULL) { + return NULL; + } - for (u = 0; u < src->pattern_id_bitarray_size && u < dst->pattern_id_bitarray_size; u++) { - dst->pattern_id_bitarray[u] |= src->pattern_id_bitarray[u]; + MpmPattern *t = ctx->init_hash[hash]; + for ( ; t != NULL; t = t->next) { + if (!(flags & MPM_PATTERN_CTX_OWNS_ID)) { + if (t->id == pid) + return t; + } else { + if (t->len == patlen && + memcmp(pat, t->original_pat, patlen) == 0 && + t->flags == flags) + { + return t; + } + } } - /** \todo now set merged flag? */ + return NULL; } -/** \brief Reset a Pmq for reusage. Meant to be called after a single search. - * \param pmq Pattern matcher to be reset. - * \todo memset is expensive, but we need it as we merge pmq's. We might use - * a flag so we can clear pmq's the old way if we can. +/** + * \internal + * \brief Allocs a new pattern instance. + * + * \param mpm_ctx Pointer to the mpm context. + * + * \retval p Pointer to the newly created pattern. */ -void PmqReset(PatternMatcherQueue *pmq) +static inline MpmPattern *MpmAllocPattern(MpmCtx *mpm_ctx) { - if (pmq == NULL) - return; - - memset(pmq->pattern_id_bitarray, 0, pmq->pattern_id_bitarray_size); - //memset(pmq->pattern_id_array, 0, pmq->pattern_id_array_size); - pmq->pattern_id_array_cnt = 0; -/* - uint32_t u; - for (u = 0; u < pmq->pattern_id_array_cnt; u++) { - pmq->pattern_id_bitarray[(pmq->pattern_id_array[u] / 8)] &= ~(1<<(pmq->pattern_id_array[u] % 8)); + MpmPattern *p = SCMalloc(sizeof(MpmPattern)); + if (unlikely(p == NULL)) { + exit(EXIT_FAILURE); } - pmq->pattern_id_array_cnt = 0; -*/ + memset(p, 0, sizeof(MpmPattern)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(MpmPattern); + + return p; } -/** \brief Cleanup a Pmq - * \param pmq Pattern matcher queue to be cleaned up. - */ -void PmqCleanup(PatternMatcherQueue *pmq) +/** + * \internal + * \brief Used to free MpmPattern instances. + * + * \param mpm_ctx Pointer to the mpm context. + * \param p Pointer to the MpmPattern instance to be freed. + */ +void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p) { - if (pmq == NULL) - return; + if (p != NULL && p->cs != NULL && p->cs != p->ci) { + SCFree(p->cs); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } - if (pmq->pattern_id_array != NULL) { - SCFree(pmq->pattern_id_array); - pmq->pattern_id_array = NULL; + if (p != NULL && p->ci != NULL) { + SCFree(p->ci); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; } - if (pmq->pattern_id_bitarray != NULL) { - SCFree(pmq->pattern_id_bitarray); - pmq->pattern_id_bitarray = NULL; + if (p != NULL && p->original_pat != NULL) { + SCFree(p->original_pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; } - pmq->pattern_id_array_cnt = 0; + if (p != NULL) { + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(MpmPattern); + } + return; } -/** \brief Cleanup and free a Pmq - * \param pmq Pattern matcher queue to be free'd. - */ -void PmqFree(PatternMatcherQueue *pmq) +static inline uint32_t MpmInitHash(MpmPattern *p) { - if (pmq == NULL) - return; + uint32_t hash = p->len * p->original_pat[0]; + if (p->len > 1) + hash += p->original_pat[1]; - PmqCleanup(pmq); + return (hash % MPM_INIT_HASH_SIZE); } -void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher, uint32_t max_id) +static inline int MpmInitHashAdd(MpmCtx *ctx, MpmPattern *p) { - mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx, max_id); -} + uint32_t hash = MpmInitHash(p); -void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher) -{ - mpm_ctx->mpm_type = matcher; - mpm_table[matcher].InitCtx(mpm_ctx); -} + if (ctx->init_hash == NULL) { + return 0; + } -void MpmTableSetup(void) -{ - memset(mpm_table, 0, sizeof(mpm_table)); + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } - MpmWuManberRegister(); - MpmB2gRegister(); - MpmB3gRegister(); - MpmB2gcRegister(); - MpmB2gmRegister(); - MpmACRegister(); - MpmACBSRegister(); - MpmACGfbsRegister(); - MpmACTileRegister(); -#ifdef __SC_CUDA_SUPPORT__ - MpmACCudaRegister(); -#endif /* __SC_CUDA_SUPPORT__ */ -} + MpmPattern *tt = NULL; + MpmPattern *t = ctx->init_hash[hash]; -/** \brief Function to return the default hash size for the mpm algorithm, - * which has been defined by the user in the config file - * - * \param conf_val pointer to the string value of hash size - * \retval hash_value returns the hash value as defined by user, otherwise - * default low size value - */ -uint32_t MpmGetHashSize(const char *conf_val) -{ - SCEnter(); - uint32_t hash_value = HASHSIZE_LOW; - - if(strcmp(conf_val, "lowest") == 0) { - hash_value = HASHSIZE_LOWEST; - } else if(strcmp(conf_val, "low") == 0) { - hash_value = HASHSIZE_LOW; - } else if(strcmp(conf_val, "medium") == 0) { - hash_value = HASHSIZE_MEDIUM; - } else if(strcmp(conf_val, "high") == 0) { - hash_value = HASHSIZE_HIGH; - /* "highest" is supported in 1.0 to 1.0.2, so we keep supporting - * it for backwards compatibility */ - } else if(strcmp(conf_val, "highest") == 0) { - hash_value = HASHSIZE_HIGHER; - } else if(strcmp(conf_val, "higher") == 0) { - hash_value = HASHSIZE_HIGHER; - } else if(strcmp(conf_val, "max") == 0) { - hash_value = HASHSIZE_MAX; - } + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; - SCReturnInt(hash_value); + return 0; } -/** \brief Function to return the default bloomfilter size for the mpm algorithm, - * which has been defined by the user in the config file +/** + * \internal + * \brief Add a pattern to the mpm-ac context. + * + * \param mpm_ctx Mpm context. + * \param pat Pointer to the pattern. + * \param patlen Length of the pattern. + * \param pid Pattern id + * \param sid Signature id (internal id). + * \param flags Pattern's MPM_PATTERN_* flags. * - * \param conf_val pointer to the string value of bloom filter size - * \retval bloom_value returns the bloom filter value as defined by user, - * otherwise default medium size value + * \retval 0 On success. + * \retval -1 On failure. */ -uint32_t MpmGetBloomSize(const char *conf_val) +int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags) { - SCEnter(); - uint32_t bloom_value = BLOOMSIZE_MEDIUM; - - if(strncmp(conf_val, "low", 3) == 0) { - bloom_value = BLOOMSIZE_LOW; - } else if(strncmp(conf_val, "medium", 6) == 0) { - bloom_value = BLOOMSIZE_MEDIUM; - } else if(strncmp(conf_val, "high", 4) == 0) { - bloom_value = BLOOMSIZE_HIGH; + SCLogDebug("Adding pattern for ctx %p, patlen %"PRIu16" and pid %" PRIu32, + mpm_ctx, patlen, pid); + + if (patlen == 0) { + SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0"); + return 0; } - SCReturnInt(bloom_value); -} + if (flags & MPM_PATTERN_CTX_OWNS_ID) + pid = UINT_MAX; + + /* check if we have already inserted this pattern */ + MpmPattern *p = MpmInitHashLookup(mpm_ctx, pat, patlen, flags, pid); + if (p == NULL) { + SCLogDebug("Allocing new pattern"); + + /* p will never be NULL */ + p = MpmAllocPattern(mpm_ctx); + + p->len = patlen; + p->flags = flags; + if (flags & MPM_PATTERN_CTX_OWNS_ID) + p->id = mpm_ctx->max_pat_id++; + else + p->id = pid; + + p->original_pat = SCMalloc(patlen); + if (p->original_pat == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->original_pat, pat, patlen); + + p->ci = SCMalloc(patlen); + if (p->ci == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy_tolower(p->ci, pat, patlen); + + /* setup the case sensitive part of the pattern */ + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + /* nocase means no difference between cs and ci */ + p->cs = p->ci; + } else { + if (memcmp(p->ci, pat, p->len) == 0) { + /* no diff between cs and ci: pat is lowercase */ + p->cs = p->ci; + } else { + p->cs = SCMalloc(patlen); + if (p->cs == NULL) + goto error; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + memcpy(p->cs, pat, patlen); + } + } -int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags) -{ - return mpm_table[mpm_ctx->mpm_type].AddPattern(mpm_ctx, pat, patlen, - offset, depth, - pid, sid, flags); -} + /* put in the pattern hash */ + MpmInitHashAdd(mpm_ctx, p); -int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, - uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags) -{ - return mpm_table[mpm_ctx->mpm_type].AddPatternNocase(mpm_ctx, pat, patlen, - offset, depth, - pid, sid, flags); -} + mpm_ctx->pattern_cnt++; + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + + if (mpm_ctx->minlen == 0) { + mpm_ctx->minlen = patlen; + } else { + if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + /* we need the max pat id */ + if (p->id > mpm_ctx->max_pat_id) + mpm_ctx->max_pat_id = p->id; + + p->sids_size = 1; + p->sids = SCMalloc(p->sids_size * sizeof(SigIntId)); + BUG_ON(p->sids == NULL); + p->sids[0] = sid; + } else { + /* we can be called multiple times for the same sid in the case + * of the 'single' modus. Here multiple rule groups share the + * same mpm ctx and might be adding the same pattern to the + * mpm_ctx */ + int found = 0; + uint32_t x = 0; + for (x = 0; x < p->sids_size; x++) { + if (p->sids[x] == sid) { + found = 1; + break; + } + } + + if (!found) { + SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1))); + BUG_ON(sids == NULL); + p->sids = sids; + p->sids[p->sids_size] = sid; + p->sids_size++; + } + } + + return 0; + +error: + MpmFreePattern(mpm_ctx, p); + return -1; +} /************************************Unittests*********************************/ diff --git a/src/util-mpm.h b/src/util-mpm.h index f45ecfa4cb22..f20bf73774fd 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2014 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -23,68 +23,28 @@ #ifndef __UTIL_MPM_H__ #define __UTIL_MPM_H__ -#include "suricata-common.h" - -#define MPM_ENDMATCH_SINGLE 0x01 /**< A single match is sufficient. No - depth, offset, etc settings. */ -#define MPM_ENDMATCH_OFFSET 0x02 /**< has offset setting */ -#define MPM_ENDMATCH_DEPTH 0x04 /**< has depth setting */ -#define MPM_ENDMATCH_NOSEARCH 0x08 /**< if this matches, no search is - required (for this pattern) */ - -#define HASHSIZE_LOWEST 2048 /**< Lowest hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_LOW 4096 /**< Low hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_MEDIUM 8192 /**< Medium hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_HIGH 16384 /**< High hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_HIGHER 32768 /**< Higher hash size for the multi - pattern matcher algorithms */ -#define HASHSIZE_MAX 65536 /**< Max hash size for the multi - pattern matcher algorithms */ -#define BLOOMSIZE_LOW 512 /*<* Low bloomfilter size for the multi - pattern matcher algorithms */ -#define BLOOMSIZE_MEDIUM 1024 /**< Medium bloomfilter size for the multi - pattern matcher algorithms */ -#define BLOOMSIZE_HIGH 2048 /**< High bloomfilter size for the multi - pattern matcher algorithms */ + +#include "util-prefilter.h" + +#define MPM_INIT_HASH_SIZE 65536 enum { MPM_NOTSET = 0, - /* wumanber as the name suggests */ - MPM_WUMANBER, - /* bndmq 2 gram */ - MPM_B2G, - /* bndmq 3 gram */ - MPM_B3G, - MPM_B2GC, - MPM_B2GM, - /* aho-corasick */ MPM_AC, #ifdef __SC_CUDA_SUPPORT__ MPM_AC_CUDA, #endif - /* aho-corasick-goto-failure state based */ - MPM_AC_GFBS, MPM_AC_BS, MPM_AC_TILE, + MPM_HS, /* table size */ MPM_TABLE_SIZE, }; -#ifdef __tile__ -#define DEFAULT_MPM MPM_AC_TILE -#else -#define DEFAULT_MPM MPM_AC -#endif - -typedef struct MpmMatchBucket_ { - uint32_t len; -} MpmMatchBucket; +/* Internal Pattern Index: 0 to pattern_cnt-1 */ +typedef uint32_t MpmPatternIndex; typedef struct MpmThreadCtx_ { void *ctx; @@ -94,19 +54,26 @@ typedef struct MpmThreadCtx_ { } MpmThreadCtx; -/** \brief helper structure for the pattern matcher engine. The Pattern Matcher - * thread has this and passes a pointer to it to the pattern matcher. - * The actual pattern matcher will fill the structure. */ -typedef struct PatternMatcherQueue_ { - uint32_t *pattern_id_array; /** array with pattern id's that had a - pattern match. These will be inspected - futher by the detection engine. */ - uint32_t pattern_id_array_cnt; - uint32_t pattern_id_array_size; /**< size in bytes */ - - uint8_t *pattern_id_bitarray; /** bitarray with pattern id matches */ - uint32_t pattern_id_bitarray_size; /**< size in bytes */ -} PatternMatcherQueue; +typedef struct MpmPattern_ { + /* length of the pattern */ + uint16_t len; + /* flags decribing the pattern */ + uint8_t flags; + /* holds the original pattern that was added */ + uint8_t *original_pat; + /* case sensitive */ + uint8_t *cs; + /* case INsensitive */ + uint8_t *ci; + /* pattern id */ + uint32_t id; + + /* sid(s) for this pattern */ + uint32_t sids_size; + SigIntId *sids; + + struct MpmPattern_ *next; +} MpmPattern; typedef struct MpmCtx_ { void *ctx; @@ -126,20 +93,22 @@ typedef struct MpmCtx_ { uint32_t memory_cnt; uint32_t memory_size; + + uint32_t max_pat_id; + + /* hash used during ctx initialization */ + MpmPattern **init_hash; } MpmCtx; /* if we want to retrieve an unique mpm context from the mpm context factory * we should supply this as the key */ #define MPM_CTX_FACTORY_UNIQUE_CONTEXT -1 -#define MPM_CTX_FACTORY_FLAGS_PREPARE_WITH_SIG_GROUP_BUILD 0x01 - typedef struct MpmCtxFactoryItem_ { - char *name; + const char *name; MpmCtx *mpm_ctx_ts; MpmCtx *mpm_ctx_tc; int32_t id; - uint8_t flags; } MpmCtxFactoryItem; typedef struct MpmCtxFactoryContainer_ { @@ -157,12 +126,14 @@ typedef struct MpmCtxFactoryContainer_ { #define MPM_PATTERN_FLAG_OFFSET 0x08 /** one byte pattern (used in b2g) */ #define MPM_PATTERN_ONE_BYTE 0x10 +/** the ctx uses it's own internal id instead of + * what is passed through the API */ +#define MPM_PATTERN_CTX_OWNS_ID 0x20 typedef struct MpmTableElmt_ { - char *name; - uint8_t max_pattern_length; + const char *name; void (*InitCtx)(struct MpmCtx_ *); - void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *, uint32_t); + void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); void (*DestroyCtx)(struct MpmCtx_ *); void (*DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *); @@ -177,11 +148,10 @@ typedef struct MpmTableElmt_ { * \param sid signature _internal_ id * \param flags pattern flags */ - int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); - int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); + int (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); + int (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t); int (*Prepare)(struct MpmCtx_ *); - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - void (*Cleanup)(struct MpmThreadCtx_ *); + uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint16_t); void (*PrintCtx)(struct MpmCtx_ *); void (*PrintThreadCtx)(struct MpmThreadCtx_ *); void (*RegisterUnittests)(void); @@ -189,6 +159,7 @@ typedef struct MpmTableElmt_ { } MpmTableElmt; MpmTableElmt mpm_table[MPM_TABLE_SIZE]; +int mpm_default_matcher; /* macros decides if cuda is enabled for the platform or not */ #ifdef __SC_CUDA_SUPPORT__ @@ -228,32 +199,34 @@ void MpmCudaEnvironmentSetup(); struct DetectEngineCtx_; -int32_t MpmFactoryRegisterMpmCtxProfile(struct DetectEngineCtx_ *, const char *, uint8_t); -void MpmFactoryReClaimMpmCtx(struct DetectEngineCtx_ *, MpmCtx *); -MpmCtx *MpmFactoryGetMpmCtxForProfile(struct DetectEngineCtx_ *, int32_t, int); +int32_t MpmFactoryRegisterMpmCtxProfile(struct DetectEngineCtx_ *, const char *); +void MpmFactoryReClaimMpmCtx(const struct DetectEngineCtx_ *, MpmCtx *); +MpmCtx *MpmFactoryGetMpmCtxForProfile(const struct DetectEngineCtx_ *, int32_t, int); void MpmFactoryDeRegisterAllMpmCtxProfiles(struct DetectEngineCtx_ *); -int32_t MpmFactoryIsMpmCtxAvailable(struct DetectEngineCtx_ *, MpmCtx *); +int32_t MpmFactoryIsMpmCtxAvailable(const struct DetectEngineCtx_ *, const MpmCtx *); -int PmqSetup(PatternMatcherQueue *, uint32_t); -void PmqMerge(PatternMatcherQueue *src, PatternMatcherQueue *dst); -void PmqReset(PatternMatcherQueue *); -void PmqCleanup(PatternMatcherQueue *); -void PmqFree(PatternMatcherQueue *); +int PmqSetup(PrefilterRuleStore *); +void PmqReset(PrefilterRuleStore *); +void PmqCleanup(PrefilterRuleStore *); +void PmqFree(PrefilterRuleStore *); void MpmTableSetup(void); void MpmRegisterTests(void); -int MpmVerifyMatch(MpmThreadCtx *, PatternMatcherQueue *, uint32_t); void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher); -void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t, uint32_t); -uint32_t MpmGetHashSize(const char *); -uint32_t MpmGetBloomSize(const char *); +void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t); int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags); + uint32_t pid, SigIntId sid, uint8_t flags); int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, - uint32_t pid, uint32_t sid, uint8_t flags); + uint32_t pid, SigIntId sid, uint8_t flags); + +void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p); + +int MpmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, + SigIntId sid, uint8_t flags); #endif /* __UTIL_MPM_H__ */ diff --git a/src/util-pages.c b/src/util-pages.c new file mode 100644 index 000000000000..900c063be9b7 --- /dev/null +++ b/src/util-pages.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Page util functions + */ + +#include "suricata-common.h" +#ifndef HAVE_SYS_MMAN_H +#define PageSupportsRWX 1 +#else +#include + +/** \brief check if OS allows for RWX pages + * + * Some OS' disallow RWX pages for security reasons. This function mmaps + * some memory RW and then tries to turn it into RWX. If this fails we + * assume that the OS doesn't allow for this. + * + * Thanks to Shawn Webb from HardenedBSD for the suggestion. + * + * \retval 1 RWX supported + * \retval 0 not supported + */ +int PageSupportsRWX(void) +{ + int retval = 1; + void *ptr; + ptr = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); + if (ptr != MAP_FAILED) { + if (mprotect(ptr, getpagesize(), PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + SCLogConfig("RWX pages denied by OS"); + retval = 0; + } + munmap(ptr, getpagesize()); + } + return retval; +} +#endif /* HAVE_SYS_MMAN_H */ + diff --git a/src/util-pages.h b/src/util-pages.h new file mode 100644 index 000000000000..dd096734a10b --- /dev/null +++ b/src/util-pages.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + */ + +#ifndef __UTIL_PAGES_H__ +#define __UTIL_PAGES_H__ + +#include "suricata-common.h" + +#ifdef __OpenBSD__ + /* OpenBSD won't allow for this test: + * "suricata(...): mprotect W^X violation" */ + #define PageSupportsRWX() 0 +#else + #ifndef HAVE_SYS_MMAN_H + #define PageSupportsRWX() 1 + #else + int PageSupportsRWX(void); + #endif /* HAVE_SYS_MMAN_H */ +#endif + +#endif /* __UTIL_PAGES_H__ */ diff --git a/src/util-pidfile.c b/src/util-pidfile.c index a13e54efedaf..a68188b7e616 100644 --- a/src/util-pidfile.c +++ b/src/util-pidfile.c @@ -89,8 +89,13 @@ void SCPidfileRemove(const char *pid_filename) } /** - * \brief Check a pid file (used at the startup) - * This commonly needed by the init scripts + * \brief Check the Suricata pid file (used at the startup) + * + * This commonly needed by the init scripts. + * + * This function will fail if the PID file exists, but tries to log a + * meaningful message if appears Suricata is running, or if the PID + * file appears to be stale. * * \param pointer to the name of the pid file to write (optarg) * @@ -113,15 +118,19 @@ int SCPidfileTestRunning(const char *pid_filename) } if (fscanf(pf, "%d", &pidv) == 1 && kill(pidv, 0) == 0) { - fclose(pf); SCLogError(SC_ERR_INITIALIZATION, - "pid file '%s' exists. Is Suricata already running? Aborting!", - pid_filename); - return -1; + "pid file '%s' exists and Suricata appears to be running. " + "Aborting!", pid_filename); + } else { + SCLogError(SC_ERR_INITIALIZATION, + "pid file '%s' exists but appears stale. " + "Make sure Suricata is not running and then remove %s. " + "Aborting!", + pid_filename, pid_filename); } - if (pf != NULL) - fclose(pf); + fclose(pf); + return -1; } return 0; } diff --git a/src/util-pool-thread.c b/src/util-pool-thread.c index fe83a788f829..2795ebcad0a4 100644 --- a/src/util-pool-thread.c +++ b/src/util-pool-thread.c @@ -439,17 +439,17 @@ static int PoolThreadTestGrow03(void) void PoolThreadRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01, 1); - UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02, 1); + UtRegisterTest("PoolThreadTestInit01", PoolThreadTestInit01); + UtRegisterTest("PoolThreadTestInit02", PoolThreadTestInit02); - UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01, 1); - UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02, 1); + UtRegisterTest("PoolThreadTestGet01", PoolThreadTestGet01); + UtRegisterTest("PoolThreadTestGet02", PoolThreadTestGet02); - UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01, 1); + UtRegisterTest("PoolThreadTestReturn01", PoolThreadTestReturn01); - UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01, 1); - UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02, 1); - UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03, 1); + UtRegisterTest("PoolThreadTestGrow01", PoolThreadTestGrow01); + UtRegisterTest("PoolThreadTestGrow02", PoolThreadTestGrow02); + UtRegisterTest("PoolThreadTestGrow03", PoolThreadTestGrow03); #endif } diff --git a/src/util-pool.c b/src/util-pool.c index 6f405252046d..4706222d8df2 100644 --- a/src/util-pool.c +++ b/src/util-pool.c @@ -54,10 +54,10 @@ static int PoolMemset(void *pitem, void *initdata) /** * \brief Check if data is preallocated - * \retval 0 or -1 if not inside */ + * \retval 0 if not inside the prealloc'd block, 1 if inside */ static int PoolDataPreAllocated(Pool *p, void *data) { - int delta = data - p->data_buffer; + ptrdiff_t delta = data - p->data_buffer; if ((delta < 0) || (delta > p->data_buffer_size)) { return 0; } @@ -239,7 +239,7 @@ void PoolFree(Pool *p) SCFree(pb->data); } pb->data = NULL; - if (! pb->flags & POOL_BUCKET_PREALLOCATED) { + if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { SCFree(pb); } } @@ -258,7 +258,7 @@ void PoolFree(Pool *p) } pb->data = NULL; } - if (! pb->flags & POOL_BUCKET_PREALLOCATED) { + if (!(pb->flags & POOL_BUCKET_PREALLOCATED)) { SCFree(pb); } } @@ -719,13 +719,13 @@ static int PoolTestInit07 (void) void PoolRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("PoolTestInit01", PoolTestInit01, 1); - UtRegisterTest("PoolTestInit02", PoolTestInit02, 1); - UtRegisterTest("PoolTestInit03", PoolTestInit03, 1); - UtRegisterTest("PoolTestInit04", PoolTestInit04, 1); - UtRegisterTest("PoolTestInit05", PoolTestInit05, 1); - UtRegisterTest("PoolTestInit06", PoolTestInit06, 1); - UtRegisterTest("PoolTestInit07", PoolTestInit07, 1); + UtRegisterTest("PoolTestInit01", PoolTestInit01); + UtRegisterTest("PoolTestInit02", PoolTestInit02); + UtRegisterTest("PoolTestInit03", PoolTestInit03); + UtRegisterTest("PoolTestInit04", PoolTestInit04); + UtRegisterTest("PoolTestInit05", PoolTestInit05); + UtRegisterTest("PoolTestInit06", PoolTestInit06); + UtRegisterTest("PoolTestInit07", PoolTestInit07); PoolThreadRegisterTests(); #endif /* UNITTESTS */ diff --git a/src/util-prefilter.c b/src/util-prefilter.c new file mode 100644 index 000000000000..406cee6bfb0b --- /dev/null +++ b/src/util-prefilter.c @@ -0,0 +1,132 @@ +/* Copyright (C) 2007-2014 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Pattern matcher utility Functions + */ + +#include "suricata-common.h" + +/** + * \brief Setup a pmq + * + * \param pmq Pattern matcher queue to be initialized + * + * \retval -1 error + * \retval 0 ok + */ +int PmqSetup(PrefilterRuleStore *pmq) +{ + SCEnter(); + + if (pmq == NULL) { + SCReturnInt(-1); + } + + memset(pmq, 0, sizeof(PrefilterRuleStore)); + + pmq->rule_id_array_size = 128; /* Initial size, TODO: Make configure option. */ + pmq->rule_id_array_cnt = 0; + + size_t bytes = pmq->rule_id_array_size * sizeof(SigIntId); + pmq->rule_id_array = (SigIntId*)SCMalloc(bytes); + if (pmq->rule_id_array == NULL) { + pmq->rule_id_array_size = 0; + SCReturnInt(-1); + } + // Don't need to zero memory since it is always written first. + + SCReturnInt(0); +} + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first + * + * \param pmq storage for match results + * \param new_size number of Signature IDs needing to be stored. + * + */ +int +PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size) +{ + /* Need to make the array bigger. Double the size needed to + * also handle the case that sids_size might still be + * larger than the old size. + */ + new_size = new_size * 2; + SigIntId *new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + /* Try again just big enough. */ + new_size = new_size / 2; + new_array = (SigIntId*)SCRealloc(pmq->rule_id_array, + new_size * sizeof(SigIntId)); + if (unlikely(new_array == NULL)) { + + SCLogError(SC_ERR_MEM_ALLOC, "Failed to realloc PatternMatchQueue" + " rule ID array. Some signature ID matches lost"); + return 0; + } + } + pmq->rule_id_array = new_array; + pmq->rule_id_array_size = new_size; + + return new_size; +} + +/** \brief Reset a Pmq for reusage. Meant to be called after a single search. + * \param pmq Pattern matcher to be reset. + * \todo memset is expensive, but we need it as we merge pmq's. We might use + * a flag so we can clear pmq's the old way if we can. + */ +void PmqReset(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + + pmq->rule_id_array_cnt = 0; + /* TODO: Realloc the rule id array smaller at some size? */ +} + +/** \brief Cleanup a Pmq + * \param pmq Pattern matcher queue to be cleaned up. + */ +void PmqCleanup(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + if (pmq->rule_id_array != NULL) { + SCFree(pmq->rule_id_array); + pmq->rule_id_array = NULL; + } +} + +/** \brief Cleanup and free a Pmq + * \param pmq Pattern matcher queue to be free'd. + */ +void PmqFree(PrefilterRuleStore *pmq) +{ + if (pmq == NULL) + return; + + PmqCleanup(pmq); +} diff --git a/src/util-prefilter.h b/src/util-prefilter.h new file mode 100644 index 000000000000..1106795d3d31 --- /dev/null +++ b/src/util-prefilter.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_PREFILTER_H__ +#define __UTIL_PREFILTER_H__ + +/** \brief structure for storing potential rule matches + * + * Helper structure for the prefilter engine. The Pattern Matchers + * and other prefilter engines will add rule id's for potential + * rule matches */ +typedef struct PrefilterRuleStore_ { + /* used for storing rule id's */ + + /* Array of rule IDs found. */ + SigIntId *rule_id_array; + /* Number of rule IDs in the array. */ + uint32_t rule_id_array_cnt; + /* The number of slots allocated for storing rule IDs */ + uint32_t rule_id_array_size; + +} PrefilterRuleStore; + +/* Resize Signature ID array. Only called from MpmAddSids(). */ +int PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size); + +/** \brief Add array of Signature IDs to rule ID array. + * + * Checks size of the array first. Calls PrefilterAddSidsResize to increase + * The size of the array, since that is the slow path. + * + * \param pmq storage for match results + * \param sids pointer to array of Signature IDs + * \param sids_size number of Signature IDs in sids array. + * + */ +static inline void +PrefilterAddSids(PrefilterRuleStore *pmq, SigIntId *sids, uint32_t sids_size) +{ + if (sids_size == 0) + return; + + uint32_t new_size = pmq->rule_id_array_cnt + sids_size; + if (new_size > pmq->rule_id_array_size) { + if (PrefilterAddSidsResize(pmq, new_size) == 0) { + // Failed to allocate larger memory for all the SIDS, but + // keep as many as we can. + sids_size = pmq->rule_id_array_size - pmq->rule_id_array_cnt; + } + } + SCLogDebug("Adding %u sids", sids_size); + // Add SIDs for this pattern to the end of the array + SigIntId *ptr = pmq->rule_id_array + pmq->rule_id_array_cnt; + SigIntId *end = ptr + sids_size; + do { + *ptr++ = *sids++; + } while (ptr != end); + pmq->rule_id_array_cnt += sids_size; +} +#endif /* __UTIL_PREFILTER_H__ */ diff --git a/src/util-print.c b/src/util-print.c index 8cdf0c47e9ec..05ccafa777f2 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -133,7 +133,7 @@ void PrintRawUriBuf(char *retbuf, uint32_t *offset, uint32_t retbuflen, return; } -void PrintRawDataFp(FILE *fp, uint8_t *buf, uint32_t buflen) +void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen) { int ch = 0; uint32_t u = 0; @@ -168,7 +168,7 @@ void PrintRawDataFp(FILE *fp, uint8_t *buf, uint32_t buflen) } void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len) + const uint8_t *src_buf, uint32_t src_buf_len) { int ch = 0; uint32_t u = 0; @@ -217,7 +217,7 @@ void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32 } void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len) + const uint8_t *src_buf, const uint32_t src_buf_len) { uint32_t ch = 0; for (ch = 0; ch < src_buf_len; ch++) { @@ -237,9 +237,10 @@ void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32 static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) { - struct in6_addr * insrc = (struct in6_addr *) src; int i; char s_part[6]; + uint16_t x[8]; + memcpy(&x, src, 16); /* current IPv6 format is fixed size */ if (size < 8 * 5) { @@ -248,7 +249,7 @@ static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size) } memset(dst, 0, size); for(i = 0; i < 8; i++) { - snprintf(s_part, 6, "%04x:", htons(insrc->s6_addr16[i])); + snprintf(s_part, sizeof(s_part), "%04x:", htons(x[i])); strlcat(dst, s_part, size); } /* suppress last ':' */ diff --git a/src/util-print.h b/src/util-print.h index bbd1e719f91b..5bad4f838529 100644 --- a/src/util-print.h +++ b/src/util-print.h @@ -46,11 +46,11 @@ void PrintRawUriFp(FILE *, uint8_t *, uint32_t); void PrintRawUriBuf(char *, uint32_t *, uint32_t, uint8_t *, uint32_t); void PrintRawJsonFp(FILE *, uint8_t *, uint32_t); -void PrintRawDataFp(FILE *, uint8_t *, uint32_t); +void PrintRawDataFp(FILE *, const uint8_t *, uint32_t); void PrintRawDataToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len); + const uint8_t *src_buf, uint32_t src_buf_len); void PrintStringsToBuffer(uint8_t *dst_buf, uint32_t *dst_buf_offset_ptr, uint32_t dst_buf_size, - uint8_t *src_buf, uint32_t src_buf_len); + const uint8_t *src_buf, const uint32_t src_buf_len); void PrintRawLineHexBuf(char *, uint32_t, uint8_t *, uint32_t ); const char *PrintInet(int , const void *, char *, socklen_t); diff --git a/src/util-privs.c b/src/util-privs.c index 2048d12ac6fa..d44cbc7b396d 100644 --- a/src/util-privs.c +++ b/src/util-privs.c @@ -28,8 +28,8 @@ #include #include -#include "util-debug.h" #include "suricata-common.h" +#include "util-debug.h" #include "suricata.h" #ifdef HAVE_LIBCAP_NG @@ -76,16 +76,19 @@ void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) case RUNMODE_AFP_DEV: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_RAW, /* needed for pcap live mode */ + CAP_SYS_NICE, + CAP_NET_ADMIN, -1); break; case RUNMODE_PFRING: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, - CAP_NET_ADMIN, + CAP_NET_ADMIN, CAP_NET_RAW, CAP_SYS_NICE, -1); break; case RUNMODE_NFQ: capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_ADMIN, /* needed for nfqueue inline mode */ + CAP_SYS_NICE, -1); break; } diff --git a/src/util-profiling-keywords.c b/src/util-profiling-keywords.c index 84073735eab8..23b31f9ea7a6 100644 --- a/src/util-profiling-keywords.c +++ b/src/util-profiling-keywords.c @@ -63,7 +63,7 @@ typedef struct SCProfileKeywordDetectCtx_ { static int profiling_keywords_output_to_file = 0; int profiling_keyword_enabled = 0; __thread int profiling_keyword_entered = 0; -static char *profiling_file_name = ""; +static char profiling_file_name[PATH_MAX]; static const char *profiling_file_mode = "a"; void SCProfilingKeywordsGlobalInit(void) @@ -80,12 +80,8 @@ void SCProfilingKeywordsGlobalInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", + log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { @@ -100,7 +96,7 @@ void SCProfilingKeywordsGlobalInit(void) } } -void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name) +static void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name) { int i; fprintf(fp, " ----------------------------------------------" @@ -163,11 +159,12 @@ SCProfilingKeywordDump(DetectEngineCtx *de_ctx) if (profiling_keyword_enabled == 0) return; + const int nlists = DetectBufferTypeMaxId(); gettimeofday(&tval, NULL); tms = SCLocalTime(tval.tv_sec, &local_tm); if (profiling_keywords_output_to_file == 1) { - SCLogInfo("file %s mode %s", profiling_file_name, profiling_file_mode); + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); fp = fopen(profiling_file_name, profiling_file_mode); @@ -190,23 +187,30 @@ SCProfilingKeywordDump(DetectEngineCtx *de_ctx) /* global stats first */ DoDump(de_ctx->profile_keyword_ctx, fp, "total"); /* per buffer stats next, but only if there are stats to print */ - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { int j; uint64_t checks = 0; for (j = 0; j < DETECT_TBLSIZE; j++) { checks += de_ctx->profile_keyword_ctx_per_list[i]->data[j].checks; } - if (checks) - DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, - DetectSigmatchListEnumToString(i)); + if (checks) { + const char *name = NULL; + if (i < DETECT_SM_LIST_DYNAMIC_START) { + name = DetectSigmatchListEnumToString(i); + } else { + name = DetectBufferTypeGetNameById(i); + } + + DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, name); + } } fprintf(fp,"\n"); if (fp != stdout) fclose(fp); - SCLogInfo("Done dumping keyword profiling data."); + SCLogPerf("Done dumping keyword profiling data."); } /** @@ -232,7 +236,7 @@ SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t p->ticks_no_match += ticks; /* store per list (buffer type) as well */ - if (det_ctx->keyword_perf_list >= 0 && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) { + if (det_ctx->keyword_perf_list >= 0) {// && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) { p = &det_ctx->keyword_perf_data_per_list[det_ctx->keyword_perf_list][id]; p->checks++; p->matches += match; @@ -278,10 +282,13 @@ void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx) SCProfilingKeywordDump(de_ctx); DetroyCtx(de_ctx->profile_keyword_ctx); + + const int nlists = DetectBufferTypeMaxId(); int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { DetroyCtx(de_ctx->profile_keyword_ctx_per_list[i]); } + SCFree(de_ctx->profile_keyword_ctx_per_list); } } @@ -296,8 +303,12 @@ void SCProfilingKeywordThreadSetup(SCProfileKeywordDetectCtx *ctx, DetectEngineT det_ctx->keyword_perf_data = a; } + const int nlists = DetectBufferTypeMaxId(); + det_ctx->keyword_perf_data_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordData *)); + BUG_ON(det_ctx->keyword_perf_data_per_list == NULL); + int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SCProfileKeywordData *b = SCMalloc(sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); if (b != NULL) { memset(b, 0x00, sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); @@ -324,8 +335,9 @@ static void SCProfilingKeywordThreadMerge(DetectEngineCtx *de_ctx, DetectEngineT de_ctx->profile_keyword_ctx->data[i].max = det_ctx->keyword_perf_data[i].max; } + const int nlists = DetectBufferTypeMaxId(); int j; - for (j = 0; j < DETECT_SM_LIST_MAX; j++) { + for (j = 0; j < nlists; j++) { for (i = 0; i < DETECT_TBLSIZE; i++) { de_ctx->profile_keyword_ctx_per_list[j]->data[i].checks += det_ctx->keyword_perf_data_per_list[j][i].checks; de_ctx->profile_keyword_ctx_per_list[j]->data[i].matches += det_ctx->keyword_perf_data_per_list[j][i].matches; @@ -349,12 +361,13 @@ void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *det_ctx) SCFree(det_ctx->keyword_perf_data); det_ctx->keyword_perf_data = NULL; + const int nlists = DetectBufferTypeMaxId(); int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { SCFree(det_ctx->keyword_perf_data_per_list[i]); det_ctx->keyword_perf_data_per_list[i] = NULL; } - + SCFree(det_ctx->keyword_perf_data_per_list); } /** @@ -368,6 +381,8 @@ SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) if (profiling_keyword_enabled == 0) return; + const int nlists = DetectBufferTypeMaxId(); + de_ctx->profile_keyword_ctx = SCProfilingKeywordInitCtx(); BUG_ON(de_ctx->profile_keyword_ctx == NULL); @@ -375,8 +390,11 @@ SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) BUG_ON(de_ctx->profile_keyword_ctx->data == NULL); memset(de_ctx->profile_keyword_ctx->data, 0x00, sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); + de_ctx->profile_keyword_ctx_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordDetectCtx *)); + BUG_ON(de_ctx->profile_keyword_ctx_per_list == NULL); + int i; - for (i = 0; i < DETECT_SM_LIST_MAX; i++) { + for (i = 0; i < nlists; i++) { de_ctx->profile_keyword_ctx_per_list[i] = SCProfilingKeywordInitCtx(); BUG_ON(de_ctx->profile_keyword_ctx_per_list[i] == NULL); de_ctx->profile_keyword_ctx_per_list[i]->data = SCMalloc(sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); @@ -384,7 +402,7 @@ SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx) memset(de_ctx->profile_keyword_ctx_per_list[i]->data, 0x00, sizeof(SCProfileKeywordData) * DETECT_TBLSIZE); } - SCLogInfo("Registered %"PRIu32" keyword profiling counters.", DETECT_TBLSIZE); + SCLogPerf("Registered %"PRIu32" keyword profiling counters.", DETECT_TBLSIZE); } #endif /* PROFILING */ diff --git a/src/util-profiling-locks.c b/src/util-profiling-locks.c index 97cc3e0d8a30..7719e6d5b732 100644 --- a/src/util-profiling-locks.c +++ b/src/util-profiling-locks.c @@ -24,13 +24,13 @@ * */ -#ifdef PROFILING -#ifdef PROFILE_LOCKING - #include "suricata-common.h" #include "util-profiling-locks.h" #include "util-hashlist.h" +#ifdef PROFILING +#ifdef PROFILE_LOCKING + __thread ProfilingLock locks[PROFILING_MAX_LOCKS]; __thread int locks_idx = 0; __thread int record_locks = 0; diff --git a/src/util-profiling-rulegroups.c b/src/util-profiling-rulegroups.c new file mode 100644 index 000000000000..8f69338a1313 --- /dev/null +++ b/src/util-profiling-rulegroups.c @@ -0,0 +1,405 @@ +/* Copyright (C) 2007-2015 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Endace Technology Limited. + * \author Victor Julien + * + * An API for rule profiling operations. + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "detect-engine.h" +#include "conf.h" + +#include "tm-threads.h" + +#include "util-unittest.h" +#include "util-byte.h" +#include "util-profiling.h" +#include "util-profiling-locks.h" + +#ifdef PROFILING + +/** + * Extra data for rule profiling. + */ +typedef struct SCProfileSghData_ { + uint64_t checks; + + uint64_t non_mpm_generic; + uint64_t non_mpm_syn; + + uint64_t post_prefilter_sigs_total; + uint64_t post_prefilter_sigs_max; + + uint64_t mpm_match_cnt_total; + uint64_t mpm_match_cnt_max; + +} SCProfileSghData; + +typedef struct SCProfileSghDetectCtx_ { + uint32_t cnt; + SCProfileSghData *data; + pthread_mutex_t data_m; +} SCProfileSghDetectCtx; + +static int profiling_sghs_output_to_file = 0; +int profiling_sghs_enabled = 0; +static char profiling_file_name[PATH_MAX]; +static const char *profiling_file_mode = "a"; +#ifdef HAVE_LIBJANSSON +static int profiling_rulegroup_json = 0; +#endif + +void SCProfilingSghsGlobalInit(void) +{ + ConfNode *conf; + + conf = ConfGetNode("profiling.rulegroups"); + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "enabled")) { + profiling_sghs_enabled = 1; + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename != NULL) { + + char *log_dir; + log_dir = ConfigGetLogDirectory(); + + snprintf(profiling_file_name, sizeof(profiling_file_name), + "%s/%s", log_dir, filename); + + const char *v = ConfNodeLookupChildValue(conf, "append"); + if (v == NULL || ConfValIsTrue(v)) { + profiling_file_mode = "a"; + } else { + profiling_file_mode = "w"; + } + + profiling_sghs_output_to_file = 1; + } + if (ConfNodeChildValueIsTrue(conf, "json")) { +#ifdef HAVE_LIBJANSSON + profiling_rulegroup_json = 1; +#else + SCLogWarning(SC_ERR_NO_JSON_SUPPORT, "no json support compiled in, using plain output"); +#endif + } + } + } +} + +#ifdef HAVE_LIBJANSSON +static void DoDumpJSON(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + char timebuf[64]; + uint32_t i; + struct timeval tval; + + json_t *js = json_object(); + if (js == NULL) + return; + json_t *jsa = json_array(); + if (jsa == NULL) { + json_decref(js); + return; + } + + gettimeofday(&tval, NULL); + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + + for (i = 0; i < rules_ctx->cnt; i++) { + SCProfileSghData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + double avgsigs = 0; + double avgmpms = 0; + + if (d->post_prefilter_sigs_total && d->checks) { + avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); + } + if (d->mpm_match_cnt_total && d->checks) { + avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); + } + + json_t *jsm = json_object(); + if (jsm) { + json_object_set_new(jsm, "id", json_integer(i)); + json_object_set_new(jsm, "checks", json_integer(d->checks)); + json_object_set_new(jsm, "non_mpm_generic", json_integer(d->non_mpm_generic)); + json_object_set_new(jsm, "non_mpm_syn", json_integer(d->non_mpm_syn)); + json_object_set_new(jsm, "avgmpms", json_real(avgmpms)); + json_object_set_new(jsm, "mpm_match_cnt_max", json_integer(d->mpm_match_cnt_max)); + json_object_set_new(jsm, "avgsigs", json_real(avgsigs)); + json_object_set_new(jsm, "post_prefilter_sigs_max", json_integer(d->post_prefilter_sigs_max)); + json_array_append_new(jsa, jsm); + } + } + json_object_set_new(js, "rule_groups", jsa); + + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + if (likely(js_s != NULL)) { + fprintf(fp, "%s", js_s); + free(js_s); + } + json_decref(js); +} +#endif /* HAVE_LIBJANSSON */ + +static void DoDump(SCProfileSghDetectCtx *rules_ctx, FILE *fp, const char *name) +{ + uint32_t i; + struct timeval tval; + struct tm *tms; + struct tm local_tm; + + gettimeofday(&tval, NULL); + tms = SCLocalTime(tval.tv_sec, &local_tm); + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, + tms->tm_hour,tms->tm_min, tms->tm_sec); + + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Stats for: %s %u\n", name, rules_ctx->cnt); + fprintf(fp, " ----------------------------------------------" + "------------------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Sgh", "Checks", "Non-MPM(gen)", "Non-Mpm(syn)", "MPM Matches", "MPM Match Max", "Post-Filter", "Post-Filter Max"); + fprintf(fp, " ---------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "--------------- " + "\n"); + for (i = 0; i < rules_ctx->cnt; i++) { + SCProfileSghData *d = &rules_ctx->data[i]; + if (d == NULL || d->checks == 0) + continue; + + double avgsigs = 0; + double avgmpms = 0; + + if (d->post_prefilter_sigs_total && d->checks) { + avgsigs = (double)((double)d->post_prefilter_sigs_total / (double)d->checks); + } + if (d->mpm_match_cnt_total && d->checks) { + avgmpms = (double)((double)d->mpm_match_cnt_total / (double)d->checks); + } + + fprintf(fp, + " %-16u %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15.2f %-15"PRIu64" %-15.2f %-15"PRIu64"\n", + i, + d->checks, + d->non_mpm_generic, + d->non_mpm_syn, + avgmpms, + d->mpm_match_cnt_max, + avgsigs, + d->post_prefilter_sigs_max); + } + fprintf(fp,"\n"); +} + +void +SCProfilingSghDump(DetectEngineCtx *de_ctx) +{ + FILE *fp; + + if (profiling_sghs_enabled == 0) + return; + + if (profiling_sghs_output_to_file == 1) { + SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode); + + fp = fopen(profiling_file_name, profiling_file_mode); + + if (fp == NULL) { + SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", profiling_file_name, + strerror(errno)); + return; + } + } else { + fp = stdout; + } + +#ifdef HAVE_LIBJANSSON + if (profiling_rulegroup_json) { + DoDumpJSON(de_ctx->profile_sgh_ctx, fp, "rule groups"); + } else +#endif + { + DoDump(de_ctx->profile_sgh_ctx, fp, "rule groups"); + } + + if (fp != stdout) + fclose(fp); + + SCLogPerf("Done dumping rulegroup profiling data."); +} + +/** + * \brief Update a rule counter. + * + * \param id The ID of this counter. + * \param ticks Number of CPU ticks for this rule. + * \param match Did the rule match? + */ +void +SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh) +{ + if (det_ctx != NULL && det_ctx->sgh_perf_data != NULL && sgh->id < det_ctx->de_ctx->sgh_array_cnt) { + SCProfileSghData *p = &det_ctx->sgh_perf_data[sgh->id]; + p->checks++; + + if (det_ctx->non_pf_store_cnt > 0) { + if (det_ctx->non_pf_store_ptr == sgh->non_pf_syn_store_array) + p->non_mpm_syn++; + else + p->non_mpm_generic++; + } + p->post_prefilter_sigs_total += det_ctx->match_array_cnt; + if (det_ctx->match_array_cnt > p->post_prefilter_sigs_max) + p->post_prefilter_sigs_max = det_ctx->match_array_cnt; + p->mpm_match_cnt_total += det_ctx->pmq.rule_id_array_cnt; + if (det_ctx->pmq.rule_id_array_cnt > p->mpm_match_cnt_max) + p->mpm_match_cnt_max = det_ctx->pmq.rule_id_array_cnt; + } +} + +SCProfileSghDetectCtx *SCProfilingSghInitCtx(void) +{ + SCProfileSghDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileSghDetectCtx)); + if (ctx != NULL) { + if (pthread_mutex_init(&ctx->data_m, NULL) != 0) { + SCLogError(SC_ERR_MUTEX, + "Failed to initialize mutex."); + exit(EXIT_FAILURE); + } + } + + return ctx; +} + +static void DetroyCtx(SCProfileSghDetectCtx *ctx) +{ + if (ctx) { + if (ctx->data != NULL) + SCFree(ctx->data); + pthread_mutex_destroy(&ctx->data_m); + SCFree(ctx); + } +} + +void SCProfilingSghDestroyCtx(DetectEngineCtx *de_ctx) +{ + if (de_ctx != NULL) { + SCProfilingSghDump(de_ctx); + + DetroyCtx(de_ctx->profile_sgh_ctx); + } +} + +void SCProfilingSghThreadSetup(SCProfileSghDetectCtx *ctx, DetectEngineThreadCtx *det_ctx) +{ + if (ctx == NULL) + return; + + uint32_t array_size = det_ctx->de_ctx->sgh_array_cnt; + + SCProfileSghData *a = SCCalloc(array_size, sizeof(SCProfileSghData)); + if (a != NULL) { + det_ctx->sgh_perf_data = a; + } +} + +static void SCProfilingSghThreadMerge(DetectEngineCtx *de_ctx, const DetectEngineThreadCtx *det_ctx) +{ + if (de_ctx == NULL || de_ctx->profile_sgh_ctx == NULL || + de_ctx->profile_sgh_ctx->data == NULL || det_ctx == NULL || + det_ctx->sgh_perf_data == NULL) + return; + +#define ADD(name) de_ctx->profile_sgh_ctx->data[i].name += det_ctx->sgh_perf_data[i].name + uint32_t i; + for (i = 0; i < de_ctx->sgh_array_cnt; i++) { + ADD(checks); + ADD(non_mpm_generic); + ADD(non_mpm_syn); + ADD(post_prefilter_sigs_total); + ADD(mpm_match_cnt_total); + + if (det_ctx->sgh_perf_data[i].mpm_match_cnt_max > de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max) + de_ctx->profile_sgh_ctx->data[i].mpm_match_cnt_max = det_ctx->sgh_perf_data[i].mpm_match_cnt_max; + if (det_ctx->sgh_perf_data[i].post_prefilter_sigs_max > de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max) + de_ctx->profile_sgh_ctx->data[i].post_prefilter_sigs_max = det_ctx->sgh_perf_data[i].post_prefilter_sigs_max; + } +#undef ADD +} + +void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *det_ctx) +{ + if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->sgh_perf_data == NULL) + return; + + pthread_mutex_lock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); + SCProfilingSghThreadMerge(det_ctx->de_ctx, det_ctx); + pthread_mutex_unlock(&det_ctx->de_ctx->profile_sgh_ctx->data_m); + + SCFree(det_ctx->sgh_perf_data); + det_ctx->sgh_perf_data = NULL; +} + +/** + * \brief Register the keyword profiling counters. + * + * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules. + */ +void +SCProfilingSghInitCounters(DetectEngineCtx *de_ctx) +{ + if (profiling_sghs_enabled == 0) + return; + + de_ctx->profile_sgh_ctx = SCProfilingSghInitCtx(); + BUG_ON(de_ctx->profile_sgh_ctx == NULL); + + de_ctx->profile_sgh_ctx->data = SCCalloc(de_ctx->sgh_array_cnt, sizeof(SCProfileSghData)); + BUG_ON(de_ctx->profile_sgh_ctx->data == NULL); + + de_ctx->profile_sgh_ctx->cnt = de_ctx->sgh_array_cnt; + + SCLogPerf("Registered %"PRIu32" rulegroup profiling counters.", de_ctx->sgh_array_cnt); +} + +#endif /* PROFILING */ diff --git a/src/util-profiling-rules.c b/src/util-profiling-rules.c index a6a4189da5e5..bab516cb87d7 100644 --- a/src/util-profiling-rules.c +++ b/src/util-profiling-rules.c @@ -38,10 +38,6 @@ #ifdef PROFILING -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - /** * Extra data for rule profiling. */ @@ -83,8 +79,11 @@ typedef struct SCProfileSummary_ { extern int profiling_output_to_file; int profiling_rules_enabled = 0; -static char *profiling_file_name = ""; +static char profiling_file_name[PATH_MAX] = ""; static const char *profiling_file_mode = "a"; +#ifdef HAVE_LIBJANSSON +static int profiling_rule_json = 0; +#endif /** * Sort orders for dumping profiled rules. @@ -98,7 +97,16 @@ enum { SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, }; -static int profiling_rules_sort_order = SC_PROFILING_RULES_SORT_BY_TICKS; + +static int profiling_rules_sort_orders[8] = { + SC_PROFILING_RULES_SORT_BY_TICKS, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH, + SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH, + SC_PROFILING_RULES_SORT_BY_CHECKS, + SC_PROFILING_RULES_SORT_BY_MATCHES, + SC_PROFILING_RULES_SORT_BY_MAX_TICKS, + -1 }; /** * Maximum number of rules to dump. @@ -107,6 +115,11 @@ static uint32_t profiling_rules_limit = UINT32_MAX; void SCProfilingRulesGlobalInit(void) { +#define SET_ONE(x) { \ + profiling_rules_sort_orders[0] = (x); \ + profiling_rules_sort_orders[1] = -1; \ + } + ConfNode *conf; const char *val; @@ -118,32 +131,25 @@ void SCProfilingRulesGlobalInit(void) val = ConfNodeLookupChildValue(conf, "sort"); if (val != NULL) { if (strcmp(val, "ticks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_TICKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS); } else if (strcmp(val, "avgticks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_AVG_TICKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS); } else if (strcmp(val, "avgticks_match") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH; + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH); } else if (strcmp(val, "avgticks_no_match") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH; + SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH); } else if (strcmp(val, "checks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_CHECKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS); } else if (strcmp(val, "matches") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_MATCHES; + SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES); } else if (strcmp(val, "maxticks") == 0) { - profiling_rules_sort_order = - SC_PROFILING_RULES_SORT_BY_MAX_TICKS; + SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS); } else { SCLogError(SC_ERR_INVALID_ARGUMENT, @@ -166,12 +172,8 @@ void SCProfilingRulesGlobalInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_file_name, sizeof(profiling_file_name), + "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { @@ -182,8 +184,16 @@ void SCProfilingRulesGlobalInit(void) profiling_output_to_file = 1; } + if (ConfNodeChildValueIsTrue(conf, "json")) { +#ifdef HAVE_LIBJANSSON + profiling_rule_json = 1; +#else + SCLogWarning(SC_ERR_NO_JSON_SUPPORT, "no json support compiled in, using plain output"); +#endif + } } } +#undef SET_ONE } /** @@ -194,7 +204,10 @@ SCProfileSummarySortByTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->ticks - s0->ticks; + if (s1->ticks == s0->ticks) + return 0; + else + return s0->ticks > s1->ticks ? -1 : 1; } /** @@ -205,7 +218,10 @@ SCProfileSummarySortByAvgTicksMatch(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->avgticks_match - s0->avgticks_match; + if (s1->avgticks_match == s0->avgticks_match) + return 0; + else + return s0->avgticks_match > s1->avgticks_match ? -1 : 1; } /** @@ -216,7 +232,10 @@ SCProfileSummarySortByAvgTicksNoMatch(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->avgticks_no_match - s0->avgticks_no_match; + if (s1->avgticks_no_match == s0->avgticks_no_match) + return 0; + else + return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1; } /** @@ -227,7 +246,10 @@ SCProfileSummarySortByAvgTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->avgticks - s0->avgticks; + if (s1->avgticks == s0->avgticks) + return 0; + else + return s0->avgticks > s1->avgticks ? -1 : 1; } /** @@ -238,7 +260,10 @@ SCProfileSummarySortByChecks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->checks - s0->checks; + if (s1->checks == s0->checks) + return 0; + else + return s0->checks > s1->checks ? -1 : 1; } /** @@ -249,7 +274,10 @@ SCProfileSummarySortByMatches(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->matches - s0->matches; + if (s1->matches == s0->matches) + return 0; + else + return s0->matches > s1->matches ? -1 : 1; } /** @@ -260,7 +288,139 @@ SCProfileSummarySortByMaxTicks(const void *a, const void *b) { const SCProfileSummary *s0 = a; const SCProfileSummary *s1 = b; - return s1->max - s0->max; + if (s1->max == s0->max) + return 0; + else + return s0->max > s1->max ? -1 : 1; +} + +#ifdef HAVE_LIBJANSSON + +static void DumpJson(FILE *fp, SCProfileSummary *summary, + uint32_t count, uint64_t total_ticks, + const char *sort_desc) +{ + char timebuf[64]; + uint32_t i; + struct timeval tval; + + json_t *js = json_object(); + if (js == NULL) + return; + json_t *jsa = json_array(); + if (jsa == NULL) { + json_decref(js); + return; + } + + gettimeofday(&tval, NULL); + CreateIsoTimeString(&tval, timebuf, sizeof(timebuf)); + json_object_set_new(js, "timestamp", json_string(timebuf)); + json_object_set_new(js, "sort", json_string(sort_desc)); + + for (i = 0; i < MIN(count, profiling_rules_limit); i++) { + /* Stop dumping when we hit our first rule with 0 checks. Due + * to sorting this will be the beginning of all the rules with + * 0 checks. */ + if (summary[i].checks == 0) + break; + + json_t *jsm = json_object(); + if (jsm) { + json_object_set_new(jsm, "signature_id", json_integer(summary[i].sid)); + json_object_set_new(jsm, "gid", json_integer(summary[i].gid)); + json_object_set_new(jsm, "rev", json_integer(summary[i].rev)); + + json_object_set_new(jsm, "checks", json_integer(summary[i].checks)); + json_object_set_new(jsm, "matches", json_integer(summary[i].matches)); + + json_object_set_new(jsm, "ticks_total", json_integer(summary[i].ticks)); + json_object_set_new(jsm, "ticks_max", json_integer(summary[i].max)); + json_object_set_new(jsm, "ticks_avg", json_integer(summary[i].avgticks)); + json_object_set_new(jsm, "ticks_avg_match", json_integer(summary[i].avgticks_match)); + json_object_set_new(jsm, "ticks_avg_nomatch", json_integer(summary[i].avgticks_no_match)); + + double percent = (long double)summary[i].ticks / + (long double)total_ticks * 100; + json_object_set_new(jsm, "percent", json_integer(percent)); + json_array_append_new(jsa, jsm); + } + } + json_object_set_new(js, "rules", jsa); + + char *js_s = json_dumps(js, + JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII| + JSON_ESCAPE_SLASH); + + if (unlikely(js_s == NULL)) + return; + fprintf(fp, "%s", js_s); + free(js_s); + json_decref(js); +} + +#endif /* HAVE_LIBJANSSON */ + +static void DumpText(FILE *fp, SCProfileSummary *summary, + uint32_t count, uint64_t total_ticks, + const char *sort_desc) +{ + uint32_t i; + struct timeval tval; + struct tm *tms; + gettimeofday(&tval, NULL); + struct tm local_tm; + tms = SCLocalTime(tval.tv_sec, &local_tm); + + fprintf(fp, " ----------------------------------------------" + "----------------------------\n"); + fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " + "%02d:%02d:%02d.", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, + tms->tm_hour,tms->tm_min, tms->tm_sec); + fprintf(fp, " Sorted by: %s.\n", sort_desc); + fprintf(fp, " ----------------------------------------------" + "----------------------------\n"); + fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); + fprintf(fp, " -------- " + "------------ " + "-------- " + "-------- " + "------------ " + "------ " + "-------- " + "-------- " + "----------- " + "----------- " + "----------- " + "-------------- " + "\n"); + for (i = 0; i < MIN(count, profiling_rules_limit); i++) { + + /* Stop dumping when we hit our first rule with 0 checks. Due + * to sorting this will be the beginning of all the rules with + * 0 checks. */ + if (summary[i].checks == 0) + break; + + double percent = (long double)summary[i].ticks / + (long double)total_ticks * 100; + fprintf(fp, + " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n", + i + 1, + summary[i].sid, + summary[i].gid, + summary[i].rev, + summary[i].ticks, + percent, + summary[i].checks, + summary[i].matches, + summary[i].max, + summary[i].avgticks, + summary[i].avgticks_match, + summary[i].avgticks_no_match); + } + + fprintf(fp,"\n"); } /** @@ -277,8 +437,6 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) if (rules_ctx == NULL) return; - struct timeval tval; - struct tm *tms; if (profiling_output_to_file == 1) { fp = fopen(profiling_file_name, profiling_file_mode); @@ -301,7 +459,7 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) uint32_t count = rules_ctx->size; uint64_t total_ticks = 0; - SCLogInfo("Dumping profiling data for %u rules.", count); + SCLogPerf("Dumping profiling data for %u rules.", count); memset(summary, 0, summary_size); for (i = 0; i < count; i++) { @@ -332,93 +490,61 @@ SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx) total_ticks += summary[i].ticks; } - switch (profiling_rules_sort_order) { - case SC_PROFILING_RULES_SORT_BY_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByTicks); - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicks); - break; - case SC_PROFILING_RULES_SORT_BY_CHECKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByChecks); - break; - case SC_PROFILING_RULES_SORT_BY_MATCHES: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByMatches); - break; - case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByMaxTicks); - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicksMatch); - break; - case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: - qsort(summary, count, sizeof(SCProfileSummary), - SCProfileSummarySortByAvgTicksNoMatch); - break; - } - - gettimeofday(&tval, NULL); - struct tm local_tm; - tms = SCLocalTime(tval.tv_sec, &local_tm); - - fprintf(fp, " ----------------------------------------------" - "----------------------------\n"); - fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- " - "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, - tms->tm_hour,tms->tm_min, tms->tm_sec); - fprintf(fp, " ----------------------------------------------" - "----------------------------\n"); - fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match"); - fprintf(fp, " -------- " - "------------ " - "-------- " - "-------- " - "------------ " - "------ " - "-------- " - "-------- " - "----------- " - "----------- " - "----------- " - "-------------- " - "\n"); - for (i = 0; i < MIN(count, profiling_rules_limit); i++) { - - /* Stop dumping when we hit our first rule with 0 checks. Due - * to sorting this will be the beginning of all the rules with - * 0 checks. */ - if (summary[i].checks == 0) - break; - - double percent = (long double)summary[i].ticks / - (long double)total_ticks * 100; - fprintf(fp, - " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n", - i + 1, - summary[i].sid, - summary[i].gid, - summary[i].rev, - summary[i].ticks, - percent, - summary[i].checks, - summary[i].matches, - summary[i].max, - summary[i].avgticks, - summary[i].avgticks_match, - summary[i].avgticks_no_match); + int *order = profiling_rules_sort_orders; + while (*order != -1) { + const char *sort_desc = NULL; + switch (*order) { + case SC_PROFILING_RULES_SORT_BY_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByTicks); + sort_desc = "ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicks); + sort_desc = "average ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_CHECKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByChecks); + sort_desc = "number of checks"; + break; + case SC_PROFILING_RULES_SORT_BY_MATCHES: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByMatches); + sort_desc = "number of matches"; + break; + case SC_PROFILING_RULES_SORT_BY_MAX_TICKS: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByMaxTicks); + sort_desc = "max ticks"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicksMatch); + sort_desc = "average ticks (match)"; + break; + case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH: + qsort(summary, count, sizeof(SCProfileSummary), + SCProfileSummarySortByAvgTicksNoMatch); + sort_desc = "average ticks (no match)"; + break; + } +#ifdef HAVE_LIBJANSSON + if (profiling_rule_json) { + DumpJson(fp, summary, count, total_ticks, sort_desc); + } else +#endif + { + DumpText(fp, summary, count, total_ticks, sort_desc); + } + order++; } - fprintf(fp,"\n"); if (fp != stdout) fclose(fp); SCFree(summary); - SCLogInfo("Done dumping profiling data."); + SCLogPerf("Done dumping profiling data."); } /** @@ -565,7 +691,7 @@ SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx) } } - SCLogInfo("Registered %"PRIu32" rule profiling counters.", count); + SCLogPerf("Registered %"PRIu32" rule profiling counters.", count); } #endif /* PROFILING */ diff --git a/src/util-profiling.c b/src/util-profiling.c index 4cdfdb57a7e6..65fe1e35141c 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -29,7 +29,9 @@ #include "suricata-common.h" #include "decode.h" #include "detect.h" +#include "detect-engine-prefilter.h" #include "conf.h" +#include "flow-worker.h" #include "tm-threads.h" @@ -86,15 +88,28 @@ SCProfilePacketData packet_profile_app_pd_data6[257]; SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]; SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]; -int profiling_packets_enabled = 0; -int profiling_packets_csv_enabled = 0; +SCProfilePacketData packet_profile_log_data4[LOGGER_SIZE][256]; +SCProfilePacketData packet_profile_log_data6[LOGGER_SIZE][256]; + +struct ProfileProtoRecords { + SCProfilePacketData records4[257]; + SCProfilePacketData records6[257]; +}; +static SCProfilePacketData prefilter4[256][256]; +static SCProfilePacketData prefilter6[256][256]; + + +struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]; +int profiling_packets_enabled = 0; int profiling_output_to_file = 0; -int profiling_packets_output_to_file = 0; -char *profiling_file_name; -char *profiling_packets_file_name; -char *profiling_csv_file_name; -const char *profiling_packets_file_mode = "a"; + +static int profiling_packets_csv_enabled = 0; +static int profiling_packets_output_to_file = 0; +static char *profiling_file_name; +static char profiling_packets_file_name[PATH_MAX]; +static char *profiling_csv_file_name; +static const char *profiling_packets_file_mode = "a"; static int rate = 1; static SC_ATOMIC_DECLARE(uint64_t, samples); @@ -106,6 +121,7 @@ __thread int profiling_rules_entered = 0; void SCProfilingDumpPacketStats(void); const char * PacketProfileDetectIdToString(PacketProfileDetectId id); +const char * PacketProfileLoggertIdToString(LoggerId id); static void FormatNumber(uint64_t num, char *str, size_t size) { @@ -159,6 +175,11 @@ SCProfilingInit(void) memset(&packet_profile_app_pd_data6, 0, sizeof(packet_profile_app_pd_data6)); memset(&packet_profile_detect_data4, 0, sizeof(packet_profile_detect_data4)); memset(&packet_profile_detect_data6, 0, sizeof(packet_profile_detect_data6)); + memset(&packet_profile_log_data4, 0, sizeof(packet_profile_log_data4)); + memset(&packet_profile_log_data6, 0, sizeof(packet_profile_log_data6)); + memset(&packet_profile_flowworker_data, 0, sizeof(packet_profile_flowworker_data)); + memset(&prefilter4, 0, sizeof(prefilter4)); + memset(&prefilter6, 0, sizeof(prefilter6)); const char *filename = ConfNodeLookupChildValue(conf, "filename"); if (filename != NULL) { @@ -166,13 +187,8 @@ SCProfilingInit(void) char *log_dir; log_dir = ConfigGetLogDirectory(); - profiling_packets_file_name = SCMalloc(PATH_MAX); - if (unlikely(profiling_packets_file_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name"); - exit(EXIT_FAILURE); - } - - snprintf(profiling_packets_file_name, PATH_MAX, "%s/%s", log_dir, filename); + snprintf(profiling_packets_file_name, sizeof(profiling_packets_file_name), + "%s/%s", log_dir, filename); const char *v = ConfNodeLookupChildValue(conf, "append"); if (v == NULL || ConfValIsTrue(v)) { @@ -217,7 +233,7 @@ SCProfilingInit(void) for (i = 0; i < ALPROTO_MAX; i++) { fprintf(packet_profile_csv_fp, "%s,", AppProtoToString(i)); } - fprintf(packet_profile_csv_fp, "STREAM (no app),proto detect,"); + fprintf(packet_profile_csv_fp, "proto detect,"); for (i = 0; i < PROF_DETECT_SIZE; i++) { fprintf(packet_profile_csv_fp, "%s,", PacketProfileDetectIdToString(i)); } @@ -279,13 +295,16 @@ SCProfilingDestroy(void) if (profiling_packets_csv_enabled) { if (packet_profile_csv_fp != NULL) fclose(packet_profile_csv_fp); + packet_profile_csv_fp = NULL; } if (profiling_csv_file_name != NULL) SCFree(profiling_csv_file_name); + profiling_csv_file_name = NULL; if (profiling_file_name != NULL) SCFree(profiling_file_name); + profiling_file_name = NULL; #ifdef PROFILE_LOCKING LockRecordFreeHash(); @@ -296,7 +315,146 @@ void SCProfilingDump(void) { SCProfilingDumpPacketStats(); - SCLogInfo("Done dumping profiling data."); + SCLogPerf("Done dumping profiling data."); +} + +static void DumpPrefilterIP(FILE *fp, int ipv, uint64_t total) +{ + char totalstr[256]; + + SCProfilePacketData total_pd; + memset(&total_pd, 0, sizeof(total_pd)); + + int i; + for (i = 0; i < 256; i++) { + const char *name = PrefilterStoreGetName(i); + + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = ipv == 4 ? &prefilter4[i][p] : &prefilter6[i][p]; + if (pd->cnt == 0) { + continue; + } + + total_pd.cnt += pd->cnt; + total_pd.tot += pd->tot; + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-30s IPv%d %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %11s %-6.2f\n", + name, ipv, p, pd->cnt, + pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + if (total_pd.cnt) { + FormatNumber(total_pd.tot, totalstr, sizeof(totalstr)); + fprintf(fp, "%-30s IPv%d %12"PRIu64" %12"PRIu64" %11s\n", + "Total", ipv, total_pd.cnt, (uint64_t)(total_pd.tot / total_pd.cnt), totalstr); + } +} + +static void DumpPrefilter(FILE *fp) +{ + uint64_t total = 0; + + int i; + for (i = 0; i < 256; i++) { + for (int p = 0; p < 256; p++) { + SCProfilePacketData *pd = &prefilter4[i][p]; + total += pd->tot; + pd = &prefilter6[i][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-30s %-6s %-5s %-12s %-12s %-12s %-12s %-11s %-3s\n", + "Prefilter", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%"); + fprintf(fp, "%-30s %-6s %-5s %-12s %-12s %-12s %-12s %-11s %-3s\n", + "--------------------", "------", "-----", "----------", + "------------", "------------", "-----------", "---------", "---"); + DumpPrefilterIP(fp, 4, total); + DumpPrefilterIP(fp, 6, total); +} + +static void SCProfilingUpdatePrefilterRecords(Packet *p) +{ + if (p->profile->prefilter.engines != NULL) { + uint32_t x; + for (x = 0; x < p->profile->prefilter.size; x++) { + uint64_t ticks = p->profile->prefilter.engines[x].ticks_spent; + if (ticks == 0) + continue; + + SCProfilePacketData *pd = NULL; + if (PKT_IS_IPV4(p)) { + pd = &prefilter4[x][p->proto]; + } else if (PKT_IS_IPV6(p)) { + pd = &prefilter6[x][p->proto]; + } else { + continue; + } + + if (pd->min == 0 || ticks < pd->min) { + pd->min = ticks; + } + if (pd->max < ticks) { + pd->max = ticks; + } + + pd->tot += ticks; + pd->cnt ++; + } + } +} + +static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total) +{ + char totalstr[256]; + + enum ProfileFlowWorkerId fwi; + for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = ipv == 4 ? &r->records4[p] : &r->records6[p]; + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-20s IPv%d %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", + ProfileFlowWorkerIdToString(fwi), ipv, p, pd->cnt, + pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } +} + +static void DumpFlowWorker(FILE *fp) +{ + uint64_t total = 0; + + enum ProfileFlowWorkerId fwi; + for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) { + struct ProfileProtoRecords *r = &packet_profile_flowworker_data[fwi]; + for (int p = 0; p < 257; p++) { + SCProfilePacketData *pd = &r->records4[p]; + total += pd->tot; + pd = &r->records6[p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", + "Flow Worker", "IP ver", "Proto", "cnt", "min", "max", "avg"); + fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n", + "--------------------", "------", "-----", "----------", "------------", "------------", "-----------"); + DumpFlowWorkerIP(fp, 4, total); + DumpFlowWorkerIP(fp, 6, total); + fprintf(fp, "Note: %s includes app-layer for TCP\n", + ProfileFlowWorkerIdToString(PROFILE_FLOWWORKER_STREAM)); } void SCProfilingDumpPacketStats(void) @@ -447,7 +605,8 @@ void SCProfilingDumpPacketStats(void) TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); } } - fprintf(fp, "Note: TMM_STREAMTCP includes TCP app layer parsers, see below.\n"); + + DumpFlowWorker(fp); fprintf(fp, "\nPer App layer parser stats:\n"); @@ -623,6 +782,60 @@ void SCProfilingDumpPacketStats(void) } } + fprintf(fp, "\nLogger/output stats:\n"); + + total = 0; + for (m = 0; m < LOGGER_SIZE; m++) { + int p; + for (p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; + total += pd->tot; + pd = &packet_profile_log_data6[m][p]; + total += pd->tot; + } + } + + fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "Logger", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot"); + fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n", + "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------"); + for (m = 0; m < LOGGER_SIZE; m++) { + int p; + for (p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_log_data4[m][p]; + + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", + PacketProfileLoggertIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + for (m = 0; m < LOGGER_SIZE; m++) { + int p; + for (p = 0; p < 257; p++) { + SCProfilePacketData *pd = &packet_profile_log_data6[m][p]; + + if (pd->cnt == 0) { + continue; + } + + FormatNumber(pd->tot, totalstr, sizeof(totalstr)); + double percent = (long double)pd->tot / + (long double)total * 100; + + fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n", + PacketProfileLoggertIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent); + } + } + + DumpPrefilter(fp); + fprintf(fp, "\nGeneral detection engine stats:\n"); total = 0; @@ -691,7 +904,6 @@ void SCProfilingPrintPacketProfile(Packet *p) int i; uint64_t tmm_total = 0; - uint64_t tmm_streamtcp_tcp = 0; for (i = 0; i < TMM_SIZE; i++) { PktProfilingTmmData *pdt = &p->profile->tmm[i]; @@ -699,10 +911,6 @@ void SCProfilingPrintPacketProfile(Packet *p) uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start; fprintf(packet_profile_csv_fp, "%"PRIu64",", tmm_delta); tmm_total += tmm_delta; - - if (p->proto == IPPROTO_TCP && i == TMM_STREAMTCP) { - tmm_streamtcp_tcp = tmm_delta; - } } fprintf(packet_profile_csv_fp, "%"PRIu64",", delta - tmm_total); @@ -718,11 +926,6 @@ void SCProfilingPrintPacketProfile(Packet *p) } } - uint64_t real_tcp = 0; - if (tmm_streamtcp_tcp > app_total) - real_tcp = tmm_streamtcp_tcp - app_total; - fprintf(packet_profile_csv_fp, "%"PRIu64",", real_tcp); - fprintf(packet_profile_csv_fp, "%"PRIu64",", p->profile->proto_detect); for (i = 0; i < PROF_DETECT_SIZE; i++) { @@ -889,6 +1092,88 @@ void SCProfilingUpdatePacketTmmRecords(Packet *p) } } +static inline void SCProfilingUpdatePacketGenericRecord(PktProfilingData *pdt, + SCProfilePacketData *pd) +{ + if (pdt == NULL || pd == NULL) { + return; + } + + uint64_t delta = pdt->ticks_end - pdt->ticks_start; + if (pd->min == 0 || delta < pd->min) { + pd->min = delta; + } + if (pd->max < delta) { + pd->max = delta; + } + + pd->tot += delta; + pd->cnt ++; +} + +static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *pd, + struct ProfileProtoRecords *records, int size) +{ + int i; + for (i = 0; i < size; i++) { + PktProfilingData *pdt = &pd[i]; + + if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) { + continue; + } + + struct ProfileProtoRecords *r = &records[i]; + SCProfilePacketData *store = NULL; + + if (PKT_IS_IPV4(p)) { + store = &(r->records4[p->proto]); + } else { + store = &(r->records6[p->proto]); + } + + SCProfilingUpdatePacketGenericRecord(pdt, store); + } +} + +static void SCProfilingUpdatePacketLogRecord(LoggerId id, + uint8_t ipproto, PktProfilingLoggerData *pdt, int ipver) +{ + if (pdt == NULL) { + return; + } + + SCProfilePacketData *pd; + if (ipver == 4) + pd = &packet_profile_log_data4[id][ipproto]; + else + pd = &packet_profile_log_data6[id][ipproto]; + + if (pd->min == 0 || pdt->ticks_spent < pd->min) { + pd->min = pdt->ticks_spent; + } + if (pd->max < pdt->ticks_spent) { + pd->max = pdt->ticks_spent; + } + + pd->tot += pdt->ticks_spent; + pd->cnt++; +} + +static void SCProfilingUpdatePacketLogRecords(Packet *p) +{ + for (LoggerId i = 0; i < LOGGER_SIZE; i++) { + PktProfilingLoggerData *pdt = &p->profile->logger[i]; + + if (pdt->ticks_spent > 0) { + if (PKT_IS_IPV4(p)) { + SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 4); + } else { + SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 6); + } + } + } +} + void SCProfilingAddPacket(Packet *p) { if (p == NULL || p->profile == NULL || @@ -930,9 +1215,13 @@ void SCProfilingAddPacket(Packet *p) pd->cnt ++; } + SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, + packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); + SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); + SCProfilingUpdatePacketLogRecords(p); } else if (PKT_IS_IPV6(p)) { SCProfilePacketData *pd = &packet_profile_data6[p->proto]; @@ -962,10 +1251,16 @@ void SCProfilingAddPacket(Packet *p) pd->cnt ++; } + SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker, + packet_profile_flowworker_data, PROFILE_FLOWWORKER_SIZE); + SCProfilingUpdatePacketTmmRecords(p); SCProfilingUpdatePacketAppRecords(p); SCProfilingUpdatePacketDetectRecords(p); + SCProfilingUpdatePacketLogRecords(p); } + + SCProfilingUpdatePrefilterRecords(p); } pthread_mutex_unlock(&packet_profile_lock); } @@ -1009,37 +1304,68 @@ int SCProfileRuleStart(Packet *p) const char * PacketProfileDetectIdToString(PacketProfileDetectId id) { switch (id) { - CASE_CODE (PROF_DETECT_MPM); - CASE_CODE (PROF_DETECT_MPM_PACKET); -// CASE_CODE (PROF_DETECT_MPM_PKT_STREAM); - CASE_CODE (PROF_DETECT_MPM_STREAM); - CASE_CODE (PROF_DETECT_MPM_URI); - CASE_CODE (PROF_DETECT_MPM_HCBD); - CASE_CODE (PROF_DETECT_MPM_HSBD); - CASE_CODE (PROF_DETECT_MPM_HHD); - CASE_CODE (PROF_DETECT_MPM_HRHD); - CASE_CODE (PROF_DETECT_MPM_HMD); - CASE_CODE (PROF_DETECT_MPM_HCD); - CASE_CODE (PROF_DETECT_MPM_HRUD); - CASE_CODE (PROF_DETECT_MPM_HSMD); - CASE_CODE (PROF_DETECT_MPM_HSCD); - CASE_CODE (PROF_DETECT_MPM_HUAD); - CASE_CODE (PROF_DETECT_MPM_DNSQUERY); CASE_CODE (PROF_DETECT_IPONLY); CASE_CODE (PROF_DETECT_RULES); CASE_CODE (PROF_DETECT_PREFILTER); + CASE_CODE (PROF_DETECT_PF_PKT); + CASE_CODE (PROF_DETECT_PF_PAYLOAD); + CASE_CODE (PROF_DETECT_PF_TX); + CASE_CODE (PROF_DETECT_PF_SORT1); + CASE_CODE (PROF_DETECT_PF_SORT2); CASE_CODE (PROF_DETECT_STATEFUL); CASE_CODE (PROF_DETECT_ALERT); CASE_CODE (PROF_DETECT_CLEANUP); CASE_CODE (PROF_DETECT_GETSGH); - case PROF_DETECT_MPM_PKT_STREAM: - return "PROF_DETECT_MPM_PKT_STR"; + CASE_CODE (PROF_DETECT_NONMPMLIST); default: return "UNKNOWN"; } } - +/** + * \brief Maps the LoggerId's to its string equivalent for profiling output. + * + * \param id LoggerId id + * + * \retval string equivalent for the LoggerId id + */ +const char * PacketProfileLoggertIdToString(LoggerId id) +{ + switch (id) { + CASE_CODE (LOGGER_UNDEFINED); + CASE_CODE (LOGGER_ALERT_DEBUG); + CASE_CODE (LOGGER_ALERT_FAST); + CASE_CODE (LOGGER_UNIFIED2); + CASE_CODE (LOGGER_ALERT_SYSLOG); + CASE_CODE (LOGGER_DROP); + CASE_CODE (LOGGER_JSON_ALERT); + CASE_CODE (LOGGER_JSON_DROP); + CASE_CODE (LOGGER_JSON_SSH); + CASE_CODE (LOGGER_DNS); + CASE_CDOE (LOGGER_HPFEEDS); + CASE_CODE (LOGGER_HTTP); + CASE_CODE (LOGGER_JSON_DNS); + CASE_CODE (LOGGER_JSON_HTTP); + CASE_CODE (LOGGER_JSON_SMTP); + CASE_CODE (LOGGER_JSON_TLS); + CASE_CODE (LOGGER_JSON_TEMPLATE); + CASE_CODE (LOGGER_TLS_STORE); + CASE_CODE (LOGGER_TLS); + CASE_CODE (LOGGER_FILE); + CASE_CODE (LOGGER_FILE_STORE); + CASE_CODE (LOGGER_JSON_FILE); + CASE_CODE (LOGGER_TCP_DATA); + CASE_CODE (LOGGER_JSON_FLOW); + CASE_CODE (LOGGER_JSON_NETFLOW); + CASE_CODE (LOGGER_STATS); + CASE_CODE (LOGGER_JSON_STATS); + CASE_CODE (LOGGER_PRELUDE); + CASE_CODE (LOGGER_PCAP); + CASE_CODE (LOGGER_JSON_VARS); + default: + return "UNKNOWN"; + } +} #ifdef UNITTESTS @@ -1149,7 +1475,7 @@ void SCProfilingRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01, 1); + UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01); #endif /* UNITTESTS */ } diff --git a/src/util-profiling.h b/src/util-profiling.h index 763d8414ae60..d10bee673e4d 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -32,6 +32,7 @@ extern int profiling_rules_enabled; extern int profiling_packets_enabled; +extern int profiling_sghs_enabled; extern __thread int profiling_rules_entered; void SCProfilingPrintPacketProfile(Packet *); @@ -95,6 +96,12 @@ PktProfiling *SCProfilePacketStart(void); (p)->profile->ticks_start = UtilCpuGetTicks(); \ } +#define PACKET_PROFILING_RESTART(p) \ + if (profiling_packets_enabled) { \ + if ((p)->profile != NULL) \ + (p)->profile->ticks_start = UtilCpuGetTicks(); \ + } + #define PACKET_PROFILING_END(p) \ if (profiling_packets_enabled && (p)->profile != NULL) { \ (p)->profile->ticks_end = UtilCpuGetTicks(); \ @@ -156,8 +163,23 @@ PktProfiling *SCProfilePacketStart(void); } \ } +#define FLOWWORKER_PROFILING_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROFILE_FLOWWORKER_SIZE) { \ + (p)->profile->flowworker[(id)].ticks_start = UtilCpuGetTicks();\ + } \ + } + +#define FLOWWORKER_PROFILING_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < PROFILE_FLOWWORKER_SIZE) { \ + (p)->profile->flowworker[(id)].ticks_end = UtilCpuGetTicks(); \ + } \ + } + #define PACKET_PROFILING_RESET(p) \ if (profiling_packets_enabled && (p)->profile != NULL) { \ + SCFree((p)->profile->prefilter.engines); \ SCFree((p)->profile); \ (p)->profile = NULL; \ } @@ -229,6 +251,58 @@ PktProfiling *SCProfilePacketStart(void); } \ } +#define PACKET_PROFILING_LOGGER_START(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < LOGGER_SIZE) { \ + (p)->profile->logger[(id)].ticks_start = UtilCpuGetTicks(); \ + } \ + } + +#define PACKET_PROFILING_LOGGER_END(p, id) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((id) < LOGGER_SIZE) { \ + (p)->profile->logger[(id)].ticks_end = UtilCpuGetTicks();\ + if ((p)->profile->logger[(id)].ticks_start != 0 && \ + (p)->profile->logger[(id)].ticks_start < (p)->profile->logger[(id)].ticks_end) { \ + (p)->profile->logger[(id)].ticks_spent += \ + ((p)->profile->logger[(id)].ticks_end - (p)->profile->logger[(id)].ticks_start); \ + } \ + } \ + } + +#define SGH_PROFILING_RECORD(det_ctx, sgh) \ + if (profiling_sghs_enabled) { \ + SCProfilingSghUpdateCounter((det_ctx), (sgh)); \ + } + +#define PROFILING_PREFILTER_RESET(p, detectsize) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((p)->profile->prefilter.size != ((detectsize) + 1)) { \ + if ((p)->profile->prefilter.engines != NULL) \ + SCFree((p)->profile->prefilter.engines); \ + (p)->profile->prefilter.engines = \ + SCCalloc((detectsize)+1, sizeof(PktProfilingPrefilterEngine)); \ + (p)->profile->prefilter.size = (detectsize)+1;\ + } else { \ + memset((p)->profile->prefilter.engines, 0x00, \ + ((detectsize)+1 * sizeof(PktProfilingPrefilterEngine))); \ + } \ + } \ + +#define PROFILING_PREFILTER_START(p) \ + uint64_t ticks_start = 0; \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + ticks_start = UtilCpuGetTicks(); \ + } \ + +#define PROFILING_PREFILTER_END(p, profile_id) \ + if (profiling_packets_enabled && (p)->profile != NULL && \ + ticks_start) \ + { \ + uint64_t ticks_end = UtilCpuGetTicks(); \ + (p)->profile->prefilter.engines[(profile_id)].ticks_spent += (ticks_end - ticks_start); \ + ticks_start = 0; \ + } \ void SCProfilingRulesGlobalInit(void); void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *); @@ -244,6 +318,13 @@ void SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uin void SCProfilingKeywordThreadSetup(struct SCProfileKeywordDetectCtx_ *, DetectEngineThreadCtx *); void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *); +void SCProfilingSghsGlobalInit(void); +void SCProfilingSghDestroyCtx(DetectEngineCtx *); +void SCProfilingSghInitCounters(DetectEngineCtx *); +void SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh); +void SCProfilingSghThreadSetup(struct SCProfileSghDetectCtx_ *, DetectEngineThreadCtx *); +void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *); + void SCProfilingInit(void); void SCProfilingDestroy(void); void SCProfilingRegisterTests(void); @@ -259,6 +340,7 @@ void SCProfilingDump(void); #define KEYWORD_PROFILING_END(a,b,c) #define PACKET_PROFILING_START(p) +#define PACKET_PROFILING_RESTART(p) #define PACKET_PROFILING_END(p) #define PACKET_PROFILING_TMM_START(p, id) @@ -277,6 +359,18 @@ void SCProfilingDump(void); #define PACKET_PROFILING_DETECT_START(p, id) #define PACKET_PROFILING_DETECT_END(p, id) +#define PACKET_PROFILING_LOGGER_START(p, id) +#define PACKET_PROFILING_LOGGER_END(p, id) + +#define SGH_PROFILING_RECORD(det_ctx, sgh) + +#define FLOWWORKER_PROFILING_START(p, id) +#define FLOWWORKER_PROFILING_END(p, id) + +#define PROFILING_PREFILTER_RESET(p, detectsize) +#define PROFILING_PREFILTER_START(p) +#define PROFILING_PREFILTER_END(p, profile_id) + #endif /* PROFILING */ #endif /* ! __UTIL_PROFILE_H__ */ diff --git a/src/util-proto-name.c b/src/util-proto-name.c index 82ec8e64ba6f..0b958884ca4e 100644 --- a/src/util-proto-name.c +++ b/src/util-proto-name.c @@ -43,27 +43,17 @@ void SCProtoNameInit() FILE *fp = fopen(PROTO_FILE,"r"); if (fp != NULL) { char line[200]; -#if !defined(__WIN32) && !defined(_WIN32) char *ptr = NULL; -#endif /* __WIN32 */ while(fgets(line, sizeof(line), fp) != NULL) { if (line[0] == '#') continue; -#if defined(__WIN32) || defined(_WIN32) - char *name = strtok(line," \t"); -#else char *name = strtok_r(line," \t", &ptr); -#endif /* __WIN32 */ if (name == NULL) continue; -#if defined(__WIN32) || defined(_WIN32) - char *proto_ch = strtok(NULL," \t"); -#else char *proto_ch = strtok_r(NULL," \t", &ptr); -#endif /* __WIN32 */ if (proto_ch == NULL) continue; @@ -71,11 +61,7 @@ void SCProtoNameInit() if (proto >= 255) continue; -#if defined(__WIN32) || defined(_WIN32) - char *cname = strtok(NULL, " \t"); -#else char *cname = strtok_r(NULL, " \t", &ptr); -#endif /* __WIN32 */ if (known_proto[proto] != NULL) { SCFree(known_proto[proto]); diff --git a/src/util-radix-tree.c b/src/util-radix-tree.c index 39f8304ef907..ba63e6432c43 100644 --- a/src/util-radix-tree.c +++ b/src/util-radix-tree.c @@ -496,9 +496,6 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixNode *parent = NULL; SCRadixNode *inter_node = NULL; SCRadixNode *bottom_node = NULL; - - SCRadixPrefix *prefix = NULL; - void *ptmp; uint8_t *stream = NULL; @@ -519,14 +516,14 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, /* chop the ip address against a netmask */ MaskIPNetblock(key_stream, netmask, key_bitlen); - if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, - netmask)) == NULL) { - SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); - return NULL; - } - /* the very first element in the radix tree */ if (tree->head == NULL) { + SCRadixPrefix *prefix = NULL; + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, + netmask)) == NULL) { + SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); + return NULL; + } node = SCRadixCreateNode(); if (node == NULL) return NULL; @@ -558,8 +555,8 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, } node = tree->head; - stream = prefix->stream; - bitlen = prefix->bitlen; + stream = key_stream; + bitlen = key_bitlen; /* we walk down the tree only when we satisfy 2 conditions. The first one * being the incoming prefix is shorter than the differ bit of the current @@ -570,7 +567,7 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, * down along one of the paths, since either paths should end up with a * node that has a common prefix whose differ bit is greater than the * bitlen of the incoming prefix */ - if (bitlen < node->bit) { + if (bitlen <= node->bit) { if (node->right == NULL) break; node = node->right; @@ -695,13 +692,19 @@ static SCRadixNode *SCRadixAddKey(uint8_t *key_stream, uint16_t key_bitlen, } } } else { - node->prefix = SCRadixCreatePrefix(prefix->stream, prefix->bitlen, + node->prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, 255); } return node; } /* create the leaf node for the new key */ + SCRadixPrefix *prefix = NULL; + if ( (prefix = SCRadixCreatePrefix(key_stream, key_bitlen, user, + netmask)) == NULL) { + SCLogError(SC_ERR_RADIX_TREE_GENERIC, "Error creating prefix"); + return NULL; + } new_node = SCRadixCreateNode(); new_node->prefix = prefix; new_node->bit = prefix->bitlen; @@ -1124,7 +1127,7 @@ static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, SCRadixPrefix *prefix = NULL; - int mask = 0; + uint32_t mask = 0; int i = 0; if (node == NULL) @@ -1154,7 +1157,7 @@ static void SCRadixRemoveKey(uint8_t *key_stream, uint16_t key_bitlen, i = prefix->bitlen / 8; if (SCMemcmp(node->prefix->stream, prefix->stream, i) == 0) { - mask = -1 << (8 - prefix->bitlen % 8); + mask = UINT_MAX << (8 - prefix->bitlen % 8); if (prefix->bitlen % 8 == 0 || (node->prefix->stream[i] & mask) == (prefix->stream[i] & mask)) { @@ -1331,7 +1334,7 @@ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t SCRadixNode *node, void **user_data_result) { SCRadixNode *netmask_node = NULL; - int mask = 0; + uint32_t mask = 0; int bytes = 0; int i = 0; int j = 0; @@ -1348,10 +1351,10 @@ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t for (j = 0; j < netmask_node->netmask_cnt; j++) { bytes = key_bitlen / 8; for (i = 0; i < bytes; i++) { - mask = -1; + mask = UINT_MAX; if ( ((i + 1) * 8) > netmask_node->netmasks[j]) { if ( ((i + 1) * 8 - netmask_node->netmasks[j]) < 8) - mask = -1 << ((i + 1) * 8 - netmask_node->netmasks[j]); + mask = UINT_MAX << ((i + 1) * 8 - netmask_node->netmasks[j]); else mask = 0; } @@ -1374,7 +1377,7 @@ static inline SCRadixNode *SCRadixFindKeyIPNetblock(uint8_t *key_stream, uint8_t return NULL; if (SCMemcmp(node->prefix->stream, key_stream, bytes) == 0) { - mask = -1 << (8 - key_bitlen % 8); + mask = UINT_MAX << (8 - key_bitlen % 8); if (key_bitlen % 8 == 0 || (node->prefix->stream[bytes] & mask) == (key_stream[bytes] & mask)) { @@ -1403,7 +1406,7 @@ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, return NULL; SCRadixNode *node = tree->head; - int mask = 0; + uint32_t mask = 0; int bytes = 0; uint8_t tmp_stream[255]; @@ -1432,7 +1435,7 @@ static SCRadixNode *SCRadixFindKey(uint8_t *key_stream, uint16_t key_bitlen, bytes = key_bitlen / 8; if (SCMemcmp(node->prefix->stream, tmp_stream, bytes) == 0) { - mask = -1 << (8 - key_bitlen % 8); + mask = UINT_MAX << (8 - key_bitlen % 8); if (key_bitlen % 8 == 0 || (node->prefix->stream[bytes] & mask) == (tmp_stream[bytes] & mask)) { @@ -4178,50 +4181,50 @@ void SCRadixRegisterTests(void) #ifdef UNITTESTS //UtRegisterTest("SCRadixTestInsertion01", SCRadixTestInsertion01, 1); //UtRegisterTest("SCRadixTestInsertion02", SCRadixTestInsertion02, 1); - UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03, 1); - UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04, 1); + UtRegisterTest("SCRadixTestIPV4Insertion03", SCRadixTestIPV4Insertion03); + UtRegisterTest("SCRadixTestIPV4Removal04", SCRadixTestIPV4Removal04); //UtRegisterTest("SCRadixTestCharacterInsertion05", // SCRadixTestCharacterInsertion05, 1); //UtRegisterTest("SCRadixTestCharacterRemoval06", // SCRadixTestCharacterRemoval06, 1); - UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07, 1); - UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08, 1); + UtRegisterTest("SCRadixTestIPV6Insertion07", SCRadixTestIPV6Insertion07); + UtRegisterTest("SCRadixTestIPV6Removal08", SCRadixTestIPV6Removal08); UtRegisterTest("SCRadixTestIPV4NetblockInsertion09", - SCRadixTestIPV4NetblockInsertion09, 1); + SCRadixTestIPV4NetblockInsertion09); UtRegisterTest("SCRadixTestIPV4NetblockInsertion10", - SCRadixTestIPV4NetblockInsertion10, 1); + SCRadixTestIPV4NetblockInsertion10); UtRegisterTest("SCRadixTestIPV4NetblockInsertion11", - SCRadixTestIPV4NetblockInsertion11, 1); + SCRadixTestIPV4NetblockInsertion11); UtRegisterTest("SCRadixTestIPV4NetblockInsertion12", - SCRadixTestIPV4NetblockInsertion12, 1); + SCRadixTestIPV4NetblockInsertion12); UtRegisterTest("SCRadixTestIPV6NetblockInsertion13", - SCRadixTestIPV6NetblockInsertion13, 1); + SCRadixTestIPV6NetblockInsertion13); UtRegisterTest("SCRadixTestIPV6NetblockInsertion14", - SCRadixTestIPV6NetblockInsertion14, 1); + SCRadixTestIPV6NetblockInsertion14); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch15", - SCRadixTestIPV4NetBlocksAndBestSearch15, 1); + SCRadixTestIPV4NetBlocksAndBestSearch15); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch16", - SCRadixTestIPV4NetBlocksAndBestSearch16, 1); + SCRadixTestIPV4NetBlocksAndBestSearch16); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch17", - SCRadixTestIPV4NetBlocksAndBestSearch17, 1); + SCRadixTestIPV4NetBlocksAndBestSearch17); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch18", - SCRadixTestIPV4NetBlocksAndBestSearch18, 1); + SCRadixTestIPV4NetBlocksAndBestSearch18); UtRegisterTest("SCRadixTestIPV4NetBlocksAndBestSearch19", - SCRadixTestIPV4NetBlocksAndBestSearch19, 1); + SCRadixTestIPV4NetBlocksAndBestSearch19); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch20", - SCRadixTestIPV6NetBlocksAndBestSearch20, 1); + SCRadixTestIPV6NetBlocksAndBestSearch20); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch21", - SCRadixTestIPV6NetBlocksAndBestSearch21, 1); + SCRadixTestIPV6NetBlocksAndBestSearch21); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch22", - SCRadixTestIPV6NetBlocksAndBestSearch22, 1); + SCRadixTestIPV6NetBlocksAndBestSearch22); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch23", - SCRadixTestIPV6NetBlocksAndBestSearch23, 1); + SCRadixTestIPV6NetBlocksAndBestSearch23); UtRegisterTest("SCRadixTestIPV6NetBlocksAndBestSearch24", - SCRadixTestIPV6NetBlocksAndBestSearch24, 1); + SCRadixTestIPV6NetBlocksAndBestSearch24); UtRegisterTest("SCRadixTestIPV4NetblockInsertion25", - SCRadixTestIPV4NetblockInsertion25, 1); + SCRadixTestIPV4NetblockInsertion25); UtRegisterTest("SCRadixTestIPV4NetblockInsertion26", - SCRadixTestIPV4NetblockInsertion26, 1); + SCRadixTestIPV4NetblockInsertion26); #endif return; diff --git a/src/util-reference-config.c b/src/util-reference-config.c index 1eb8047e055c..3703353940b3 100644 --- a/src/util-reference-config.c +++ b/src/util-reference-config.c @@ -41,9 +41,6 @@ /* Default path for the reference.conf file */ #define SC_RCONF_DEFAULT_FILE_PATH CONFIG_DIR "/reference.config" -/* Holds a pointer to the default path for the reference.config file */ -static const char *file_path = SC_RCONF_DEFAULT_FILE_PATH; -static FILE *fd = NULL; static pcre *regex = NULL; static pcre_extra *regex_study = NULL; @@ -54,7 +51,44 @@ char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1, void SCRConfReferenceHashFree(void *ch); /* used to get the reference.config file path */ -static char *SCRConfGetConfFilename(void); +static char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx); + +void SCReferenceConfInit(void) +{ + const char *eb = NULL; + int eo; + int opts = 0; + + regex = pcre_compile(SC_RCONF_REGEX, opts, &eb, &eo, NULL); + if (regex == NULL) { + SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", + SC_RCONF_REGEX, eo, eb); + return; + } + + regex_study = pcre_study(regex, 0, &eb); + if (eb != NULL) { + pcre_free(regex); + regex = NULL; + SCLogDebug("pcre study failed: %s", eb); + return; + } + + return; +} + +void SCReferenceConfDeinit(void) +{ + if (regex != NULL) { + pcre_free(regex); + regex = NULL; + } + if (regex_study != NULL) { + pcre_free(regex_study); + regex_study = NULL; + } +} + /** * \brief Inits the context to be used by the Reference Config parsing API. @@ -69,12 +103,9 @@ static char *SCRConfGetConfFilename(void); * \retval 0 On success. * \retval -1 On failure. */ -static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) +static FILE *SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { char *filename = NULL; - const char *eb = NULL; - int eo; - int opts = 0; /* init the hash table to be used by the reference config references */ de_ctx->reference_conf_ht = HashTableInit(128, SCRConfReferenceHashFunc, @@ -91,28 +122,19 @@ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) * instead use an input stream against a buffer containing the * reference strings */ if (fd == NULL) { - filename = SCRConfGetConfFilename(); + filename = SCRConfGetConfFilename(de_ctx); if ((fd = fopen(filename, "r")) == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests()) + goto error; // silently fail +#endif SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } } - regex = pcre_compile(SC_RCONF_REGEX, opts, &eb, &eo, NULL); - if (regex == NULL) { - SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s", - SC_RCONF_REGEX, eo, eb); - goto error; - } - - regex_study = pcre_study(regex, 0, &eb); - if (eb != NULL) { - SCLogDebug("pcre study failed: %s", eb); - goto error; - } - - return 0; + return fd; error: if (de_ctx->reference_conf_ht != NULL) { @@ -124,16 +146,7 @@ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) fd = NULL; } - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; - } - - return -1; + return NULL; } @@ -146,11 +159,26 @@ static int SCRConfInitContextAndLocalResources(DetectEngineCtx *de_ctx) * \retval log_filename Pointer to a string containing the path for the * reference.config file. */ -static char *SCRConfGetConfFilename(void) +static char *SCRConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *path = NULL; - if (ConfGet("reference-config-file", &path) != 1) { - return (char *)file_path; + + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; + snprintf(config_value, sizeof(config_value), + "%s.reference-config-file", de_ctx->config_prefix); + + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &path) != 1) { + if (ConfGet("reference-config-file", &path) != 1) { + return (char *)SC_RCONF_DEFAULT_FILE_PATH; + } + } + } else { + if (ConfGet("reference-config-file", &path) != 1) { + return (char *)SC_RCONF_DEFAULT_FILE_PATH; + } } return path; } @@ -158,20 +186,11 @@ static char *SCRConfGetConfFilename(void) /** * \brief Releases local resources used by the Reference Config API. */ -static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx) +static void SCRConfDeInitLocalResources(DetectEngineCtx *de_ctx, FILE *fd) { - if (fd != NULL) + if (fd != NULL) { fclose(fd); - file_path = SC_RCONF_DEFAULT_FILE_PATH; - fd = NULL; - - if (regex != NULL) { - pcre_free(regex); - regex = NULL; - } - if (regex_study != NULL) { - pcre_free(regex_study); - regex_study = NULL; + fd = NULL; } return; @@ -225,8 +244,8 @@ static char *SCRConfStringToLowercase(const char *str) */ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) { - const char *system = NULL; - const char *url = NULL; + char system[64]; + char url[1024]; SCRConfReference *ref_new = NULL; SCRConfReference *ref_lookup = NULL; @@ -243,21 +262,23 @@ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) } /* retrieve the reference system */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &system); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, system, sizeof(system)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring() failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring() failed"); goto error; } /* retrieve the reference url */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &url); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, url, sizeof(url)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring() failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring() failed"); goto error; } /* Create a new instance of the parsed Reference string */ ref_new = SCRConfAllocSCRConfReference(system, url); + if (ref_new == NULL) + goto error; /* Check if the Reference is present in the HashTable. In case it's present * ignore it, as it's a duplicate. If not present, add it to the table */ @@ -271,17 +292,9 @@ static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx) SCRConfDeAllocSCRConfReference(ref_new); } - /* free the substrings */ - pcre_free_substring(system); - pcre_free_substring(url); return 0; error: - if (system) - pcre_free_substring(system); - if (url) - pcre_free_substring(url); - return -1; } @@ -321,7 +334,7 @@ static int SCRConfIsLineBlankOrComment(char *line) * * \param de_ctx Pointer to the Detection Engine Context. */ -static void SCRConfParseFile(DetectEngineCtx *de_ctx) +static void SCRConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) { char line[1024]; uint8_t i = 1; @@ -489,15 +502,22 @@ void SCRConfReferenceHashFree(void *data) * \retval 0 On success. * \retval -1 On failure. */ -int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx) +int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx, FILE *fd) { - if (SCRConfInitContextAndLocalResources(de_ctx) == -1) { - SCLogInfo("Please check the \"reference-config-file\" option in your suricata.yaml file"); - exit(EXIT_FAILURE); + fd = SCRConfInitContextAndLocalResources(de_ctx, fd); + if (fd == NULL) { +#ifdef UNITTESTS + if (RunmodeIsUnittests() && fd == NULL) { + return -1; + } +#endif + SCLogError(SC_ERR_OPENING_FILE, "please check the \"reference-config-file\" " + "option in your suricata.yaml file"); + return -1; } - SCRConfParseFile(de_ctx); - SCRConfDeInitLocalResources(de_ctx); + SCRConfParseFile(de_ctx, fd); + SCRConfDeInitLocalResources(de_ctx, fd); return 0; } @@ -518,7 +538,7 @@ SCRConfReference *SCRConfGetReference(const char *rconf_name, { SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(rconf_name, NULL); if (ref_conf == NULL) - exit(EXIT_FAILURE); + return NULL; SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht, ref_conf, 0); @@ -535,7 +555,7 @@ SCRConfReference *SCRConfGetReference(const char *rconf_name, * \brief Creates a dummy reference config, with all valid references, for * testing purposes. */ -void SCRConfGenerateValidDummyReferenceConfigFD01(void) +FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void) { const char *buffer = "config reference: one http://www.one.com\n" @@ -544,18 +564,18 @@ void SCRConfGenerateValidDummyReferenceConfigFD01(void) "config reference: one http://www.one.com\n" "config reference: three http://www.three.com\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - return; + return fd; } /** * \brief Creates a dummy reference config, with some valid references and a * couple of invalid references, for testing purposes. */ -void SCRConfGenerateInValidDummyReferenceConfigFD02(void) +FILE *SCRConfGenerateInValidDummyReferenceConfigFD02(void) { const char *buffer = "config reference: one http://www.one.com\n" @@ -564,18 +584,18 @@ void SCRConfGenerateInValidDummyReferenceConfigFD02(void) "config reference: four\n" "config reference five http://www.five.com\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - return; + return fd; } /** * \brief Creates a dummy reference config, with all invalid references, for * testing purposes. */ -void SCRConfGenerateInValidDummyReferenceConfigFD03(void) +FILE *SCRConfGenerateInValidDummyReferenceConfigFD03(void) { const char *buffer = "config reference one http://www.one.com\n" @@ -583,24 +603,11 @@ void SCRConfGenerateInValidDummyReferenceConfigFD03(void) "config reference_: three http://www.three.com\n" "config reference: four\n"; - fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + FILE *fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); if (fd == NULL) SCLogDebug("Error with SCFmemopen() called by Reference Config test code"); - return; -} - -/** - * \brief Deletes the FD, if set by the other testing functions. - */ -void SCRConfDeleteDummyReferenceConfigFD(void) -{ - if (fd != NULL) { - fclose(fd); - fd = NULL; - } - - return; + return fd; } /** @@ -615,9 +622,8 @@ int SCRConfTest01(void) if (de_ctx == NULL) return result; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -644,9 +650,8 @@ int SCRConfTest02(void) if (de_ctx == NULL) return result; - SCRConfGenerateInValidDummyReferenceConfigFD03(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD03(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -672,9 +677,8 @@ int SCRConfTest03(void) if (de_ctx == NULL) return result; - SCRConfGenerateInValidDummyReferenceConfigFD02(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD02(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -699,9 +703,8 @@ int SCRConfTest04(void) if (de_ctx == NULL) return 0; - SCRConfGenerateValidDummyReferenceConfigFD01(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateValidDummyReferenceConfigFD01(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -732,9 +735,8 @@ int SCRConfTest05(void) if (de_ctx == NULL) return 0; - SCRConfGenerateInValidDummyReferenceConfigFD03(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD03(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -765,9 +767,8 @@ int SCRConfTest06(void) if (de_ctx == NULL) return 0; - SCRConfGenerateInValidDummyReferenceConfigFD02(); - SCRConfLoadReferenceConfigFile(de_ctx); - SCRConfDeleteDummyReferenceConfigFD(); + FILE *fd = SCRConfGenerateInValidDummyReferenceConfigFD02(); + SCRConfLoadReferenceConfigFile(de_ctx, fd); if (de_ctx->reference_conf_ht == NULL) goto end; @@ -795,12 +796,12 @@ void SCRConfRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCRConfTest01", SCRConfTest01, 1); - UtRegisterTest("SCRConfTest02", SCRConfTest02, 1); - UtRegisterTest("SCRConfTest03", SCRConfTest03, 1); - UtRegisterTest("SCRConfTest04", SCRConfTest04, 1); - UtRegisterTest("SCRConfTest05", SCRConfTest05, 1); - UtRegisterTest("SCRConfTest06", SCRConfTest06, 1); + UtRegisterTest("SCRConfTest01", SCRConfTest01); + UtRegisterTest("SCRConfTest02", SCRConfTest02); + UtRegisterTest("SCRConfTest03", SCRConfTest03); + UtRegisterTest("SCRConfTest04", SCRConfTest04); + UtRegisterTest("SCRConfTest05", SCRConfTest05); + UtRegisterTest("SCRConfTest06", SCRConfTest06); #endif /* UNITTESTS */ return; diff --git a/src/util-reference-config.h b/src/util-reference-config.h index f5b7ddb296b5..f7fe4cc1ebdb 100644 --- a/src/util-reference-config.h +++ b/src/util-reference-config.h @@ -36,16 +36,18 @@ typedef struct SCRConfReference_ { SCRConfReference *SCRConfAllocSCRConfReference(const char *, const char *); void SCRConfDeAllocSCRConfReference(SCRConfReference *); -int SCRConfLoadReferenceConfigFile(DetectEngineCtx *); +int SCRConfLoadReferenceConfigFile(DetectEngineCtx *, FILE *); void SCRConfDeInitContext(DetectEngineCtx *); SCRConfReference *SCRConfGetReference(const char *, DetectEngineCtx *); void SCRConfRegisterTests(void); /* these below functions are only used by unittests */ -void SCRConfGenerateValidDummyReferenceConfigFD01(void); -void SCRConfGenerateInValidDummyReferenceConfigFD02(void); -void SCRConfGenerateInValidDummyReferenceConfigFD03(void); -void SCRConfDeleteDummyReferenceConfigFD(void); +FILE *SCRConfGenerateValidDummyReferenceConfigFD01(void); +FILE *SCRConfGenerateInValidDummyReferenceConfigFD02(void); +FILE *SCRConfGenerateInValidDummyReferenceConfigFD03(void); + +void SCReferenceConfInit(void); +void SCReferenceConfDeinit(void); #endif /* __UTIL_REFERENCE_CONFIG_H__ */ diff --git a/src/util-ringbuffer.c b/src/util-ringbuffer.c index 4566bf9f527a..e4457f40d4a1 100644 --- a/src/util-ringbuffer.c +++ b/src/util-ringbuffer.c @@ -1078,11 +1078,11 @@ static int RingBuffer8SrSwGet02 (void) void DetectRingBufferRegisterTests(void) { #ifdef UNITTESTS /* UNITTESTS */ - UtRegisterTest("RingBuffer8SrSwInit01", RingBuffer8SrSwInit01, 1); - UtRegisterTest("RingBuffer8SrSwPut01", RingBuffer8SrSwPut01, 1); - UtRegisterTest("RingBuffer8SrSwPut02", RingBuffer8SrSwPut02, 1); - UtRegisterTest("RingBuffer8SrSwGet01", RingBuffer8SrSwGet01, 1); - UtRegisterTest("RingBuffer8SrSwGet02", RingBuffer8SrSwGet02, 1); + UtRegisterTest("RingBuffer8SrSwInit01", RingBuffer8SrSwInit01); + UtRegisterTest("RingBuffer8SrSwPut01", RingBuffer8SrSwPut01); + UtRegisterTest("RingBuffer8SrSwPut02", RingBuffer8SrSwPut02); + UtRegisterTest("RingBuffer8SrSwGet01", RingBuffer8SrSwGet01); + UtRegisterTest("RingBuffer8SrSwGet02", RingBuffer8SrSwGet02); #endif /* UNITTESTS */ } diff --git a/src/util-rule-vars.c b/src/util-rule-vars.c index bf7515f82e23..12ced4d193e6 100644 --- a/src/util-rule-vars.c +++ b/src/util-rule-vars.c @@ -62,26 +62,39 @@ SCEnumCharMap sc_rule_vars_type_map[ ] = { * \retval conf_var_name_value Pointer to the string containing the conf value * on success; NULL on failure. */ -char *SCRuleVarsGetConfVar(const char *conf_var_name, +char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, + const char *conf_var_name, SCRuleVarsType conf_vars_type) { SCEnter(); const char *conf_var_type_name = NULL; - char conf_var_full_name[1024] = ""; + char conf_var_full_name[2048]; char *conf_var_full_name_value = NULL; if (conf_var_name == NULL) goto end; + + while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) { + conf_var_name++; + } + (conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name; conf_var_type_name = SCMapEnumValueToName(conf_vars_type, sc_rule_vars_type_map); if (conf_var_type_name == NULL) goto end; - if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s", - conf_var_type_name, conf_var_name) < 0) { - goto end; + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s.%s", + de_ctx->config_prefix, conf_var_type_name, conf_var_name) < 0) { + goto end; + } + } else { + if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s", + conf_var_type_name, conf_var_name) < 0) { + goto end; + } } if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) { @@ -180,44 +193,49 @@ int SCRuleVarsPositiveTest01(void) ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); /* check for address-groups */ - result &= (SCRuleVarsGetConfVar("$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), "[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:" "5AFE::/64,2001:888:13c5:CAFE::/64]") == 0); - result &= (SCRuleVarsGetConfVar("$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS), "[!192.168.0.0/16,2000::/3]") == 0); - result &= (SCRuleVarsGetConfVar("$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); - result &= (SCRuleVarsGetConfVar("$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); - result &= (SCRuleVarsGetConfVar("$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "!192.168.0.0/16") == 0); - result &= (SCRuleVarsGetConfVar("$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); - result &= (SCRuleVarsGetConfVar("$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); - result &= (SCRuleVarsGetConfVar("$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), + "any") == 0); + + /* Test that a leading space is stripped. */ + result &= (SCRuleVarsGetConfVar(NULL," $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL," $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS), "any") == 0); /* check for port-groups */ - result &= (SCRuleVarsGetConfVar("$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), "80:81,88") == 0); - result &= (SCRuleVarsGetConfVar("$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS), "80") == 0); - result &= (SCRuleVarsGetConfVar("$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS), "1521") == 0); - result &= (SCRuleVarsGetConfVar("$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && - strcmp(SCRuleVarsGetConfVar("$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), + result &= (SCRuleVarsGetConfVar(NULL,"$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0); ConfDeInit(); @@ -238,11 +256,11 @@ int SCRuleVarsNegativeTest02(void) ConfInit(); ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string)); - result &= (SCRuleVarsGetConfVar("$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); - result &= (SCRuleVarsGetConfVar("$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL); - result &= (SCRuleVarsGetConfVar("$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); - result &= (SCRuleVarsGetConfVar("$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL); + result &= (SCRuleVarsGetConfVar(NULL,"$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL); ConfDeInit(); ConfRestoreContextBackup(); @@ -422,16 +440,92 @@ int SCRuleVarsNegativeTest04(void) return result; } +static const char *dummy_mt_conf_string = + "%YAML 1.1\n" + "---\n" + "vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[1.2.3.4]\"\n" + " port-groups:\n" + " HTTP_PORTS: \"12345\"\n" + "multi-detect:\n" + " 0:\n" + " vars:\n" + "\n" + " address-groups:\n" + "\n" + " HOME_NET: \"[8.8.8.8]\"\n" + " port-groups:\n" + " HTTP_PORTS: \"54321\"\n" + "\n"; + +/** + * \test Check that valid address and port group vars are correctly retrieved + * from the configuration. + */ +int SCRuleVarsMTest01(void) +{ + int result = 0; + DetectEngineCtx *de_ctx = NULL; + + ConfCreateContextBackup(); + ConfInit(); + ConfYamlLoadString(dummy_mt_conf_string, strlen(dummy_mt_conf_string)); + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + return 0; + de_ctx->flags |= DE_QUIET; + snprintf(de_ctx->config_prefix, sizeof(de_ctx->config_prefix), + "multi-detect.0"); + + /* check for address-groups */ + result = (SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[8.8.8.8]") == 0); + if (result == 0) + goto end; + + result = (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS), + "[1.2.3.4]") == 0); + if (result == 0) + goto end; + + /* check for port-groups */ + result = (SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "54321") == 0); + if (result == 0) + goto end; + + result = (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL && + strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS), + "12345") == 0); + if (result == 0) + goto end; + +end: + ConfDeInit(); + ConfRestoreContextBackup(); + + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + return result; +} + #endif /* UNITTESTS */ void SCRuleVarsRegisterTests(void) { - #ifdef UNITTESTS - UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01, 1); - UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02, 1); - UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03, 1); - UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04, 1); + UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01); + UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02); + UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03); + UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04); + + UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01); #endif return; diff --git a/src/util-rule-vars.h b/src/util-rule-vars.h index 35f677ffb6d9..57d161e9f154 100644 --- a/src/util-rule-vars.h +++ b/src/util-rule-vars.h @@ -30,7 +30,7 @@ typedef enum { SC_RULE_VARS_PORT_GROUPS, } SCRuleVarsType; -char *SCRuleVarsGetConfVar(const char *, SCRuleVarsType); +char *SCRuleVarsGetConfVar(const DetectEngineCtx *, const char *, SCRuleVarsType); void SCRuleVarsRegisterTests(void); #endif /* __UTIL_RULE_VARS_H__ */ diff --git a/src/util-runmodes.c b/src/util-runmodes.c index e4cd5e0139d1..e4b05a64ad74 100644 --- a/src/util-runmodes.c +++ b/src/util-runmodes.c @@ -32,6 +32,8 @@ #include "runmode-af-packet.h" #include "log-httplog.h" #include "output.h" + +#include "detect-engine.h" #include "detect-engine-mpm.h" #include "alert-fastlog.h" @@ -47,249 +49,7 @@ #include "util-runmodes.h" -int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, - ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, - const char *live_dev) -{ - /* Available cpus */ - uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - int nlive = LiveGetDeviceCount(); - TmModule *tm_module; - char tname[TM_THREAD_NAME_MAX]; - int thread; - - if (de_ctx == NULL) { - SCLogError(SC_ERR_RUNMODE, "can't use runmode 'auto' when detection is disabled"); - return -1; - } - - if ((nlive <= 1) && (live_dev != NULL)) { - void *aconf; - SCLogDebug("live_dev %s", live_dev); - - aconf = ConfigParser(live_dev); - if (aconf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Single dev: Failed to allocate config"); - exit(EXIT_FAILURE); - } - - if (ModThreadsCount(aconf) > 1) { - SCLogWarning(SC_ERR_UNIMPLEMENTED, "'Auto' running mode does not honor 'threads'" - " variable (set on '%s'). Please use another mode as" - " 'autofp' or 'worker'", - live_dev); - } - - /* create the threads */ - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(recv_mod_name, - "packetpool", "packetpool", - "pickup-queue", "simple", - "pktacqloop"); - if (tv_receive == NULL) { - SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receive, tm_module, aconf); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } else { - SCLogInfo("Using %d live device(s).", nlive); - - for (thread = 0; thread < nlive; thread++) { - char *live_dev = LiveGetDeviceName(thread); - char *tnamec = NULL; - void *aconf; - - if (live_dev == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "Multidev: Failed to lookup live dev %d", thread); - exit(EXIT_FAILURE); - } - SCLogDebug("live_dev %s", live_dev); - - aconf = ConfigParser(live_dev); - if (aconf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate config for %s (%d)", - live_dev, thread); - exit(EXIT_FAILURE); - } - - if (ModThreadsCount(aconf) > 1) { - SCLogWarning(SC_ERR_UNIMPLEMENTED, "'Auto' running mode does not honor 'threads'" - " variable (set on '%s'). Please use another mode as" - " 'autofp' or 'worker'", - live_dev); - } - - snprintf(tname, sizeof(tname),"%s-%s", thread_name, live_dev); - tnamec = SCStrdup(tname); - if (unlikely(tnamec == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } - - /* create the threads */ - ThreadVars *tv_receive = - TmThreadCreatePacketHandler(tnamec, - "packetpool", "packetpool", - "pickup-queue", "simple", - "pktacqloop"); - if (tv_receive == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receive, tm_module, (void *)aconf); - - TmThreadSetCPU(tv_receive, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receive) != TM_ECODE_OK) { - SCLogError(SC_ERR_INVALID_VALUE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - } - - ThreadVars *tv_decode1 = - TmThreadCreatePacketHandler("Decode & Stream", - "pickup-queue", "simple", - "stream-queue1", "simple", - "varslot"); - if (tv_decode1 == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); - - tm_module = TmModuleGetByName("StreamTcp"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode1, tm_module, NULL); - - TmThreadSetCPU(tv_decode1, DECODE_CPU_SET); - - if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); - if (thread_max == 0) - thread_max = ncpus * threading_detect_ratio; - if (thread_max < 1) - thread_max = 1; - - for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname),"Detect%"PRIu16, thread+1); - - char *thread_name = SCStrdup(tname); - - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, - "stream-queue1", "simple", - "verdict-queue", "simple", - "1slot"); - if (tv_detect_ncpu == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - - ThreadVars *tv_rreject = - TmThreadCreatePacketHandler("RespondReject", - "verdict-queue", "simple", - "alert-queue", "simple", - "1slot"); - if (tv_rreject == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for RespondReject failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_rreject, tm_module, NULL); - - TmThreadSetCPU(tv_rreject, REJECT_CPU_SET); - - if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - ThreadVars *tv_outputs = - TmThreadCreatePacketHandler("Outputs", - "alert-queue", "simple", - "packetpool", "packetpool", - "varslot"); - if (tv_outputs == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); - exit(EXIT_FAILURE); - } - - SetupOutputs(tv_outputs); - - TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); - - if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - return 0; -} +#include "flow-hash.h" /** \brief create a queue string for autofp to pass to * the flow queue handler. @@ -315,7 +75,7 @@ char *RunmodeAutoFpCreatePickupQueuesString(int n) if (strlen(queues) > 0) strlcat(queues, ",", queues_size); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); strlcat(queues, qname, queues_size); } @@ -324,13 +84,12 @@ char *RunmodeAutoFpCreatePickupQueuesString(int n) } /** - * \param de_ctx detection engine, can be NULL */ -int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, +int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, + const char *thread_name, const char *live_dev) { char tname[TM_THREAD_NAME_MAX]; @@ -340,7 +99,7 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nlive = LiveGetDeviceCount(); - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); /* always create at least one thread */ if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; @@ -372,14 +131,9 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s%"PRIu16, thread_name, thread+1); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } + snprintf(tname, sizeof(tname), "%s#%02d", thread_name, thread+1); ThreadVars *tv_receive = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { @@ -415,34 +169,31 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, int lthread; for (lthread = 0; lthread < nlive; lthread++) { - char *live_dev = LiveGetDeviceName(lthread); + const char *dev = LiveGetDeviceName(lthread); + const char *visual_devname = LiveGetShortName(live_dev); void *aconf; int threads_count; - if (live_dev == NULL) { + if (dev == NULL) { SCLogError(SC_ERR_RUNMODE, "Failed to lookup live dev %d", lthread); exit(EXIT_FAILURE); } - SCLogDebug("live_dev %s", live_dev); + SCLogDebug("dev %s", dev); - aconf = ConfigParser(live_dev); + aconf = ConfigParser(dev); if (aconf == NULL) { SCLogError(SC_ERR_RUNMODE, "Multidev: Failed to allocate config for %s (%d)", - live_dev, lthread); + dev, lthread); exit(EXIT_FAILURE); } threads_count = ModThreadsCount(aconf); for (thread = 0; thread < threads_count; thread++) { - snprintf(tname, sizeof(tname), "%s%s%"PRIu16, thread_name, - live_dev, thread+1); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } + snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, + thread+1, visual_devname); + ThreadVars *tv_receive = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { @@ -474,18 +225,13 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "packetpool", "packetpool", "varslot"); @@ -493,31 +239,16 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName("StreamTcp"); + TmModule *tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - } - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { @@ -526,9 +257,6 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - /* add outputs as well */ - SetupOutputs(tv_detect_ncpu); - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); exit(EXIT_FAILURE); @@ -540,12 +268,10 @@ int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, } /** - * \param de_ctx detection engine, can be NULL */ -static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, - ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, +static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc ModThreadsCount, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev, void *aconf, unsigned char single_mode) { @@ -562,22 +288,17 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, /* create the threads */ for (thread = 0; thread < threads_count; thread++) { char tname[TM_THREAD_NAME_MAX]; - char *n_thread_name = NULL; ThreadVars *tv = NULL; TmModule *tm_module = NULL; + const char *visual_devname = LiveGetShortName(live_dev); if (single_mode) { - snprintf(tname, sizeof(tname), "%s", thread_name); + snprintf(tname, sizeof(tname), "%s#01-%s", thread_name, visual_devname); } else { - snprintf(tname, sizeof(tname), "%s%s%"PRIu16, - thread_name, live_dev, thread+1); + snprintf(tname, sizeof(tname), "%s#%02d-%s", thread_name, + thread+1, visual_devname); } - n_thread_name = SCStrdup(tname); - if (unlikely(n_thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } - tv = TmThreadCreatePacketHandler(n_thread_name, + tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -600,23 +321,13 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - } - tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName RespondReject failed"); @@ -624,9 +335,7 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv, tm_module, NULL); - SetupOutputs(tv); - - TmThreadSetCPU(tv, DETECT_CPU_SET); + TmThreadSetCPU(tv, WORKER_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed"); @@ -637,11 +346,10 @@ static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx, return 0; } -int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, +int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) { int nlive = LiveGetDeviceCount(); @@ -649,10 +357,10 @@ int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, int ldev; for (ldev = 0; ldev < nlive; ldev++) { - char *live_dev_c = NULL; - if (live_dev != NULL) { + const char *live_dev_c = NULL; + if ((nlive <= 1) && (live_dev != NULL)) { aconf = ConfigParser(live_dev); - live_dev_c = SCStrdup(live_dev); + live_dev_c = live_dev; if (unlikely(live_dev_c == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate interface name"); exit(EXIT_FAILURE); @@ -661,8 +369,7 @@ int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, live_dev_c = LiveGetDeviceName(ldev); aconf = ConfigParser(live_dev_c); } - RunModeSetLiveCaptureWorkersForDevice(de_ctx, - ModThreadsCount, + RunModeSetLiveCaptureWorkersForDevice(ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, @@ -674,14 +381,14 @@ int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, return 0; } -int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc ConfigParser, +int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev) { int nlive = LiveGetDeviceCount(); + const char *live_dev_c = NULL; void *aconf; if (nlive > 1) { @@ -692,243 +399,36 @@ int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, if (live_dev != NULL) { aconf = ConfigParser(live_dev); + live_dev_c = live_dev; } else { - char *live_dev_c = LiveGetDeviceName(0); + live_dev_c = LiveGetDeviceName(0); aconf = ConfigParser(live_dev_c); /* \todo Set threads number in config to 1 */ } - return RunModeSetLiveCaptureWorkersForDevice(de_ctx, + return RunModeSetLiveCaptureWorkersForDevice( ModThreadsCount, recv_mod_name, decode_mod_name, thread_name, - live_dev, + live_dev_c, aconf, 1); } -int RunModeSetIPSAuto(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name) -{ - SCEnter(); - char tname[TM_THREAD_NAME_MAX]; - TmModule *tm_module ; - char *cur_queue = NULL; - - /* Available cpus */ - uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); - int nqueue = LiveGetDeviceCount(); - - if (de_ctx == NULL) { - SCLogError(SC_ERR_RUNMODE, "can't use runmode 'auto' when detection is disabled"); - return -1; - } - - for (int i = 0; i < nqueue; i++) { - /* create the threads */ - cur_queue = LiveGetDeviceName(i); - if (cur_queue == NULL) { - SCLogError(SC_ERR_RUNMODE, "invalid queue number"); - exit(EXIT_FAILURE); - } - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "failed to create thread name"); - exit(EXIT_FAILURE); - } - ThreadVars *tv_receivenfq = - TmThreadCreatePacketHandler(thread_name, - "packetpool", "packetpool", - "pickup-queue", "simple", - "1slot_noinout"); - if (tv_receivenfq == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(recv_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_receivenfq, tm_module, (void *) ConfigParser(i)); - - TmThreadSetCPU(tv_receivenfq, RECEIVE_CPU_SET); - - if (TmThreadSpawn(tv_receivenfq) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - - /* decode and stream */ - ThreadVars *tv_decode = - TmThreadCreatePacketHandler("Decode1", - "pickup-queue", "simple", - "decode-queue", "simple", - "varslot"); - if (tv_decode == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed for Decode1"); - exit(EXIT_FAILURE); - } - - tm_module = TmModuleGetByName(decode_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", decode_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode,tm_module,NULL); - - tm_module = TmModuleGetByName("StreamTcp"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_decode, tm_module, NULL); - - TmThreadSetCPU(tv_decode, DECODE_CPU_SET); - - if (TmThreadSpawn(tv_decode) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - /* always create at least one thread */ - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); - if (thread_max == 0) - thread_max = ncpus * threading_detect_ratio; - if (thread_max < 1) - thread_max = 1; - - int thread; - for (thread = 0; thread < thread_max; thread++) { - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "thread name creation failed"); - exit(EXIT_FAILURE); - } - SCLogDebug("Assigning %s affinity", thread_name); - - ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, - "decode-queue", "simple", - "verdict-queue", "simple", - "1slot"); - if (tv_detect_ncpu == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; - - if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - } - - /* create the threads */ - for (int i = 0; i < nqueue; i++) { - memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Verdict%"PRIu16, i); - - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "thread name creation failed"); - exit(EXIT_FAILURE); - } - ThreadVars *tv_verdict = - TmThreadCreatePacketHandler(thread_name, - "verdict-queue", "simple", - "alert-queue", "simple", - "varslot"); - if (tv_verdict == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); - exit(EXIT_FAILURE); - } - tm_module = TmModuleGetByName(verdict_mod_name); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_verdict, tm_module, (void *)ConfigParser(i)); - - tm_module = TmModuleGetByName("RespondReject"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for RespondReject failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppend(tv_verdict, tm_module, NULL); - - TmThreadSetCPU(tv_verdict, VERDICT_CPU_SET); - - if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - }; - - ThreadVars *tv_outputs = - TmThreadCreatePacketHandler("Outputs", - "alert-queue", "simple", - "packetpool", "packetpool", - "varslot"); - - if (tv_outputs == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmThreadCreatePacketHandler for Outputs failed"); - exit(EXIT_FAILURE); - } - - TmThreadSetCPU(tv_outputs, OUTPUT_CPU_SET); - - SetupOutputs(tv_outputs); - if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) { - SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); - exit(EXIT_FAILURE); - } - - return 0; - -} - /** - * \param de_ctx detection engine, can be NULL */ -int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name) +int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name) { SCEnter(); char tname[TM_THREAD_NAME_MAX]; char qname[TM_QUEUE_NAME_MAX]; TmModule *tm_module ; - char *cur_queue = NULL; + const char *cur_queue = NULL; char *queues = NULL; int thread; @@ -936,7 +436,7 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); int nqueue = LiveGetDeviceCount(); - int thread_max = TmThreadGetNbThreads(DETECT_CPU_SET); + int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET); /* always create at least one thread */ if (thread_max == 0) thread_max = ncpus * threading_detect_ratio; @@ -957,22 +457,17 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Recv-Q%s", cur_queue); + snprintf(tname, sizeof(tname), "%s-Q%s", thread_name_autofp, cur_queue); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "thread name creation failed"); - exit(EXIT_FAILURE); - } ThreadVars *tv_receive = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", queues, "flow", "pktacqloop"); if (tv_receive == NULL) { SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName(recv_mod_name); + tm_module = TmModuleGetByName(recv_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName failed for %s", recv_mod_name); exit(EXIT_FAILURE); @@ -995,18 +490,13 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, } for (thread = 0; thread < thread_max; thread++) { - snprintf(tname, sizeof(tname), "Detect%"PRIu16, thread+1); - snprintf(qname, sizeof(qname), "pickup%"PRIu16, thread+1); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_workers, thread+1); + snprintf(qname, sizeof(qname), "pickup%d", thread+1); SCLogDebug("tname %s, qname %s", tname, qname); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate thread name"); - exit(EXIT_FAILURE); - } ThreadVars *tv_detect_ncpu = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, qname, "flow", "verdict-queue", "simple", "varslot"); @@ -1014,33 +504,17 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, SCLogError(SC_ERR_RUNMODE, "TmThreadsCreate failed"); exit(EXIT_FAILURE); } - TmModule *tm_module = TmModuleGetByName("StreamTcp"); + + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv_detect_ncpu, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv_detect_ncpu, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - } - - TmThreadSetCPU(tv_detect_ncpu, DETECT_CPU_SET); + TmThreadSetCPU(tv_detect_ncpu, WORKER_CPU_SET); - SetupOutputs(tv_detect_ncpu); - - char *thread_group_name = SCStrdup("Detect"); - if (unlikely(thread_group_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv_detect_ncpu->thread_group_name = thread_group_name; + TmThreadSetGroupName(tv_detect_ncpu, "Detect"); if (TmThreadSpawn(tv_detect_ncpu) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); @@ -1051,15 +525,10 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, /* create the threads */ for (int i = 0; i < nqueue; i++) { memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Verdict%"PRIu16, i); + snprintf(tname, sizeof(tname), "%s#%02d", thread_name_verdict, i); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } ThreadVars *tv_verdict = - TmThreadCreatePacketHandler(thread_name, + TmThreadCreatePacketHandler(tname, "verdict-queue", "simple", "packetpool", "packetpool", "varslot"); @@ -1094,18 +563,16 @@ int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, } /** - * \param de_ctx detection engine, can be NULL */ -int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name) +int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name) { char tname[TM_THREAD_NAME_MAX]; ThreadVars *tv = NULL; TmModule *tm_module = NULL; - char *cur_queue = NULL; + const char *cur_queue = NULL; int nqueue = LiveGetDeviceCount(); @@ -1117,14 +584,9 @@ int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, exit(EXIT_FAILURE); } memset(tname, 0, sizeof(tname)); - snprintf(tname, sizeof(tname), "Worker-Q%s", cur_queue); + snprintf(tname, sizeof(tname), "%s-Q%s", thread_name_workers, cur_queue); - char *thread_name = SCStrdup(tname); - if (unlikely(thread_name == NULL)) { - SCLogError(SC_ERR_RUNMODE, "Error allocating memory"); - exit(EXIT_FAILURE); - } - tv = TmThreadCreatePacketHandler(thread_name, + tv = TmThreadCreatePacketHandler(tname, "packetpool", "packetpool", "packetpool", "packetpool", "pktacqloop"); @@ -1147,30 +609,20 @@ int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv, tm_module, NULL); - tm_module = TmModuleGetByName("StreamTcp"); + tm_module = TmModuleGetByName("FlowWorker"); if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed"); + SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed"); exit(EXIT_FAILURE); } TmSlotSetFuncAppend(tv, tm_module, NULL); - if (de_ctx != NULL) { - tm_module = TmModuleGetByName("Detect"); - if (tm_module == NULL) { - SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed"); - exit(EXIT_FAILURE); - } - TmSlotSetFuncAppendDelayed(tv, tm_module, - (void *)de_ctx, de_ctx->delayed_detect); - } - tm_module = TmModuleGetByName(verdict_mod_name); if (tm_module == NULL) { SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name); exit(EXIT_FAILURE); } - TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx); + TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i)); tm_module = TmModuleGetByName("RespondReject"); if (tm_module == NULL) { @@ -1179,9 +631,7 @@ int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, } TmSlotSetFuncAppend(tv, tm_module, NULL); - SetupOutputs(tv); - - TmThreadSetCPU(tv, DETECT_CPU_SET); + TmThreadSetCPU(tv, WORKER_CPU_SET); if (TmThreadSpawn(tv) != TM_ECODE_OK) { SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed"); diff --git a/src/util-runmodes.h b/src/util-runmodes.h index 2d562c34727d..02d1323749e1 100644 --- a/src/util-runmodes.h +++ b/src/util-runmodes.h @@ -23,56 +23,46 @@ #ifndef __UTIL_RUNMODES_H__ #define __UTIL_RUNMODES_H__ +void RunmodeSetFlowStreamAsync(void); +int RunmodeGetFlowStreamAsync(void); typedef void *(*ConfigIfaceParserFunc) (const char *); typedef void *(*ConfigIPSParserFunc) (int); typedef int (*ConfigIfaceThreadsCountFunc) (void *); -int RunModeSetLiveCaptureAuto(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureAuto(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); -int RunModeSetLiveCaptureAutoFp(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); -int RunModeSetLiveCaptureSingle(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); -int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx, - ConfigIfaceParserFunc configparser, +int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc configparser, ConfigIfaceThreadsCountFunc ModThreadsCount, - char *recv_mod_name, - char *decode_mod_name, char *thread_name, + const char *recv_mod_name, + const char *decode_mod_name, const char *thread_name, const char *live_dev); -int RunModeSetIPSAuto(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name); +int RunModeSetIPSAutoFp(ConfigIPSParserFunc ConfigParser, + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name); -int RunModeSetIPSAutoFp(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name); - -int RunModeSetIPSWorker(DetectEngineCtx *de_ctx, - ConfigIPSParserFunc ConfigParser, - char *recv_mod_name, - char *verdict_mod_name, - char *decode_mod_name); +int RunModeSetIPSWorker(ConfigIPSParserFunc ConfigParser, + const char *recv_mod_name, + const char *verdict_mod_name, + const char *decode_mod_name); char *RunmodeAutoFpCreatePickupQueuesString(int n); diff --git a/src/util-running-modes.c b/src/util-running-modes.c index 8f30044dc7d2..30699c40c3c0 100644 --- a/src/util-running-modes.c +++ b/src/util-running-modes.c @@ -24,11 +24,19 @@ #include "config.h" #include "app-layer-detect-proto.h" #include "app-layer.h" +#include "app-layer-parser.h" #include "util-cuda.h" #include "util-unittest.h" +#include "util-debug.h" +#include "conf-yaml-loader.h" int ListKeywords(const char *keyword_info) { + if (ConfYamlLoadFile(DEFAULT_CONF_FILE) != -1) + SCLogLoadConfig(0, 0); + MpmTableSetup(); + SpmTableSetup(); + AppLayerSetup(); SigTableSetup(); /* load the rule keywords */ SigTableList(keyword_info); exit(EXIT_SUCCESS); @@ -36,7 +44,10 @@ int ListKeywords(const char *keyword_info) int ListAppLayerProtocols() { + if (ConfYamlLoadFile(DEFAULT_CONF_FILE) != -1) + SCLogLoadConfig(0, 0); MpmTableSetup(); + SpmTableSetup(); AppLayerSetup(); AppLayerListSupportedProtocols(); diff --git a/src/util-spm-bm.c b/src/util-spm-bm.c index 7c5b8d2d4d65..906927697ecd 100644 --- a/src/util-spm-bm.c +++ b/src/util-spm-bm.c @@ -34,6 +34,7 @@ #include "suricata.h" #include "util-spm-bm.h" +#include "util-spm.h" #include "util-debug.h" #include "util-error.h" #include "util-memcpy.h" @@ -73,7 +74,7 @@ void BoyerMooreCtxToNocase(BmCtx *bm_ctx, uint8_t *needle, uint16_t needle_len) * \retval BmCtx pointer to the newly created Context for the pattern * \initonly BoyerMoore contexts should be created at init */ -BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint16_t needle_len) +BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len) { BmCtx *new = SCMalloc(sizeof(BmCtx)); if (unlikely(new == NULL)) { @@ -302,7 +303,7 @@ static void PreBmGsNocase(const uint8_t *x, uint16_t m, uint16_t *bmGs) * * \retval ptr to start of the match; NULL if no match */ -uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx) +uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx) { uint16_t *bmGs = bm_ctx->bmGs; uint16_t *bmBc = bm_ctx->bmBc; @@ -324,7 +325,7 @@ uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx for (i = m - 1; i >= 0 && x[i] == y[i + j]; --i); if (i < 0) { - return y + j; + return (uint8_t *)(y + j); //j += bmGs[0]; } else { // printf("%c", y[i+j]); @@ -351,7 +352,7 @@ uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx * * \retval ptr to start of the match; NULL if no match */ -uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx) +uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx) { uint16_t *bmGs = bm_ctx->bmGs; uint16_t *bmBc = bm_ctx->bmBc; @@ -372,7 +373,7 @@ uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx * for (i = m - 1; i >= 0 && x[i] == u8_tolower(y[i + j]); --i); if (i < 0) { - return y + j; + return (uint8_t *)(y + j); } else { j += (m1=bmGs[i]) > (m2=bmBc[u8_tolower(y[i + j])] - m + 1 + i)?m1:m2; } @@ -380,3 +381,133 @@ uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx * return NULL; } +typedef struct SpmBmCtx_ { + BmCtx *bm_ctx; + uint8_t *needle; + uint16_t needle_len; + int nocase; +} SpmBmCtx; + +static SpmCtx *BMInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmCtx *ctx = SCMalloc(sizeof(SpmCtx)); + if (ctx == NULL) { + SCLogDebug("Unable to alloc SpmCtx."); + return NULL; + } + memset(ctx, 0, sizeof(*ctx)); + ctx->matcher = SPM_BM; + + SpmBmCtx *sctx = SCMalloc(sizeof(SpmBmCtx)); + if (sctx == NULL) { + SCLogDebug("Unable to alloc SpmBmCtx."); + SCFree(ctx); + return NULL; + } + memset(sctx, 0, sizeof(*sctx)); + + sctx->needle = SCMalloc(needle_len); + if (sctx->needle == NULL) { + SCLogDebug("Unable to alloc string."); + SCFree(sctx); + SCFree(ctx); + return NULL; + } + memcpy(sctx->needle, needle, needle_len); + sctx->needle_len = needle_len; + + if (nocase) { + sctx->bm_ctx = BoyerMooreNocaseCtxInit(sctx->needle, sctx->needle_len); + sctx->nocase = 1; + } else { + sctx->bm_ctx = BoyerMooreCtxInit(sctx->needle, sctx->needle_len); + sctx->nocase = 0; + } + + ctx->ctx = sctx; + return ctx; +} + +static void BMDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + + SpmBmCtx *sctx = ctx->ctx; + if (sctx != NULL) { + BoyerMooreCtxDeInit(sctx->bm_ctx); + if (sctx->needle != NULL) { + SCFree(sctx->needle); + } + SCFree(sctx); + } + + SCFree(ctx); +} + +static uint8_t *BMScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len) +{ + const SpmBmCtx *sctx = ctx->ctx; + + if (sctx->nocase) { + return BoyerMooreNocase(sctx->needle, sctx->needle_len, haystack, + haystack_len, sctx->bm_ctx); + } else { + return BoyerMoore(sctx->needle, sctx->needle_len, haystack, + haystack_len, sctx->bm_ctx); + } +} + +static SpmGlobalThreadCtx *BMInitGlobalThreadCtx(void) +{ + SpmGlobalThreadCtx *global_thread_ctx = SCMalloc(sizeof(SpmGlobalThreadCtx)); + if (global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + memset(global_thread_ctx, 0, sizeof(*global_thread_ctx)); + global_thread_ctx->matcher = SPM_BM; + return global_thread_ctx; +} + +static void BMDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + SCFree(global_thread_ctx); +} + +static void BMDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + SCFree(thread_ctx); +} + +static SpmThreadCtx *BMMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) { + SpmThreadCtx *thread_ctx = SCMalloc(sizeof(SpmThreadCtx)); + if (thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + memset(thread_ctx, 0, sizeof(*thread_ctx)); + thread_ctx->matcher = SPM_BM; + return thread_ctx; +} + +void SpmBMRegister(void) +{ + spm_table[SPM_BM].name = "bm"; + spm_table[SPM_BM].InitGlobalThreadCtx = BMInitGlobalThreadCtx; + spm_table[SPM_BM].DestroyGlobalThreadCtx = BMDestroyGlobalThreadCtx; + spm_table[SPM_BM].MakeThreadCtx = BMMakeThreadCtx; + spm_table[SPM_BM].DestroyThreadCtx = BMDestroyThreadCtx; + spm_table[SPM_BM].InitCtx = BMInitCtx; + spm_table[SPM_BM].DestroyCtx = BMDestroyCtx; + spm_table[SPM_BM].Scan = BMScan; +} diff --git a/src/util-spm-bm.h b/src/util-spm-bm.h index b3b97ced4bf5..a1c6b4c3158c 100644 --- a/src/util-spm-bm.h +++ b/src/util-spm-bm.h @@ -37,13 +37,15 @@ typedef struct BmCtx_ { } BmCtx; /** Prepare and return a Boyer Moore context */ -BmCtx *BoyerMooreCtxInit(uint8_t *needle, uint16_t needle_len); +BmCtx *BoyerMooreCtxInit(const uint8_t *needle, uint16_t needle_len); BmCtx *BoyerMooreNocaseCtxInit(uint8_t *needle, uint16_t needle_len); void BoyerMooreCtxToNocase(BmCtx *, uint8_t *, uint16_t); -uint8_t *BoyerMoore(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx); -uint8_t *BoyerMooreNocase(uint8_t *x, uint16_t m, uint8_t *y, int32_t n, BmCtx *bm_ctx); +uint8_t *BoyerMoore(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx); +uint8_t *BoyerMooreNocase(const uint8_t *x, uint16_t m, const uint8_t *y, int32_t n, BmCtx *bm_ctx); void BoyerMooreCtxDeInit(BmCtx *); +void SpmBMRegister(void); + #endif /* __UTIL_SPM_BM__ */ diff --git a/src/util-spm-hs.c b/src/util-spm-hs.c new file mode 100644 index 000000000000..898b6e9067a4 --- /dev/null +++ b/src/util-spm-hs.c @@ -0,0 +1,241 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Justin Viiret + * + * Single pattern matcher that uses the Hyperscan regex matcher. + */ + +#include "suricata-common.h" +#include "suricata.h" + +#include "util-hyperscan.h" +#include "util-spm-hs.h" + +#ifdef BUILD_HYPERSCAN + +#include + +/** + * \internal + * \brief Hyperscan match callback, called by hs_scan. + */ +static int MatchEvent(unsigned int id, unsigned long long from, + unsigned long long to, unsigned int flags, void *context) +{ + uint64_t *match_offset = context; + BUG_ON(*match_offset != UINT64_MAX); + *match_offset = to; + return 1; /* Terminate matching. */ +} + +typedef struct SpmHsCtx_ { + hs_database_t *db; + uint16_t needle_len; +} SpmHsCtx; + +static void HSDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + SpmHsCtx *sctx = ctx->ctx; + if (sctx) { + hs_free_database(sctx->db); + SCFree(sctx); + } + SCFree(ctx); +} + +static int HSBuildDatabase(const uint8_t *needle, uint16_t needle_len, + int nocase, SpmHsCtx *sctx, + SpmGlobalThreadCtx *global_thread_ctx) +{ + char *expr = HSRenderPattern(needle, needle_len); + if (expr == NULL) { + SCLogDebug("HSRenderPattern returned NULL"); + return -1; + } + + unsigned flags = nocase ? HS_FLAG_CASELESS : 0; + + hs_database_t *db = NULL; + hs_compile_error_t *compile_err = NULL; + hs_error_t err = hs_compile(expr, flags, HS_MODE_BLOCK, NULL, &db, + &compile_err); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to compile '%s' with Hyperscan, " + "returned %d.", expr, err); + exit(EXIT_FAILURE); + } + + SCFree(expr); + + /* Update scratch for this database. */ + hs_scratch_t *scratch = global_thread_ctx->ctx; + err = hs_alloc_scratch(db, &scratch); + if (err != HS_SUCCESS) { + /* If scratch allocation failed, this is not recoverable: other SPM + * contexts may need this scratch space. */ + SCLogError(SC_ERR_FATAL, + "Unable to alloc scratch for Hyperscan, returned %d.", err); + exit(EXIT_FAILURE); + } + global_thread_ctx->ctx = scratch; + sctx->db = db; + sctx->needle_len = needle_len; + + return 0; +} + +static SpmCtx *HSInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmCtx *ctx = SCMalloc(sizeof(SpmCtx)); + if (ctx == NULL) { + SCLogDebug("Unable to alloc SpmCtx."); + return NULL; + } + memset(ctx, 0, sizeof(SpmCtx)); + ctx->matcher = SPM_HS; + + SpmHsCtx *sctx = SCMalloc(sizeof(SpmHsCtx)); + if (sctx == NULL) { + SCLogDebug("Unable to alloc SpmHsCtx."); + SCFree(ctx); + return NULL; + } + ctx->ctx = sctx; + + memset(sctx, 0, sizeof(SpmHsCtx)); + if (HSBuildDatabase(needle, needle_len, nocase, sctx, + global_thread_ctx) != 0) { + SCLogDebug("HSBuildDatabase failed."); + HSDestroyCtx(ctx); + return NULL; + } + + return ctx; +} + +static uint8_t *HSScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len) +{ + const SpmHsCtx *sctx = ctx->ctx; + hs_scratch_t *scratch = thread_ctx->ctx; + + if (unlikely(haystack_len == 0)) { + return NULL; + } + + uint64_t match_offset = UINT64_MAX; + hs_error_t err = hs_scan(sctx->db, (const char *)haystack, haystack_len, 0, + scratch, MatchEvent, &match_offset); + if (err != HS_SUCCESS && err != HS_SCAN_TERMINATED) { + /* An error value (other than HS_SCAN_TERMINATED) from hs_scan() + * indicates that it was passed an invalid database or scratch region, + * which is not something we can recover from at scan time. */ + SCLogError(SC_ERR_FATAL, "Hyperscan returned fatal error %d.", err); + exit(EXIT_FAILURE); + } + + if (match_offset == UINT64_MAX) { + return NULL; + } + + BUG_ON(match_offset < sctx->needle_len); + BUG_ON(match_offset > UINT16_MAX); /* haystack_len is a uint16_t */ + + /* Note: existing API returns non-const ptr */ + return (uint8_t *)haystack + (match_offset - sctx->needle_len); +} + +static SpmGlobalThreadCtx *HSInitGlobalThreadCtx(void) +{ + SpmGlobalThreadCtx *global_thread_ctx = SCMalloc(sizeof(SpmGlobalThreadCtx)); + if (global_thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmGlobalThreadCtx."); + return NULL; + } + memset(global_thread_ctx, 0, sizeof(*global_thread_ctx)); + global_thread_ctx->matcher = SPM_HS; + + /* We store scratch in the HS-specific ctx. This will be initialized as + * patterns are compiled by SpmInitCtx. */ + global_thread_ctx->ctx = NULL; + + return global_thread_ctx; +} + +static void HSDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + hs_free_scratch(global_thread_ctx->ctx); + SCFree(global_thread_ctx); +} + +static void HSDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + hs_free_scratch(thread_ctx->ctx); + SCFree(thread_ctx); +} + +static SpmThreadCtx *HSMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + SpmThreadCtx *thread_ctx = SCMalloc(sizeof(SpmThreadCtx)); + if (thread_ctx == NULL) { + SCLogDebug("Unable to alloc SpmThreadCtx."); + return NULL; + } + memset(thread_ctx, 0, sizeof(*thread_ctx)); + thread_ctx->matcher = SPM_HS; + + if (global_thread_ctx->ctx != NULL) { + hs_scratch_t *scratch = NULL; + hs_error_t err = hs_clone_scratch(global_thread_ctx->ctx, &scratch); + if (err != HS_SUCCESS) { + SCLogError(SC_ERR_FATAL, "Unable to clone scratch (error %d).", + err); + exit(EXIT_FAILURE); + } + thread_ctx->ctx = scratch; + } + + return thread_ctx; +} + +void SpmHSRegister(void) +{ + spm_table[SPM_HS].name = "hs"; + spm_table[SPM_HS].InitGlobalThreadCtx = HSInitGlobalThreadCtx; + spm_table[SPM_HS].DestroyGlobalThreadCtx = HSDestroyGlobalThreadCtx; + spm_table[SPM_HS].MakeThreadCtx = HSMakeThreadCtx; + spm_table[SPM_HS].DestroyThreadCtx = HSDestroyThreadCtx; + spm_table[SPM_HS].InitCtx = HSInitCtx; + spm_table[SPM_HS].DestroyCtx = HSDestroyCtx; + spm_table[SPM_HS].Scan = HSScan; +} + +#endif /* BUILD_HYPERSCAN */ diff --git a/src/util-spm-hs.h b/src/util-spm-hs.h new file mode 100644 index 000000000000..e362198819c8 --- /dev/null +++ b/src/util-spm-hs.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Justin Viiret + * + * Single pattern matcher that uses the Hyperscan regex matcher. + */ + +#ifndef __UTIL_SPM_HS_H__ +#define __UTIL_SPM_HS_H__ + +void SpmHSRegister(void); + +#endif /* __UTIL_SPM_HS_H__ */ diff --git a/src/util-spm.c b/src/util-spm.c index 2da12e77889e..52432b8adc0e 100644 --- a/src/util-spm.c +++ b/src/util-spm.c @@ -47,12 +47,148 @@ #include "suricata.h" #include "util-unittest.h" +#include "conf.h" + #include "util-spm.h" #include "util-spm-bs.h" #include "util-spm-bs2bm.h" #include "util-spm-bm.h" +#include "util-spm-hs.h" #include "util-clock.h" +#ifdef BUILD_HYPERSCAN +#include "hs.h" +#endif + +/** + * \brief Returns the single pattern matcher algorithm to be used, based on the + * spm-algo setting in yaml. + */ +uint16_t SinglePatternMatchDefaultMatcher(void) +{ + char *spm_algo; + if ((ConfGet("spm-algo", &spm_algo)) == 1) { + if (spm_algo != NULL) { + if (strcmp("auto", spm_algo) == 0) { + goto default_matcher; + } + for (uint16_t i = 0; i < SPM_TABLE_SIZE; i++) { + if (spm_table[i].name == NULL) { + continue; + } + if (strcmp(spm_table[i].name, spm_algo) == 0) { + return i; + } + } + } + + SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, + "Invalid spm algo supplied " + "in the yaml conf file: \"%s\"", + spm_algo); + exit(EXIT_FAILURE); + } + +default_matcher: + /* When Suricata is built with Hyperscan support, default to using it for + * SPM. */ +#ifdef BUILD_HYPERSCAN + #ifdef HAVE_HS_VALID_PLATFORM + /* Enable runtime check for SSSE3. Do not use Hyperscan SPM matcher if + * check is not successful. */ + if (hs_valid_platform() != HS_SUCCESS) { + SCLogInfo("SSSE3 support not detected, disabling Hyperscan for " + "SPM"); + /* Use Boyer-Moore as fallback. */ + return SPM_BM; + } else { + return SPM_HS; + } + #else + return SPM_HS; + #endif +#else + /* Otherwise, default to Boyer-Moore */ + return SPM_BM; +#endif +} + +void SpmTableSetup(void) +{ + memset(spm_table, 0, sizeof(spm_table)); + + SpmBMRegister(); +#ifdef BUILD_HYPERSCAN + #ifdef HAVE_HS_VALID_PLATFORM + if (hs_valid_platform() == HS_SUCCESS) { + SpmHSRegister(); + } + #else + SpmHSRegister(); + #endif +#endif +} + +SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint16_t matcher) +{ + BUG_ON(spm_table[matcher].InitGlobalThreadCtx == NULL); + return spm_table[matcher].InitGlobalThreadCtx(); +} + +void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return; + } + uint16_t matcher = global_thread_ctx->matcher; + spm_table[matcher].DestroyGlobalThreadCtx(global_thread_ctx); +} + +SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *global_thread_ctx) +{ + if (global_thread_ctx == NULL) { + return NULL; + } + uint16_t matcher = global_thread_ctx->matcher; + BUG_ON(spm_table[matcher].MakeThreadCtx == NULL); + return spm_table[matcher].MakeThreadCtx(global_thread_ctx); +} +void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx) +{ + if (thread_ctx == NULL) { + return; + } + uint16_t matcher = thread_ctx->matcher; + BUG_ON(spm_table[matcher].DestroyThreadCtx == NULL); + spm_table[matcher].DestroyThreadCtx(thread_ctx); +} + +SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *global_thread_ctx) +{ + BUG_ON(global_thread_ctx == NULL); + uint16_t matcher = global_thread_ctx->matcher; + BUG_ON(spm_table[matcher].InitCtx == NULL); + return spm_table[matcher].InitCtx(needle, needle_len, nocase, + global_thread_ctx); +} + +void SpmDestroyCtx(SpmCtx *ctx) +{ + if (ctx == NULL) { + return; + } + uint16_t matcher = ctx->matcher; + BUG_ON(spm_table[matcher].DestroyCtx == NULL); + spm_table[matcher].DestroyCtx(ctx); +} + +uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len) +{ + uint16_t matcher = ctx->matcher; + return spm_table[matcher].Scan(ctx, thread_ctx, haystack, haystack_len); +} /** * Wrappers for building context and searching (Bs2Bm and boyermoore) @@ -68,7 +204,8 @@ * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, + const uint8_t *needle, uint16_t needlelen) { uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); @@ -84,7 +221,8 @@ uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, + const uint8_t *needle, uint16_t needlelen) { uint8_t badchars[ALPHABET_SIZE]; Bs2BmBadchars(needle, needlelen, badchars); @@ -101,7 +239,8 @@ uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uin * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *BoyerMooreSearch(const uint8_t *text, uint32_t textlen, + const uint8_t *needle, uint16_t needlelen) { BmCtx *bm_ctx = BoyerMooreCtxInit(needle, needlelen); @@ -120,7 +259,8 @@ uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint * \param needle pattern to search for * \param needlelen length of the pattern */ -uint8_t *BoyerMooreNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen) +uint8_t *BoyerMooreNocaseSearch(const uint8_t *text, uint32_t textlen, + uint8_t *needle, uint16_t needlelen) { BmCtx *bm_ctx = BoyerMooreNocaseCtxInit(needle, needlelen); @@ -2312,56 +2452,284 @@ int UtilSpmNocaseSearchStatsTest07() return 1; } -#endif +/* Unit tests for new SPM API. */ -/* Register unittests */ -void UtilSpmSearchRegistertests(void) +#define SPM_NO_MATCH UINT32_MAX + +/* Helper structure describing a particular search. */ +typedef struct SpmTestData_ { + const char *needle; + uint16_t needle_len; + const char *haystack; + uint16_t haystack_len; + int nocase; + uint32_t match_offset; /* offset in haystack, or SPM_NO_MATCH. */ +} SpmTestData; + +/* Helper function to conduct a search with a particular SPM matcher. */ +static int SpmTestSearch(const SpmTestData *d, uint16_t matcher) { -#ifdef UNITTESTS - /* Generic tests */ - UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01, 1); - UtRegisterTest("UtilSpmBasicSearchNocaseTest01", UtilSpmBasicSearchNocaseTest01, 1); + int ret = 1; + SpmGlobalThreadCtx *global_thread_ctx = NULL; + SpmThreadCtx *thread_ctx = NULL; + SpmCtx *ctx = NULL; + uint8_t *found = NULL; - UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01, 1); - UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", UtilSpmBs2bmSearchNocaseTest01, 1); + global_thread_ctx = SpmInitGlobalThreadCtx(matcher); + if (global_thread_ctx == NULL) { + ret = 0; + goto exit; + } - UtRegisterTest("UtilSpmBoyerMooreSearchTest01", UtilSpmBoyerMooreSearchTest01, 1); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", UtilSpmBoyerMooreSearchNocaseTest01, 1); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTestIssue130", UtilSpmBoyerMooreSearchNocaseTestIssue130, 1); + ctx = SpmInitCtx((const uint8_t *)d->needle, d->needle_len, d->nocase, + global_thread_ctx); + if (ctx == NULL) { + ret = 0; + goto exit; + } - UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02, 1); - UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", UtilSpmBs2bmSearchNocaseTest02, 1); + thread_ctx = SpmMakeThreadCtx(global_thread_ctx); + if (thread_ctx == NULL) { + ret = 0; + goto exit; + } - UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02, 1); - UtRegisterTest("UtilSpmBasicSearchNocaseTest02", UtilSpmBasicSearchNocaseTest02, 1); + found = SpmScan(ctx, thread_ctx, (const uint8_t *)d->haystack, + d->haystack_len); + if (found == NULL) { + if (d->match_offset != SPM_NO_MATCH) { + printf(" should have matched at %" PRIu32 " but didn't\n", + d->match_offset); + ret = 0; + } + } else { + uint32_t offset = (uint32_t)(found - (const uint8_t *)d->haystack); + if (offset != d->match_offset) { + printf(" should have matched at %" PRIu32 + " but matched at %" PRIu32 "\n", + d->match_offset, offset); + ret = 0; + } + } - UtRegisterTest("UtilSpmBoyerMooreSearchTest02", UtilSpmBoyerMooreSearchTest02, 1); - UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", UtilSpmBoyerMooreSearchNocaseTest02, 1); +exit: + SpmDestroyCtx(ctx); + SpmDestroyThreadCtx(thread_ctx); + SpmDestroyGlobalThreadCtx(global_thread_ctx); + return ret; +} + +int SpmSearchTest01() { + SpmTableSetup(); + printf("\n"); + + /* Each of the following tests will be run against every registered SPM + * algorithm. */ + + static const SpmTestData data[] = { + /* Some trivial single-character case/nocase tests */ + {"a", 1, "a", 1, 0, 0}, + {"a", 1, "A", 1, 1, 0}, + {"A", 1, "A", 1, 0, 0}, + {"A", 1, "a", 1, 1, 0}, + {"a", 1, "A", 1, 0, SPM_NO_MATCH}, + {"A", 1, "a", 1, 0, SPM_NO_MATCH}, + /* Nulls and odd characters */ + {"\x00", 1, "test\x00test", 9, 0, 4}, + {"\x00", 1, "testtest", 8, 0, SPM_NO_MATCH}, + {"\n", 1, "new line\n", 9, 0, 8}, + {"\n", 1, "new line\x00\n", 10, 0, 9}, + {"\xff", 1, "abcdef\xff", 7, 0, 6}, + {"\xff", 1, "abcdef\xff", 7, 1, 6}, + {"$", 1, "dollar$", 7, 0, 6}, + {"^", 1, "caret^", 6, 0, 5}, + /* Longer literals */ + {"Suricata", 8, "This is a Suricata test", 23, 0, 10}, + {"Suricata", 8, "This is a suricata test", 23, 1, 10}, + {"Suricata", 8, "This is a suriCATA test", 23, 1, 10}, + {"suricata", 8, "This is a Suricata test", 23, 0, SPM_NO_MATCH}, + {"Suricata", 8, "This is a Suricat_ test", 23, 0, SPM_NO_MATCH}, + {"Suricata", 8, "This is a _uricata test", 23, 0, SPM_NO_MATCH}, + /* First occurrence with the correct case should match */ + {"foo", 3, "foofoofoo", 9, 0, 0}, + {"foo", 3, "_foofoofoo", 9, 0, 1}, + {"FOO", 3, "foofoofoo", 9, 1, 0}, + {"FOO", 3, "_foofoofoo", 9, 1, 1}, + {"FOO", 3, "foo Foo FOo fOo foO FOO", 23, 0, 20}, + {"foo", 3, "Foo FOo fOo foO FOO foo", 23, 0, 20}, + }; + + int ret = 1; + + uint16_t matcher; + for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { + const SpmTableElmt *m = &spm_table[matcher]; + if (m->name == NULL) { + continue; + } + printf("matcher: %s\n", m->name); + + uint32_t i; + for (i = 0; i < sizeof(data)/sizeof(data[0]); i++) { + const SpmTestData *d = &data[i]; + if (SpmTestSearch(d, matcher) == 0) { + printf(" test %" PRIu32 ": fail\n", i); + ret = 0; + } + } + printf(" %" PRIu32 " tests passed\n", i); + } + + return ret; +} + +int SpmSearchTest02() { + SpmTableSetup(); + printf("\n"); + + /* Test that we can find needles of various lengths at various alignments + * in the haystack. Note that these are passed to strlen. */ + + static const char* needles[] = { + /* Single bytes */ + "a", "b", "c", ":", "/", "\x7f", "\xff", + /* Repeats */ + "aa", "aaa", "aaaaaaaaaaaaaaaaaaaaaaa", + /* Longer literals */ + "suricata", "meerkat", "aardvark", "raptor", "marmot", "lemming", + /* Mixed case */ + "Suricata", "CAPS LOCK", "mIxEd cAsE", + }; + + int ret = 1; + + uint16_t matcher; + for (matcher = 0; matcher < SPM_TABLE_SIZE; matcher++) { + const SpmTableElmt *m = &spm_table[matcher]; + if (m->name == NULL) { + continue; + } + printf("matcher: %s\n", m->name); + + SpmTestData d; + + uint32_t i; + for (i = 0; i < sizeof(needles) / sizeof(needles[0]); i++) { + const char *needle = needles[i]; + uint16_t prefix; + for (prefix = 0; prefix < 32; prefix++) { + d.needle = needle; + d.needle_len = strlen(needle); + uint16_t haystack_len = prefix + d.needle_len; + char *haystack = SCMalloc(haystack_len); + if (haystack == NULL) { + printf("alloc failure\n"); + return 0; + } + memset(haystack, ' ', haystack_len); + memcpy(haystack + prefix, d.needle, d.needle_len); + d.haystack = haystack; + d.haystack_len = haystack_len; + d.nocase = 0; + d.match_offset = prefix; + + /* Case-sensitive scan */ + if (SpmTestSearch(&d, matcher) == 0) { + printf(" test %" PRIu32 ": fail (case-sensitive)\n", i); + ret = 0; + } + + /* Case-insensitive scan */ + d.nocase = 1; + uint16_t j; + for (j = 0; j < haystack_len; j++) { + haystack[j] = toupper(haystack[j]); + } + if (SpmTestSearch(&d, matcher) == 0) { + printf(" test %" PRIu32 ": fail (case-insensitive)\n", i); + ret = 0; + } + + SCFree(haystack); + } + } + printf(" %" PRIu32 " tests passed\n", i); + } + + return ret; +} + +#endif + +/* Register unittests */ +void UtilSpmSearchRegistertests(void) +{ +#ifdef UNITTESTS + /* Generic tests */ + UtRegisterTest("UtilSpmBasicSearchTest01", UtilSpmBasicSearchTest01); + UtRegisterTest("UtilSpmBasicSearchNocaseTest01", + UtilSpmBasicSearchNocaseTest01); + + UtRegisterTest("UtilSpmBs2bmSearchTest01", UtilSpmBs2bmSearchTest01); + UtRegisterTest("UtilSpmBs2bmSearchNocaseTest01", + UtilSpmBs2bmSearchNocaseTest01); + + UtRegisterTest("UtilSpmBoyerMooreSearchTest01", + UtilSpmBoyerMooreSearchTest01); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest01", + UtilSpmBoyerMooreSearchNocaseTest01); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTestIssue130", + UtilSpmBoyerMooreSearchNocaseTestIssue130); + + UtRegisterTest("UtilSpmBs2bmSearchTest02", UtilSpmBs2bmSearchTest02); + UtRegisterTest("UtilSpmBs2bmSearchNocaseTest02", + UtilSpmBs2bmSearchNocaseTest02); + + UtRegisterTest("UtilSpmBasicSearchTest02", UtilSpmBasicSearchTest02); + UtRegisterTest("UtilSpmBasicSearchNocaseTest02", + UtilSpmBasicSearchNocaseTest02); + + UtRegisterTest("UtilSpmBoyerMooreSearchTest02", + UtilSpmBoyerMooreSearchTest02); + UtRegisterTest("UtilSpmBoyerMooreSearchNocaseTest02", + UtilSpmBoyerMooreSearchNocaseTest02); /* test matches at any offset */ - UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01, 1); - UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", UtilSpmSearchOffsetsNocaseTest01, 1); + UtRegisterTest("UtilSpmSearchOffsetsTest01", UtilSpmSearchOffsetsTest01); + UtRegisterTest("UtilSpmSearchOffsetsNocaseTest01", + UtilSpmSearchOffsetsNocaseTest01); + + /* new SPM API */ + UtRegisterTest("SpmSearchTest01", SpmSearchTest01); + UtRegisterTest("SpmSearchTest02", SpmSearchTest02); #ifdef ENABLE_SEARCH_STATS /* Give some stats searching given a prepared context (look at the wrappers) */ - UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01, 1); - UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02, 1); - UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03, 1); + UtRegisterTest("UtilSpmSearchStatsTest01", UtilSpmSearchStatsTest01); + UtRegisterTest("UtilSpmSearchStatsTest02", UtilSpmSearchStatsTest02); + UtRegisterTest("UtilSpmSearchStatsTest03", UtilSpmSearchStatsTest03); - UtRegisterTest("UtilSpmNocaseSearchStatsTest01", UtilSpmNocaseSearchStatsTest01, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest02", UtilSpmNocaseSearchStatsTest02, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest03", UtilSpmNocaseSearchStatsTest03, 1); + UtRegisterTest("UtilSpmNocaseSearchStatsTest01", + UtilSpmNocaseSearchStatsTest01); + UtRegisterTest("UtilSpmNocaseSearchStatsTest02", + UtilSpmNocaseSearchStatsTest02); + UtRegisterTest("UtilSpmNocaseSearchStatsTest03", + UtilSpmNocaseSearchStatsTest03); /* Stats building context and searching */ - UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04, 1); - UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05, 1); - UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06, 1); - UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07, 1); - - UtRegisterTest("UtilSpmNocaseSearchStatsTest04", UtilSpmNocaseSearchStatsTest04, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest05", UtilSpmNocaseSearchStatsTest05, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest06", UtilSpmNocaseSearchStatsTest06, 1); - UtRegisterTest("UtilSpmNocaseSearchStatsTest07", UtilSpmNocaseSearchStatsTest07, 1); + UtRegisterTest("UtilSpmSearchStatsTest04", UtilSpmSearchStatsTest04); + UtRegisterTest("UtilSpmSearchStatsTest05", UtilSpmSearchStatsTest05); + UtRegisterTest("UtilSpmSearchStatsTest06", UtilSpmSearchStatsTest06); + UtRegisterTest("UtilSpmSearchStatsTest07", UtilSpmSearchStatsTest07); + + UtRegisterTest("UtilSpmNocaseSearchStatsTest04", + UtilSpmNocaseSearchStatsTest04); + UtRegisterTest("UtilSpmNocaseSearchStatsTest05", + UtilSpmNocaseSearchStatsTest05); + UtRegisterTest("UtilSpmNocaseSearchStatsTest06", + UtilSpmNocaseSearchStatsTest06); + UtRegisterTest("UtilSpmNocaseSearchStatsTest07", + UtilSpmNocaseSearchStatsTest07); #endif #endif diff --git a/src/util-spm.h b/src/util-spm.h index 2dea657ee607..a29da29d32d9 100644 --- a/src/util-spm.h +++ b/src/util-spm.h @@ -28,11 +28,74 @@ #include "util-spm-bs2bm.h" #include "util-spm-bm.h" +enum { + SPM_BM, /* Boyer-Moore */ + SPM_HS, /* Hyperscan */ + /* Other SPM matchers will go here. */ + SPM_TABLE_SIZE +}; + +uint16_t SinglePatternMatchDefaultMatcher(void); + +/** Structure holding an immutable "built" SPM matcher (such as the Boyer-Moore + * tables, Hyperscan database etc) that is passed to the Scan call. */ +typedef struct SpmCtx_ { + uint16_t matcher; + void *ctx; +} SpmCtx; + +/** Structure holding a global prototype for per-thread scratch space, passed + * to each InitCtx call. */ +typedef struct SpmGlobalThreadCtx_ { + uint16_t matcher; + void *ctx; +} SpmGlobalThreadCtx; + +/** Structure holding some mutable per-thread space for use by a matcher at + * scan time. Constructed from SpmGlobalThreadCtx by the MakeThreadCtx call. */ +typedef struct SpmThreadCtx_ { + uint16_t matcher; + void *ctx; +} SpmThreadCtx; + +typedef struct SpmTableElmt_ { + const char *name; + SpmGlobalThreadCtx *(*InitGlobalThreadCtx)(void); + void (*DestroyGlobalThreadCtx)(SpmGlobalThreadCtx *g_thread_ctx); + SpmThreadCtx *(*MakeThreadCtx)(const SpmGlobalThreadCtx *g_thread_ctx); + void (*DestroyThreadCtx)(SpmThreadCtx *thread_ctx); + SpmCtx *(*InitCtx)(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *g_thread_ctx); + void (*DestroyCtx)(SpmCtx *); + uint8_t *(*Scan)(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len); +} SpmTableElmt; + +SpmTableElmt spm_table[SPM_TABLE_SIZE]; + +void SpmTableSetup(void); + +SpmGlobalThreadCtx *SpmInitGlobalThreadCtx(uint16_t matcher); + +void SpmDestroyGlobalThreadCtx(SpmGlobalThreadCtx *g_thread_ctx); + +SpmThreadCtx *SpmMakeThreadCtx(const SpmGlobalThreadCtx *g_thread_ctx); + +void SpmDestroyThreadCtx(SpmThreadCtx *thread_ctx); + +SpmCtx *SpmInitCtx(const uint8_t *needle, uint16_t needle_len, int nocase, + SpmGlobalThreadCtx *g_thread_ctx); + +void SpmDestroyCtx(SpmCtx *ctx); + +uint8_t *SpmScan(const SpmCtx *ctx, SpmThreadCtx *thread_ctx, + const uint8_t *haystack, uint16_t haystack_len); + /** Default algorithm to use: Boyer Moore */ -uint8_t *Bs2bmSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); -uint8_t *Bs2bmNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); -uint8_t *BoyerMooreSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); -uint8_t *BoyerMooreNocaseSearch(uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); +uint8_t *Bs2bmSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *Bs2bmNocaseSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *BoyerMooreSearch(const uint8_t *text, uint32_t textlen, const uint8_t *needle, uint16_t needlelen); +uint8_t *BoyerMooreNocaseSearch(const uint8_t *text, uint32_t textlen, uint8_t *needle, uint16_t needlelen); /* Macros for automatic algorithm selection (use them only when you can't store the context) */ #define SpmSearch(text, textlen, needle, needlelen) ({\ diff --git a/src/util-storage.c b/src/util-storage.c index cfba8461a036..5c4c0e05bb9b 100644 --- a/src/util-storage.c +++ b/src/util-storage.c @@ -54,6 +54,8 @@ const char *StoragePrintType(StorageEnum type) return "host"; case STORAGE_FLOW: return "flow"; + case STORAGE_IPPAIR: + return "ippair"; case STORAGE_MAX: return "max"; } @@ -536,8 +538,8 @@ static int StorageTest03(void) void StorageRegisterTests(void) { - UtRegisterTest("StorageTest01", StorageTest01, 1); - UtRegisterTest("StorageTest02", StorageTest02, 1); - UtRegisterTest("StorageTest03", StorageTest03, 1); + UtRegisterTest("StorageTest01", StorageTest01); + UtRegisterTest("StorageTest02", StorageTest02); + UtRegisterTest("StorageTest03", StorageTest03); } #endif diff --git a/src/util-storage.h b/src/util-storage.h index 0165ad5d55d0..d88b030fbd96 100644 --- a/src/util-storage.h +++ b/src/util-storage.h @@ -29,6 +29,7 @@ typedef enum StorageEnum_ { STORAGE_HOST, STORAGE_FLOW, + STORAGE_IPPAIR, STORAGE_MAX, } StorageEnum; diff --git a/src/util-streaming-buffer.c b/src/util-streaming-buffer.c new file mode 100644 index 000000000000..9305a41ef126 --- /dev/null +++ b/src/util-streaming-buffer.c @@ -0,0 +1,745 @@ +/* Copyright (C) 2015-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "util-streaming-buffer.h" +#include "util-unittest.h" +#include "util-print.h" + +/** + * \file + * + * \author Victor Julien + * + * \brief Streaming Buffer API + */ + +/* memory handling wrappers. If config doesn't define it's own set of + * functions, use the defaults */ +#define MALLOC(cfg, s) \ + (cfg)->Malloc ? (cfg)->Malloc((s)) : SCMalloc((s)) +#define CALLOC(cfg, n, s) \ + (cfg)->Calloc ? (cfg)->Calloc((n), (s)) : SCCalloc((n), (s)) +#define REALLOC(cfg, ptr, orig_s, s) \ + (cfg)->Realloc ? (cfg)->Realloc((ptr), (orig_s), (s)) : SCRealloc((ptr), (s)) +#define FREE(cfg, ptr, s) \ + (cfg)->Free ? (cfg)->Free((ptr), (s)) : SCFree((ptr)) + +static inline int InitBuffer(StreamingBuffer *sb) +{ + sb->buf = CALLOC(sb->cfg, 1, sb->cfg->buf_size); + if (sb->buf == NULL) { + return -1; + } + sb->buf_size = sb->cfg->buf_size; + return 0; +} + +StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg) +{ + StreamingBuffer *sb = CALLOC(cfg, 1, sizeof(StreamingBuffer)); + if (sb != NULL) { + sb->buf_size = cfg->buf_size; + sb->cfg = cfg; + + if (cfg->buf_size > 0) { + if (InitBuffer(sb) == 0) { + return sb; + } + FREE(cfg, sb, sizeof(StreamingBuffer)); + /* implied buf_size == 0 */ + } else { + return sb; + } + } + return NULL; +} + +void StreamingBufferClear(StreamingBuffer *sb) +{ + if (sb != NULL) { + SCLogDebug("sb->buf_size %u max %u", sb->buf_size, sb->buf_size_max); + + if (sb->buf != NULL) { + FREE(sb->cfg, sb->buf, sb->buf_size); + sb->buf = NULL; + } + } +} + +void StreamingBufferFree(StreamingBuffer *sb) +{ + if (sb != NULL) { + StreamingBufferClear(sb); + FREE(sb->cfg, sb, sizeof(StreamingBuffer)); + } +} + +/** + * \internal + * \brief move buffer forward by 'slide' + */ +static void AutoSlide(StreamingBuffer *sb) +{ + uint32_t size = sb->cfg->buf_slide; + uint32_t slide = sb->buf_offset - size; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size); + memmove(sb->buf, sb->buf+slide, size); + sb->stream_offset += slide; + sb->buf_offset = size; +} + +static int __attribute__((warn_unused_result)) +GrowToSize(StreamingBuffer *sb, uint32_t size) +{ + /* try to grow in multiples of sb->cfg->buf_size */ + uint32_t x = sb->cfg->buf_size ? size % sb->cfg->buf_size : 0; + uint32_t base = size - x; + uint32_t grow = base + sb->cfg->buf_size; + + void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow); + if (ptr == NULL) + return -1; + + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - sb->buf_size; + void *new_mem = ((char *)ptr) + sb->buf_size; + memset(new_mem, 0, diff); + + sb->buf = ptr; + sb->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); +#ifdef DEBUG + if (sb->buf_size > sb->buf_size_max) { + sb->buf_size_max = sb->buf_size; + } +#endif + return 0; +} + +/** \internal + * \brief try to double the buffer size + * \retval 0 ok + * \retval -1 failed, buffer unchanged + */ +static int __attribute__((warn_unused_result)) Grow(StreamingBuffer *sb) +{ + uint32_t grow = sb->buf_size * 2; + void *ptr = REALLOC(sb->cfg, sb->buf, sb->buf_size, grow); + if (ptr == NULL) + return -1; + + /* for safe printing and general caution, lets memset the + * new data to 0 */ + size_t diff = grow - sb->buf_size; + void *new_mem = ((char *)ptr) + sb->buf_size; + memset(new_mem, 0, diff); + + sb->buf = ptr; + sb->buf_size = grow; + SCLogDebug("grown buffer to %u", grow); +#ifdef DEBUG + if (sb->buf_size > sb->buf_size_max) { + sb->buf_size_max = sb->buf_size; + } +#endif + return 0; +} + +/** + * \brief slide to absolute offset + * \todo if sliding beyond window, we could perhaps reset? + */ +void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset) +{ + if (offset > sb->stream_offset && + offset <= sb->stream_offset + sb->buf_offset) + { + uint32_t slide = offset - sb->stream_offset; + uint32_t size = sb->buf_offset - slide; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size); + memmove(sb->buf, sb->buf+slide, size); + sb->stream_offset += slide; + sb->buf_offset = size; + } +} + +void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide) +{ + uint32_t size = sb->buf_offset - slide; + SCLogDebug("sliding %u forward, size of original buffer left after slide %u", slide, size); + memmove(sb->buf, sb->buf+slide, size); + sb->stream_offset += slide; + sb->buf_offset = size; +} + +#define DATA_FITS(sb, len) \ + ((sb)->buf_offset + (len) <= (sb)->buf_size) + +StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, const uint8_t *data, uint32_t data_len) +{ + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return NULL; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + if (GrowToSize(sb, data_len) != 0) + return NULL; + } else { + while (!DATA_FITS(sb, data_len)) { + if (Grow(sb) != 0) { + return NULL; + } + } + } + } + if (!DATA_FITS(sb, data_len)) { + return NULL; + } + + StreamingBufferSegment *seg = CALLOC(sb->cfg, 1, sizeof(StreamingBufferSegment)); + if (seg != NULL) { + memcpy(sb->buf + sb->buf_offset, data, data_len); + seg->stream_offset = sb->stream_offset + sb->buf_offset; + seg->segment_len = data_len; + sb->buf_offset += data_len; + return seg; + } + return NULL; +} + +int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len) +{ + BUG_ON(seg == NULL); + + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return -1; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + if (GrowToSize(sb, data_len) != 0) + return -1; + } else { + while (!DATA_FITS(sb, data_len)) { + if (Grow(sb) != 0) { + return -1; + } + } + } + } + if (!DATA_FITS(sb, data_len)) { + return -1; + } + + memcpy(sb->buf + sb->buf_offset, data, data_len); + seg->stream_offset = sb->stream_offset + sb->buf_offset; + seg->segment_len = data_len; + sb->buf_offset += data_len; + return 0; +} + +/** + * \brief add data w/o tracking a segment + */ +int StreamingBufferAppendNoTrack(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len) +{ + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return -1; + } + + if (!DATA_FITS(sb, data_len)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) + AutoSlide(sb); + if (sb->buf_size == 0) { + if (GrowToSize(sb, data_len) != 0) + return -1; + } else { + while (!DATA_FITS(sb, data_len)) { + if (Grow(sb) != 0) { + return -1; + } + } + } + } + if (!DATA_FITS(sb, data_len)) { + return -1; + } + + memcpy(sb->buf + sb->buf_offset, data, data_len); + sb->buf_offset += data_len; + return 0; +} + +#define DATA_FITS_AT_OFFSET(sb, len, offset) \ + ((offset) + (len) <= (sb)->buf_size) + +/** + * \param offset offset relative to StreamingBuffer::stream_offset + */ +int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len, + uint64_t offset) +{ + BUG_ON(seg == NULL); + + if (offset < sb->stream_offset) + return -1; + + if (sb->buf == NULL) { + if (InitBuffer(sb) == -1) + return -1; + } + + uint32_t rel_offset = offset - sb->stream_offset; + if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) { + if (sb->cfg->flags & STREAMING_BUFFER_AUTOSLIDE) { + AutoSlide(sb); + rel_offset = offset - sb->stream_offset; + } + if (!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)) { + if (GrowToSize(sb, (rel_offset + data_len)) != 0) + return -1; + } + } + BUG_ON(!DATA_FITS_AT_OFFSET(sb, data_len, rel_offset)); + + memcpy(sb->buf + rel_offset, data, data_len); + seg->stream_offset = offset; + seg->segment_len = data_len; + if (rel_offset + data_len > sb->buf_offset) + sb->buf_offset = rel_offset + data_len; + return 0; +} + +int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, + const StreamingBufferSegment *seg) +{ + if (seg->stream_offset < sb->stream_offset) { + if (seg->stream_offset + seg->segment_len <= sb->stream_offset) { + return 1; + } + } + return 0; +} + +void StreamingBufferSegmentGetData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t **data, uint32_t *data_len) +{ + if (seg->stream_offset >= sb->stream_offset) { + uint64_t offset = seg->stream_offset - sb->stream_offset; + *data = sb->buf + offset; + if (offset + seg->segment_len > sb->buf_size) + *data_len = sb->buf_size - offset; + else + *data_len = seg->segment_len; + return; + } else { + uint64_t offset = sb->stream_offset - seg->stream_offset; + if (offset < seg->segment_len) { + *data = sb->buf; + *data_len = seg->segment_len - offset; + return; + } + } + *data = NULL; + *data_len = 0; + return; +} + +/** + * \retval 1 data is the same + * \retval 0 data is different + */ +int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t *rawdata, uint32_t rawdata_len) +{ + const uint8_t *segdata = NULL; + uint32_t segdata_len = 0; + StreamingBufferSegmentGetData(sb, seg, &segdata, &segdata_len); + if (segdata && segdata_len && + segdata_len == rawdata_len && + memcmp(segdata, rawdata, segdata_len) == 0) + { + return 1; + } + return 0; +} + +int StreamingBufferGetData(const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t *stream_offset) +{ + if (sb != NULL && sb->buf != NULL) { + *data = sb->buf; + *data_len = sb->buf_offset; + *stream_offset = sb->stream_offset; + return 1; + } else { + *data = NULL; + *data_len = 0; + *stream_offset = 0; + return 0; + } +} + +int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t offset) +{ + if (sb != NULL && sb->buf != NULL && + offset >= sb->stream_offset && + offset < (sb->stream_offset + sb->buf_offset)) + { + uint32_t skip = offset - sb->stream_offset; + *data = sb->buf + skip; + *data_len = sb->buf_offset - skip; + return 1; + } else { + *data = NULL; + *data_len = 0; + return 0; + } +} + +/** + * \retval 1 data is the same + * \retval 0 data is different + */ +int StreamingBufferCompareRawData(const StreamingBuffer *sb, + const uint8_t *rawdata, uint32_t rawdata_len) +{ + const uint8_t *sbdata = NULL; + uint32_t sbdata_len = 0; + uint64_t offset = 0; + StreamingBufferGetData(sb, &sbdata, &sbdata_len, &offset); + if (offset == 0 && + sbdata && sbdata_len && + sbdata_len == rawdata_len && + memcmp(sbdata, rawdata, sbdata_len) == 0) + { + return 1; + } + SCLogInfo("sbdata_len %u, offset %u", sbdata_len, (uint)offset); + PrintRawDataFp(stdout, sbdata,sbdata_len); + return 0; +} + +void Dump(StreamingBuffer *sb) +{ + PrintRawDataFp(stdout, sb->buf, sb->buf_offset); +} + +void DumpSegment(StreamingBuffer *sb, StreamingBufferSegment *seg) +{ + const uint8_t *data = NULL; + uint32_t data_len = 0; + StreamingBufferSegmentGetData(sb, seg, &data, &data_len); + if (data && data_len) { + PrintRawDataFp(stdout, data, data_len); + } +} + +#ifdef UNITTESTS +static int StreamingBufferTest01(void) +{ + StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 16, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(sb, (const uint8_t *)"ABCDEFGH", 8); + StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(sb, (const uint8_t *)"01234567", 8); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 16); + FAIL_IF(seg1->stream_offset != 0); + FAIL_IF(seg2->stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg1,(const uint8_t *)"ABCDEFGH", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg2,(const uint8_t *)"01234567", 8)); + Dump(sb); + + StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(sb, (const uint8_t *)"QWERTY", 6); + FAIL_IF(sb->stream_offset != 8); + FAIL_IF(sb->buf_offset != 14); + FAIL_IF(seg3->stream_offset != 16); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg3,(const uint8_t *)"QWERTY", 6)); + Dump(sb); + + StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(sb, (const uint8_t *)"KLM", 3); + FAIL_IF(sb->stream_offset != 14); + FAIL_IF(sb->buf_offset != 11); + FAIL_IF(seg4->stream_offset != 22); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg4,(const uint8_t *)"KLM", 3)); + Dump(sb); + + StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(sb, (const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27); + FAIL_IF(sb->stream_offset != 17); + FAIL_IF(sb->buf_offset != 35); + FAIL_IF(seg5->stream_offset != 25); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg5,(const uint8_t *)"!@#$%^&*()_+<>?/,.;:'[]{}-=", 27)); + Dump(sb); + + StreamingBufferSegment *seg6 = StreamingBufferAppendRaw(sb, (const uint8_t *)"UVWXYZ", 6); + FAIL_IF(sb->stream_offset != 17); + FAIL_IF(sb->buf_offset != 41); + FAIL_IF(seg6->stream_offset != 52); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg1)); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg4)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg5)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,seg6)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,seg6,(const uint8_t *)"UVWXYZ", 6)); + Dump(sb); + + SCFree(seg1); + SCFree(seg2); + SCFree(seg3); + SCFree(seg4); + SCFree(seg5); + SCFree(seg6); + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest02(void) +{ + StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferAppend(sb, &seg2, (const uint8_t *)"01234567", 8) != 0); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 16); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + + StreamingBufferSlide(sb, 6); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferAppend(sb, &seg3, (const uint8_t *)"QWERTY", 6) != 0); + FAIL_IF(sb->stream_offset != 6); + FAIL_IF(sb->buf_offset != 16); + FAIL_IF(seg3.stream_offset != 16); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferSlide(sb, 6); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest03(void) +{ + StreamingBufferConfig cfg = { 0, 8, 24, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 14); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg3.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferSlide(sb, 10); + FAIL_IF(!StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest04(void) +{ + StreamingBufferConfig cfg = { 0, 8, 16, NULL, NULL, NULL, NULL }; + StreamingBuffer *sb = StreamingBufferInit(&cfg); + FAIL_IF(sb == NULL); + + StreamingBufferSegment seg1; + FAIL_IF(StreamingBufferAppend(sb, &seg1, (const uint8_t *)"ABCDEFGH", 8) != 0); + StreamingBufferSegment seg2; + FAIL_IF(StreamingBufferInsertAt(sb, &seg2, (const uint8_t *)"01234567", 8, 14) != 0); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg1.stream_offset != 0); + FAIL_IF(seg2.stream_offset != 14); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + + StreamingBufferSegment seg3; + FAIL_IF(StreamingBufferInsertAt(sb, &seg3, (const uint8_t *)"QWERTY", 6, 8) != 0); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 22); + FAIL_IF(seg3.stream_offset != 8); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + + /* far ahead of curve: */ + StreamingBufferSegment seg4; + FAIL_IF(StreamingBufferInsertAt(sb, &seg4, (const uint8_t *)"XYZ", 3, 124) != 0); + FAIL_IF(sb->stream_offset != 0); + FAIL_IF(sb->buf_offset != 127); + FAIL_IF(sb->buf_size != 128); + FAIL_IF(seg4.stream_offset != 124); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(sb,&seg4)); + Dump(sb); + DumpSegment(sb, &seg1); + DumpSegment(sb, &seg2); + DumpSegment(sb, &seg3); + DumpSegment(sb, &seg4); + + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg1,(const uint8_t *)"ABCDEFGH", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg2,(const uint8_t *)"01234567", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg3,(const uint8_t *)"QWERTY", 6)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(sb,&seg4,(const uint8_t *)"XYZ", 3)); + + StreamingBufferFree(sb); + PASS; +} + +static int StreamingBufferTest05(void) +{ + StreamingBufferConfig cfg = { STREAMING_BUFFER_AUTOSLIDE, 8, 32, NULL, NULL, NULL, NULL }; + StreamingBuffer sb = STREAMING_BUFFER_INITIALIZER(&cfg); + + StreamingBufferSegment *seg1 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"AAAAAAAA", 8); + StreamingBufferSegment *seg2 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"BBBBBBBB", 8); + StreamingBufferSegment *seg3 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"CCCCCCCC", 8); + StreamingBufferSegment *seg4 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"DDDDDDDD", 8); + FAIL_IF(sb.stream_offset != 0); + FAIL_IF(sb.buf_offset != 32); + FAIL_IF(seg1->stream_offset != 0); + FAIL_IF(seg2->stream_offset != 8); + FAIL_IF(seg3->stream_offset != 16); + FAIL_IF(seg4->stream_offset != 24); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg1)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg2)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg3)); + FAIL_IF(StreamingBufferSegmentIsBeforeWindow(&sb,seg4)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg1,(const uint8_t *)"AAAAAAAA", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg2,(const uint8_t *)"BBBBBBBB", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg3,(const uint8_t *)"CCCCCCCC", 8)); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg4,(const uint8_t *)"DDDDDDDD", 8)); + Dump(&sb); + StreamingBufferSegment *seg5 = StreamingBufferAppendRaw(&sb, (const uint8_t *)"EEEEEEEE", 8); + FAIL_IF(!StreamingBufferSegmentCompareRawData(&sb,seg5,(const uint8_t *)"EEEEEEEE", 8)); + Dump(&sb); + + SCFree(seg1); + SCFree(seg2); + SCFree(seg3); + SCFree(seg4); + SCFree(seg5); + StreamingBufferClear(&sb); + PASS; +} +#endif + +void StreamingBufferRegisterTests(void) +{ +#ifdef UNITTESTS + UtRegisterTest("StreamingBufferTest01", StreamingBufferTest01); + UtRegisterTest("StreamingBufferTest02", StreamingBufferTest02); + UtRegisterTest("StreamingBufferTest03", StreamingBufferTest03); + UtRegisterTest("StreamingBufferTest04", StreamingBufferTest04); + UtRegisterTest("StreamingBufferTest05", StreamingBufferTest05); +#endif +} diff --git a/src/util-streaming-buffer.h b/src/util-streaming-buffer.h new file mode 100644 index 000000000000..20c0a8904b79 --- /dev/null +++ b/src/util-streaming-buffer.h @@ -0,0 +1,140 @@ +/* Copyright (C) 2015-2016 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * This API is meant to be used with streaming data. A single memory + * block is used to store the data. StreamingBufferSegment points to + * chunk of data in the single StreamingBuffer. It points by offset + * and length, so no pointers. The buffer is resized on demand and + * slides forward, either automatically or manually. + * + * When a segment needs it's data it uses StreamingBufferSegmentGetData + * which takes care of checking if the segment still has a valid offset + * and length. + * + * The StreamingBuffer::stream_offset is an absolute offset since the + * start of the data streaming. + * + * Similarly, StreamingBufferSegment::stream_offset is also an absolute + * offset. + * + * Using the segments is optional. + * + * + * stream_offset buf_offset stream_offset + buf_size + * ^ ^ ^ + * | | | + * | | | + * +--------------------------------------------+ + * | data | empty | + * | xxxxxxxxxx | | + * +------^--------^--------+-------------------+ + * | | + * | | + * | | + * | | + * | | + * +------+--------+-------+ + * | StreamingBufferSegment| + * +-----------+-----------+ + * | offset | len | + * +-----------+-----------+ + */ + + +#ifndef __UTIL_STREAMING_BUFFER_H__ +#define __UTIL_STREAMING_BUFFER_H__ + +#define STREAMING_BUFFER_NOFLAGS 0 +#define STREAMING_BUFFER_AUTOSLIDE (1<<0) + +typedef struct StreamingBufferConfig_ { + uint32_t flags; + uint32_t buf_slide; + uint32_t buf_size; + void *(*Malloc)(size_t size); + void *(*Calloc)(size_t n, size_t size); + void *(*Realloc)(void *ptr, size_t orig_size, size_t size); + void (*Free)(void *ptr, size_t size); +} StreamingBufferConfig; + +#define STREAMING_BUFFER_CONFIG_INITIALIZER { 0, 0, 0, NULL, NULL, NULL, NULL, } + +typedef struct StreamingBuffer_ { + const StreamingBufferConfig *cfg; + uint64_t stream_offset; /**< offset of the start of the memory block */ + + uint8_t *buf; /**< memory block for reassembly */ + uint32_t buf_size; /**< size of memory block */ + uint32_t buf_offset; /**< how far we are in buf_size */ +#ifdef DEBUG + uint32_t buf_size_max; +#endif +} StreamingBuffer; + +#ifndef DEBUG +#define STREAMING_BUFFER_INITIALIZER(cfg) { (cfg), 0, NULL, 0, 0, }; +#else +#define STREAMING_BUFFER_INITIALIZER(cfg) { (cfg), 0, NULL, 0, 0, 0 }; +#endif + +typedef struct StreamingBufferSegment_ { + uint64_t stream_offset; + uint32_t segment_len; +} __attribute__((__packed__)) StreamingBufferSegment; + +StreamingBuffer *StreamingBufferInit(const StreamingBufferConfig *cfg); +void StreamingBufferClear(StreamingBuffer *sb); +void StreamingBufferFree(StreamingBuffer *sb); + +void StreamingBufferSlide(StreamingBuffer *sb, uint32_t slide); +void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset); + +StreamingBufferSegment *StreamingBufferAppendRaw(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len) __attribute__((warn_unused_result)); +int StreamingBufferAppend(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len) __attribute__((warn_unused_result)); +int StreamingBufferAppendNoTrack(StreamingBuffer *sb, + const uint8_t *data, uint32_t data_len) __attribute__((warn_unused_result)); +int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, + const uint8_t *data, uint32_t data_len, + uint64_t offset) __attribute__((warn_unused_result)); + +void StreamingBufferSegmentGetData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t **data, uint32_t *data_len); + +int StreamingBufferSegmentCompareRawData(const StreamingBuffer *sb, + const StreamingBufferSegment *seg, + const uint8_t *rawdata, uint32_t rawdata_len); +int StreamingBufferCompareRawData(const StreamingBuffer *sb, + const uint8_t *rawdata, uint32_t rawdata_len); + +int StreamingBufferGetData(const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t *stream_offset); + +int StreamingBufferGetDataAtOffset (const StreamingBuffer *sb, + const uint8_t **data, uint32_t *data_len, + uint64_t offset); + +int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, + const StreamingBufferSegment *seg); + +void StreamingBufferRegisterTests(void); + +#endif /* __UTIL_STREAMING_BUFFER_H__ */ diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 92ddce6a3296..b43173281410 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -57,7 +57,10 @@ typedef enum ThresholdRuleType { THRESHOLD_TYPE_SUPPRESS, } ThresholdRuleType; +#ifdef UNITTESTS /* File descriptor for unittests */ +static FILE *g_ut_threshold_fp = NULL; +#endif /* common base for all options */ #define DETECT_BASE_REGEX "^\\s*(event_filter|threshold|rate_filter|suppress)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*(.*)\\s*$" @@ -73,7 +76,7 @@ typedef enum ThresholdRuleType { * suppress gen_id 1, sig_id 2000328 * suppress gen_id 1, sig_id 2000328, track by_src, ip fe80::/10 */ -#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src)\\s*,\\s*ip\\s*([\\da-fA-F.:/]+)*\\s*$" +#define DETECT_SUPPRESS_REGEX "^,\\s*track\\s*(by_dst|by_src|by_either)\\s*,\\s*ip\\s*([\\[\\],\\$\\s\\da-zA-Z.:/_]+)*\\s*$" /* Default path for the threshold.config file */ #if defined OS_WIN32 || defined __CYGWIN__ @@ -94,6 +97,8 @@ static pcre_extra *regex_rate_study = NULL; static pcre *regex_suppress = NULL; static pcre_extra *regex_suppress_study = NULL; +static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd); + /** * \brief Returns the path for the Threshold Config file. We check if we * can retrieve the path from the yaml conf file. If it is not present, @@ -103,14 +108,27 @@ static pcre_extra *regex_suppress_study = NULL; * \retval log_filename Pointer to a string containing the path for the * Threshold Config file. */ -char *SCThresholdConfGetConfFilename(void) +static char *SCThresholdConfGetConfFilename(const DetectEngineCtx *de_ctx) { char *log_filename = NULL; - if (ConfGet("threshold-file", &log_filename) != 1) { - log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; - } + if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) { + char config_value[256]; + snprintf(config_value, sizeof(config_value), + "%s.threshold-file", de_ctx->config_prefix); + /* try loading prefix setting, fall back to global if that + * fails. */ + if (ConfGet(config_value, &log_filename) != 1) { + if (ConfGet("threshold-file", &log_filename) != 1) { + log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; + } + } + } else { + if (ConfGet("threshold-file", &log_filename) != 1) { + log_filename = (char *)THRESHOLD_CONF_DEF_CONF_FILEPATH; + } + } return log_filename; } @@ -124,26 +142,30 @@ char *SCThresholdConfGetConfFilename(void) * file. * * \param de_ctx Pointer to the Detection Engine Context. - * \param utfd Pointer for unit test file descriptor. * * \retval 0 On success. * \retval -1 On failure. */ -int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) +int SCThresholdConfInitContext(DetectEngineCtx *de_ctx) { char *filename = NULL; const char *eb = NULL; - FILE *fd = utfd; int eo; int opts = 0; - +#ifndef UNITTESTS + FILE *fd = NULL; +#else + FILE *fd = g_ut_threshold_fp; if (fd == NULL) { - filename = SCThresholdConfGetConfFilename(); +#endif + filename = SCThresholdConfGetConfFilename(de_ctx); if ( (fd = fopen(filename, "r")) == NULL) { SCLogWarning(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno)); goto error; } +#ifdef UNITTESTS } +#endif regex_base = pcre_compile(DETECT_BASE_REGEX, opts, &eb, &eo, NULL); if (regex_base == NULL) { @@ -196,6 +218,9 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) SCThresholdConfParseFile(de_ctx, fd); SCThresholdConfDeInitContext(de_ctx, fd); +#ifdef UNITTESTS + g_ut_threshold_fp = NULL; +#endif SCLogDebug("Global thresholding options defined"); return 0; @@ -210,9 +235,8 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) * \param de_ctx Pointer to the Detection Engine Context. * \param fd Pointer to file descriptor. */ -void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) +static void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) { - if (fd != NULL) fclose(fd); @@ -296,16 +320,10 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; if (parsed_track != TRACK_RULE) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) != 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip); goto error; } } @@ -347,16 +365,10 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; if (parsed_track != TRACK_RULE) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) != 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip); goto error; } } @@ -400,13 +412,8 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); + if (DetectAddressParse((const DetectEngineCtx *)de_ctx, &de->addrs, (char *)th_ip) != 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "failed to parse %s", th_ip); goto error; } @@ -427,8 +434,7 @@ static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, return 0; error: if (de != NULL) { - if (de->addr != NULL) - DetectAddressFree(de->addr); + DetectAddressHeadCleanup(&de->addrs); SCFree(de); } return -1; @@ -454,8 +460,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid /* Install it */ if (id == 0 && gid == 0) { for (s = de_ctx->sig_list; s != NULL; s = s->next) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -464,8 +470,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid continue; } - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_THRESHOLD, DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -485,7 +491,6 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; sm = SigMatchAlloc(); if (sm == NULL) { @@ -518,18 +523,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } else if (id == 0 && gid > 0) { for (s = de_ctx->sig_list; s != NULL; s = s->next) { if (s->gid == gid) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - if (sm != NULL) { - SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", id); - continue; - } - - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "an event var set. The signature event var is " @@ -549,7 +544,6 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; sm = SigMatchAlloc(); if (sm == NULL) { @@ -592,8 +586,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, + DETECT_SM_LIST_THRESHOLD, DETECT_THRESHOLD, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a threshold set. The signature event var is " @@ -602,8 +596,8 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid goto end; } - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " "a detection_filter set. The signature event var is " @@ -613,20 +607,14 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid } /* replace threshold on sig if we have a global override for it */ -#if 1 } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - if (sm == NULL) { - sm = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - } + sm = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, DETECT_DETECTION_FILTER, -1); if (sm != NULL) { SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_THRESHOLD); SigMatchFree(sm); sm = NULL; } -#endif } de = SCMalloc(sizeof(DetectThresholdData)); @@ -640,7 +628,6 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid de->seconds = parsed_seconds; de->new_action = parsed_new_action; de->timeout = parsed_timeout; - de->addr = NULL; sm = SigMatchAlloc(); if (sm == NULL) { @@ -675,8 +662,7 @@ static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid return 0; error: if (de != NULL) { - if (de->addr != NULL) - DetectAddressFree(de->addr); + DetectAddressHeadCleanup(&de->addrs); SCFree(de); } return -1; @@ -689,9 +675,10 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, uint8_t *ret_parsed_new_action, const char **ret_th_ip) { - const char *th_rule_type = NULL; - const char *th_gid = NULL; - const char *th_sid = NULL; + char th_rule_type[32]; + char th_gid[16]; + char th_sid[16]; + char rule_extend[1024]; const char *th_type = NULL; const char *th_track = NULL; const char *th_count = NULL; @@ -699,7 +686,6 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, const char *th_new_action= NULL; const char *th_timeout = NULL; const char *th_ip = NULL; - const char *rule_extend = NULL; uint8_t parsed_type = 0; uint8_t parsed_track = 0; @@ -724,39 +710,39 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, } /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &th_rule_type); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 1, th_rule_type, sizeof(th_rule_type)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &th_gid); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 2, th_gid, sizeof(th_gid)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &th_sid); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 3, th_sid, sizeof(th_sid)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } - ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &rule_extend); + ret = pcre_copy_substring((char *)rawstr, ov, 30, 4, rule_extend, sizeof(rule_extend)); if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed"); goto error; } /* get type of rule */ - if (strncasecmp(th_rule_type,"event_filter",strlen("event_filter")) == 0) { + if (strcasecmp(th_rule_type,"event_filter") == 0) { rule_type = THRESHOLD_TYPE_EVENT_FILTER; - } else if (strncasecmp(th_rule_type,"threshold",strlen("threshold")) == 0) { + } else if (strcasecmp(th_rule_type,"threshold") == 0) { rule_type = THRESHOLD_TYPE_THRESHOLD; - } else if (strncasecmp(th_rule_type,"rate",strlen("rate")) == 0) { + } else if (strcasecmp(th_rule_type,"rate_filter") == 0) { rule_type = THRESHOLD_TYPE_RATE; - } else if (strncasecmp(th_rule_type,"suppress",strlen("suppress")) == 0) { + } else if (strcasecmp(th_rule_type,"suppress") == 0) { rule_type = THRESHOLD_TYPE_SUPPRESS; } else { SCLogError(SC_ERR_INVALID_VALUE, "rule type %s is unknown", th_rule_type); @@ -957,6 +943,9 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, parsed_track = TRACK_DST; else if (strcasecmp(th_track,"by_src") == 0) parsed_track = TRACK_SRC; + else if (strcasecmp(th_track,"by_either") == 0) { + parsed_track = TRACK_EITHER; + } else { SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rule_extend); goto error; @@ -984,12 +973,6 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, *ret_th_ip = th_ip; return 0; error: - if (th_rule_type != NULL) - SCFree((char *)th_rule_type); - if (th_sid != NULL) - SCFree((char *)th_sid); - if (th_gid != NULL) - SCFree((char *)th_gid); if (th_track != NULL) SCFree((char *)th_track); if (th_count != NULL) @@ -1000,8 +983,6 @@ static int ParseThresholdRule(DetectEngineCtx *de_ctx, char *rawstr, SCFree((char *)th_type); if (th_ip != NULL) SCFree((char *)th_ip); - if (rule_extend != NULL) - SCFree((char *)rule_extend); return -1; } @@ -1439,40 +1420,28 @@ FILE *SCThresholdConfGenerateValidDummyFD11() int SCThresholdConfTest01(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD01(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1484,39 +1453,28 @@ int SCThresholdConfTest01(void) int SCThresholdConfTest02(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:100;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD01(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60)) - result = 1; - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_BOTH && de->track == TRACK_DST && de->count == 10 && de->seconds == 60); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1528,39 +1486,28 @@ int SCThresholdConfTest02(void) int SCThresholdConfTest03(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD01(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD01(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60)) - result = 1; - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1572,40 +1519,24 @@ int SCThresholdConfTest03(void) int SCThresholdConfTest04(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateInValidDummyFD02(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInValidDummyFD02(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NOT_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de == NULL) - return result; - else - result = 1; - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - return result; + DetectEngineCtxFree(de_ctx); + PASS; } /** @@ -1617,66 +1548,50 @@ int SCThresholdConfTest04(void) int SCThresholdConfTest05(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - Signature *s = NULL, *ns = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); - if (sig == NULL) { - goto end; - } - - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } - - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD03(); - SCThresholdConfInitContext(de_ctx,fd); - - for (s = de_ctx->sig_list; s != NULL;) { - - ns = s->next; - - if(s->id == 1 || s->id == 10 || s->id == 100) { - - m = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - - if(m == NULL) { - goto end; - } else { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60)) - result++; - } - } - - s = ns; - } - - if(result == 3) - result = 1; - -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineCtxFree(de_ctx); - return result; + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit\"; gid:1; sid:100;)"); + FAIL_IF_NULL(sig); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD03(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); + + Signature *s = de_ctx->sig_list; + SigMatch *m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); + + s = de_ctx->sig_list->next; + m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); + + s = de_ctx->sig_list->next->next; + m = DetectGetLastSMByListId(s, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); + FAIL_IF_NULL(m->ctx); + de = (DetectThresholdData *)m->ctx; + FAIL_IF_NOT(de->type == TYPE_THRESHOLD && de->track == TRACK_SRC && de->count == 100 && de->seconds == 60); + + PASS; } /** @@ -1688,40 +1603,28 @@ int SCThresholdConfTest05(void) int SCThresholdConfTest06(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD04(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD04(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1733,40 +1636,28 @@ int SCThresholdConfTest06(void) int SCThresholdConfTest07(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD05(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD05(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_DETECTION_FILTER, -1); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1779,40 +1670,28 @@ int SCThresholdConfTest07(void) int SCThresholdConfTest08(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD06(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD06(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + SigMatch *m = DetectGetLastSMByListId(sig, DETECT_SM_LIST_THRESHOLD, + DETECT_DETECTION_FILTER, -1); + FAIL_IF_NULL(m); - if(m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) - result = 1; - } + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60); -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - return result; + PASS; } /** @@ -1823,65 +1702,49 @@ int SCThresholdConfTest08(void) */ int SCThresholdConfTest09(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - - HostInitConfig(HOST_QUIET); - - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + HostInitConfig(HOST_QUIET); + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); + + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); - fd = SCThresholdConfGenerateValidDummyFD07(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD07(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); - p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } - + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } - + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); TimeSetIncrementTime(2); TimeGet(&p->ts); @@ -1889,10 +1752,7 @@ int SCThresholdConfTest09(void) p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))); TimeSetIncrementTime(3); TimeGet(&p->ts); @@ -1900,10 +1760,7 @@ int SCThresholdConfTest09(void) p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || !(PACKET_TEST_ACTION(p, ACTION_DROP))); TimeSetIncrementTime(10); TimeGet(&p->ts); @@ -1911,31 +1768,18 @@ int SCThresholdConfTest09(void) p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); p->alerts.cnt = 0; p->action = 0; SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - if (p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)) { - result = 0; - goto end; - } - - result = 1; + FAIL_IF(p->alerts.cnt != 1 || PACKET_TEST_ACTION(p, ACTION_DROP)); -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -1946,96 +1790,68 @@ int SCThresholdConfTest09(void) */ int SCThresholdConfTest10(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); - - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int alerts = 0; - - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL || p2 == NULL) - return result; + Packet *p1 = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p1); + Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, + "172.26.0.1", "172.26.0.10"); + FAIL_IF_NULL(p2); + + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); - if (sig == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); - fd = SCThresholdConfGenerateValidDummyFD08(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD08(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + TimeGet(&p1->ts); - TimeGet(&p->ts); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts = PacketAlertCheck(p, 10); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF(PacketAlertCheck(p1, 10)); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - alerts += PacketAlertCheck(p2, 10); - if (alerts > 0) { - result = 0; - goto end; - } + FAIL_IF(PacketAlertCheck(p2, 10)); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts += PacketAlertCheck(p, 10); - if (alerts != 1) { - result = 0; - goto end; - } + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1); TimeSetIncrementTime(2); - TimeGet(&p->ts); + TimeGet(&p1->ts); SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); - alerts += PacketAlertCheck(p2, 10); - if (alerts != 2) { - result = 0; - goto end; - } + FAIL_IF_NOT(PacketAlertCheck(p2, 10) == 1); TimeSetIncrementTime(10); - TimeGet(&p->ts); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - alerts += PacketAlertCheck(p, 10); + TimeGet(&p1->ts); - if (alerts == 2) - result = 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 0); /* Ensure that a Threshold entry was installed at the sig */ - if (de_ctx->ths_ctx.th_entry[sig->num] == NULL) { - result = 0; - goto end; - } - -end: - UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NULL(de_ctx->ths_ctx.th_entry[s->num]); + UTHFreePacket(p1); + UTHFreePacket(p2); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2046,47 +1862,47 @@ int SCThresholdConfTest10(void) */ int SCThresholdConfTest11(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int alerts10 = 0; - int alerts11 = 0; - int alerts12 = 0; - - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); - de_ctx->flags |= DE_QUIET; + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); - if (sig == NULL) { - goto end; - } + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; - fd = SCThresholdConfGenerateValidDummyFD09(); - SCThresholdConfInitContext(de_ctx,fd); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD09(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); @@ -2135,26 +1951,16 @@ int SCThresholdConfTest11(void) alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); - if (alerts10 == 4) - result = 1; - + FAIL_IF_NOT(alerts10 == 4); /* One on the first interval, another on the second */ - if (alerts11 == 2) - result = 1; + FAIL_IF_NOT(alerts11 == 2); + FAIL_IF_NOT(alerts12 == 2); - if (alerts12 == 2) - result = 1; - -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2165,47 +1971,47 @@ int SCThresholdConfTest11(void) */ int SCThresholdConfTest12(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - int alerts10 = 0; - int alerts11 = 0; - int alerts12 = 0; - - memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + FAIL_IF_NULL(p); - de_ctx->flags |= DE_QUIET; + ThreadVars th_v; + memset(&th_v, 0, sizeof(th_v)); - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); - if (sig == NULL) { - goto end; - } + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + DetectEngineThreadCtx *det_ctx = NULL; - fd = SCThresholdConfGenerateValidDummyFD10(); - SCThresholdConfInitContext(de_ctx,fd); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + FAIL_IF_NULL(s); + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + FAIL_IF_NULL(s); + + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD10(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); TimeGet(&p->ts); + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); alerts10 += PacketAlertCheck(p, 10); alerts11 += PacketAlertCheck(p, 11); @@ -2254,27 +2060,16 @@ int SCThresholdConfTest12(void) alerts11 += PacketAlertCheck(p, 11); alerts12 += PacketAlertCheck(p, 12); - /* Yes, none of the alerts will be out of the count of the given interval for type limit */ - if (alerts10 == 10) - result = 1; - + FAIL_IF_NOT(alerts10 == 10); /* One on the first interval, another on the second */ - if (alerts11 == 1) - result = 1; + FAIL_IF_NOT(alerts11 == 1); + FAIL_IF_NOT(alerts12 == 1); - if (alerts12 == 1) - result = 1; - -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2286,43 +2081,28 @@ int SCThresholdConfTest12(void) int SCThresholdConfTest13(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - - HostInitConfig(HOST_QUIET); - - if (de_ctx == NULL) - return result; - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); + SigMatch *m = DetectGetLastSMByListId(sig, + DETECT_SM_LIST_SUPPRESS, DETECT_THRESHOLD, -1); + FAIL_IF_NULL(m); - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if(de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) - result = 1; + DetectThresholdData *de = (DetectThresholdData *)m->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); - } -end: - SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2333,61 +2113,61 @@ int SCThresholdConfTest13(void) */ int SCThresholdConfTest14(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", + Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); - Packet *p1 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", + FAIL_IF_NULL(p1); + Packet *p2 = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); - ThreadVars th_v; + FAIL_IF_NULL(p2); + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + + Signature *sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); + FAIL_IF_NULL(sig); + sig = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); struct timeval ts; - memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; - - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:10000;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test 2\"; gid:1; sid:10;)"); - sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"suppress test 3\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); - if ((PacketAlertCheck(p, 10000) == 0) && (PacketAlertCheck(p, 10) == 1) && - (PacketAlertCheck(p, 1000) == 1) && (PacketAlertCheck(p1, 1000) == 0)) - result = 1; + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); -end: - UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(PacketAlertCheck(p1, 10000) == 0); + FAIL_IF_NOT(PacketAlertCheck(p1, 10) == 1); + FAIL_IF_NOT(PacketAlertCheck(p1, 1000) == 1); + FAIL_IF_NOT(PacketAlertCheck(p2, 1000) == 0); + + UTHFreePacket(p1); + UTHFreePacket(p2); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2398,37 +2178,32 @@ int SCThresholdConfTest14(void) */ static int SCThresholdConfTest15(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + FAIL_IF_NULL(p); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; - - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)"); - if (sig == NULL) { - goto end; - } + Signature *sig = DetectEngineAppendSig(de_ctx, + "drop tcp any any -> any any (msg:\"suppress test\"; content:\"lalala\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -2436,27 +2211,15 @@ static int SCThresholdConfTest15(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ - if (PacketAlertCheck(p, 10000) != 0) { - printf("sid 10000 should not have alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 10000) != 0); /* however, it should have set the drop flag */ - if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { - printf("sid 10000 should have set DROP flag even if suppressed: "); - goto end; - } + FAIL_IF(!(PACKET_TEST_ACTION(p, ACTION_DROP))); - result = 1; -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2467,65 +2230,47 @@ static int SCThresholdConfTest15(void) */ static int SCThresholdConfTest16(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.1.1", "192.168.0.100", 1234, 24); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + FAIL_IF_NULL(p); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Signature *sig = DetectEngineAppendSig(de_ctx, + "drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); + FAIL_IF_NULL(sig); - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp any any -> any any (msg:\"suppress test\"; gid:1; sid:1000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); - /* 10000 shouldn't match */ - if (PacketAlertCheck(p, 1000) != 0) { - printf("sid 1000 should not have alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 1000) != 0); /* however, it should have set the drop flag */ - if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { - printf("sid 1000 should have set DROP flag even if suppressed: "); - goto end; - } + FAIL_IF(!(PACKET_TEST_ACTION(p, ACTION_DROP))); - result = 1; -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2536,37 +2281,32 @@ static int SCThresholdConfTest16(void) */ static int SCThresholdConfTest17(void) { - Signature *sig = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); Packet *p = UTHBuildPacketReal((uint8_t*)"lalala", 6, IPPROTO_TCP, "192.168.0.10", "192.168.0.100", 1234, 24); - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; + FAIL_IF_NULL(p); + ThreadVars th_v; memset(&th_v, 0, sizeof(th_v)); - struct timeval ts; + DetectEngineThreadCtx *det_ctx = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); + de_ctx->flags |= DE_QUIET; + struct timeval ts; memset (&ts, 0, sizeof(struct timeval)); TimeGet(&ts); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL || p == NULL) - return result; + Signature *sig = DetectEngineAppendSig(de_ctx, + "drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)"); + FAIL_IF_NULL(sig); - de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"drop tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:10000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD11(); - SCThresholdConfInitContext(de_ctx,fd); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD11(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); @@ -2574,27 +2314,15 @@ static int SCThresholdConfTest17(void) SigMatchSignatures(&th_v, de_ctx, det_ctx, p); /* 10000 shouldn't match */ - if (PacketAlertCheck(p, 10000) != 0) { - printf("sid 10000 should not have alerted: "); - goto end; - } + FAIL_IF(PacketAlertCheck(p, 10000) != 0); /* however, it should have set the drop flag */ - if (!(PACKET_TEST_ACTION(p, ACTION_DROP))) { - printf("sid 10000 should have set DROP flag even if suppressed: "); - goto end; - } + FAIL_IF(!(PACKET_TEST_ACTION(p, ACTION_DROP))); - result = 1; -end: UTHFreePacket(p); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - HostShutdown(); - return result; + PASS; } /** @@ -2624,52 +2352,29 @@ static FILE *SCThresholdConfGenerateInvalidDummyFD12() */ static int SCThresholdConfTest18(void) { - Signature *s = NULL; - int result = 0; - FILE *fd = NULL; - SigMatch *sm = NULL; - DetectThresholdData *de = NULL; - HostInitConfig(HOST_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return result; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); - if (s == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateInvalidDummyFD12(); - SCThresholdConfInitContext(de_ctx,fd); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD12(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); - if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] == NULL) { - printf("no thresholds: "); - goto end; - } - sm = s->sm_lists[DETECT_SM_LIST_SUPPRESS]; - if (sm == NULL) { - printf("no sm: "); - goto end; - } - - de = (DetectThresholdData *)sm->ctx; - if (de == NULL) { - printf("no de: "); - goto end; - } - if (!(de->type == TYPE_SUPPRESS && de->track == TRACK_DST)) { - printf("de state wrong: "); - goto end; - } + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); - result = 1; -end: DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2699,52 +2404,26 @@ static FILE *SCThresholdConfGenerateInvalidDummyFD13() */ static int SCThresholdConfTest19(void) { - Signature *s = NULL; - int result = 0; - FILE *fd = NULL; - SigMatch *sm = NULL; - DetectThresholdData *de = NULL; - HostInitConfig(HOST_QUIET); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) - return result; + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); - if (s == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateInvalidDummyFD13(); - SCThresholdConfInitContext(de_ctx,fd); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp 192.168.0.10 any -> 192.168.0.100 any (msg:\"suppress test\"; gid:1; sid:2200029;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateInvalidDummyFD13(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); - - if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] == NULL) { - printf("no thresholds: "); - goto end; - } - sm = s->sm_lists[DETECT_SM_LIST_SUPPRESS]; - if (sm == NULL) { - printf("no sm: "); - goto end; - } - - de = (DetectThresholdData *)sm->ctx; - if (de == NULL) { - printf("no de: "); - goto end; - } - if (!(de->type == TYPE_SUPPRESS && de->track == TRACK_DST)) { - printf("de state wrong: "); - goto end; - } - - result = 1; -end: + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_DST); DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2775,55 +2454,41 @@ FILE *SCThresholdConfGenerateValidDummyFD20() */ static int SCThresholdConfTest20(void) { - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - - if (de_ctx == NULL) - return result; - + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD20(); - SCThresholdConfInitContext(de_ctx,fd); - - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - result = 1; - } - } - } - } - } - } -end: + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; sid:1000;)"); + FAIL_IF_NULL(s); + FAIL_IF_NOT_NULL(g_ut_threshold_fp); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF_NOT(smd->is_last); + DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } /** @@ -2835,55 +2500,40 @@ static int SCThresholdConfTest20(void) */ static int SCThresholdConfTest21(void) { - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - DetectThresholdData *de = NULL; - Signature *sig = NULL; - SigMatch *m = NULL; - int result = 0; - FILE *fd = NULL; - HostInitConfig(HOST_QUIET); - - if (de_ctx == NULL) - return result; - + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - - sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); - if (sig == NULL) { - goto end; - } - - fd = SCThresholdConfGenerateValidDummyFD20(); - SCThresholdConfInitContext(de_ctx,fd); - - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - m = m->next; - if (m != NULL) { - de = (DetectThresholdData *)m->ctx; - if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { - result = 1; - } - } - } - } - } - } -end: + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any any (msg:\"Threshold limit\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + FAIL_IF_NULL(s); + g_ut_threshold_fp = SCThresholdConfGenerateValidDummyFD20(); + FAIL_IF_NULL(g_ut_threshold_fp); + SCThresholdConfInitContext(de_ctx); SigGroupBuild(de_ctx); - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NULL(s->sm_arrays[DETECT_SM_LIST_SUPPRESS]); + + SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_SUPPRESS]; + DetectThresholdData *de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF(smd->is_last); + + smd++; + de = (DetectThresholdData *)smd->ctx; + FAIL_IF_NULL(de); + FAIL_IF_NOT(de->type == TYPE_SUPPRESS && de->track == TRACK_SRC); + FAIL_IF_NOT(smd->is_last); + DetectEngineCtxFree(de_ctx); HostShutdown(); - return result; + PASS; } #endif /* UNITTESTS */ @@ -2894,28 +2544,39 @@ static int SCThresholdConfTest21(void) void SCThresholdConfRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01, 1); - UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02, 1); - UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03, 1); - UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04, 0); - UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05, 1); - UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06, 1); - UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07, 1); - UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08, 1); - UtRegisterTest("SCThresholdConfTest09 - rate_filter", SCThresholdConfTest09, 1); - UtRegisterTest("SCThresholdConfTest10 - rate_filter", SCThresholdConfTest10, 1); - UtRegisterTest("SCThresholdConfTest11 - event_filter", SCThresholdConfTest11, 1); - UtRegisterTest("SCThresholdConfTest12 - event_filter", SCThresholdConfTest12, 1); - UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13, 1); - UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14, 1); - UtRegisterTest("SCThresholdConfTest15 - suppress drop", SCThresholdConfTest15, 1); - UtRegisterTest("SCThresholdConfTest16 - suppress drop", SCThresholdConfTest16, 1); - UtRegisterTest("SCThresholdConfTest17 - suppress drop", SCThresholdConfTest17, 1); - - UtRegisterTest("SCThresholdConfTest18 - suppress parsing", SCThresholdConfTest18, 1); - UtRegisterTest("SCThresholdConfTest19 - suppress parsing", SCThresholdConfTest19, 1); - UtRegisterTest("SCThresholdConfTest20 - suppress parsing", SCThresholdConfTest20, 1); - UtRegisterTest("SCThresholdConfTest21 - suppress parsing", SCThresholdConfTest21, 1); + UtRegisterTest("SCThresholdConfTest01", SCThresholdConfTest01); + UtRegisterTest("SCThresholdConfTest02", SCThresholdConfTest02); + UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03); + UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04); + UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05); + UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06); + UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07); + UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08); + UtRegisterTest("SCThresholdConfTest09 - rate_filter", + SCThresholdConfTest09); + UtRegisterTest("SCThresholdConfTest10 - rate_filter", + SCThresholdConfTest10); + UtRegisterTest("SCThresholdConfTest11 - event_filter", + SCThresholdConfTest11); + UtRegisterTest("SCThresholdConfTest12 - event_filter", + SCThresholdConfTest12); + UtRegisterTest("SCThresholdConfTest13", SCThresholdConfTest13); + UtRegisterTest("SCThresholdConfTest14 - suppress", SCThresholdConfTest14); + UtRegisterTest("SCThresholdConfTest15 - suppress drop", + SCThresholdConfTest15); + UtRegisterTest("SCThresholdConfTest16 - suppress drop", + SCThresholdConfTest16); + UtRegisterTest("SCThresholdConfTest17 - suppress drop", + SCThresholdConfTest17); + + UtRegisterTest("SCThresholdConfTest18 - suppress parsing", + SCThresholdConfTest18); + UtRegisterTest("SCThresholdConfTest19 - suppress parsing", + SCThresholdConfTest19); + UtRegisterTest("SCThresholdConfTest20 - suppress parsing", + SCThresholdConfTest20); + UtRegisterTest("SCThresholdConfTest21 - suppress parsing", + SCThresholdConfTest21); #endif /* UNITTESTS */ } diff --git a/src/util-threshold-config.h b/src/util-threshold-config.h index 906ed7c6daae..459c956d0789 100644 --- a/src/util-threshold-config.h +++ b/src/util-threshold-config.h @@ -24,9 +24,8 @@ #ifndef __UTIL_THRESHOLD_CONFIG_H__ #define __UTIL_THRESHOLD_CONFIG_H__ -void SCThresholdConfDeInitContext(DetectEngineCtx *, FILE *); void SCThresholdConfParseFile(DetectEngineCtx *, FILE *); -int SCThresholdConfInitContext(DetectEngineCtx *, FILE *); +int SCThresholdConfInitContext(DetectEngineCtx *); void SCThresholdConfRegisterTests(); diff --git a/src/util-time.c b/src/util-time.c index e8f6fe107dbf..3e2b6058bbff 100644 --- a/src/util-time.c +++ b/src/util-time.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2013 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,18 +25,46 @@ * And time string generation for alerts. */ +/* Real time vs offline time + * + * When we run on live traffic, time handling is simple. Packets have a + * timestamp set by the capture method. Management threads can simply + * use 'gettimeofday' to know the current time. There should never be + * any serious gap between the two. + * + * In offline mode, things are dramatically different. Here we try to keep + * the time from the pcap, which means that if the packets are in 2011 the + * log output should also reflect this. Multiple issues: + * 1. merged pcaps might have huge time jumps or time going backward + * 2. slowly recorded pcaps may be processed much faster than their 'realtime' + * 3. management threads need a concept of what the 'current' time is for + * enforcing timeouts + * 4. due to (1) individual threads may have very different views on what + * the current time is. E.g. T1 processed packet 1 with TS X, while T2 + * at the very same time processes packet 2 with TS X+100000s. + * + * In offline mode we keep the timestamp per thread. If a management thread + * needs current time, it will get the minimum of the threads' values. This + * is to avoid the problem that T2s time value might already trigger a flow + * timeout as the flow lastts + 100000s is almost certainly meaning the flow + * would be considered timed out. + */ + #include "suricata-common.h" #include "detect.h" #include "threads.h" +#include "tm-threads.h" #include "util-debug.h" +#ifdef UNITTESTS static struct timeval current_time = { 0, 0 }; +#endif //static SCMutex current_time_mutex = SCMUTEX_INITIALIZER; static SCSpinlock current_time_spinlock; static char live = TRUE; - struct tm *SCLocalTime(time_t timep, struct tm *result); +struct tm *SCUtcTime(time_t timep, struct tm *result); void TimeInit(void) { @@ -63,6 +91,20 @@ void TimeModeSetOffline (void) SCLogDebug("offline time mode enabled"); } +int TimeModeIsLive(void) +{ + return live; +} + +void TimeSetByThread(const int thread_id, const struct timeval *tv) +{ + if (live == TRUE) + return; + + TmThreadsSetThreadTimestamp(thread_id, tv); +} + +#ifdef UNITTESTS void TimeSet(struct timeval *tv) { if (live == TRUE) @@ -91,6 +133,7 @@ void TimeSetToCurrentTime(void) TimeSet(&tv); } +#endif void TimeGet(struct timeval *tv) { @@ -100,16 +143,25 @@ void TimeGet(struct timeval *tv) if (live == TRUE) { gettimeofday(tv, NULL); } else { - SCSpinLock(¤t_time_spinlock); - tv->tv_sec = current_time.tv_sec; - tv->tv_usec = current_time.tv_usec; - SCSpinUnlock(¤t_time_spinlock); +#ifdef UNITTESTS + if (unlikely(RunmodeIsUnittests())) { + SCSpinLock(¤t_time_spinlock); + tv->tv_sec = current_time.tv_sec; + tv->tv_usec = current_time.tv_usec; + SCSpinUnlock(¤t_time_spinlock); + } else { +#endif + TmreadsGetMinimalTimestamp(tv); +#ifdef UNITTESTS + } +#endif } SCLogDebug("time we got is %" PRIuMAX " sec, %" PRIuMAX " usec", (uintmax_t)tv->tv_sec, (uintmax_t)tv->tv_usec); } +#ifdef UNITTESTS /** \brief increment the time in the engine * \param tv_sec seconds to increment the time with */ void TimeSetIncrementTime(uint32_t tv_sec) @@ -122,16 +174,52 @@ void TimeSetIncrementTime(uint32_t tv_sec) TimeSet(&tv); } +#endif void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size) { time_t time = ts->tv_sec; struct tm local_tm; + memset(&local_tm, 0, sizeof(local_tm)); struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); + char time_fmt[64] = { 0 }; - snprintf(str, size, "%04d-%02d-%02dT%02d:%02d:%02d.%06u", - t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, - t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + if (likely(t != NULL)) { + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S.%%06u%z", t); + snprintf(str, size, time_fmt, ts->tv_usec); + } else { + snprintf(str, size, "ts-error"); + } +} + +void CreateUtcIsoTimeString (const struct timeval *ts, char *str, size_t size) +{ + time_t time = ts->tv_sec; + struct tm local_tm; + memset(&local_tm, 0, sizeof(local_tm)); + struct tm *t = (struct tm*)SCUtcTime(time, &local_tm); + char time_fmt[64] = { 0 }; + + if (likely(t != NULL)) { + strftime(time_fmt, sizeof(time_fmt), "%Y-%m-%dT%H:%M:%S", t); + snprintf(str, size, time_fmt, ts->tv_usec); + } else { + snprintf(str, size, "ts-error"); + } +} + +void CreateFormattedTimeString (const struct tm *t, const char *fmt, char *str, size_t size) +{ + if (likely(t != NULL && fmt != NULL && str != NULL)) { + strftime(str, size, fmt, t); + } else { + snprintf(str, size, "ts-error"); + } +} + +struct tm *SCUtcTime(time_t timep, struct tm *result) +{ + return gmtime_r(&timep, result); } /* @@ -152,9 +240,13 @@ void CreateTimeString (const struct timeval *ts, char *str, size_t size) struct tm local_tm; struct tm *t = (struct tm*)SCLocalTime(time, &local_tm); - snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", - t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, - t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + if (likely(t != NULL)) { + snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", + t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, + t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); + } else { + snprintf(str, size, "ts-error"); + } } #else @@ -294,3 +386,206 @@ void CreateTimeString (const struct timeval *ts, char *str, size_t size) } #endif /* defined(__OpenBSD__) */ + +/** + * \brief Convert broken-down time to seconds since Unix epoch. + * + * This function is based on: http://www.catb.org/esr/time-programming + * (released to the public domain). + * + * \param tp Pointer to broken-down time. + * + * \retval Seconds since Unix epoch. + */ +time_t SCMkTimeUtc (struct tm *tp) +{ + time_t result; + long year; +#define MONTHSPERYEAR 12 + static const int mdays[MONTHSPERYEAR] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + year = 1900 + tp->tm_year + tp->tm_mon / MONTHSPERYEAR; + result = (year - 1970) * 365 + mdays[tp->tm_mon % MONTHSPERYEAR]; + result += (year - 1968) / 4; + result -= (year - 1900) / 100; + result += (year - 1600) / 400; + if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) && + (tp->tm_mon % MONTHSPERYEAR) < 2) + result--; + result += tp->tm_mday - 1; + result *= 24; + result += tp->tm_hour; + result *= 60; + result += tp->tm_min; + result *= 60; + result += tp->tm_sec; + if (tp->tm_gmtoff) + result -= tp->tm_gmtoff; + return result; +} + +/** + * \brief Parse a date string based on specified patterns. + * + * This function is based on GNU C library getdate. + * + * \param string Date string to parse. + * \param patterns String array containing patterns. + * \param num_patterns Number of patterns to check. + * \param tp Pointer to broken-down time. + * + * \retval 0 on success. + * \retval 1 on failure. + */ +int SCStringPatternToTime (char *string, char **patterns, int num_patterns, + struct tm *tp) +{ + char *result = NULL; + int i = 0; + + /* Do the pattern matching */ + for (i = 0; i < num_patterns; i++) + { + if (patterns[i] == NULL) + continue; + + tp->tm_hour = tp->tm_min = tp->tm_sec = 0; + tp->tm_year = tp->tm_mon = tp->tm_mday = tp->tm_wday = INT_MIN; + tp->tm_isdst = -1; + tp->tm_gmtoff = 0; + tp->tm_zone = NULL; + result = strptime(string, patterns[i], tp); + + if (result && *result == '\0') + break; + } + + /* Return if no patterns matched */ + if (result == NULL || *result != '\0') + return 1; + + /* Return if no date is given */ + if (tp->tm_year == INT_MIN && tp->tm_mon == INT_MIN && + tp->tm_mday == INT_MIN) + return 1; + + /* The first of the month is assumed, if only year and + month is given */ + if (tp->tm_year != INT_MIN && tp->tm_mon != INT_MIN && + tp->tm_mday <= 0) + tp->tm_mday = 1; + + return 0; +} + +/** + * \brief Convert epoch time to string pattern. + * + * This function converts epoch time to a string based on a pattern. + * + * \param epoch Epoch time. + * \param pattern String pattern. + * \param str Formated string. + * \param size Size of allocated string. + * + * \retval 0 on success. + * \retval 1 on failure. + */ +int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, size_t size) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + char buffer[PATH_MAX] = { 0 }; + + if (unlikely(tp == NULL)) { + return 1; + } + + int r = strftime(buffer, sizeof(buffer), pattern, tp); + if (r == 0) { + return 1; + } + + strlcpy(str, buffer, size); + + return 0; +} + +/** + * \brief Parse string containing time size (1m, 1h, etc). + * + * \param str String to parse. + * + * \retval size on success. + * \retval 0 on failure. + */ +uint64_t SCParseTimeSizeString (const char *str) +{ + uint64_t size = 0; + uint64_t modifier = 1; + char last = str[strlen(str)-1]; + + switch (last) + { + case '0' ... '9': + break; + /* seconds */ + case 's': + break; + /* minutes */ + case 'm': + modifier = 60; + break; + /* hours */ + case 'h': + modifier = 60 * 60; + break; + /* days */ + case 'd': + modifier = 60 * 60 * 24; + break; + /* weeks */ + case 'w': + modifier = 60 * 60 * 24 * 7; + break; + /* invalid */ + default: + return 0; + } + + errno = 0; + size = strtoumax(str, NULL, 10); + if (errno) { + return 0; + } + + return (size * modifier); +} + +/** + * \brief Get seconds until a time unit changes. + * + * \param str String containing time type (minute, hour, etc). + * \param epoch Epoch time. + * + * \retval seconds. + */ +uint64_t SCGetSecondsUntil (const char *str, time_t epoch) +{ + uint64_t seconds = 0; + struct tm tm; + memset(&tm, 0, sizeof(tm)); + struct tm *tp = (struct tm *)SCLocalTime(epoch, &tm); + + if (strcmp(str, "minute") == 0) + seconds = 60 - tp->tm_sec; + else if (strcmp(str, "hour") == 0) + seconds = (60 * (60 - tp->tm_min)) + (60 - tp->tm_sec); + else if (strcmp(str, "day") == 0) + seconds = (3600 * (24 - tp->tm_hour)) + (60 * (60 - tp->tm_min)) + + (60 - tp->tm_sec); + + return seconds; +} diff --git a/src/util-time.h b/src/util-time.h index cdf1d5bf7afe..4bf965e729ff 100644 --- a/src/util-time.h +++ b/src/util-time.h @@ -37,18 +37,31 @@ typedef struct SCTimeval32_ { void TimeInit(void); void TimeDeinit(void); -void TimeSet(struct timeval *); +void TimeSetByThread(const int thread_id, const struct timeval *tv); void TimeGet(struct timeval *); +#ifdef UNITTESTS +void TimeSet(struct timeval *); void TimeSetToCurrentTime(void); void TimeSetIncrementTime(uint32_t); +#endif void TimeModeSetLive(void); void TimeModeSetOffline (void); +int TimeModeIsLive(void); struct tm *SCLocalTime(time_t timep, struct tm *result); -void CreateTimeString (const struct timeval *ts, char *str, size_t size); -void CreateIsoTimeString (const struct timeval *ts, char *str, size_t size); +void CreateTimeString(const struct timeval *ts, char *str, size_t size); +void CreateIsoTimeString(const struct timeval *ts, char *str, size_t size); +void CreateUtcIsoTimeString(const struct timeval *ts, char *str, size_t size); +void CreateFormattedTimeString(const struct tm *t, const char * fmt, char *str, size_t size); +time_t SCMkTimeUtc(struct tm *tp); +int SCStringPatternToTime(char *string, char **patterns, + int num_patterns, struct tm *time); +int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str, + size_t size); +uint64_t SCParseTimeSizeString (const char *str); +uint64_t SCGetSecondsUntil (const char *str, time_t epoch); #endif /* __UTIL_TIME_H__ */ diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c index a318205d70f0..f82da37bda99 100644 --- a/src/util-unittest-helper.c +++ b/src/util-unittest-helper.c @@ -85,7 +85,7 @@ Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len, if (unlikely(p == NULL)) return NULL; - TimeSet(&p->ts); + TimeGet(&p->ts); p->src.family = AF_INET6; p->dst.family = AF_INET6; @@ -233,7 +233,9 @@ Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, /* TODO: Add more protocols */ } - PacketCopyDataOffset(p, hdr_offset, payload, payload_len); + if (payload && payload_len) { + PacketCopyDataOffset(p, hdr_offset, payload, payload_len); + } SET_PKT_LEN(p, hdr_offset + payload_len); p->payload = GET_PKT_DATA(p)+hdr_offset; @@ -568,7 +570,7 @@ int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], for (; i < numsids; i++) { uint16_t r = PacketAlertCheck(p, sids[i]); if (r != results[i]) { - SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu16 + SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu32 " as expected", sids[i], r, results[i]); res = 0; } else { @@ -852,8 +854,10 @@ uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir) p->dst.addr_data32[0] = i; } FlowHandlePacket(NULL, NULL, p); - if (p->flow != NULL) + if (p->flow != NULL) { SC_ATOMIC_RESET(p->flow->use_cnt); + FLOWLOCK_UNLOCK(p->flow); + } /* Now the queues shoul be updated */ UTHFreePacket(p); @@ -1066,15 +1070,17 @@ int UTHBuildPacketSrcDstPortsTest02(void) void UTHRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01, 1); - UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02, 1); - UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01, 1); - UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02, 1); - UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01, 1); - UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02, 1); - UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", UTHBuildPacketSrcDstPortsTest01, 1); - UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", UTHBuildPacketSrcDstPortsTest02, 1); - UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01, 1); + UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01); + UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02); + UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01); + UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02); + UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01); + UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", + UTHBuildPacketSrcDstPortsTest01); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", + UTHBuildPacketSrcDstPortsTest02); + UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01); #endif /* UNITTESTS */ } diff --git a/src/util-unittest.c b/src/util-unittest.c index c3f0fdb29604..0503a2431b0a 100644 --- a/src/util-unittest.c +++ b/src/util-unittest.c @@ -24,6 +24,14 @@ * Unit test framework */ +/** + * \defgroup Testing Testing + * + * \brief Unit testing support functions. + * + * @{ + */ + #include "suricata-common.h" #include "runmodes.h" #include "util-unittest.h" @@ -38,6 +46,8 @@ static pcre_extra *parse_regex_study; static UtTest *ut_list; +int unittests_fatal = 0; + /** * \brief Allocate UtTest list member * @@ -85,11 +95,9 @@ static int UtAppendTest(UtTest **list, UtTest *test) * * \param name Unit test name * \param TestFn Unit test function - * \param evalue Unit test function return value - * */ -void UtRegisterTest(char *name, int(*TestFn)(void), int evalue) +void UtRegisterTest(char *name, int(*TestFn)(void)) { UtTest *ut = UtAllocTest(); if (ut == NULL) @@ -97,7 +105,6 @@ void UtRegisterTest(char *name, int(*TestFn)(void), int evalue) ut->name = name; ut->TestFn = TestFn; - ut->evalue = evalue; ut->next = NULL; /* append */ @@ -184,12 +191,6 @@ uint32_t UtRunTests(char *regex_arg) uint32_t good = 0, bad = 0, matchcnt = 0; int ret = 0, rcomp = 0; int ov[MAX_SUBSTRINGS]; - int failure_fatal; - - if (ConfGetBool("unittests.failure-fatal", &failure_fatal) != 1) { - SCLogDebug("ConfGetBool could not load the value."); - failure_fatal = 0; - } rcomp = UtRegex(regex_arg); @@ -206,9 +207,9 @@ uint32_t UtRunTests(char *regex_arg) TimeSetToCurrentTime(); ret = ut->TestFn(); - printf("%s\n", (ret == ut->evalue) ? "pass" : "FAILED"); - if (ret != ut->evalue) { - if (failure_fatal == 1) { + printf("%s\n", ret ? "pass" : "FAILED"); + if (!ret) { + if (unittests_fatal == 1) { fprintf(stderr, "ERROR: unittest failed.\n"); exit(EXIT_FAILURE); } @@ -292,9 +293,10 @@ int UtSelftestTrue(void) int UtSelftestFalse(void) { - if (0)return 1; - else return 0; + if (0)return 0; + else return 1; } + #endif /* UNITTESTS */ /** \brief Run self tests @@ -311,8 +313,8 @@ int UtRunSelftest (char *regex_arg) UtInitialize(); - UtRegisterTest("true", UtSelftestTrue, 1); - UtRegisterTest("false", UtSelftestFalse, 0); + UtRegisterTest("true", UtSelftestTrue); + UtRegisterTest("false", UtSelftestFalse); int ret = UtRunTests(regex_arg); if (ret == 0) @@ -324,3 +326,7 @@ int UtRunSelftest (char *regex_arg) #endif /* UNITTESTS */ return 0; } + +/** + * @} + */ diff --git a/src/util-unittest.h b/src/util-unittest.h index ebad947089b9..7a0e110be9cb 100644 --- a/src/util-unittest.h +++ b/src/util-unittest.h @@ -24,6 +24,12 @@ * Unit test framework */ +/** + * \addtogroup Testing + * + * @{ + */ + #ifndef __UTIL_UNITTEST_H__ #define __UTIL_UNITTEST_H__ @@ -33,14 +39,12 @@ typedef struct UtTest_ { char *name; int(*TestFn)(void); - int evalue; struct UtTest_ *next; } UtTest; - -void UtRegisterTest(char *name, int(*TestFn)(void), int evalue); +void UtRegisterTest(char *name, int(*TestFn)(void)); uint32_t UtRunTests(char *regex_arg); void UtInitialize(void); void UtCleanup(void); @@ -48,7 +52,75 @@ int UtRunSelftest (char *regex_arg); void UtListTests(char *regex_arg); void UtRunModeRegister(void); +extern int unittests_fatal; + +/** + * \breif Fail a test. + */ +#define FAIL do { \ + if (unittests_fatal) { \ + BUG_ON(1); \ + } else { \ + return 0; \ + } \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to false. + */ +#define FAIL_IF(expr) do { \ + if (unittests_fatal) { \ + BUG_ON(expr); \ + } else if (expr) { \ + return 0; \ + } \ + } while (0) + +/** + * \brief Fail a test if expression to true. + */ +#define FAIL_IF_NOT(expr) do { \ + FAIL_IF(!(expr)); \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to NULL. + */ +#define FAIL_IF_NULL(expr) do { \ + FAIL_IF(NULL == expr); \ + } while (0) + +/** + * \brief Fail a test if expression evaluates to non-NULL. + */ +#define FAIL_IF_NOT_NULL(expr) do { \ + FAIL_IF(NULL != expr); \ + } while (0) + +/** + * \brief Pass the test. + * + * Only to be used at the end of a function instead instead of "return 1." + */ +#define PASS do { \ + return 1; \ + } while (0) + #endif +/** + * \brief Pass the test if expression evaluates to true. + * + * Only to be used at the end of a function instead of returning the + * result of an expression. + */ +#define PASS_IF(expr) do { \ + FAIL_IF(!(expr)); \ + PASS; \ + } while (0) + #endif /* __UTIL_UNITTEST_H__ */ +/** + * @} + */ diff --git a/src/util-validate.h b/src/util-validate.h index b5c3da26b2c3..c0dac20b78be 100644 --- a/src/util-validate.h +++ b/src/util-validate.h @@ -53,14 +53,12 @@ */ #define DEBUG_VALIDATE_FLOW(f) do { \ if ((f) != NULL) { \ - SCMutexLock(&(f)->m); \ BUG_ON((f)->flags & FLOW_IPV4 && \ (f)->flags & FLOW_IPV6); \ if ((f)->proto == IPPROTO_TCP) { \ BUG_ON((f)->alstate != NULL && \ (f)->alparser == NULL); \ } \ - SCMutexUnlock(&(f)->m); \ } \ } while(0) @@ -96,11 +94,14 @@ } \ } while(0) +#define DEBUG_VALIDATE_BUG_ON(exp) BUG_ON((exp)) + #else /* DEBUG_VALIDATE */ #define DEBUG_ASSERT_FLOW_LOCKED(f) #define DEBUG_VALIDATE_FLOW(f) #define DEBUG_VALIDATE_PACKET(p) +#define DEBUG_VALIDATE_BUG_ON(exp) #endif /* DEBUG_VALIDATE */ diff --git a/src/util-var-name.c b/src/util-var-name.c index b50e35c9c46f..276b8723dc2e 100644 --- a/src/util-var-name.c +++ b/src/util-var-name.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -26,13 +26,43 @@ #include "suricata-common.h" #include "detect.h" #include "util-hashlist.h" +#include "util-var-name.h" + +/* the way this can be used w/o locking lookups: + * - Lookups use only g_varnamestore_current which is read only + * - Detection setups a new ctx in staging, which will include the 'current' + * entries keeping ID's stable + * - Detection hot swaps staging into current after a new detect engine was + * created. Current remains available through 'old'. + * - When detect reload is complete (threads are all moved over), 'old' can + * be freed. + */ + +typedef struct VarNameStore_ { + HashListTable *names; + HashListTable *ids; + uint32_t max_id; + uint32_t de_ctx_version; /**< de_ctx version 'owning' this */ +} VarNameStore; + +static int initialized = 0; +/* currently VarNameStore that is READ ONLY. This way lookups can + * be done w/o locking or synchronization */ +SC_ATOMIC_DECLARE(VarNameStore *, g_varnamestore_current); + +/* old VarNameStore on the way out */ +static VarNameStore *g_varnamestore_old = NULL; + +/* new VarNameStore that is being prepared. Multiple DetectLoader threads + * may be updating it so a lock is used for synchronization. */ +static VarNameStore *g_varnamestore_staging = NULL; +static SCMutex g_varnamestore_staging_m = SCMUTEX_INITIALIZER; /** \brief Name2idx mapping structure for flowbits, flowvars and pktvars. */ typedef struct VariableName_ { char *name; uint8_t type; /* flowbit, pktvar, etc */ - uint8_t flags; - uint16_t idx; + uint32_t idx; } VariableName; static uint32_t VariableNameHash(HashListTable *ht, void *buf, uint16_t buflen) @@ -99,45 +129,49 @@ static void VariableNameFree(void *data) } /** \brief Initialize the Name idx hash. - * \param de_ctx Ptr to the detection engine ctx. - * \retval -1 in case of error - * \retval 0 in case of success */ -int VariableNameInitHash(DetectEngineCtx *de_ctx) +static VarNameStore *VarNameStoreInit(void) { - de_ctx->variable_names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree); - if (de_ctx->variable_names == NULL) - return -1; + VarNameStore *v = SCCalloc(1, sizeof(*v)); + if (v == NULL) + return NULL; + + v->names = HashListTableInit(4096, VariableNameHash, VariableNameCompare, VariableNameFree); + if (v->names == NULL) { + SCFree(v); + return NULL; + } - de_ctx->variable_idxs = HashListTableInit(4096, VariableIdxHash, VariableIdxCompare, NULL); - if (de_ctx->variable_idxs == NULL) - return -1; + v->ids = HashListTableInit(4096, VariableIdxHash, VariableIdxCompare, NULL); + if (v->ids == NULL) { + HashListTableFree(v->names); + SCFree(v); + return NULL; + } - de_ctx->variable_names_idx = 0; - return 0; + v->max_id = 0; + return v; } -void VariableNameFreeHash(DetectEngineCtx *de_ctx) +static void VarNameStoreDoFree(VarNameStore *v) { - if (de_ctx->variable_names != NULL) { - HashListTableFree(de_ctx->variable_names); - HashListTableFree(de_ctx->variable_idxs); - de_ctx->variable_names = NULL; - de_ctx->variable_idxs = NULL; + if (v) { + HashListTableFree(v->names); + HashListTableFree(v->ids); + SCFree(v); } - - return; } + /** \brief Get a name idx for a name. If the name is already used reuse the idx. * \param name nul terminated string with the name - * \param type variable type (DETECT_FLOWBITS, DETECT_PKTVAR, etc) + * \param type variable type * \retval 0 in case of error - * \retval _ the idx. + * \retval idx the idx or 0 */ -uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, uint8_t type) +static uint32_t VariableNameGetIdx(VarNameStore *v, const char *name, enum VarTypes type) { - uint16_t idx = 0; + uint32_t idx = 0; VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) @@ -150,13 +184,14 @@ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, uint8_t type) if (fn->name == NULL) goto error; - VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_names, (void *)fn, 0); + VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->names, (void *)fn, 0); if (lookup_fn == NULL) { - de_ctx->variable_names_idx++; + v->max_id++; - idx = fn->idx = de_ctx->variable_names_idx; - HashListTableAdd(de_ctx->variable_names, (void *)fn, 0); - HashListTableAdd(de_ctx->variable_idxs, (void *)fn, 0); + idx = fn->idx = v->max_id; + HashListTableAdd(v->names, (void *)fn, 0); + HashListTableAdd(v->ids, (void *)fn, 0); + SCLogDebug("new registration %s id %u type %u", fn->name, fn->idx, fn->type); } else { idx = lookup_fn->idx; VariableNameFree(fn); @@ -168,13 +203,15 @@ uint16_t VariableNameGetIdx(DetectEngineCtx *de_ctx, char *name, uint8_t type) return 0; } +#if 0 /** \brief Get a name from the idx. * \param idx index of the variable whose name is to be fetched - * \param type variable type (DETECT_FLOWBITS, DETECT_PKTVAR, etc) + * \param type variable type * \retval NULL in case of error * \retval name of the variable if successful. + * \todo no alloc on lookup */ -char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, uint8_t type) +static const char *VariableIdxGetName(VarNameStore *v, uint32_t idx, enum VarTypes type) { VariableName *fn = SCMalloc(sizeof(VariableName)); if (unlikely(fn == NULL)) @@ -186,7 +223,7 @@ char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, uint8_t type) fn->type = type; fn->idx = idx; - VariableName *lookup_fn = (VariableName *)HashListTableLookup(de_ctx->variable_idxs, (void *)fn, 0); + VariableName *lookup_fn = (VariableName *)HashListTableLookup(v->ids, (void *)fn, 0); if (lookup_fn != NULL) { name = SCStrdup(lookup_fn->name); if (unlikely(name == NULL)) @@ -202,3 +239,141 @@ char *VariableIdxGetName(DetectEngineCtx *de_ctx, uint16_t idx, uint8_t type) VariableNameFree(fn); return NULL; } +#endif +/** \brief setup staging store. Include current store if there is one. + */ +int VarNameStoreSetupStaging(uint32_t de_ctx_version) +{ + SCMutexLock(&g_varnamestore_staging_m); + + if (!initialized) { + SC_ATOMIC_INIT(g_varnamestore_current); + initialized = 1; + } + + if (g_varnamestore_staging != NULL && + g_varnamestore_staging->de_ctx_version == de_ctx_version) { + SCMutexUnlock(&g_varnamestore_staging_m); + return 0; + } + + VarNameStore *nv = VarNameStoreInit(); + if (nv == NULL) { + SCMutexUnlock(&g_varnamestore_staging_m); + return -1; + } + g_varnamestore_staging = nv; + nv->de_ctx_version = de_ctx_version; + + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + if (current) { + /* add all entries from the current hash into this new one. */ + HashListTableBucket *b = HashListTableGetListHead(current->names); + while (b) { + VariableName *var = HashListTableGetListData(b); + + VariableName *newvar = SCCalloc(1, sizeof(*newvar)); + BUG_ON(newvar == NULL); + memcpy(newvar, var, sizeof(*newvar)); + newvar->name = SCStrdup(var->name); + BUG_ON(newvar->name == NULL); + + HashListTableAdd(nv->names, (void *)newvar, 0); + HashListTableAdd(nv->ids, (void *)newvar, 0); + nv->max_id = MAX(nv->max_id, newvar->idx); + SCLogDebug("xfer %s id %u type %u", newvar->name, newvar->idx, newvar->type); + + b = HashListTableGetListNext(b); + } + } + + SCLogDebug("set up staging with detect engine ver %u", nv->de_ctx_version); + SCMutexUnlock(&g_varnamestore_staging_m); + return 0; +} + +const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type) +{ + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + BUG_ON(current == NULL); + VariableName lookup = { NULL, type, id }; + VariableName *found = (VariableName *)HashListTableLookup(current->ids, (void *)&lookup, 0); + if (found == NULL) { + return NULL; + } + return found->name; +} + +uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type) +{ + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + BUG_ON(current == NULL); + VariableName lookup = { (char *)name, type, 0 }; + VariableName *found = (VariableName *)HashListTableLookup(current->names, (void *)&lookup, 0); + if (found == NULL) { + return 0; + } + SCLogDebug("found %u for %s type %u", found->idx, name, type); + return found->idx; +} + +/** \brief add to staging or return existing id if already in there */ +uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type) +{ + uint32_t id; + SCMutexLock(&g_varnamestore_staging_m); + id = VariableNameGetIdx(g_varnamestore_staging, name, type); + SCMutexUnlock(&g_varnamestore_staging_m); + return id; +} + +void VarNameStoreActivateStaging(void) +{ + SCMutexLock(&g_varnamestore_staging_m); + if (g_varnamestore_old) { + VarNameStoreDoFree(g_varnamestore_old); + g_varnamestore_old = NULL; + } + g_varnamestore_old = SC_ATOMIC_GET(g_varnamestore_current); + SC_ATOMIC_SET(g_varnamestore_current, g_varnamestore_staging); + g_varnamestore_staging = NULL; + SCMutexUnlock(&g_varnamestore_staging_m); +} + +void VarNameStoreFreeOld(void) +{ + SCMutexLock(&g_varnamestore_staging_m); + SCLogDebug("freeing g_varnamestore_old %p", g_varnamestore_old); + if (g_varnamestore_old) { + VarNameStoreDoFree(g_varnamestore_old); + g_varnamestore_old = NULL; + } + SCMutexUnlock(&g_varnamestore_staging_m); +} + +void VarNameStoreFree(uint32_t de_ctx_version) +{ + SCLogDebug("freeing detect engine version %u", de_ctx_version); + SCMutexLock(&g_varnamestore_staging_m); + if (g_varnamestore_old && g_varnamestore_old->de_ctx_version == de_ctx_version) { + VarNameStoreDoFree(g_varnamestore_old); + g_varnamestore_old = NULL; + SCLogDebug("freeing detect engine version %u: old done", de_ctx_version); + } + + /* if at this point we have a staging area which matches our version + * we didn't complete the setup and are cleaning up the mess. */ + if (g_varnamestore_staging && g_varnamestore_staging->de_ctx_version == de_ctx_version) { + VarNameStoreDoFree(g_varnamestore_staging); + g_varnamestore_staging = NULL; + SCLogDebug("freeing detect engine version %u: staging done", de_ctx_version); + } + + VarNameStore *current = SC_ATOMIC_GET(g_varnamestore_current); + if (current && current->de_ctx_version == de_ctx_version) { + VarNameStoreDoFree(current); + SC_ATOMIC_SET(g_varnamestore_current, NULL); + SCLogDebug("freeing detect engine version %u: current done", de_ctx_version); + } + SCMutexUnlock(&g_varnamestore_staging_m); +} diff --git a/src/util-var-name.h b/src/util-var-name.h index 10bd4165c314..c620d74eb5a4 100644 --- a/src/util-var-name.h +++ b/src/util-var-name.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2016 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -24,11 +24,13 @@ #ifndef __UTIL_VAR_NAME_H__ #define __UTIL_VAR_NAME_H__ -int VariableNameInitHash(DetectEngineCtx *); -void VariableNameFreeHash(DetectEngineCtx *); - -uint16_t VariableNameGetIdx(DetectEngineCtx *, char *, uint8_t); -char * VariableIdxGetName(DetectEngineCtx *, uint16_t , uint8_t); +int VarNameStoreSetupStaging(uint32_t de_ctx_version); +const char *VarNameStoreLookupById(const uint32_t id, const enum VarTypes type); +uint32_t VarNameStoreLookupByName(const char *name, const enum VarTypes type); +uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type); +void VarNameStoreActivateStaging(void); +void VarNameStoreFreeOld(void); +void VarNameStoreFree(uint32_t de_ctx_version); #endif diff --git a/src/util-var.c b/src/util-var.c index 832a2d31f1c0..8a2df63f1fa7 100644 --- a/src/util-var.c +++ b/src/util-var.c @@ -31,9 +31,19 @@ #include "flow-var.h" #include "flow-bit.h" #include "pkt-var.h" +#include "host-bit.h" +#include "ippair-bit.h" #include "util-debug.h" +void XBitFree(XBit *fb) +{ + if (fb == NULL) + return; + + SCFree(fb); +} + void GenericVarFree(GenericVar *gv) { if (gv == NULL) @@ -50,6 +60,13 @@ void GenericVarFree(GenericVar *gv) FlowBitFree(fb); break; } + case DETECT_XBITS: + { + XBit *fb = (XBit *)gv; + //printf("GenericVarFree: fb %p, removing\n", fb); + XBitFree(fb); + break; + } case DETECT_FLOWVAR: { FlowVar *fv = (FlowVar *)gv; @@ -111,3 +128,47 @@ void GenericVarRemove(GenericVar **list, GenericVar *gv) listgv = listgv->next; } } + +// Checks if a variable is already in a resolve list and if it's not, adds it. +int AddVariableToResolveList(ResolvedVariablesList *list, const char *var) +{ + ResolvedVariable *p_item; + + if (list == NULL || var == NULL) + return 0; + + if (var[0] != '$') { + return 0; + } + + TAILQ_FOREACH(p_item, list, next) { + if (!strcmp(p_item->var_name, var)) { + return -1; + } + } + + p_item = SCMalloc(sizeof(ResolvedVariable)); + + if (unlikely(p_item == NULL)) { + return -1; + } + + strlcpy(p_item->var_name, var, sizeof(p_item->var_name) - 1); + TAILQ_INSERT_TAIL(list, p_item, next); + + return 0; +} + +void CleanVariableResolveList(ResolvedVariablesList *var_list) +{ + if (var_list == NULL) { + return; + } + + ResolvedVariable *p_item; + + while ((p_item = TAILQ_FIRST(var_list))) { + TAILQ_REMOVE(var_list, p_item, next); + SCFree(p_item); + } +} diff --git a/src/util-var.h b/src/util-var.h index 5d28cc7cc11f..ce491ecdcd82 100644 --- a/src/util-var.h +++ b/src/util-var.h @@ -24,15 +24,59 @@ #ifndef __UTIL_VAR_H__ #define __UTIL_VAR_H__ +enum VarTypes { + VAR_TYPE_NOT_SET, + + VAR_TYPE_PKT_BIT, + VAR_TYPE_PKT_INT, + VAR_TYPE_PKT_VAR, + VAR_TYPE_PKT_VAR_KV, // key-value + + VAR_TYPE_FLOW_BIT, + VAR_TYPE_FLOW_INT, + VAR_TYPE_FLOW_VAR, + + VAR_TYPE_HOST_BIT, + VAR_TYPE_HOST_INT, + VAR_TYPE_HOST_VAR, + + VAR_TYPE_IPPAIR_BIT, + VAR_TYPE_IPPAIR_INT, + VAR_TYPE_IPPAIR_VAR, +}; + typedef struct GenericVar_ { uint8_t type; - uint16_t idx; + uint8_t pad[3]; + uint32_t idx; struct GenericVar_ *next; } GenericVar; +typedef struct XBit_ { + uint8_t type; /* type, DETECT_XBITS in this case */ + uint8_t pad[3]; + uint32_t idx; /* name idx */ + GenericVar *next; + uint32_t expire; +} XBit; + +void XBitFree(XBit *); + +// A list of variables we try to resolve while parsing configuration file. +// Helps to detect recursive declarations. +typedef struct ResolvedVariable_ { + char var_name[256]; + TAILQ_ENTRY(ResolvedVariable_) next; +} ResolvedVariable; + +typedef TAILQ_HEAD(, ResolvedVariable_) ResolvedVariablesList; + void GenericVarFree(GenericVar *); void GenericVarAppend(GenericVar **, GenericVar *); void GenericVarRemove(GenericVar **, GenericVar *); +int AddVariableToResolveList(ResolvedVariablesList *list, const char *var); +void CleanVariableResolveList(ResolvedVariablesList *var_list); + #endif /* __UTIL_VAR_H__ */ diff --git a/suricata.yaml.in b/suricata.yaml.in index 562085ed3767..0a80d2b62017 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -5,76 +5,128 @@ # options in this file, full documentation can be found at: # https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricatayaml +## +## Step 1: inform Suricata about your network +## -# Number of packets preallocated per thread. The default is 1024. A higher number -# will make sure each CPU will be more easily kept busy, but may negatively -# impact caching. -# -# If you are using the CUDA pattern matcher (mpm-algo: ac-cuda), different rules -# apply. In that case try something like 60000 or more. This is because the CUDA -# pattern matcher buffers and scans as many packets as possible in parallel. -#max-pending-packets: 1024 +vars: + # more specifc is better for alert accuracy and performance + address-groups: + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + #HOME_NET: "[192.168.0.0/16]" + #HOME_NET: "[10.0.0.0/8]" + #HOME_NET: "[172.16.0.0/12]" + #HOME_NET: "any" -# Runmode the engine should use. Please check --list-runmodes to get the available -# runmodes for each packet acquisition method. Defaults to "autofp" (auto flow pinned -# load balancing). -#runmode: autofp + EXTERNAL_NET: "!$HOME_NET" + #EXTERNAL_NET: "any" -# Specifies the kind of flow load balancer used by the flow pinned autofp mode. -# -# Supported schedulers are: -# -# round-robin - Flows assigned to threads in a round robin fashion. -# active-packets - Flows assigned to threads that have the lowest number of -# unprocessed packets (default). -# hash - Flow alloted usihng the address hash. More of a random -# technique. Was the default in Suricata 1.2.1 and older. -# -#autofp-scheduler: active-packets + HTTP_SERVERS: "$HOME_NET" + SMTP_SERVERS: "$HOME_NET" + SQL_SERVERS: "$HOME_NET" + DNS_SERVERS: "$HOME_NET" + TELNET_SERVERS: "$HOME_NET" + AIM_SERVERS: "$EXTERNAL_NET" + DNP3_SERVER: "$HOME_NET" + DNP3_CLIENT: "$HOME_NET" + MODBUS_CLIENT: "$HOME_NET" + MODBUS_SERVER: "$HOME_NET" + ENIP_CLIENT: "$HOME_NET" + ENIP_SERVER: "$HOME_NET" -# If suricata box is a router for the sniffed networks, set it to 'router'. If -# it is a pure sniffing setup, set it to 'sniffer-only'. -# If set to auto, the variable is internally switch to 'router' in IPS mode -# and 'sniffer-only' in IDS mode. -# This feature is currently only used by the reject* keywords. -host-mode: auto + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + ORACLE_PORTS: 1521 + SSH_PORTS: 22 + DNP3_PORTS: 20000 + MODBUS_PORTS: 502 -# Run suricata as user and group. -#run-as: -# user: suri -# group: suri -# Default pid file. -# Will use this file if no --pidfile in command options. -#pid-file: /var/run/suricata.pid +## +## Step 2: select the rules to enable or disable +## -# Daemon working directory -# Suricata will change directory to this one if provided -# Default: "/" -#daemon-directory: "/" +default-rule-path: @e_sysconfdir@rules +rule-files: + - botcc.rules + # - botcc.portgrouped.rules + - ciarmy.rules + - compromised.rules + - drop.rules + - dshield.rules +# - emerging-activex.rules + - emerging-attack_response.rules + - emerging-chat.rules + - emerging-current_events.rules + - emerging-dns.rules + - emerging-dos.rules + - emerging-exploit.rules + - emerging-ftp.rules +# - emerging-games.rules +# - emerging-icmp_info.rules +# - emerging-icmp.rules + - emerging-imap.rules +# - emerging-inappropriate.rules +# - emerging-info.rules + - emerging-malware.rules + - emerging-misc.rules + - emerging-mobile_malware.rules + - emerging-netbios.rules + - emerging-p2p.rules + - emerging-policy.rules + - emerging-pop3.rules + - emerging-rpc.rules +# - emerging-scada.rules +# - emerging-scada_special.rules + - emerging-scan.rules +# - emerging-shellcode.rules + - emerging-smtp.rules + - emerging-snmp.rules + - emerging-sql.rules + - emerging-telnet.rules + - emerging-tftp.rules + - emerging-trojan.rules + - emerging-user_agents.rules + - emerging-voip.rules + - emerging-web_client.rules + - emerging-web_server.rules +# - emerging-web_specific_apps.rules + - emerging-worm.rules + - tor.rules +# - decoder-events.rules # available in suricata sources under rules dir +# - stream-events.rules # available in suricata sources under rules dir + - http-events.rules # available in suricata sources under rules dir + - smtp-events.rules # available in suricata sources under rules dir + - dns-events.rules # available in suricata sources under rules dir + - tls-events.rules # available in suricata sources under rules dir +# - modbus-events.rules # available in suricata sources under rules dir +# - app-layer-events.rules # available in suricata sources under rules dir +# - dnp3-events.rules # available in suricata sources under rules dir -# Preallocated size for packet. Default is 1514 which is the classical -# size for pcap on ethernet. You should adjust this value to the highest -# packet size (MTU + hardware header) on your system. -#default-packet-size: 1514 +classification-file: @e_sysconfdir@classification.config +reference-config-file: @e_sysconfdir@reference.config +# threshold-file: @e_sysconfdir@threshold.config + + +## +## Step 3: select outputs to enable +## # The default logging directory. Any log or output file will be -# placed here if its not specified with a full path name. This can be +# placed here if its not specified with a full path name. This can be # overridden with the -l command line parameter. default-log-dir: @e_logdir@ -# Unix command socket can be used to pass commands to suricata. -# An external tool can then connect to get information from suricata -# or trigger some modifications of the engine. Set enabled to yes -# to activate the feature. You can use the filename variable to set -# the file name of the socket. -unix-command: - enabled: no - #filename: custom.socket +# global stats configuration +stats: + enabled: yes + # The interval field (in seconds) controls at what interval + # the loggers are invoked. + interval: 8 # Configure the type of alert (and other) logging you would like. outputs: - # a line based alerts log similar to Snort's fast.log - fast: enabled: yes @@ -82,56 +134,153 @@ outputs: append: yes #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' + + + # hpfeeds output + - alert-hpfeeds: + enabled: yes + host: 104.131.177.234 + ident: suricata + secret: s3cr3t + channel: suricata.events + reconnect: yes # do we reconnect if publish fails ?! + # Extensible Event Format (nicknamed EVE) event log in JSON format - eve-log: - enabled: yes - filetype: regular #regular|syslog|unix_dgram|unix_stream + enabled: @e_enable_evelog@ + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis filename: eve.json + #prefix: "@cee: " # prefix to prepend to each log entry # the following are valid when type: syslog above #identity: "suricata" #facility: local5 #level: Info ## possible levels: Emergency, Alert, Critical, ## Error, Warning, Notice, Info, Debug + #redis: + # server: 127.0.0.1 + # port: 6379 + # mode: list ## possible values: list (default), channel + # key: suricata ## key or channel to use (default to suricata) + # Redis pipelining set up. This will enable to only do a query every + # 'batch-size' events. This should lower the latency induced by network + # connection at the cost of some memory. There is no flushing implemented + # so this setting as to be reserved to high traffic suricata. + # pipelining: + # enabled: yes ## set enable to yes to enable query pipelining + # batch-size: 10 ## number of entry to keep in buffer types: - alert: - # payload: yes # enable dumping payload in Base64 - # payload-printable: yes # enable dumping payload in printable (lossy) format - # packet: yes # enable dumping of packet (without stream segments) - # http: yes # enable dumping of http fields + # payload: yes # enable dumping payload in Base64 + # payload-buffer-size: 4kb # max size of payload buffer to output in eve-log + # payload-printable: yes # enable dumping payload in printable (lossy) format + # packet: yes # enable dumping of packet (without stream segments) + http: yes # enable dumping of http fields + tls: yes # enable dumping of tls fields + ssh: yes # enable dumping of ssh fields + smtp: yes # enable dumping of smtp fields + dnp3: yes # enable dumping of DNP3 fields + vars: yes # enable dumping of flowbits and other vars + + # Enable the logging of tagged packets for rules using the + # "tag" keyword. + tagged-packets: yes + + # HTTP X-Forwarded-For support by adding an extra field or overwriting + # the source or destination IP address (depending on flow direction) + # with the one reported in the X-Forwarded-For HTTP header. This is + # helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. + xff: + enabled: no + # Two operation modes are available, "extra-data" and "overwrite". + mode: extra-data + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For - http: extended: yes # enable this for extended logging information # custom allows additional http fields to be included in eve-log # the example below adds three additional fields when uncommented #custom: [Accept-Encoding, Accept-Language, Authorization] - - dns + - dns: + # control logging of queries and answers + # default yes, no to disable + query: yes # enable logging of DNS queries + answer: yes # enable logging of DNS answers + # control which RR types are logged + # all enabled if custom not specified + #custom: [a, aaaa, cname, mx, ns, ptr, txt] - tls: extended: yes # enable this for extended logging information + # custom allows to control which tls fields that are included + # in eve-log + #custom: [subject, issuer, serial, fingerprint, sni, version, not_before, not_after, certificate, chain] - files: force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums - #- drop + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + #- drop: + # alerts: yes # log alerts that caused drops + # flows: all # start or all: 'start' logs only a single drop + # # per flow direction. All logs each dropped pkt. + - smtp: + #extended: yes # enable this for extended logging information + # this includes: bcc, message-id, subject, x_mailer, user-agent + # custom fields logging from the list: + # reply-to, bcc, message-id, subject, x-mailer, user-agent, received, + # x-originating-ip, in-reply-to, references, importance, priority, + # sensitivity, organization, content-md5, date + #custom: [received, x-mailer, x-originating-ip, relays, reply-to, bcc] + # output md5 of fields: body, subject + # for the body you need to set app-layer.protocols.smtp.mime.body-md5 + # to yes + #md5: [body, subject] + - ssh + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values # bi-directional flows - #- flow + - flow # uni-directional flows - #- newflow + #- netflow + #- dnp3 + # Vars log flowbits and other packet and flow vars + #- vars # alert output for use with Barnyard2 - unified2-alert: - enabled: yes + enabled: no filename: unified2.alert # File size limit. Can be specified in kb, mb, gb. Just a number # is parsed as bytes. #limit: 32mb + # By default unified2 log files have the file creation time (in + # unix epoch format) appended to the filename. Set this to yes to + # disable this behaviour. + #nostamp: no + # Sensor ID field of unified2 alerts. #sensor-id: 0 - # HTTP X-Forwarded-For support by adding the unified2 extra header that - # will contain the actual client IP address or by overwriting the source - # IP address (helpful when inspecting traffic that is being reversed - # proxied). + # Include payload of packets related to alerts. Defaults to true, set to + # false if payload is not required. + #payload: yes + + # HTTP X-Forwarded-For support by adding the unified2 extra header or + # overwriting the source or destination IP address (depending on flow + # direction) with the one reported in the X-Forwarded-For HTTP header. + # This is helpful when reviewing alerts for traffic that is being reverse + # or forward proxied. xff: enabled: no # Two operation modes are available, "extra-data" and "overwrite". Note @@ -139,14 +288,18 @@ outputs: # X-Forwarded-For header is of a different version of the packet # received, it will fall-back to "extra-data" mode. mode: extra-data - # Header name were the actual IP address will be reported, if more than - # one IP address is present, the last IP address will be the one taken - # into consideration. - header: X-Forwarded-For + # Two proxy deployments are supported, "reverse" and "forward". In + # a "reverse" deployment the IP address used is the last one, in a + # "forward" deployment the first IP address is used. + deployment: reverse + # Header name where the actual IP address will be reported, if more + # than one IP address is present, the last IP address will be the + # one taken into consideration. + header: X-Forwarded-For # a line based log of HTTP requests (no alerts) - http-log: - enabled: yes + enabled: no filename: http.log append: yes #extended: yes # enable this for extended logging information @@ -159,9 +312,15 @@ outputs: enabled: no # Log TLS connections. filename: tls.log # File to store TLS logs. append: yes + #extended: yes # Log extended information like fingerprint + #custom: yes # enabled the custom logging format (defined by customformat) + #customformat: "%{%D-%H:%M:%S}t.%z %a:%p -> %A:%P %v %n %d %D" #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' - #extended: yes # Log extended information like fingerprint - certs-log-dir: certs # directory to store the certificates files + + # output module to store certificates chain to disk + - tls-store: + enabled: no + #certs-log-dir: certs # directory to store the certificates files # a line based log of DNS requests and/or replies (no alerts) - dns-log: @@ -201,7 +360,7 @@ outputs: # - encrypted streams after the key exchange # - pcap-log: - enabled: no + enabled: no filename: log.pcap # File size limit. Can be specified in kb, mb, gb. Just a number @@ -212,7 +371,11 @@ outputs: max-files: 2000 mode: normal # normal, multi or sguil. - #sguil-base-dir: /nsm_data/ + + # Directory to place pcap files. If not provided the default log + # directory will be used. Required for "sguil" mode. + #dir: /nsm_data/ + #ts-format: usec # sec or usec second format (default) is filename.sec usec is filename.sec.usec use-stream-depth: no #If set to "yes" packets seen after reaching stream inspection depth are ignored. "no" logs all packets honor-pass-rules: no # If set to "yes", flows in which a pass rule matched will stopped being logged. @@ -234,12 +397,12 @@ outputs: log-packet-header: yes # Stats.log contains data from various counters of the suricata engine. - # The interval field (in seconds) tells after how long output will be written - # on the log file. - stats: enabled: yes filename: stats.log - interval: 8 + totals: yes # stats for all threads merged together + threads: no # per thread stats + #null-values: yes # print counters that have value 0 # a line based alerts log similar to fast.log into syslog - syslog: @@ -265,14 +428,20 @@ outputs: # file "file..meta" is created. # # File extraction depends on a lot of things to be fully done: - # - stream reassembly depth. For optimal results, set this to 0 (unlimited) + # - file-store stream-depth. For optimal results, set this to 0 (unlimited) # - http request / response body sizes. Again set to 0 for optimal results. # - rules that contain the "filestore" keyword. - file-store: enabled: no # set to yes to enable log-dir: files # directory to store the files force-magic: no # force logging magic on all stored files - force-md5: no # force logging of md5 checksums + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + force-filestore: no # force storing of all files + # override global stream-depth for sessions in which we want to + # perform file extraction. Set to 0 for unlimited. + #stream-depth: 0 #waldo: file.waldo # waldo file to store the file_id across runs # output module to log files tracked in a easily parsable json format @@ -283,7 +452,9 @@ outputs: #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram' force-magic: no # force logging magic on all logged files - force-md5: no # force logging of md5 checksums + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] # Log TCP data after stream normalization # 2 types: file or dir. File logs into a single logfile. Dir creates @@ -317,57 +488,60 @@ outputs: scripts: # - script1.lua -# Magic file. The extension .mgc is added to the value here. -#magic-file: /usr/share/file/magic -magic-file: @e_magic_file@ +# Logging configuration. This is not about logging IDS alerts/events, but +# output about what Suricata is doing, like startup messages, errors, etc. +logging: + # The default log level, can be overridden in an output section. + # Note that debug level logging will only be emitted if Suricata was + # compiled with the --enable-debug configure option. + # + # This value is overriden by the SC_LOG_LEVEL env var. + default-log-level: notice -# When running in NFQ inline mode, it is possible to use a simulated -# non-terminal NFQUEUE verdict. -# This permit to do send all needed packet to suricata via this a rule: -# iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE -# And below, you can have your standard filtering ruleset. To activate -# this mode, you need to set mode to 'repeat' -# If you want packet to be sent to another queue after an ACCEPT decision -# set mode to 'route' and set next-queue value. -# On linux >= 3.1, you can set batchcount to a value > 1 to improve performance -# by processing several packets before sending a verdict (worker runmode only). -# On linux >= 3.6, you can set the fail-open option to yes to have the kernel -# accept the packet if suricata is not able to keep pace. -nfq: -# mode: accept -# repeat-mark: 1 -# repeat-mask: 1 -# route-queue: 2 -# batchcount: 20 -# fail-open: yes + # The default output format. Optional parameter, should default to + # something reasonable if not provided. Can be overriden in an + # output section. You can leave this out to get the default. + # + # This value is overriden by the SC_LOG_FORMAT env var. + #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " -#nflog support -nflog: - # netlink multicast group - # (the same as the iptables --nflog-group param) - # Group 0 is used by the kernel, so you can't use it - - group: 2 - # netlink buffer size - buffer-size: 18432 - # put default value here - - group: default - # set number of packet to queue inside kernel - qthreshold: 1 - # set the delay before flushing packet in the queue inside kernel - qtimeout: 100 - # netlink max buffer size - max-size: 20000 + # A regex to filter output. Can be overridden in an output section. + # Defaults to empty (no filter). + # + # This value is overriden by the SC_LOG_OP_FILTER env var. + default-output-filter: + + # Define your logging outputs. If none are defined, or they are all + # disabled you will get the default - console output. + outputs: + - console: + enabled: yes + # type: json + - file: + enabled: yes + level: info + filename: @e_logdir@suricata.log + # type: json + - syslog: + enabled: no + facility: local5 + format: "[%i] <%d> -- " + # type: json + + +## +## Step 4: configure common capture settings +## +## See "Advanced Capture Options" below for more options, including NETMAP +## and PF_RING. +## -# af-packet support -# Set threads to > 1 to use PACKET_FANOUT support +# Linux high speed capture support af-packet: - interface: eth0 - # Number of receive threads (>1 will enable experimental flow pinned - # runmode) - threads: 1 - # Default clusterid. AF_PACKET will load balance packets based on flow. - # All threads/processes that will participate need to have the same - # clusterid. + # Number of receive threads. "auto" uses the number of cores + #threads: auto + # Default clusterid. AF_PACKET will load balance packets based on flow. cluster-id: 99 # Default AF_PACKET cluster type. AF_PACKET can load balance per flow or per hash. # This is only supported for Linux kernel > 3.1 @@ -375,18 +549,42 @@ af-packet: # * cluster_round_robin: round robin load balancing # * cluster_flow: all packets of a given flow are send to the same socket # * cluster_cpu: all packets treated in kernel by a CPU are send to the same socket + # * cluster_qm: all packets linked by network card to a RSS queue are sent to the same + # socket. Requires at least Linux 3.14. + # * cluster_random: packets are sent randomly to sockets but with an equipartition. + # Requires at least Linux 3.14. + # * cluster_rollover: kernel rotates between sockets filling each socket before moving + # to the next. Requires at least Linux 3.10. + # Recommended modes are cluster_flow on most boxes and cluster_cpu or cluster_qm on system + # with capture card using RSS (require cpu affinity tuning and system irq tuning) cluster-type: cluster_flow # In some fragmentation case, the hash can not be computed. If "defrag" is set # to yes, the kernel will do the needed defragmentation before sending the packets. defrag: yes + # After Linux kernel 3.10 it is possible to activate the rollover option: if a socket is + # full then kernel will send the packet on the next socket with room available. This option + # can minimize packet drop and increase the treated bandwidth on single intensive flow. + #rollover: yes # To use the ring feature of AF_PACKET, set 'use-mmap' to yes - use-mmap: yes + #use-mmap: yes + # Lock memory map to avoid it goes to swap. Be careful that over suscribing could lock + # your system + #mmap-locked: yes + # Use experimental tpacket_v3 capture mode, only active if use-mmap is true + #tpacket-v3: yes # Ring size will be computed with respect to max_pending_packets and number # of threads. You can set manually the ring size in number of packets by setting # the following value. If you are using flow cluster-type and have really network - # intensive single-flow you could want to set the ring-size independantly of the number + # intensive single-flow you could want to set the ring-size independently of the number # of threads: #ring-size: 2048 + # Block size is used by tpacket_v3 only. It should set to a value high enough to contain + # a decent number of packets. Size is in bytes so please consider your MTU. It should be + # a power of 2 and it must be multiple of page size (usually 4096). + #block-size: 32768 + # tpacket_v3 block timeout: an open block is passed to userspace if it is not + # filled after block-timeout milliseconds. + #block-timeout: 10 # On busy system, this could help to set it to yes to recover from a packet drop # phase. This will result in some packets (at max a ring flush) being non treated. #use-emergency-flush: yes @@ -407,285 +605,524 @@ af-packet: #checksum-checks: kernel # BPF filter to apply to this interface. The pcap filter syntax apply here. #bpf-filter: port 80 or udp - # You can use the following variables to activate AF_PACKET tap od IPS mode. + # You can use the following variables to activate AF_PACKET tap or IPS mode. # If copy-mode is set to ips or tap, the traffic coming to the current # interface will be copied to the copy-iface interface. If 'tap' is set, the # copy is complete. If 'ips' is set, the packet matching a 'drop' action # will not be copied. #copy-mode: ips #copy-iface: eth1 - - interface: eth1 - threads: 1 - cluster-id: 98 - cluster-type: cluster_flow - defrag: yes - # buffer-size: 32768 - # disable-promisc: no - # Put default values here - - interface: default - #threads: 2 - #use-mmap: yes -legacy: - uricontent: enabled + # Put default values here. These will be used for an interface that is not + # in the list above. + - interface: default + #threads: auto + #use-mmap: no + #rollover: yes + #tpacket-v3: yes -# You can specify a threshold config file by setting "threshold-file" -# to the path of the threshold config file: -# threshold-file: /etc/suricata/threshold.config +# Cross platform libpcap capture support +pcap: + - interface: eth0 + # On Linux, pcap will try to use mmaped capture and will use buffer-size + # as total of memory used by the ring. So set this to something bigger + # than 1% of your bandwidth. + #buffer-size: 16777216 + #bpf-filter: "tcp and port 25" + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # With some accelerator cards using a modified libpcap (like myricom), you + # may want to have the same number of capture threads as the number of capture + # rings. In this case, set up the threads variable to N to start N threads + # listening on the same interface. + #threads: 16 + # set to no to disable promiscuous mode: + #promisc: no + # set snaplen, if not set it defaults to MTU if MTU can be known + # via ioctl call and to full capture if not. + #snaplen: 1518 + # Put default values here + - interface: default + #checksum-checks: auto -# The detection engine builds internal groups of signatures. The engine -# allow us to specify the profile to use for them, to manage memory on an -# efficient way keeping a good performance. For the profile keyword you -# can use the words "low", "medium", "high" or "custom". If you use custom -# make sure to define the values at "- custom-values" as your convenience. -# Usually you would prefer medium/high/low. -# -# "sgh mpm-context", indicates how the staging should allot mpm contexts for -# the signature groups. "single" indicates the use of a single context for -# all the signature group heads. "full" indicates a mpm-context for each -# group head. "auto" lets the engine decide the distribution of contexts -# based on the information the engine gathers on the patterns from each -# group head. -# -# The option inspection-recursion-limit is used to limit the recursive calls -# in the content inspection code. For certain payload-sig combinations, we -# might end up taking too much time in the content inspection code. -# If the argument specified is 0, the engine uses an internally defined -# default limit. On not specifying a value, we use no limits on the recursion. -detect-engine: - - profile: medium - - custom-values: - toclient-src-groups: 2 - toclient-dst-groups: 2 - toclient-sp-groups: 2 - toclient-dp-groups: 3 - toserver-src-groups: 2 - toserver-dst-groups: 4 - toserver-sp-groups: 2 - toserver-dp-groups: 25 - - sgh-mpm-context: auto - - inspection-recursion-limit: 3000 - # When rule-reload is enabled, sending a USR2 signal to the Suricata process - # will trigger a live rule reload. Experimental feature, use with care. - #- rule-reload: true - # If set to yes, the loading of signatures will be made after the capture - # is started. This will limit the downtime in IPS mode. - #- delayed-detect: yes - -# Suricata is multi-threaded. Here the threading can be influenced. -threading: - # On some cpu's/architectures it is beneficial to tie individual threads - # to specific CPU's/CPU cores. In this case all threads are tied to CPU0, - # and each extra CPU/core has one "detect" thread. - # - # On Intel Core2 and Nehalem CPU's enabling this will degrade performance. - # - set-cpu-affinity: no - # Tune cpu affinity of suricata threads. Each family of threads can be bound - # on specific CPUs. - cpu-affinity: - - management-cpu-set: - cpu: [ 0 ] # include only these cpus in affinity settings - - receive-cpu-set: - cpu: [ 0 ] # include only these cpus in affinity settings - - decode-cpu-set: - cpu: [ 0, 1 ] - mode: "balanced" - - stream-cpu-set: - cpu: [ "0-1" ] - - detect-cpu-set: - cpu: [ "all" ] - mode: "exclusive" # run detect threads in these cpus - # Use explicitely 3 threads and don't compute number by using - # detect-thread-ratio variable: - # threads: 3 - prio: - low: [ 0 ] - medium: [ "1-2" ] - high: [ 3 ] - default: "medium" - - verdict-cpu-set: - cpu: [ 0 ] - prio: - default: "high" - - reject-cpu-set: - cpu: [ 0 ] - prio: - default: "low" - - output-cpu-set: - cpu: [ "all" ] - prio: - default: "medium" - # - # By default Suricata creates one "detect" thread per available CPU/CPU core. - # This setting allows controlling this behaviour. A ratio setting of 2 will - # create 2 detect threads for each CPU/CPU core. So for a dual core CPU this - # will result in 4 detect threads. If values below 1 are used, less threads - # are created. So on a dual core CPU a setting of 0.5 results in 1 detect - # thread being created. Regardless of the setting at a minimum 1 detect - # thread will always be created. - # - detect-thread-ratio: 1.5 +# Settings for reading pcap files +pcap-file: + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have checksum tested + checksum-checks: auto -# Cuda configuration. -cuda: - # The "mpm" profile. On not specifying any of these parameters, the engine's - # internal default values are used, which are same as the ones specified in - # in the default conf file. - mpm: - # The minimum length required to buffer data to the gpu. - # Anything below this is MPM'ed on the CPU. - # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. - # A value of 0 indicates there's no limit. - data-buffer-size-min-limit: 0 - # The maximum length for data that we would buffer to the gpu. - # Anything over this is MPM'ed on the CPU. - # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. - data-buffer-size-max-limit: 1500 - # The ring buffer size used by the CudaBuffer API to buffer data. - cudabuffer-buffer-size: 500mb - # The max chunk size that can be sent to the gpu in a single go. - gpu-transfer-size: 50mb - # The timeout limit for batching of packets in microseconds. - batching-timeout: 2000 - # The device to use for the mpm. Currently we don't support load balancing - # on multiple gpus. In case you have multiple devices on your system, you - # can specify the device to use, using this conf. By default we hold 0, to - # specify the first device cuda sees. To find out device-id associated with - # the card(s) on the system run "suricata --list-cuda-cards". - device-id: 0 - # No of Cuda streams used for asynchronous processing. All values > 0 are valid. - # For this option you need a device with Compute Capability > 1.0. - cuda-streams: 2 +# See "Advanced Capture Options" below for more options, including NETMAP +# and PF_RING. -# Select the multi pattern algorithm you want to run for scan/search the -# in the engine. The supported algorithms are b2g, b2gc, b2gm, b3g, wumanber, -# ac and ac-gfbs. -# -# The mpm you choose also decides the distribution of mpm contexts for -# signature groups, specified by the conf - "detect-engine.sgh-mpm-context". -# Selecting "ac" as the mpm would require "detect-engine.sgh-mpm-context" -# to be set to "single", because of ac's memory requirements, unless the -# ruleset is small enough to fit in one's memory, in which case one can -# use "full" with "ac". Rest of the mpms can be run in "full" mode. -# -# There is also a CUDA pattern matcher (only available if Suricata was -# compiled with --enable-cuda: b2g_cuda. Make sure to update your -# max-pending-packets setting above as well if you use b2g_cuda. -mpm-algo: ac +## +## Step 5: App Layer Protocol Configuration +## -# The memory settings for hash size of these algorithms can vary from lowest -# (2048) - low (4096) - medium (8192) - high (16384) - higher (32768) - max -# (65536). The bloomfilter sizes of these algorithms can vary from low (512) - -# medium (1024) - high (2048). -# -# For B2g/B3g algorithms, there is a support for two different scan/search -# algorithms. For B2g the scan algorithms are B2gScan & B2gScanBNDMq, and -# search algorithms are B2gSearch & B2gSearchBNDMq. For B3g scan algorithms -# are B3gScan & B3gScanBNDMq, and search algorithms are B3gSearch & -# B3gSearchBNDMq. +# Configure the app-layer parsers. The protocols section details each +# protocol. # -# For B2g the different scan/search algorithms and, hash and bloom -# filter size settings. For B3g the different scan/search algorithms and, hash -# and bloom filter size settings. For wumanber the hash and bloom filter size -# settings. - -pattern-matcher: - - b2gc: - search-algo: B2gSearchBNDMq - hash-size: low - bf-size: medium - - b2gm: - search-algo: B2gSearchBNDMq - hash-size: low - bf-size: medium - - b2g: - search-algo: B2gSearchBNDMq - hash-size: low - bf-size: medium - - b3g: - search-algo: B3gSearchBNDMq - hash-size: low - bf-size: medium - - wumanber: - hash-size: low - bf-size: medium +# The option "enabled" takes 3 values - "yes", "no", "detection-only". +# "yes" enables both detection and the parser, "no" disables both, and +# "detection-only" enables protocol detection only (parser disabled). +app-layer: + protocols: + tls: + enabled: yes + detection-ports: + dp: 443 -# Defrag settings: + # Completely stop processing TLS/SSL session after the handshake + # completed. If bypass is enabled this will also trigger flow + # bypass. If disabled (the default), TLS/SSL session is still + # tracked for Heartbleed and other anomalies. + #no-reassemble: yes + dcerpc: + enabled: yes + ftp: + enabled: yes + ssh: + enabled: yes + smtp: + enabled: yes + # Configure SMTP-MIME Decoder + mime: + # Decode MIME messages from SMTP transactions + # (may be resource intensive) + # This field supercedes all others because it turns the entire + # process on or off + decode-mime: yes + + # Decode MIME entity bodies (ie. base64, quoted-printable, etc.) + decode-base64: yes + decode-quoted-printable: yes + + # Maximum bytes per header data value stored in the data structure + # (default is 2000) + header-value-depth: 2000 + + # Extract URLs and save in state data structure + extract-urls: yes + # Set to yes to compute the md5 of the mail body. You will then + # be able to journalize it. + body-md5: no + # Configure inspected-tracker for file_data keyword + inspected-tracker: + content-limit: 100000 + content-inspect-min-size: 32768 + content-inspect-window: 4096 + imap: + enabled: detection-only + msn: + enabled: detection-only + smb: + enabled: yes + detection-ports: + dp: 139, 445 + # smb2 detection is disabled internally inside the engine. + #smb2: + # enabled: yes + dns: + # memcaps. Globally and per flow/state. + #global-memcap: 16mb + #state-memcap: 512kb -defrag: - memcap: 32mb - hash-size: 65536 - trackers: 65535 # number of defragmented flows to follow - max-frags: 65535 # number of fragments to keep (higher than trackers) - prealloc: yes - timeout: 60 + # How many unreplied DNS requests are considered a flood. + # If the limit is reached, app-layer-event:dns.flooded; will match. + #request-flood: 500 -# Enable defrag per host settings -# host-config: -# -# - dmz: -# timeout: 30 -# address: [192.168.1.0/24, 127.0.0.0/8, 1.1.1.0/24, 2.2.2.0/24, "1.1.1.1", "2.2.2.2", "::1"] -# -# - lan: -# timeout: 45 -# address: -# - 192.168.0.0/24 -# - 192.168.10.0/24 -# - 172.16.14.0/24 + tcp: + enabled: yes + detection-ports: + dp: 53 + udp: + enabled: yes + detection-ports: + dp: 53 + http: + enabled: yes + # memcap: 64mb -# Flow settings: -# By default, the reserved memory (memcap) for flows is 32MB. This is the limit -# for flow allocation inside the engine. You can change this value to allow -# more memory usage for flows. -# The hash-size determine the size of the hash used to identify flows inside -# the engine, and by default the value is 65536. -# At the startup, the engine can preallocate a number of flows, to get a better -# performance. The number of flows preallocated is 10000 by default. -# emergency-recovery is the percentage of flows that the engine need to -# prune before unsetting the emergency state. The emergency state is activated -# when the memcap limit is reached, allowing to create new flows, but -# prunning them with the emergency timeouts (they are defined below). -# If the memcap is reached, the engine will try to prune flows -# with the default timeouts. If it doens't find a flow to prune, it will set -# the emergency bit and it will try again with more agressive timeouts. -# If that doesn't work, then it will try to kill the last time seen flows -# not in use. -# The memcap can be specified in kb, mb, gb. Just a number indicates it's -# in bytes. + # default-config: Used when no server-config matches + # personality: List of personalities used by default + # request-body-limit: Limit reassembly of request body for inspection + # by http_client_body & pcre /P option. + # response-body-limit: Limit reassembly of response body for inspection + # by file_data, http_server_body & pcre /Q option. + # double-decode-path: Double decode path section of the URI + # double-decode-query: Double decode query section of the URI + # response-body-decompress-layer-limit: + # Limit to how many layers of compression will be + # decompressed. Defaults to 2. + # + # server-config: List of server configurations to use if address matches + # address: List of ip addresses or networks for this block + # personalitiy: List of personalities used by this block + # request-body-limit: Limit reassembly of request body for inspection + # by http_client_body & pcre /P option. + # response-body-limit: Limit reassembly of response body for inspection + # by file_data, http_server_body & pcre /Q option. + # double-decode-path: Double decode path section of the URI + # double-decode-query: Double decode query section of the URI + # + # uri-include-all: Include all parts of the URI. By default the + # 'scheme', username/password, hostname and port + # are excluded. Setting this option to true adds + # all of them to the normalized uri as inspected + # by http_uri, urilen, pcre with /U and the other + # keywords that inspect the normalized uri. + # Note that this does not affect http_raw_uri. + # Also, note that including all was the default in + # 1.4 and 2.0beta1. + # + # meta-field-limit: Hard size limit for request and response size + # limits. Applies to request line and headers, + # response line and headers. Does not apply to + # request or response bodies. Default is 18k. + # If this limit is reached an event is raised. + # + # Currently Available Personalities: + # Minimal, Generic, IDS (default), IIS_4_0, IIS_5_0, IIS_5_1, IIS_6_0, + # IIS_7_0, IIS_7_5, Apache_2 + libhtp: + default-config: + personality: IDS -flow: - memcap: 64mb - hash-size: 65536 - prealloc: 10000 - emergency-recovery: 30 - #managers: 1 # default to one flow manager - #recyclers: 1 # default to one flow recycler thread + # Can be specified in kb, mb, gb. Just a number indicates + # it's in bytes. + request-body-limit: 100kb + response-body-limit: 100kb -# This option controls the use of vlan ids in the flow (and defrag) -# hashing. Normally this should be enabled, but in some (broken) -# setups where both sides of a flow are not tagged with the same vlan -# tag, we can ignore the vlan id's in the flow hashing. -vlan: - use-for-tracking: true + # inspection limits + request-body-minimal-inspect-size: 32kb + request-body-inspect-window: 4kb + response-body-minimal-inspect-size: 40kb + response-body-inspect-window: 16kb -# Specific timeouts for flows. Here you can specify the timeouts that the -# active flows will wait to transit from the current state to another, on each -# protocol. The value of "new" determine the seconds to wait after a hanshake or -# stream startup before the engine free the data of that flow it doesn't -# change the state to established (usually if we don't receive more packets -# of that flow). The value of "established" is the amount of -# seconds that the engine will wait to free the flow if it spend that amount -# without receiving new packets or closing the connection. "closed" is the -# amount of time to wait after a flow is closed (usually zero). -# -# There's an emergency mode that will become active under attack circumstances, -# making the engine to check flow status faster. This configuration variables -# use the prefix "emergency-" and work similar as the normal ones. -# Some timeouts doesn't apply to all the protocols, like "closed", for udp and -# icmp. + # response body decompression (0 disables) + response-body-decompress-layer-limit: 2 + + # auto will use http-body-inline mode in IPS mode, yes or no set it statically + http-body-inline: auto + + # Take a random value for inspection sizes around the specified value. + # This lower the risk of some evasion technics but could lead + # detection change between runs. It is set to 'yes' by default. + #randomize-inspection-sizes: yes + # If randomize-inspection-sizes is active, the value of various + # inspection size will be choosen in the [1 - range%, 1 + range%] + # range + # Default value of randomize-inspection-range is 10. + #randomize-inspection-range: 10 + + # decoding + double-decode-path: no + double-decode-query: no + + server-config: + + #- apache: + # address: [192.168.1.0/24, 127.0.0.0/8, "::1"] + # personality: Apache_2 + # # Can be specified in kb, mb, gb. Just a number indicates + # # it's in bytes. + # request-body-limit: 4096 + # response-body-limit: 4096 + # double-decode-path: no + # double-decode-query: no + + #- iis7: + # address: + # - 192.168.0.0/24 + # - 192.168.10.0/24 + # personality: IIS_7_0 + # # Can be specified in kb, mb, gb. Just a number indicates + # # it's in bytes. + # request-body-limit: 4096 + # response-body-limit: 4096 + # double-decode-path: no + # double-decode-query: no + + # Note: Modbus probe parser is minimalist due to the poor significant field + # Only Modbus message length (greater than Modbus header length) + # And Protocol ID (equal to 0) are checked in probing parser + # It is important to enable detection port and define Modbus port + # to avoid false positive + modbus: + # How many unreplied Modbus requests are considered a flood. + # If the limit is reached, app-layer-event:modbus.flooded; will match. + #request-flood: 500 + + enabled: no + detection-ports: + dp: 502 + # According to MODBUS Messaging on TCP/IP Implementation Guide V1.0b, it + # is recommended to keep the TCP connection opened with a remote device + # and not to open and close it for each MODBUS/TCP transaction. In that + # case, it is important to set the depth of the stream reassembling as + # unlimited (stream.reassembly.depth: 0) + + # Stream reassembly size for modbus. By default track it completely. + stream-depth: 0 + + # DNP3 + dnp3: + enabled: no + detection-ports: + dp: 20000 + + # SCADA EtherNet/IP and CIP protocol support + enip: + enabled: no + detection-ports: + dp: 44818 + sp: 44818 + +# Limit for the maximum number of asn1 frames to decode (default 256) +asn1-max-frames: 256 + + +############################################################################## +## +## Advanced settings below +## +############################################################################## + +## +## Run Options +## + +# Run suricata as user and group. +#run-as: +# user: suri +# group: suri + +# Some logging module will use that name in event as identifier. The default +# value is the hostname +#sensor-name: suricata + +# Default pid file. +# Will use this file if no --pidfile in command options. +#pid-file: @e_rundir@suricata.pid + +# Daemon working directory +# Suricata will change directory to this one if provided +# Default: "/" +#daemon-directory: "/" + +# Suricata core dump configuration. Limits the size of the core dump file to +# approximately max-dump. The actual core dump size will be a multiple of the +# page size. Core dumps that would be larger than max-dump are truncated. On +# Linux, the actual core dump size may be a few pages larger than max-dump. +# Setting max-dump to 0 disables core dumping. +# Setting max-dump to 'unlimited' will give the full core dump file. +# On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size +# to be 'unlimited'. + +coredump: + max-dump: unlimited + +# If suricata box is a router for the sniffed networks, set it to 'router'. If +# it is a pure sniffing setup, set it to 'sniffer-only'. +# If set to auto, the variable is internally switch to 'router' in IPS mode +# and 'sniffer-only' in IDS mode. +# This feature is currently only used by the reject* keywords. +host-mode: auto + +# Number of packets preallocated per thread. The default is 1024. A higher number +# will make sure each CPU will be more easily kept busy, but may negatively +# impact caching. +# +# If you are using the CUDA pattern matcher (mpm-algo: ac-cuda), different rules +# apply. In that case try something like 60000 or more. This is because the CUDA +# pattern matcher buffers and scans as many packets as possible in parallel. +#max-pending-packets: 1024 + +# Runmode the engine should use. Please check --list-runmodes to get the available +# runmodes for each packet acquisition method. Defaults to "autofp" (auto flow pinned +# load balancing). +#runmode: autofp + +# Specifies the kind of flow load balancer used by the flow pinned autofp mode. +# +# Supported schedulers are: +# +# round-robin - Flows assigned to threads in a round robin fashion. +# active-packets - Flows assigned to threads that have the lowest number of +# unprocessed packets (default). +# hash - Flow alloted usihng the address hash. More of a random +# technique. Was the default in Suricata 1.2.1 and older. +# +#autofp-scheduler: active-packets + +# Preallocated size for packet. Default is 1514 which is the classical +# size for pcap on ethernet. You should adjust this value to the highest +# packet size (MTU + hardware header) on your system. +#default-packet-size: 1514 + +# Unix command socket can be used to pass commands to suricata. +# An external tool can then connect to get information from suricata +# or trigger some modifications of the engine. Set enabled to yes +# to activate the feature. In auto mode, the feature will only be +# activated in live capture mode. You can use the filename variable to set +# the file name of the socket. +unix-command: + enabled: auto + #filename: custom.socket + +# Magic file. The extension .mgc is added to the value here. +#magic-file: /usr/share/file/magic +@e_magic_file_comment@magic-file: @e_magic_file@ + +legacy: + uricontent: enabled + + +## +## Detection settings +## + +# Set the order of alerts bassed on actions +# The default order is pass, drop, reject, alert +# action-order: +# - pass +# - drop +# - reject +# - alert + +# IP Reputation +#reputation-categories-file: @e_sysconfdir@iprep/categories.txt +#default-reputation-path: @e_sysconfdir@iprep +#reputation-files: +# - reputation.list + +# When run with the option --engine-analysis, the engine will read each of +# the parameters below, and print reports for each of the enabled sections +# and exit. The reports are printed to a file in the default log dir +# given by the parameter "default-log-dir", with engine reporting +# subsection below printing reports in its own report file. +engine-analysis: + # enables printing reports for fast-pattern for every rule. + rules-fast-pattern: yes + # enables printing reports for each rule + rules: yes + +#recursion and match limits for PCRE where supported +pcre: + match-limit: 3500 + match-limit-recursion: 1500 + +## +## Advanced Traffic Tracking and Reconstruction Settings +## + +# Host specific policies for defragmentation and TCP stream +# reassembly. The host OS lookup is done using a radix tree, just +# like a routing table so the most specific entry matches. +host-os-policy: + # Make the default policy windows. + windows: [0.0.0.0/0] + bsd: [] + bsd-right: [] + old-linux: [] + linux: [] + old-solaris: [] + solaris: [] + hpux10: [] + hpux11: [] + irix: [] + macos: [] + vista: [] + windows2k3: [] + +# Defrag settings: + +defrag: + memcap: 32mb + hash-size: 65536 + trackers: 65535 # number of defragmented flows to follow + max-frags: 65535 # number of fragments to keep (higher than trackers) + prealloc: yes + timeout: 60 + +# Enable defrag per host settings +# host-config: +# +# - dmz: +# timeout: 30 +# address: [192.168.1.0/24, 127.0.0.0/8, 1.1.1.0/24, 2.2.2.0/24, "1.1.1.1", "2.2.2.2", "::1"] +# +# - lan: +# timeout: 45 +# address: +# - 192.168.0.0/24 +# - 192.168.10.0/24 +# - 172.16.14.0/24 + +# Flow settings: +# By default, the reserved memory (memcap) for flows is 32MB. This is the limit +# for flow allocation inside the engine. You can change this value to allow +# more memory usage for flows. +# The hash-size determine the size of the hash used to identify flows inside +# the engine, and by default the value is 65536. +# At the startup, the engine can preallocate a number of flows, to get a better +# performance. The number of flows preallocated is 10000 by default. +# emergency-recovery is the percentage of flows that the engine need to +# prune before unsetting the emergency state. The emergency state is activated +# when the memcap limit is reached, allowing to create new flows, but +# prunning them with the emergency timeouts (they are defined below). +# If the memcap is reached, the engine will try to prune flows +# with the default timeouts. If it doens't find a flow to prune, it will set +# the emergency bit and it will try again with more agressive timeouts. +# If that doesn't work, then it will try to kill the last time seen flows +# not in use. +# The memcap can be specified in kb, mb, gb. Just a number indicates it's +# in bytes. + +flow: + memcap: 128mb + hash-size: 65536 + prealloc: 10000 + emergency-recovery: 30 + #managers: 1 # default to one flow manager + #recyclers: 1 # default to one flow recycler thread + +# This option controls the use of vlan ids in the flow (and defrag) +# hashing. Normally this should be enabled, but in some (broken) +# setups where both sides of a flow are not tagged with the same vlan +# tag, we can ignore the vlan id's in the flow hashing. +vlan: + use-for-tracking: true + +# Specific timeouts for flows. Here you can specify the timeouts that the +# active flows will wait to transit from the current state to another, on each +# protocol. The value of "new" determine the seconds to wait after a hanshake or +# stream startup before the engine free the data of that flow it doesn't +# change the state to established (usually if we don't receive more packets +# of that flow). The value of "established" is the amount of +# seconds that the engine will wait to free the flow if it spend that amount +# without receiving new packets or closing the connection. "closed" is the +# amount of time to wait after a flow is closed (usually zero). "bypassed" +# timeout controls locally bypassed flows. For these flows we don't do any other +# tracking. If no packets have been seen after this timeout, the flow is discarded. +# +# There's an emergency mode that will become active under attack circumstances, +# making the engine to check flow status faster. This configuration variables +# use the prefix "emergency-" and work similar as the normal ones. +# Some timeouts doesn't apply to all the protocols, like "closed", for udp and +# icmp. flow-timeouts: @@ -693,26 +1130,34 @@ flow-timeouts: new: 30 established: 300 closed: 0 + bypassed: 100 emergency-new: 10 emergency-established: 100 emergency-closed: 0 + emergency-bypassed: 50 tcp: new: 60 - established: 3600 - closed: 120 - emergency-new: 10 - emergency-established: 300 - emergency-closed: 20 + established: 600 + closed: 60 + bypassed: 100 + emergency-new: 5 + emergency-established: 100 + emergency-closed: 10 + emergency-bypassed: 50 udp: new: 30 established: 300 + bypassed: 100 emergency-new: 10 emergency-established: 100 + emergency-bypassed: 50 icmp: new: 30 established: 300 + bypassed: 100 emergency-new: 10 emergency-established: 100 + emergency-bypassed: 50 # Stream engine settings. Here the TCP stream tracking and reassembly # engine is configured. @@ -734,6 +1179,7 @@ flow-timeouts: # async-oneside: false # don't enable async stream handling # inline: no # stream inline mode # max-synack-queued: 5 # Max different SYN/ACKs to queue +# bypass: no # Bypass packets when stream.depth is reached # # reassembly: # memcap: 64mb # Can be specified in kb, mb, gb. Just a number @@ -752,9 +1198,10 @@ flow-timeouts: # # This lower the risk of some evasion technics but could lead # # detection change between runs. It is set to 'yes' by default. # randomize-chunk-range: 10 # If randomize-chunk-size is active, the value of chunk-size is -# # a random value between (1 - randomize-chunk-range/100)*randomize-chunk-size -# # and (1 + randomize-chunk-range/100)*randomize-chunk-size. Default value -# # of randomize-chunk-range is 10. +# # a random value between (1 - randomize-chunk-range/100)*toserver-chunk-size +# # and (1 + randomize-chunk-range/100)*toserver-chunk-size and the same +# # calculation for toclient-chunk-size. +# # Default value of randomize-chunk-range is 10. # # raw: yes # 'Raw' reassembly enabled or disabled. # # raw is for content inspection by detection @@ -766,13 +1213,18 @@ flow-timeouts: # - size: 4 # Size of the (data)segment for a pool # prealloc: 256 # Number of segments to prealloc and keep # # in the pool. +# zero-copy-size: 128 # This option sets in bytes the value at +# # which segment data is passed to the app +# # layer API directly. Data sizes equal to +# # and higher than the value set are passed +# # on directly. # stream: - memcap: 32mb + memcap: 64mb checksum-validation: yes # reject wrong csums inline: auto # auto will use inline mode in IPS mode, yes or no set it statically reassembly: - memcap: 128mb + memcap: 256mb depth: 1mb # reassemble 1mb into a stream toserver-chunk-size: 2560 toclient-chunk-size: 2560 @@ -793,10 +1245,13 @@ stream: # prealloc: 512 # - size: 768 # prealloc: 1024 - # - size: 1448 + # 'from_mtu' means that the size is mtu - 40, + # or 1460 if mtu couldn't be determined. + # - size: from_mtu # prealloc: 1024 # - size: 65535 # prealloc: 128 + #zero-copy-size: 128 # Host table: # @@ -805,494 +1260,165 @@ stream: host: hash-size: 4096 prealloc: 1000 - memcap: 16777216 - -# Logging configuration. This is not about logging IDS alerts, but -# IDS output about what its doing, errors, etc. -logging: - - # The default log level, can be overridden in an output section. - # Note that debug level logging will only be emitted if Suricata was - # compiled with the --enable-debug configure option. - # - # This value is overriden by the SC_LOG_LEVEL env var. - default-log-level: notice - - # The default output format. Optional parameter, should default to - # something reasonable if not provided. Can be overriden in an - # output section. You can leave this out to get the default. - # - # This value is overriden by the SC_LOG_FORMAT env var. - #default-log-format: "[%i] %t - (%f:%l) <%d> (%n) -- " - - # A regex to filter output. Can be overridden in an output section. - # Defaults to empty (no filter). - # - # This value is overriden by the SC_LOG_OP_FILTER env var. - default-output-filter: - - # Define your logging outputs. If none are defined, or they are all - # disabled you will get the default - console output. - outputs: - - console: - enabled: yes - - file: - enabled: no - filename: /var/log/suricata.log - - syslog: - enabled: no - facility: local5 - format: "[%i] <%d> -- " - -# Tilera mpipe configuration. for use on Tilera TILE-Gx. -mpipe: - - # Load balancing modes: "static", "dynamic", "sticky", or "round-robin". - load-balance: dynamic - - # Number of Packets in each ingress packet queue. Must be 128, 512, 2028 or 65536 - iqueue-packets: 2048 - - # List of interfaces we will listen on. - inputs: - - interface: xgbe2 - - interface: xgbe3 - - interface: xgbe4 - - - # Relative weight of memory for packets of each mPipe buffer size. - stack: - size128: 0 - size256: 9 - size512: 0 - size1024: 0 - size1664: 7 - size4096: 0 - size10386: 0 - size16384: 0 - -# PF_RING configuration. for use with native PF_RING support -# for more info see http://www.ntop.org/PF_RING.html -pfring: - - interface: eth0 - # Number of receive threads (>1 will enable experimental flow pinned - # runmode) - threads: 1 - - # Default clusterid. PF_RING will load balance packets based on flow. - # All threads/processes that will participate need to have the same - # clusterid. - cluster-id: 99 - - # Default PF_RING cluster type. PF_RING can load balance per flow or per hash. - # This is only supported in versions of PF_RING > 4.1.1. - cluster-type: cluster_flow - # bpf filter for this interface - #bpf-filter: tcp - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - rxonly: only compute checksum for packets received by network card. - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: auto - # Second interface - #- interface: eth1 - # threads: 3 - # cluster-id: 93 - # cluster-type: cluster_flow - # Put default values here - - interface: default - #threads: 2 - -pcap: - - interface: eth0 - # On Linux, pcap will try to use mmaped capture and will use buffer-size - # as total of memory used by the ring. So set this to something bigger - # than 1% of your bandwidth. - #buffer-size: 16777216 - #bpf-filter: "tcp and port 25" - # Choose checksum verification mode for the interface. At the moment - # of the capture, some packets may be with an invalid checksum due to - # offloading to the network card of the checksum computation. - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have any validation - #checksum-checks: auto - # With some accelerator cards using a modified libpcap (like myricom), you - # may want to have the same number of capture threads as the number of capture - # rings. In this case, set up the threads variable to N to start N threads - # listening on the same interface. - #threads: 16 - # set to no to disable promiscuous mode: - #promisc: no - # set snaplen, if not set it defaults to MTU if MTU can be known - # via ioctl call and to full capture if not. - #snaplen: 1518 - # Put default values here - - interface: default - #checksum-checks: auto - -pcap-file: - # Possible values are: - # - yes: checksum validation is forced - # - no: checksum validation is disabled - # - auto: suricata uses a statistical approach to detect when - # checksum off-loading is used. (default) - # Warning: 'checksum-validation' must be set to yes to have checksum tested - checksum-checks: auto + memcap: 32mb -# For FreeBSD ipfw(8) divert(4) support. -# Please make sure you have ipfw_load="YES" and ipdivert_load="YES" -# in /etc/loader.conf or kldload'ing the appropriate kernel modules. -# Additionally, you need to have an ipfw rule for the engine to see -# the packets from ipfw. For Example: +# IP Pair table: # -# ipfw add 100 divert 8000 ip from any to any +# Used by xbits 'ippair' tracking. # -# The 8000 above should be the same number you passed on the command -# line, i.e. -d 8000 -# -ipfw: - - # Reinject packets at the specified ipfw rule number. This config - # option is the ipfw rule number AT WHICH rule processing continues - # in the ipfw processing system after the engine has finished - # inspecting the packet for acceptance. If no rule number is specified, - # accepted packets are reinjected at the divert rule which they entered - # and IPFW rule processing continues. No check is done to verify - # this will rule makes sense so care must be taken to avoid loops in ipfw. - # - ## The following example tells the engine to reinject packets - # back into the ipfw firewall AT rule number 5500: - # - # ipfw-reinjection-rule-number: 5500 - -# Set the default rule path here to search for the files. -# if not set, it will look at the current working dir -default-rule-path: @e_sysconfdir@rules -rule-files: - - botcc.rules - - ciarmy.rules - - compromised.rules - - drop.rules - - dshield.rules - - emerging-activex.rules - - emerging-attack_response.rules - - emerging-chat.rules - - emerging-current_events.rules - - emerging-dns.rules - - emerging-dos.rules - - emerging-exploit.rules - - emerging-ftp.rules - - emerging-games.rules - - emerging-icmp_info.rules -# - emerging-icmp.rules - - emerging-imap.rules - - emerging-inappropriate.rules - - emerging-malware.rules - - emerging-misc.rules - - emerging-mobile_malware.rules - - emerging-netbios.rules - - emerging-p2p.rules - - emerging-policy.rules - - emerging-pop3.rules - - emerging-rpc.rules - - emerging-scada.rules - - emerging-scan.rules - - emerging-shellcode.rules - - emerging-smtp.rules - - emerging-snmp.rules - - emerging-sql.rules - - emerging-telnet.rules - - emerging-tftp.rules - - emerging-trojan.rules - - emerging-user_agents.rules - - emerging-voip.rules - - emerging-web_client.rules - - emerging-web_server.rules - - emerging-web_specific_apps.rules - - emerging-worm.rules - - tor.rules - - decoder-events.rules # available in suricata sources under rules dir - - stream-events.rules # available in suricata sources under rules dir - - http-events.rules # available in suricata sources under rules dir - - smtp-events.rules # available in suricata sources under rules dir - - dns-events.rules # available in suricata sources under rules dir - - tls-events.rules # available in suricata sources under rules dir - -classification-file: @e_sysconfdir@classification.config -reference-config-file: @e_sysconfdir@reference.config - -# Holds variables that would be used by the engine. -vars: - - # Holds the address group vars that would be passed in a Signature. - # These would be retrieved during the Signature address parsing stage. - address-groups: - - HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" - - EXTERNAL_NET: "!$HOME_NET" - - HTTP_SERVERS: "$HOME_NET" - - SMTP_SERVERS: "$HOME_NET" - - SQL_SERVERS: "$HOME_NET" - - DNS_SERVERS: "$HOME_NET" - - TELNET_SERVERS: "$HOME_NET" - - AIM_SERVERS: "$EXTERNAL_NET" - - DNP3_SERVER: "$HOME_NET" - - DNP3_CLIENT: "$HOME_NET" - - MODBUS_CLIENT: "$HOME_NET" - - MODBUS_SERVER: "$HOME_NET" - - ENIP_CLIENT: "$HOME_NET" - - ENIP_SERVER: "$HOME_NET" - - # Holds the port group vars that would be passed in a Signature. - # These would be retrieved during the Signature port parsing stage. - port-groups: - - HTTP_PORTS: "80" - - SHELLCODE_PORTS: "!80" - - ORACLE_PORTS: 1521 - - SSH_PORTS: 22 - - DNP3_PORTS: 20000 - -# Set the order of alerts bassed on actions -# The default order is pass, drop, reject, alert -# action-order: -# - pass -# - drop -# - reject -# - alert - -# IP Reputation -#reputation-categories-file: @e_sysconfdir@iprep/categories.txt -#default-reputation-path: @e_sysconfdir@iprep -#reputation-files: -# - reputation.list - -# Host specific policies for defragmentation and TCP stream -# reassembly. The host OS lookup is done using a radix tree, just -# like a routing table so the most specific entry matches. -host-os-policy: - # Make the default policy windows. - windows: [0.0.0.0/0] - bsd: [] - bsd-right: [] - old-linux: [] - linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"] - old-solaris: [] - solaris: ["::1"] - hpux10: [] - hpux11: [] - irix: [] - macos: [] - vista: [] - windows2k3: [] - - -# Limit for the maximum number of asn1 frames to decode (default 256) -asn1-max-frames: 256 - -# When run with the option --engine-analysis, the engine will read each of -# the parameters below, and print reports for each of the enabled sections -# and exit. The reports are printed to a file in the default log dir -# given by the parameter "default-log-dir", with engine reporting -# subsection below printing reports in its own report file. -engine-analysis: - # enables printing reports for fast-pattern for every rule. - rules-fast-pattern: yes - # enables printing reports for each rule - rules: yes - -#recursion and match limits for PCRE where supported -pcre: - match-limit: 3500 - match-limit-recursion: 1500 - -# Holds details on the app-layer. The protocols section details each protocol. -# Under each protocol, the default value for detection-enabled and " -# parsed-enabled is yes, unless specified otherwise. -# Each protocol covers enabling/disabling parsers for all ipprotos -# the app-layer protocol runs on. For example "dcerpc" refers to the tcp -# version of the protocol as well as the udp version of the protocol. -# The option "enabled" takes 3 values - "yes", "no", "detection-only". -# "yes" enables both detection and the parser, "no" disables both, and -# "detection-only" enables detection only(parser disabled). -app-layer: - protocols: - tls: - enabled: yes - detection-ports: - dp: 443 - - #no-reassemble: yes - dcerpc: - enabled: yes - ftp: - enabled: yes - ssh: - enabled: yes - smtp: - enabled: yes - imap: - enabled: detection-only - msn: - enabled: detection-only - smb: - enabled: yes - detection-ports: - dp: 139 - # smb2 detection is disabled internally inside the engine. - #smb2: - # enabled: yes - dns: - # memcaps. Globally and per flow/state. - #global-memcap: 16mb - #state-memcap: 512kb - - # How many unreplied DNS requests are considered a flood. - # If the limit is reached, app-layer-event:dns.flooded; will match. - #request-flood: 500 +#ippair: +# hash-size: 4096 +# prealloc: 1000 +# memcap: 32mb - tcp: - enabled: yes - detection-ports: - dp: 53 - udp: - enabled: yes - detection-ports: - dp: 53 - http: - enabled: yes - # memcap: 64mb - ########################################################################### - # Configure libhtp. - # - # - # default-config: Used when no server-config matches - # personality: List of personalities used by default - # request-body-limit: Limit reassembly of request body for inspection - # by http_client_body & pcre /P option. - # response-body-limit: Limit reassembly of response body for inspection - # by file_data, http_server_body & pcre /Q option. - # double-decode-path: Double decode path section of the URI - # double-decode-query: Double decode query section of the URI - # - # server-config: List of server configurations to use if address matches - # address: List of ip addresses or networks for this block - # personalitiy: List of personalities used by this block - # request-body-limit: Limit reassembly of request body for inspection - # by http_client_body & pcre /P option. - # response-body-limit: Limit reassembly of response body for inspection - # by file_data, http_server_body & pcre /Q option. - # double-decode-path: Double decode path section of the URI - # double-decode-query: Double decode query section of the URI - # - # uri-include-all: Include all parts of the URI. By default the - # 'scheme', username/password, hostname and port - # are excluded. Setting this option to true adds - # all of them to the normalized uri as inspected - # by http_uri, urilen, pcre with /U and the other - # keywords that inspect the normalized uri. - # Note that this does not affect http_raw_uri. - # Also, note that including all was the default in - # 1.4 and 2.0beta1. - # - # meta-field-limit: Hard size limit for request and response size - # limits. Applies to request line and headers, - # response line and headers. Does not apply to - # request or response bodies. Default is 18k. - # If this limit is reached an event is raised. - # - # Currently Available Personalities: - # Minimal - # Generic - # IDS (default) - # IIS_4_0 - # IIS_5_0 - # IIS_5_1 - # IIS_6_0 - # IIS_7_0 - # IIS_7_5 - # Apache_2 - ########################################################################### - libhtp: +## +## Performance tuning and profiling +## - default-config: - personality: IDS +# The detection engine builds internal groups of signatures. The engine +# allow us to specify the profile to use for them, to manage memory on an +# efficient way keeping a good performance. For the profile keyword you +# can use the words "low", "medium", "high" or "custom". If you use custom +# make sure to define the values at "- custom-values" as your convenience. +# Usually you would prefer medium/high/low. +# +# "sgh mpm-context", indicates how the staging should allot mpm contexts for +# the signature groups. "single" indicates the use of a single context for +# all the signature group heads. "full" indicates a mpm-context for each +# group head. "auto" lets the engine decide the distribution of contexts +# based on the information the engine gathers on the patterns from each +# group head. +# +# The option inspection-recursion-limit is used to limit the recursive calls +# in the content inspection code. For certain payload-sig combinations, we +# might end up taking too much time in the content inspection code. +# If the argument specified is 0, the engine uses an internally defined +# default limit. On not specifying a value, we use no limits on the recursion. +detect: + profile: medium + custom-values: + toclient-groups: 3 + toserver-groups: 25 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 + # If set to yes, the loading of signatures will be made after the capture + # is started. This will limit the downtime in IPS mode. + #delayed-detect: yes + + prefilter: + # default prefiltering setting. "mpm" only creates MPM/fast_pattern + # engines. "auto" also sets up prefilter engines for other keywords. + # Use --list-keywords=all to see which keywords support prefiltering. + default: mpm + + # the grouping values above control how many groups are created per + # direction. Port whitelisting forces that port to get it's own group. + # Very common ports will benefit, as well as ports with many expensive + # rules. + grouping: + #tcp-whitelist: 53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080 + #udp-whitelist: 53, 135, 5060 + + profiling: + # Log the rules that made it past the prefilter stage, per packet + # default is off. The threshold setting determines how many rules + # must have made it past pre-filter for that rule to trigger the + # logging. + #inspect-logging-threshold: 200 + grouping: + dump-to-disk: false + include-rules: false # very verbose + include-mpm-stats: false - # Can be specified in kb, mb, gb. Just a number indicates - # it's in bytes. - request-body-limit: 3072 - response-body-limit: 3072 +# Select the multi pattern algorithm you want to run for scan/search the +# in the engine. +# +# The supported algorithms are: +# "ac" - Aho-Corasick, default implementation +# "ac-bs" - Aho-Corasick, reduced memory implementation +# "ac-cuda" - Aho-Corasick, CUDA implementation +# "ac-ks" - Aho-Corasick, "Ken Steele" variant +# "hs" - Hyperscan, available when built with Hyperscan support +# +# The default mpm-algo value of "auto" will use "hs" if Hyperscan is +# available, "ac" otherwise. +# +# The mpm you choose also decides the distribution of mpm contexts for +# signature groups, specified by the conf - "detect.sgh-mpm-context". +# Selecting "ac" as the mpm would require "detect.sgh-mpm-context" +# to be set to "single", because of ac's memory requirements, unless the +# ruleset is small enough to fit in one's memory, in which case one can +# use "full" with "ac". Rest of the mpms can be run in "full" mode. +# +# There is also a CUDA pattern matcher (only available if Suricata was +# compiled with --enable-cuda: b2g_cuda. Make sure to update your +# max-pending-packets setting above as well if you use b2g_cuda. - # inspection limits - request-body-minimal-inspect-size: 32kb - request-body-inspect-window: 4kb - response-body-minimal-inspect-size: 32kb - response-body-inspect-window: 4kb - # Take a random value for inspection sizes around the specified value. - # This lower the risk of some evasion technics but could lead - # detection change between runs. It is set to 'yes' by default. - #randomize-inspection-sizes: yes - # If randomize-inspection-sizes is active, the value of various - # inspection size will be choosen in the [1 - range%, 1 + range%] - # range - # Default value of randomize-inspection-range is 10. - #randomize-inspection-range: 10 +mpm-algo: auto - # decoding - double-decode-path: no - double-decode-query: no +# Select the matching algorithm you want to use for single-pattern searches. +# +# Supported algorithms are "bm" (Boyer-Moore) and "hs" (Hyperscan, only +# available if Suricata has been built with Hyperscan support). +# +# The default of "auto" will use "hs" if available, otherwise "bm". - server-config: +spm-algo: auto - #- apache: - # address: [192.168.1.0/24, 127.0.0.0/8, "::1"] - # personality: Apache_2 - # # Can be specified in kb, mb, gb. Just a number indicates - # # it's in bytes. - # request-body-limit: 4096 - # response-body-limit: 4096 - # double-decode-path: no - # double-decode-query: no +# Suricata is multi-threaded. Here the threading can be influenced. +threading: + set-cpu-affinity: no + # Tune cpu affinity of threads. Each family of threads can be bound + # on specific CPUs. + # + # These 2 apply to the all runmodes: + # management-cpu-set is used for flow timeout handling, counters + # worker-cpu-set is used for 'worker' threads + # + # Additionally, for autofp these apply: + # receive-cpu-set is used for capture threads + # verdict-cpu-set is used for IPS verdict threads + # + cpu-affinity: + - management-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - receive-cpu-set: + cpu: [ 0 ] # include only these cpus in affinity settings + - worker-cpu-set: + cpu: [ "all" ] + mode: "exclusive" + # Use explicitely 3 threads and don't compute number by using + # detect-thread-ratio variable: + # threads: 3 + prio: + low: [ 0 ] + medium: [ "1-2" ] + high: [ 3 ] + default: "medium" + #- verdict-cpu-set: + # cpu: [ 0 ] + # prio: + # default: "high" + # + # By default Suricata creates one "detect" thread per available CPU/CPU core. + # This setting allows controlling this behaviour. A ratio setting of 2 will + # create 2 detect threads for each CPU/CPU core. So for a dual core CPU this + # will result in 4 detect threads. If values below 1 are used, less threads + # are created. So on a dual core CPU a setting of 0.5 results in 1 detect + # thread being created. Regardless of the setting at a minimum 1 detect + # thread will always be created. + # + detect-thread-ratio: 1.0 - #- iis7: - # address: - # - 192.168.0.0/24 - # - 192.168.10.0/24 - # personality: IIS_7_0 - # # Can be specified in kb, mb, gb. Just a number indicates - # # it's in bytes. - # request-body-limit: 4096 - # response-body-limit: 4096 - # double-decode-path: no - # double-decode-query: no +# Luajit has a strange memory requirement, it's 'states' need to be in the +# first 2G of the process' memory. +# +# 'luajit.states' is used to control how many states are preallocated. +# State use: per detect script: 1 per detect thread. Per output script: 1 per +# script. +luajit: + states: 128 # Profiling settings. Only effective if Suricata has been built with the # the --enable-profiling configure flag. @@ -1313,10 +1439,14 @@ profiling: append: yes # Sort options: ticks, avgticks, checks, matches, maxticks - sort: avgticks + # If commented out all the sort options will be used. + #sort: avgticks - # Limit the number of items printed at exit. - limit: 100 + # Limit the number of sids for which stats are shown at exit (per sort). + limit: 10 + + # output to json + json: @e_enable_evelog@ # per keyword profiling keywords: @@ -1324,6 +1454,12 @@ profiling: filename: keyword_perf.log append: yes + # per rulegroup profiling + rulegroups: + enabled: yes + filename: rule_group_perf.log + append: yes + # packet profiling packets: @@ -1353,17 +1489,181 @@ profiling: filename: pcaplog_stats.log append: yes -# Suricata core dump configuration. Limits the size of the core dump file to -# approximately max-dump. The actual core dump size will be a multiple of the -# page size. Core dumps that would be larger than max-dump are truncated. On -# Linux, the actual core dump size may be a few pages larger than max-dump. -# Setting max-dump to 0 disables core dumping. -# Setting max-dump to 'unlimited' will give the full core dump file. -# On 32-bit Linux, a max-dump value >= ULONG_MAX may cause the core dump size -# to be 'unlimited'. +## +## Netfilter integration +## + +# When running in NFQ inline mode, it is possible to use a simulated +# non-terminal NFQUEUE verdict. +# This permit to do send all needed packet to suricata via this a rule: +# iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE +# And below, you can have your standard filtering ruleset. To activate +# this mode, you need to set mode to 'repeat' +# If you want packet to be sent to another queue after an ACCEPT decision +# set mode to 'route' and set next-queue value. +# On linux >= 3.1, you can set batchcount to a value > 1 to improve performance +# by processing several packets before sending a verdict (worker runmode only). +# On linux >= 3.6, you can set the fail-open option to yes to have the kernel +# accept the packet if suricata is not able to keep pace. +# bypass mark and mask can be used to implement NFQ bypass. If bypass mark is +# set then the NFQ bypass is activated. Suricata will set the bypass mark/mask +# on packet of a flow that need to be bypassed. The Nefilter ruleset has to +# directly accept all packets of a flow once a packet has been marked. +nfq: +# mode: accept +# repeat-mark: 1 +# repeat-mask: 1 +# bypass-mark: 1 +# bypass-mask: 1 +# route-queue: 2 +# batchcount: 20 +# fail-open: yes + +#nflog support +nflog: + # netlink multicast group + # (the same as the iptables --nflog-group param) + # Group 0 is used by the kernel, so you can't use it + - group: 2 + # netlink buffer size + buffer-size: 18432 + # put default value here + - group: default + # set number of packet to queue inside kernel + qthreshold: 1 + # set the delay before flushing packet in the queue inside kernel + qtimeout: 100 + # netlink max buffer size + max-size: 20000 + +## +## Advanced Capture Options +## + +# general settings affecting packet capture +capture: + # disable NIC offloading. It's restored when Suricata exists. + # Enabled by default + #disable-offloading: false + # + # disable checksum validation. Same as setting '-k none' on the + # commandline + #checksum-validation: none + +# Netmap support +# +# Netmap operates with NIC directly in driver, so you need FreeBSD wich have +# built-in netmap support or compile and install netmap module and appropriate +# NIC driver on your Linux system. +# To reach maximum throughput disable all receive-, segmentation-, +# checksum- offloadings on NIC. +# Disabling Tx checksum offloading is *required* for connecting OS endpoint +# with NIC endpoint. +# You can find more information at https://github.com/luigirizzo/netmap +# +netmap: + # To specify OS endpoint add plus sign at the end (e.g. "eth0+") + - interface: eth0 + # Number of receive threads. "auto" uses number of RSS queues on interface. + #threads: auto + # You can use the following variables to activate netmap tap or IPS mode. + # If copy-mode is set to ips or tap, the traffic coming to the current + # interface will be copied to the copy-iface interface. If 'tap' is set, the + # copy is complete. If 'ips' is set, the packet matching a 'drop' action + # will not be copied. + # To specify the OS as the copy-iface (so the OS can route packets, or forward + # to a service running on the same machine) add a plus sign at the end + # (e.g. "copy-iface: eth0+"). Don't forget to set up a symmetrical eth0+ -> eth0 + # for return packets. Hardware checksumming must be *off* on the interface if + # using an OS endpoint (e.g. 'ifconfig eth0 -rxcsum -txcsum -rxcsum6 -txcsum6' for FreeBSD + # or 'ethtool -K eth0 tx off rx off' for Linux). + #copy-mode: tap + #copy-iface: eth3 + # Set to yes to disable promiscuous mode + # disable-promisc: no + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # BPF filter to apply to this interface. The pcap filter syntax apply here. + #bpf-filter: port 80 or udp + #- interface: eth3 + #threads: auto + #copy-mode: tap + #copy-iface: eth2 + # Put default values here + - interface: default + +# PF_RING configuration. for use with native PF_RING support +# for more info see http://www.ntop.org/products/pf_ring/ +pfring: + - interface: eth0 + # Number of receive threads (>1 will enable experimental flow pinned + # runmode) + threads: 1 + + # Default clusterid. PF_RING will load balance packets based on flow. + # All threads/processes that will participate need to have the same + # clusterid. + cluster-id: 99 + + # Default PF_RING cluster type. PF_RING can load balance per flow. + # Possible values are cluster_flow or cluster_round_robin. + cluster-type: cluster_flow + # bpf filter for this interface + #bpf-filter: tcp + # Choose checksum verification mode for the interface. At the moment + # of the capture, some packets may be with an invalid checksum due to + # offloading to the network card of the checksum computation. + # Possible values are: + # - rxonly: only compute checksum for packets received by network card. + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have any validation + #checksum-checks: auto + # Second interface + #- interface: eth1 + # threads: 3 + # cluster-id: 93 + # cluster-type: cluster_flow + # Put default values here + - interface: default + #threads: 2 + +# For FreeBSD ipfw(8) divert(4) support. +# Please make sure you have ipfw_load="YES" and ipdivert_load="YES" +# in /etc/loader.conf or kldload'ing the appropriate kernel modules. +# Additionally, you need to have an ipfw rule for the engine to see +# the packets from ipfw. For Example: +# +# ipfw add 100 divert 8000 ip from any to any +# +# The 8000 above should be the same number you passed on the command +# line, i.e. -d 8000 +# +ipfw: + + # Reinject packets at the specified ipfw rule number. This config + # option is the ipfw rule number AT WHICH rule processing continues + # in the ipfw processing system after the engine has finished + # inspecting the packet for acceptance. If no rule number is specified, + # accepted packets are reinjected at the divert rule which they entered + # and IPFW rule processing continues. No check is done to verify + # this will rule makes sense so care must be taken to avoid loops in ipfw. + # + ## The following example tells the engine to reinject packets + # back into the ipfw firewall AT rule number 5500: + # + # ipfw-reinjection-rule-number: 5500 -coredump: - max-dump: unlimited napatech: # The Host Buffer Allowance for all streams @@ -1378,6 +1678,72 @@ napatech: # The streams to listen on streams: [1, 2, 3] +# Tilera mpipe configuration. for use on Tilera TILE-Gx. +mpipe: + + # Load balancing modes: "static", "dynamic", "sticky", or "round-robin". + load-balance: dynamic + + # Number of Packets in each ingress packet queue. Must be 128, 512, 2028 or 65536 + iqueue-packets: 2048 + + # List of interfaces we will listen on. + inputs: + - interface: xgbe2 + - interface: xgbe3 + - interface: xgbe4 + + + # Relative weight of memory for packets of each mPipe buffer size. + stack: + size128: 0 + size256: 9 + size512: 0 + size1024: 0 + size1664: 7 + size4096: 0 + size10386: 0 + size16384: 0 + +## +## Hardware accelaration +## + +# Cuda configuration. +cuda: + # The "mpm" profile. On not specifying any of these parameters, the engine's + # internal default values are used, which are same as the ones specified in + # in the default conf file. + mpm: + # The minimum length required to buffer data to the gpu. + # Anything below this is MPM'ed on the CPU. + # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. + # A value of 0 indicates there's no limit. + data-buffer-size-min-limit: 0 + # The maximum length for data that we would buffer to the gpu. + # Anything over this is MPM'ed on the CPU. + # Can be specified in kb, mb, gb. Just a number indicates it's in bytes. + data-buffer-size-max-limit: 1500 + # The ring buffer size used by the CudaBuffer API to buffer data. + cudabuffer-buffer-size: 500mb + # The max chunk size that can be sent to the gpu in a single go. + gpu-transfer-size: 50mb + # The timeout limit for batching of packets in microseconds. + batching-timeout: 2000 + # The device to use for the mpm. Currently we don't support load balancing + # on multiple gpus. In case you have multiple devices on your system, you + # can specify the device to use, using this conf. By default we hold 0, to + # specify the first device cuda sees. To find out device-id associated with + # the card(s) on the system run "suricata --list-cuda-cards". + device-id: 0 + # No of Cuda streams used for asynchronous processing. All values > 0 are valid. + # For this option you need a device with Compute Capability > 1.0. + cuda-streams: 2 + +## +## Include other configs +## + # Includes. Files included here will be handled as if they were # inlined in this configuration file. #include: include1.yaml